T5.TextTemplating by Atif Aziz,Mikayla Hutchinson

<PackageReference Include="T5.TextTemplating" Version="1.1.0" />

 Tokeniser

public class Tokeniser
using System; namespace T5.TextTemplating { public class Tokeniser { private readonly string content; private int position; private string value; private State nextState; private Location nextStateLocation; private Location nextStateTagStartLocation; public State State { get; set; } public int Position => position; public string Content => content; public string Value => value; public Location Location { get; set; } public Location TagStartLocation { get; set; } public Location TagEndLocation { get; set; } public Tokeniser(string fileName, string content) { State = State.Content; this.content = content; Location = (nextStateLocation = (nextStateTagStartLocation = new Location(fileName, 1, 1))); } public bool Advance() { value = null; State = nextState; Location = nextStateLocation; TagStartLocation = nextStateTagStartLocation; if (nextState == State.EOF) return false; nextState = GetNextStateAndCurrentValue(); return true; } private State GetNextStateAndCurrentValue() { switch (State) { case State.Expression: case State.Block: case State.Helper: return GetBlockEnd(); case State.Directive: return NextStateInDirective(); case State.Content: return NextStateInContent(); case State.DirectiveName: return GetDirectiveName(); case State.DirectiveValue: return GetDirectiveValue(); default: throw new InvalidOperationException("Unexpected state '" + State + "'"); } } private State GetBlockEnd() { int num = position; while (position < content.Length) { char c = content[position]; nextStateTagStartLocation = nextStateLocation; nextStateLocation = nextStateLocation.AddCol(); switch (c) { case '\r': if (position + 1 < content.Length && content[position + 1] == '\n') position++; nextStateLocation = nextStateLocation.AddLine(); break; case '\n': nextStateLocation = nextStateLocation.AddLine(); break; case '>': if (content[position - 1] == '#' && content[position - 2] != '\\') { value = content.Substring(num, position - num - 1); position++; TagEndLocation = nextStateLocation; if (State != State.Expression && (position += IsNewLine()) > 0) nextStateLocation = nextStateLocation.AddLine(); return State.Content; } break; } position++; } throw new ParserException("Unexpected end of file.", nextStateLocation); } private State GetDirectiveName() { int num = position; while (position < content.Length) { if (!char.IsLetterOrDigit(content[position])) { value = content.Substring(num, position - num); return State.Directive; } nextStateLocation = nextStateLocation.AddCol(); position++; } throw new ParserException("Unexpected end of file.", nextStateLocation); } private State GetDirectiveValue() { int num = position; int num2 = 0; while (position < content.Length) { char c = content[position]; nextStateLocation = nextStateLocation.AddCol(); switch (c) { case '\r': if (position + 1 < content.Length && content[position + 1] == '\n') position++; nextStateLocation = nextStateLocation.AddLine(); break; case '\n': nextStateLocation = nextStateLocation.AddLine(); break; } if (num2 == 0) { if (c == '\'' || c == '"') { num = position; num2 = c; } else if (!char.IsWhiteSpace(c)) { throw new ParserException("Unexpected character '" + c.ToString() + "'. Expecting attribute value.", nextStateLocation); } } else if (c == num2) { value = content.Substring(num + 1, position - num - 1); position++; return State.Directive; } position++; } throw new ParserException("Unexpected end of file.", nextStateLocation); } private State NextStateInContent() { int num = position; while (position < content.Length) { char c = content[position]; nextStateTagStartLocation = nextStateLocation; nextStateLocation = nextStateLocation.AddCol(); switch (c) { case '\r': if (position + 1 < content.Length && content[position + 1] == '\n') position++; nextStateLocation = nextStateLocation.AddLine(); break; case '\n': nextStateLocation = nextStateLocation.AddLine(); break; case '<': if (position + 2 < content.Length && content[position + 1] == '#') { TagEndLocation = nextStateLocation; switch (content[position + 2]) { case '@': nextStateLocation = nextStateLocation.AddCols(2); value = content.Substring(num, position - num); position += 3; return State.Directive; case '=': nextStateLocation = nextStateLocation.AddCols(2); value = content.Substring(num, position - num); position += 3; return State.Expression; case '+': nextStateLocation = nextStateLocation.AddCols(2); value = content.Substring(num, position - num); position += 3; return State.Helper; default: value = content.Substring(num, position - num); nextStateLocation = nextStateLocation.AddCol(); position += 2; return State.Block; } } break; } position++; } value = content.Substring(num); return State.EOF; } private int IsNewLine() { int num = 0; if (position < content.Length && content[position] == '\r') num++; if (position + num < content.Length && content[position + num] == '\n') num++; return num; } private State NextStateInDirective() { while (position < content.Length) { char c = content[position]; switch (c) { case '\r': if (position + 1 < content.Length && content[position + 1] == '\n') position++; nextStateLocation = nextStateLocation.AddLine(); break; case '\n': nextStateLocation = nextStateLocation.AddLine(); break; default: if (char.IsLetter(c)) return State.DirectiveName; switch (c) { case '=': nextStateLocation = nextStateLocation.AddCol(); position++; return State.DirectiveValue; case '#': if (position + 1 < content.Length && content[position + 1] == '>') { position += 2; TagEndLocation = nextStateLocation.AddCols(2); nextStateLocation = nextStateLocation.AddCols(3); if ((position += IsNewLine()) > 0) nextStateLocation = nextStateLocation.AddLine(); return State.Content; } break; } if (!char.IsWhiteSpace(c)) throw new ParserException("Directive ended unexpectedly with character '" + c.ToString() + "'", nextStateLocation); nextStateLocation = nextStateLocation.AddCol(); break; } position++; } throw new ParserException("Unexpected end of file.", nextStateLocation); } } }