package parser // TokenType represents the type of a token type TokenType int const ( // Literals IDENT TokenType = iota NUMBER STRING TRUE FALSE NIL // Operators ASSIGN // = PLUS // + MINUS // - STAR // * SLASH // / MOD // % DOT // . // Comparison operators EQ // == NOT_EQ // != LT // < GT // > LT_EQ // <= GT_EQ // >= // Logical operators AND // and OR // or NOT // not // Delimiters LPAREN // ( RPAREN // ) LBRACE // { RBRACE // } LBRACKET // [ RBRACKET // ] COMMA // , ELLIPSIS // ... COLON // : // Keywords IF THEN ELSEIF ELSE END ECHO FOR WHILE IN DO BREAK EXIT FN RETURN STRUCT // Special EOF ILLEGAL ) // Token represents a single token type Token struct { Type TokenType Literal string Line int Column int } // Precedence levels for Pratt parsing type Precedence int const ( _ Precedence = iota LOWEST PREC_OR // or PREC_AND // and EQUALS // ==, != LESSGREATER // >, <, >=, <= SUM // +, - PRODUCT // *, /, % PREFIX // -x, not x MEMBER // table[key], table.key CALL // function() ) // precedences maps token types to their precedence levels var precedences = map[TokenType]Precedence{ OR: PREC_OR, AND: PREC_AND, EQ: EQUALS, NOT_EQ: EQUALS, LT: LESSGREATER, GT: LESSGREATER, LT_EQ: LESSGREATER, GT_EQ: LESSGREATER, PLUS: SUM, MINUS: SUM, SLASH: PRODUCT, STAR: PRODUCT, MOD: PRODUCT, DOT: MEMBER, LBRACKET: MEMBER, LPAREN: CALL, LBRACE: CALL, } // lookupIdent checks if an identifier is a keyword func lookupIdent(ident string) TokenType { keywords := map[string]TokenType{ "true": TRUE, "false": FALSE, "nil": NIL, "and": AND, "or": OR, "not": NOT, "if": IF, "then": THEN, "elseif": ELSEIF, "else": ELSE, "end": END, "echo": ECHO, "for": FOR, "while": WHILE, "in": IN, "do": DO, "break": BREAK, "exit": EXIT, "fn": FN, "return": RETURN, "struct": STRUCT, } if tok, ok := keywords[ident]; ok { return tok } return IDENT }