using System; using System.Collections.Generic; namespace luaaaaah; class Tokenizer { private readonly List tokens = []; private State state = State.Start; int? lastIndex; int index; int openingLongBracketLevel; int closingLongBracketLevel; Token? currentToken; CodeLocation currentLocation = new(line: 0, col: 0); public Token[] Tokenize(string content) { if(content.StartsWith("#!")) { content = content[content.IndexOf('\n')..]; } while(index < content.Length) { TokenizeChar(content[index]); if(content[index] == '\n') { currentLocation.line += 1; currentLocation.col = 0; } else { currentLocation.col += 1; } index += 1; } TokenizeChar('\n'); return [.. tokens]; } private void AppendDataChar(char ch) { if((Token.StringData?)currentToken!.data == null) { currentToken!.data = new Token.StringData($"{ch}"); } else { ((Token.StringData?)currentToken!.data!).data += ch; } currentToken.region.end = new(currentLocation); } private void AppendDataInt(char ch) { if((Token.NumeralData?)currentToken!.data == null) { currentToken!.data = new Token.NumeralData(new INumeral.Integer(ch - '0')); } else { ((INumeral.Integer)((Token.NumeralData?)currentToken!.data!).numeral).value *= 10; ((INumeral.Integer)((Token.NumeralData?)currentToken!.data!).numeral).value += ch - '0'; } currentToken.region.end = new(currentLocation); } private void AppendDataIntHex(char ch) { int v = char.IsAsciiDigit(ch) ? ch - '0' : 10 + char.ToLower(ch) - 'a'; if((Token.NumeralData?)currentToken!.data == null) { currentToken!.data = new Token.NumeralData(new INumeral.Integer(v)); } else { ((INumeral.Integer)((Token.NumeralData?)currentToken!.data!).numeral).value *= 16; ((INumeral.Integer)((Token.NumeralData?)currentToken!.data!).numeral).value += v; } currentToken.region.end = new(currentLocation); } private void TokenizeChar(char ch) { switch(state) { case State.Start: { switch(ch) { case '-': { lastIndex = index; state = State.Minus; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Minus); } /* tokenizeTerminalBase(TokenType.Minus, TokenizerState.Minus); */ break; case ',': { lastIndex = index; state = State.Comma; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Comma); } /* tokenizeTerminalBase(TokenType.Comma, TokenizerState.Comma); */ break; case '=': { lastIndex = index; state = State.Equals; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Equals); } /* tokenizeTerminalBase(TokenType.Equals, TokenizerState.Equals); */ break; case '(': { lastIndex = index; state = State.RoundOpen; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.RoundOpen); } /* tokenizeTerminalBase(TokenType.RoundOpen, TokenizerState.RoundOpen); */ break; case ')': { lastIndex = index; state = State.RoundClosed; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.RoundClosed); } /* tokenizeTerminalBase(TokenType.RoundClosed, TokenizerState.RoundClosed); */ break; case '.': { lastIndex = index; state = State.Dot; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Dot); } /* tokenizeTerminalBase(TokenType.Dot, TokenizerState.Dot); */ break; case ':': { lastIndex = index; state = State.Colon; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Colon); } /* tokenizeTerminalBase(TokenType.Colon, TokenizerState.Colon); */ break; case '{': { lastIndex = index; state = State.CurlyOpen; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.CurlyOpen); } /* tokenizeTerminalBase(TokenType.CurlyOpen, TokenizerState.CurlyOpen); */ break; case '}': { lastIndex = index; state = State.CurlyClosed; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.CurlyClosed); } /* tokenizeTerminalBase(TokenType.CurlyClosed, TokenizerState.CurlyClosed); */ break; case '[': { lastIndex = index; state = State.SquareOpen; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.SquareOpen); } /* tokenizeTerminalBase(TokenType.SquareOpen, TokenizerState.SquareOpen); */ break; case ']': { lastIndex = index; state = State.SquareClosed; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.SquareClosed); } /* tokenizeTerminalBase(TokenType.SquareClosed, TokenizerState.SquareClosed); */ break; case '+': { lastIndex = index; state = State.Plus; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Plus); } /* tokenizeTerminalBase(TokenType.Plus, TokenizerState.Plus); */ break; case '~': { lastIndex = index; state = State.Tilde; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Tilde); } /* tokenizeTerminalBase(TokenType.Tilde, TokenizerState.Tilde); */ break; case '>': { lastIndex = index; state = State.Gt; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Gt); } /* tokenizeTerminalBase(TokenType.Gt, TokenizerState.Gt); */ break; case '<': { lastIndex = index; state = State.Lt; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Lt); } /* tokenizeTerminalBase(TokenType.Lt, TokenizerState.Lt); */ break; case '#': { lastIndex = index; state = State.Hash; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Hash); } /* tokenizeTerminalBase(TokenType.Hash, TokenizerState.Hash); */ break; case '|': { lastIndex = index; state = State.Pipe; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Pipe); } /* tokenizeTerminalBase(TokenType.Pipe, TokenizerState.Pipe); */ break; case '&': { lastIndex = index; state = State.Ampersand; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Equals); } /* tokenizeTerminalBase(TokenType.Ampersand, TokenizerState.Ampersand); */ break; case '%': { lastIndex = index; state = State.Percent; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Percent); } /* tokenizeTerminalBase(TokenType.Percent, TokenizerState.Percent); */ break; case '*': { lastIndex = index; state = State.Star; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Star); } /* tokenizeTerminalBase(TokenType.Star, TokenizerState.Star); */ break; case '/': { lastIndex = index; state = State.Slash; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Slash); } /* tokenizeTerminalBase(TokenType.Slash, TokenizerState.Slash); */ break; case ';': { lastIndex = index; state = State.Semicolon; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Semicolon); } /* tokenizeTerminalBase(TokenType.Semicolon, TokenizerState.Semicolon); */ break; case '^': { lastIndex = index; state = State.Caret; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Caret); } /* tokenizeTerminalBase(TokenType.Caret, TokenizerState.Caret); */ break; case 'a': { lastIndex = index; state = State.A; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.A, tokenStr, ch); */ break; case 'b': { lastIndex = index; state = State.B; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.B, tokenStr, ch); */ break; case 'd': { lastIndex = index; state = State.D; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.D, tokenStr, ch); */ break; case 'e': { lastIndex = index; state = State.E; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.E, tokenStr, ch); */ break; case 'f': { lastIndex = index; state = State.F; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.F, tokenStr, ch); */ break; case 'i': { lastIndex = index; state = State.I; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.I, tokenStr, ch); */ break; case 'g': { lastIndex = index; state = State.G; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.G, tokenStr, ch); */ break; case 'l': { lastIndex = index; state = State.L; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.L, tokenStr, ch); */ break; case 'n': { lastIndex = index; state = State.N; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.N, tokenStr, ch); */ break; case 'o': { lastIndex = index; state = State.O; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.O, tokenStr, ch); */ break; case 'r': { lastIndex = index; state = State.R; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.R, tokenStr, ch); */ break; case 't': { lastIndex = index; state = State.T; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.T, tokenStr, ch); */ break; case 'u': { lastIndex = index; state = State.U; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.U, tokenStr, ch); */ break; case 'w': { lastIndex = index; state = State.W; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } /* tokenizeTerminalStr(TokenType.Name, TokenizerState.W, tokenStr, ch); */ break; case '0': { lastIndex = index; state = State.Zero; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Numeral, data: new Token.NumeralData(new INumeral.Integer(0))); } /* tokenizeTerminalIntNum(TokenType.Numeral, TokenizerState.Zero, tokenNumeral, ch); */ break; case '"': { currentToken = null; state = State.Quote; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } break; case '\'': { currentToken = null; state = State.SingleQuote; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } break; default: { if(char.IsWhiteSpace(ch)) { } else if(char.IsAsciiLetter(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Name, data: new Token.StringData($"{ch}")); } else if(char.IsDigit(ch)) { lastIndex = index; state = State.Integer; currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.Numeral, data: new Token.NumeralData(new INumeral.Integer(ch - '0'))); } else { throw new NotImplementedException(ch.ToString()); } } break; } } break; case State.Quote: { if(ch == '\\') { state = State.QuoteBackslash; } else if(ch == '"') { lastIndex = index; state = State.String; if(currentToken == null || currentToken.type == null) { currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } else { currentToken.type = TokenType.StringLiteral; currentToken.region.end = new(currentLocation); } } else { AppendDataChar(ch); } } break; case State.QuoteBackslash: { switch(ch) { case 'a': { AppendDataChar('\u0007'); state = State.Quote; } break; case 'b': { AppendDataChar('\u0008'); state = State.Quote; } break; case 't': { AppendDataChar('\t'); state = State.Quote; } break; case 'n': case '\n': { AppendDataChar('\n'); state = State.Quote; } break; case 'v': { AppendDataChar('\u000b'); state = State.Quote; } break; case 'f': { AppendDataChar('\u000c'); state = State.Quote; } break; case 'r': { AppendDataChar('\r'); state = State.Quote; } break; case '\\': { AppendDataChar('\\'); state = State.Quote; } break; case '"': { AppendDataChar('"'); state = State.Quote; } break; case '\'': { AppendDataChar('\''); state = State.Quote; } break; case 'z': { state = State.QuoteBackslashZ; } break; default: throw new Exception($"Unknown escape sequence: \\{ch}"); } } break; case State.QuoteBackslashZ: { if(ch == '\\') { state = State.QuoteBackslash; } else if(ch == '"') { lastIndex = index; state = State.String; if(currentToken == null || currentToken.type == null) { currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } else { currentToken.type = TokenType.StringLiteral; currentToken.region.end = new(currentLocation); } } else if(!char.IsWhiteSpace(ch)) { AppendDataChar(ch); state = State.Quote; } else { // Noop, https://www.lua.org/manual/5.4/manual.html#3.1: // "The escape sequence '\z' skips the following span of whitespace characters, including line breaks;" } } break; case State.SingleQuote: { if(ch == '\\') { state = State.SingleQuoteBackslash; } else if(ch == '\'') { lastIndex = index; state = State.String; if(currentToken == null || currentToken.type == null) { currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } else { currentToken.type = TokenType.StringLiteral; currentToken.region.end = new(currentLocation); } } else { AppendDataChar(ch); } } break; case State.SingleQuoteBackslash: { switch(ch) { case 'a': { AppendDataChar('\u0007'); state = State.SingleQuote; } break; case 'b': { AppendDataChar('\u0008'); state = State.SingleQuote; } break; case 't': { AppendDataChar('\t'); state = State.SingleQuote; } break; case 'n': case '\n': { AppendDataChar('\n'); state = State.SingleQuote; } break; case 'v': { AppendDataChar('\u000b'); state = State.SingleQuote; } break; case 'f': { AppendDataChar('\u000c'); state = State.SingleQuote; } break; case 'r': { AppendDataChar('\r'); state = State.SingleQuote; } break; case '\\': { AppendDataChar('\\'); state = State.SingleQuote; } break; case '"': { AppendDataChar('"'); state = State.SingleQuote; } break; case '\'': { AppendDataChar('\''); state = State.SingleQuote; } break; case 'z': { state = State.SingleQuoteBackslashZ; } break; default: throw new Exception($"Unknown escape sequence: \\{ch}"); } } break; case State.SingleQuoteBackslashZ: { if(ch == '\\') { state = State.SingleQuoteBackslash; } else if(ch == '\'') { lastIndex = index; state = State.String; if(currentToken == null || currentToken.type == null) { currentToken = new(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); } else { currentToken.type = TokenType.StringLiteral; currentToken.region.end = new(currentLocation); } } else if(!char.IsWhiteSpace(ch)) { AppendDataChar(ch); state = State.Quote; } else { // Noop, https://www.lua.org/manual/5.4/manual.html#3.1: // "The escape sequence '\z' skips the following span of whitespace characters, including line breaks;" } } break; case State.String: { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.StringLiteral; //currentToken.region.end = new(currentLocation); currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } break; case State.Name: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Zero: { if(ch == 'x') { currentToken!.type = null; state = State.HexNumberX; } else if(ch == '.') { state = State.Float; currentToken!.type = null; currentToken!.data = null; AppendDataChar('0'); AppendDataChar('.'); } else if(char.IsAsciiDigit(ch)) { lastIndex = index; AppendDataInt(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Float: { if(char.IsAsciiDigit(ch)) { lastIndex = index; AppendDataChar(ch); } else { if(currentToken == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); currentToken.type = TokenType.Numeral; currentToken.data = new Token.NumeralData(new INumeral.Float(float.Parse(((Token.StringData)currentToken.data!).data))); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.HexNumberX: { if(char.IsAsciiHexDigit(ch)) { lastIndex = index; currentToken!.type = TokenType.Numeral; AppendDataIntHex(ch); state = State.HexNumber; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.HexNumber: { if(ch == 'p') { currentToken!.type = null; state = State.HexExpNumber; } else if(char.IsAsciiHexDigit(ch)) { lastIndex = index; currentToken!.type = TokenType.Numeral; AppendDataIntHex(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Integer: { if(ch == 'e') { currentToken!.type = null; state = State.ExpNumber; } else if(ch == '.') { currentToken!.type = null; currentToken.data = new Token.StringData($"{((INumeral.Integer)((Token.NumeralData)currentToken!.data!).numeral).value}."); state = State.Float; } else if(char.IsAsciiDigit(ch)) { lastIndex = index; currentToken!.type = TokenType.Numeral; AppendDataInt(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.SquareOpen: { if(ch == '[') { currentToken = new Token(region: new(start: new(currentLocation), end: new(currentLocation)), type: TokenType.StringLiteral); state = State.StringWithLongBracket; } else if(ch == '=') { openingLongBracketLevel = 1; state = State.StringStartLongBracket; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Comma: case State.RoundOpen: case State.RoundClosed: case State.CurlyOpen: case State.CurlyClosed: case State.Plus: case State.TildeEquals: case State.EqualsEquals: case State.Hash: case State.GtEquals: case State.LtEquals: case State.SquareClosed: case State.Pipe: case State.Ampersand: case State.Percent: case State.Star: case State.Semicolon: case State.Caret: case State.DotDotDot: case State.GtGt: case State.LtLt: case State.ColonColon: case State.SlashSlash: { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } break; case State.Tilde: { if(ch == '=') { lastIndex = index; state = State.TildeEquals; currentToken!.type = TokenType.TildeEquals; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Gt: { if(ch == '=') { lastIndex = index; state = State.GtEquals; currentToken!.type = TokenType.GtEquals; } else if(ch == '>') { lastIndex = index; state = State.GtGt; currentToken!.type = TokenType.GtGt; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Lt: { if(ch == '=') { lastIndex = index; state = State.LtEquals; currentToken!.type = TokenType.LtEquals; } else if(ch == '<') { lastIndex = index; state = State.LtLt; currentToken!.type = TokenType.LtLt; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Slash: { if(ch == '/') { lastIndex = index; state = State.SlashSlash; currentToken!.type = TokenType.SlashSlash; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Dot: { if(ch == '.') { lastIndex = index; state = State.DotDot; currentToken!.type = TokenType.DotDot; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.DotDot: { if(ch == '.') { lastIndex = index; state = State.DotDotDot; currentToken!.type = TokenType.DotDotDot; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Colon: { if(ch == ':') { lastIndex = index; state = State.ColonColon; currentToken!.type = TokenType.ColonColon; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Equals: { if(ch == '=') { lastIndex = index; state = State.EqualsEquals; currentToken!.type = TokenType.EqualsEquals; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Minus: { if(ch == '-') { lastIndex = index; state = State.SmallCommentStart; currentToken = null; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.SmallCommentStart: { if(ch == '[') { state = State.BigCommentStartLongBracket; } else if(ch == '\n') { state = State.Start; lastIndex = null; } else { state = State.SmallComment; } } break; case State.SmallComment: { if(ch == '\n') { state = State.Start; lastIndex = null; } } break; case State.BigCommentStartLongBracket: { if(ch == '=') { openingLongBracketLevel += 1; } else if(ch == '[') { state = State.BigComment; } else if(ch == '\n') { state = State.Start; } else { state = State.SmallComment; } } break; case State.BigComment: { if(ch == ']') { state = State.BigCommentEndLongBracket; closingLongBracketLevel = 0; } } break; case State.BigCommentEndLongBracket: { if(ch == '=') { closingLongBracketLevel += 1; if(openingLongBracketLevel < closingLongBracketLevel) { state = State.BigComment; } } else if(ch == ']' && openingLongBracketLevel == closingLongBracketLevel) { state = State.Start; openingLongBracketLevel = 0; closingLongBracketLevel = 0; } else { closingLongBracketLevel = 0; } } break; case State.StringStartLongBracket: { if(ch == '=') { openingLongBracketLevel += 1; } else if(ch == '[') { state = State.StringWithLongBracket; } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.StringWithLongBracket: { if(ch == ']') { state = State.StringEndLongBracket; closingLongBracketLevel = 0; } else { AppendDataChar(ch); } } break; case State.StringEndLongBracket: { if(ch == '=') { closingLongBracketLevel += 1; if(openingLongBracketLevel < closingLongBracketLevel) { state = State.StringWithLongBracket; } AppendDataChar(ch); } else if(ch == ']' && openingLongBracketLevel == closingLongBracketLevel) { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } if((Token.StringData?)currentToken.data == null) { currentToken.data = new Token.StringData(""); } currentToken.type = TokenType.StringLiteral; ((Token.StringData)currentToken.data).data = ((Token.StringData)currentToken.data).data.Remove(((Token.StringData)currentToken.data).data.Length - closingLongBracketLevel); currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; lastIndex = null; state = State.Start; openingLongBracketLevel = 0; closingLongBracketLevel = 0; } else { closingLongBracketLevel = 0; AppendDataChar(ch); } } break; case State.A: { if(ch == 'n') { lastIndex = index; state = State.An; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.An: { if(ch == 'd') { lastIndex = index; state = State.And; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.And: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.And; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.W: { if(ch == 'h') { lastIndex = index; state = State.Wh; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Wh: { if(ch == 'i') { lastIndex = index; state = State.Whi; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Whi: { if(ch == 'l') { lastIndex = index; state = State.Whil; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Whil: { if(ch == 'e') { lastIndex = index; state = State.While; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.While: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.While; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.B: { if(ch == 'r') { lastIndex = index; state = State.Br; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Br: { if(ch == 'e') { lastIndex = index; state = State.Bre; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Bre: { if(ch == 'a') { lastIndex = index; state = State.Brea; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Brea: { if(ch == 'k') { lastIndex = index; state = State.Break; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Break: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Break; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.G: { if(ch == 'o') { lastIndex = index; state = State.Go; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Go: { if(ch == 't') { lastIndex = index; state = State.Got; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Got: { if(ch == 'o') { lastIndex = index; state = State.Goto; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Goto: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Goto; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.R: { if(ch == 'e') { lastIndex = index; state = State.Re; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Re: { if(ch == 't') { lastIndex = index; state = State.Ret; AppendDataChar(ch); } else if(ch == 'p') { lastIndex = index; state = State.Rep; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Ret: { if(ch == 'u') { lastIndex = index; state = State.Retu; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Retu: { if(ch == 'r') { lastIndex = index; state = State.Retur; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Retur: { if(ch == 'n') { lastIndex = index; state = State.Return; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Return: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Return; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Rep: { if(ch == 'e') { lastIndex = index; state = State.Repe; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Repe: { if(ch == 'a') { lastIndex = index; state = State.Repea; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Repea: { if(ch == 't') { lastIndex = index; state = State.Repeat; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Repeat: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Repeat; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.N: { if(ch == 'i') { lastIndex = index; state = State.Ni; AppendDataChar(ch); } else if(ch == 'o') { lastIndex = index; state = State.No; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Ni: { if(ch == 'l') { lastIndex = index; state = State.Nil; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Nil: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Nil; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.No: { if(ch == 't') { lastIndex = index; state = State.Not; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Not: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Not; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.T: { if(ch == 'h') { lastIndex = index; state = State.Th; AppendDataChar(ch); } else if(ch == 'r') { lastIndex = index; state = State.Tr; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Th: { if(ch == 'e') { lastIndex = index; state = State.The; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.The: { if(ch == 'n') { lastIndex = index; state = State.Then; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Then: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Then; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Tr: { if(ch == 'u') { lastIndex = index; state = State.Tru; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Tru: { if(ch == 'e') { lastIndex = index; state = State.True; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.True: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.True; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.E: { if(ch == 'l') { lastIndex = index; state = State.El; AppendDataChar(ch); } else if(ch == 'n') { lastIndex = index; state = State.En; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.El: { if(ch == 's') { lastIndex = index; state = State.Els; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Els: { if(ch == 'e') { lastIndex = index; state = State.Else; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Else: { if(ch == 'i') { lastIndex = index; state = State.Elsei; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Else; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Elsei: { if(ch == 'f') { lastIndex = index; state = State.Elseif; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Elseif: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Elseif; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.En: { if(ch == 'd') { lastIndex = index; state = State.End; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.End: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.End; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.O: { if(ch == 'r') { lastIndex = index; state = State.Or; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Or: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Or; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.D: { if(ch == 'o') { lastIndex = index; state = State.Do; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Do: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Do; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.I: { if(ch == 'f') { lastIndex = index; state = State.If; AppendDataChar(ch); } else if(ch == 'n') { lastIndex = index; state = State.In; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.In: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.In; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.If: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.If; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.F: { if(ch == 'u') { lastIndex = index; state = State.Fu; AppendDataChar(ch); } else if(ch == 'a') { lastIndex = index; state = State.Fa; AppendDataChar(ch); } else if(ch == 'o') { lastIndex = index; state = State.Fo; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fu: { if(ch == 'n') { lastIndex = index; state = State.Fun; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fun: { if(ch == 'c') { lastIndex = index; state = State.Func; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Func: { if(ch == 't') { lastIndex = index; state = State.Funct; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Funct: { if(ch == 'i') { lastIndex = index; state = State.Functi; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Functi: { if(ch == 'o') { lastIndex = index; state = State.Functio; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Functio: { if(ch == 'n') { lastIndex = index; state = State.Function; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Function: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Function; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fa: { if(ch == 'l') { lastIndex = index; state = State.Fal; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fal: { if(ch == 's') { lastIndex = index; state = State.Fals; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fals: { if(ch == 'e') { lastIndex = index; state = State.False; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.False: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.False; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Fo: { if(ch == 'r') { lastIndex = index; state = State.For; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.For: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.For; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.L: { if(ch == 'o') { lastIndex = index; state = State.Lo; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Lo: { if(ch == 'c') { lastIndex = index; state = State.Loc; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Loc: { if(ch == 'a') { lastIndex = index; state = State.Loca; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Loca: { if(ch == 'l') { lastIndex = index; state = State.Local; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Local: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Local; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.U: { if(ch == 'n') { lastIndex = index; state = State.Un; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Un: { if(ch == 't') { lastIndex = index; state = State.Unt; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Unt: { if(ch == 'i') { lastIndex = index; state = State.Unti; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Unti: { if(ch == 'l') { lastIndex = index; state = State.Until; AppendDataChar(ch); } else if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Name; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; case State.Until: { if(char.IsAsciiLetterOrDigit(ch) || ch == '_') { lastIndex = index; state = State.Name; currentToken!.type = TokenType.Name; AppendDataChar(ch); } else { if(currentToken == null || currentToken.type == null) { throw new Exception($"Lexer error at {currentLocation}"); } currentToken.type = TokenType.Until; currentToken.data = null; currentLocation = new(currentToken.region.end); tokens.Add(currentToken); currentToken = null; index = lastIndex!.Value; lastIndex = null; state = State.Start; } } break; default: throw new NotImplementedException(state.ToString()); } } private enum State { Start, Quote, SingleQuote, Name, Integer, Float, Zero, A, B, D, E, F, G, I, L, N, O, R, T, U, W, Plus, Minus, Star, Slash, Percent, Caret, Hash, Ampersand, Tilde, Pipe, Lt, Gt, Equals, RoundOpen, RoundClosed, CurlyOpen, CurlyClosed, SquareOpen, SquareClosed, StringStartLongBracket, StringWithLongBracket, StringEndLongBracket, Colon, Semicolon, Comma, Dot, An, Br, Do, El, En, Fa, Fo, Fu, Go, If, In, Lo, Ni, No, Or, Re, Th, Tr, Un, Wh, LtLt, GtGt, SlashSlash, EqualsEquals, TildeEquals, LtEquals, GtEquals, ColonColon, DotDot, SmallCommentStart, QuoteBackslash, SingleQuoteBackslash, String, HexNumberX, ExpNumber, And, Bre, Els, End, Fal, For, Fun, Got, Loc, Nil, Not, Rep, Ret, The, Tru, Unt, Whi, DotDotDot, HexNumber, QuoteBackslashZ, SingleQuoteBackslashZ, SmallComment, BigComment, BigCommentStartLongBracket, BigCommentEndLongBracket, Brea, Else, Fals, Func, Goto, Loca, Repe, Retu, Then, True, Unti, Whil, HexExpNumber, Break, Elsei, False, Funct, Local, Repea, Retur, Until, While, Elseif, Functi, Repeat, Return, Functio, Function, } } class CodeRegion(CodeLocation start, CodeLocation end) { public CodeLocation start = start; public CodeLocation end = end; public override string ToString() { return $"{start}-{end}"; } } class CodeLocation(int line, int col) { public int line = line; public int col = col; public CodeLocation(CodeLocation other) : this(line: other.line, col: other.col) { } public override string ToString() { return $"{line + 1}:{col + 1}"; } } class Token(CodeRegion region, TokenType? type = null, Token.IData? data = null) { public CodeRegion region = region; public IData? data = data; public TokenType? type = type; public interface IData { } public class NumeralData(INumeral numeral) : IData { public INumeral numeral = numeral; public override string ToString() { return $"NumeralData {numeral}"; } } public class StringData(string data) : IData { public string data = data; public override string ToString() { return $"StringData \"{data}\""; } } } public enum TokenType { Name, And, Break, Do, Else, Elseif, End, False, For, Function, Goto, If, In, Local, Nil, Not, Or, Repeat, Return, Then, True, Until, While, Plus, Minus, Star, Slash, Percent, Caret, Hash, Ampersand, Tilde, Pipe, LtLt, GtGt, SlashSlash, EqualsEquals, TildeEquals, LtEquals, GtEquals, Lt, Gt, Equals, RoundOpen, RoundClosed, CurlyOpen, CurlyClosed, SquareOpen, SquareClosed, ColonColon, Semicolon, Colon, Comma, Dot, DotDot, DotDotDot, Numeral, StringLiteral, } public interface INumeral { public class Integer(int value) : INumeral { public int value = value; public bool RawEqual(INumeral other) { if(other is Integer integer) { return integer.value == value; } // TODO: Check if this is actually doing what is expected return ((Float)other).value == value; } public override string ToString() { return $"Numeral Integer {value}"; } } public class Float(float value) : INumeral { public float value = value; public bool RawEqual(INumeral other) { if(other is Float float_val) { return float_val.value == value; } // TODO: Check if this is actually doing what is expected return ((Integer)other).value == value; } public override string ToString() { return $"Numeral Float {value}"; } } public bool RawEqual(INumeral other); }