package gott // TokenType represents the type of a lexical token type TokenType int const ( TokenError TokenType = iota // error occurred TokenEOF // end of input // Literals TokenText // raw text outside [% %] TokenIdent // identifier (variable name, block name) TokenString // "string" or 'string' TokenNumber // 123 or 45.67 // Delimiters TokenTagOpen // [% TokenTagClose // %] TokenLParen // ( TokenRParen // ) TokenDot // . TokenPipe // | TokenComma // , TokenAssign // = TokenDollar // $ (variable interpolation in paths) // Operators TokenOr // || TokenAnd // && TokenEq // == TokenNe // != TokenLt // < TokenLe // <= TokenGt // > TokenGe // >= TokenPlus // + TokenMinus // - TokenMul // * TokenDiv // / TokenMod // % (modulo, only inside tags) // Keywords TokenIF TokenELSIF TokenELSE TokenUNLESS TokenEND TokenFOREACH TokenIN TokenBLOCK TokenINCLUDE TokenWRAPPER TokenSET TokenTRY TokenCATCH ) // String returns a human-readable name for the token type func (t TokenType) String() string { switch t { case TokenError: return "Error" case TokenEOF: return "EOF" case TokenText: return "Text" case TokenIdent: return "Ident" case TokenString: return "String" case TokenNumber: return "Number" case TokenTagOpen: return "[%" case TokenTagClose: return "%]" case TokenLParen: return "(" case TokenRParen: return ")" case TokenDot: return "." case TokenPipe: return "|" case TokenComma: return "," case TokenAssign: return "=" case TokenDollar: return "$" case TokenOr: return "||" case TokenAnd: return "&&" case TokenEq: return "==" case TokenNe: return "!=" case TokenLt: return "<" case TokenLe: return "<=" case TokenGt: return ">" case TokenGe: return ">=" case TokenPlus: return "+" case TokenMinus: return "-" case TokenMul: return "*" case TokenDiv: return "/" case TokenMod: return "%" case TokenIF: return "IF" case TokenELSIF: return "ELSIF" case TokenELSE: return "ELSE" case TokenUNLESS: return "UNLESS" case TokenEND: return "END" case TokenFOREACH: return "FOREACH" case TokenIN: return "IN" case TokenBLOCK: return "BLOCK" case TokenINCLUDE: return "INCLUDE" case TokenWRAPPER: return "WRAPPER" case TokenSET: return "SET" case TokenTRY: return "TRY" case TokenCATCH: return "CATCH" default: return "Unknown" } } // Position represents a location in the source template type Position struct { Line int // 1-based line number Column int // 1-based column number Offset int // byte offset from start of input } // Token represents a lexical token with its type, value, and position type Token struct { Type TokenType Value string // literal value for idents, strings, numbers, text, errors Pos Position // source position for error reporting } // keywords maps keyword strings to their token types var keywords = map[string]TokenType{ "IF": TokenIF, "ELSIF": TokenELSIF, "ELSE": TokenELSE, "UNLESS": TokenUNLESS, "END": TokenEND, "FOREACH": TokenFOREACH, "IN": TokenIN, "BLOCK": TokenBLOCK, "INCLUDE": TokenINCLUDE, "WRAPPER": TokenWRAPPER, "SET": TokenSET, "TRY": TokenTRY, "CATCH": TokenCATCH, } // LookupKeyword returns the token type for an identifier, // returning TokenIdent if it's not a keyword func LookupKeyword(ident string) TokenType { if tok, ok := keywords[ident]; ok { return tok } return TokenIdent }