public void ShouldIndexStringSegment() { var segment = new StringSegment("012345"); Assert.Equal('0', segment.Index(0)); Assert.Equal('5', segment.Index(-1)); segment = segment.Subsegment(1, 4); Assert.Equal('1', segment.Index(0)); Assert.Equal('4', segment.Index(-1)); }
public bool TryParse(string template, bool stripEmptyLines, out List <Statement> result, out IEnumerable <string> errors) { errors = Array.Empty <string>(); var segment = new StringSegment(template); Parser parser = null; _context = new ParserContext(); result = _context.CurrentBlock.Statements; try { bool trimBefore = false; bool trimAfter = false; int previous = 0, index = 0; Statement s; while (true) { previous = index; if (!MatchTag(segment, index, out var start, out var end)) { index = segment.Length; if (index != previous) { // Consume last Text statement ConsumeTextStatement(segment, previous, index, trimAfter, false, stripEmptyLines); } break; } else { trimBefore = segment.Index(start + 2) == '-'; // Only create a parser if there are tags in the template if (parser == null) { parser = new Parser(_languageData); } if (start != previous) { // Consume current Text statement ConsumeTextStatement(segment, previous, start, trimAfter, trimBefore, stripEmptyLines); } trimAfter = segment.Index(end - 2) == '-'; var tag = segment.Subsegment(start, end - start + 1).ToString(); if (trimAfter || trimBefore) { // Remove the dashes for the parser StringBuilder sb = new StringBuilder(tag); if (trimBefore) { sb[2] = ' '; } if (trimAfter) { sb[end - start - 2] = ' '; } tag = sb.ToString(); } var tree = parser.Parse(tag); if (tree.HasErrors()) { int line = 1, col = 1; for (var i = segment.Offset; i < start; i++) { var ch = segment.Index(i); switch (ch) { case '\n': line++; col = 1; break; case '\r': // Ignore break; default: col++; break; } } errors = tree .ParserMessages .Select(x => $"{x.Message} at line:{line + x.Location.Line}, col:{col + x.Location.Column}") .ToArray(); return(false); } switch (tree.Root.Term.Name) { case "output": s = BuildOutputStatement(tree.Root); break; case "tag": s = BuildTagStatement(tree.Root); break; default: s = null; break; } index = end + 1; // Entered a comment block? if (_isComment) { s = new CommentStatement(ConsumeTag(segment, end + 1, "endcomment", out end)); index = end; } // Entered a raw block? if (_isRaw) { s = new TextStatement(ConsumeTag(segment, end + 1, "endraw", out end)); index = end; } if (s != null) { _context.CurrentBlock.AddStatement(s); } } }