package gott // Node is the interface implemented by all AST nodes type Node interface { Pos() Position // position of the first token of this node node() // marker method to ensure only AST types implement Node } // Expr is the interface implemented by all expression nodes type Expr interface { Node expr() // marker method } // Stmt is the interface implemented by all statement nodes type Stmt interface { Node stmt() // marker method } // ---- Template (root node) ---- // Template is the root node containing all parsed nodes type Template struct { Position Position Nodes []Node // mix of TextNode, statements, and output expressions } func (t *Template) Pos() Position { return t.Position } func (t *Template) node() {} // ---- Literal/Text Nodes ---- // TextNode holds literal text outside of tags type TextNode struct { Position Position Text string } func (n *TextNode) Pos() Position { return n.Position } func (n *TextNode) node() {} // ---- Expression Nodes ---- // IdentExpr represents a variable reference with optional dot notation // e.g., "foo", "foo.bar", "foo.bar.baz" type IdentExpr struct { Position Position Parts []string // ["foo", "bar", "baz"] for foo.bar.baz } func (e *IdentExpr) Pos() Position { return e.Position } func (e *IdentExpr) node() {} func (e *IdentExpr) expr() {} // LiteralExpr holds a string or number literal type LiteralExpr struct { Position Position Value any // string or float64 } func (e *LiteralExpr) Pos() Position { return e.Position } func (e *LiteralExpr) node() {} func (e *LiteralExpr) expr() {} // BinaryExpr represents a binary operation: left op right type BinaryExpr struct { Position Position Op TokenType Left Expr Right Expr } func (e *BinaryExpr) Pos() Position { return e.Position } func (e *BinaryExpr) node() {} func (e *BinaryExpr) expr() {} // UnaryExpr represents a unary operation: op expr type UnaryExpr struct { Position Position Op TokenType X Expr } func (e *UnaryExpr) Pos() Position { return e.Position } func (e *UnaryExpr) node() {} func (e *UnaryExpr) expr() {} // CallExpr represents a function call: func(args...) type CallExpr struct { Position Position Func string Args []Expr } func (e *CallExpr) Pos() Position { return e.Position } func (e *CallExpr) node() {} func (e *CallExpr) expr() {} // MethodCallExpr represents a virtual method call: obj.method(args...) type MethodCallExpr struct { Position Position Receiver Expr Method string Args []Expr } func (e *MethodCallExpr) Pos() Position { return e.Position } func (e *MethodCallExpr) node() {} func (e *MethodCallExpr) expr() {} // FilterExpr represents a filter application: expr | filter or expr | filter(args) type FilterExpr struct { Position Position Input Expr Filter string Args []Expr } func (e *FilterExpr) Pos() Position { return e.Position } func (e *FilterExpr) node() {} func (e *FilterExpr) expr() {} // DefaultExpr represents a default value expression: expr || default type DefaultExpr struct { Position Position Expr Expr Default Expr } func (e *DefaultExpr) Pos() Position { return e.Position } func (e *DefaultExpr) node() {} func (e *DefaultExpr) expr() {} // ---- Statement Nodes ---- // OutputStmt represents an expression to be output: [% expr %] type OutputStmt struct { Position Position Expr Expr } func (s *OutputStmt) Pos() Position { return s.Position } func (s *OutputStmt) node() {} func (s *OutputStmt) stmt() {} // IfStmt represents an IF/ELSIF/ELSE chain type IfStmt struct { Position Position Condition Expr Body []Node ElsIf []*ElsIfClause // zero or more ELSIF clauses Else []Node // optional ELSE body } func (s *IfStmt) Pos() Position { return s.Position } func (s *IfStmt) node() {} func (s *IfStmt) stmt() {} // ElsIfClause represents an ELSIF branch type ElsIfClause struct { Position Position Condition Expr Body []Node } // UnlessStmt represents an UNLESS conditional type UnlessStmt struct { Position Position Condition Expr Body []Node Else []Node // optional ELSE body } func (s *UnlessStmt) Pos() Position { return s.Position } func (s *UnlessStmt) node() {} func (s *UnlessStmt) stmt() {} // ForeachStmt represents a FOREACH loop type ForeachStmt struct { Position Position ItemVar string // loop variable name ListExpr Expr // expression for the list/map to iterate Body []Node } func (s *ForeachStmt) Pos() Position { return s.Position } func (s *ForeachStmt) node() {} func (s *ForeachStmt) stmt() {} // BlockStmt represents a named block definition type BlockStmt struct { Position Position Name string Body []Node } func (s *BlockStmt) Pos() Position { return s.Position } func (s *BlockStmt) node() {} func (s *BlockStmt) stmt() {} // PathPart represents a segment of a dynamic path for INCLUDE/WRAPPER. // A path like "templates/$category/page.html" becomes: // [{IsVariable: false, Value: "templates/"}, {IsVariable: true, Parts: ["category"]}, {IsVariable: false, Value: "/page.html"}] type PathPart struct { IsVariable bool // true if this is a $variable reference Value string // literal text (when IsVariable is false) Parts []string // variable parts for dot notation: $user.name -> ["user", "name"] } // IncludeStmt represents an INCLUDE directive type IncludeStmt struct { Position Position Name string // static path (used when PathParts is empty) PathParts []PathPart // dynamic path parts (used when path contains $variables) } func (s *IncludeStmt) Pos() Position { return s.Position } func (s *IncludeStmt) node() {} func (s *IncludeStmt) stmt() {} // WrapperStmt represents a WRAPPER directive type WrapperStmt struct { Position Position Name string // static path (used when PathParts is empty) PathParts []PathPart // dynamic path parts (used when path contains $variables) Content []Node // content to be wrapped } func (s *WrapperStmt) Pos() Position { return s.Position } func (s *WrapperStmt) node() {} func (s *WrapperStmt) stmt() {} // SetStmt represents a SET variable assignment type SetStmt struct { Position Position Var string Value Expr } func (s *SetStmt) Pos() Position { return s.Position } func (s *SetStmt) node() {} func (s *SetStmt) stmt() {} // TryStmt represents a TRY/CATCH error handling block type TryStmt struct { Position Position Try []Node // content to try Catch []Node // fallback content if error occurs } func (s *TryStmt) Pos() Position { return s.Position } func (s *TryStmt) node() {} func (s *TryStmt) stmt() {}