// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // AST node definitions for the Five language. // // Design references: // - Harbour: HB_EXPR (hbcompdf.h:349) — expression union with ExprType discriminant // - Harbour: HB_HFUNC (hbcompdf.h:497) — function with separated pLocals/pStatics/pFields/pMemvars // - tsgo: Node with Kind discriminant + nodeData interface (internal/ast/ast.go) // // Key Harbour rules applied: // - LOCAL/STATIC/FIELD declarations must appear at function top, before executable code // - FuncDecl separates Decls (declarations) from Body (executable statements) // - (expr)->field for dynamic alias access (HB_ET_ALIASEXPR) // - &variable for macro (6 subtypes from Harbour: VAR, SYMBOL, ALIASED, EXPR, LIST, PARE) package ast import "five/compiler/token" // --- Interfaces --- // Node is the base interface for all AST nodes. type Node interface { Pos() token.Position End() token.Position } // Expr represents an expression node (produces a value). type Expr interface { Node exprNode() } // Stmt represents a statement node (performs an action). type Stmt interface { Node stmtNode() } // Decl represents a declaration node (LOCAL, STATIC, FIELD, etc.). type Decl interface { Node declNode() } // --- Program (top-level) --- // File represents a single .prg source file. type File struct { Name string // filename Imports []*ImportDecl Decls []Decl // top-level: FUNCTION, PROCEDURE, CLASS, etc. } func (f *File) Pos() token.Position { if len(f.Decls) > 0 { return f.Decls[0].Pos() } return token.Position{} } func (f *File) End() token.Position { if len(f.Decls) > 0 { return f.Decls[len(f.Decls)-1].End() } return token.Position{} } // --- Declarations --- // ImportDecl: IMPORT "package/path" or IMPORT _ "package/path" type ImportDecl struct { ImportPos token.Position Alias string // "" = normal, "_" = blank import, "name" = alias Path string // package path } func (d *ImportDecl) Pos() token.Position { return d.ImportPos } func (d *ImportDecl) End() token.Position { return d.ImportPos } func (d *ImportDecl) declNode() {} // FuncDecl represents FUNCTION or PROCEDURE. // Harbour: HB_HFUNC — pLocals, pStatics, pFields separated from pcode. // LOCAL/STATIC/FIELD must appear before executable code. type FuncDecl struct { FuncPos token.Position Name string IsProc bool // PROCEDURE (no return value) IsStatic bool // STATIC FUNCTION/PROCEDURE — file-local visibility Params []*ParamDecl // declared parameters Decls []Decl // LOCAL, STATIC, FIELD — must come first Body []Stmt // executable statements — after declarations EndPos token.Position } func (d *FuncDecl) Pos() token.Position { return d.FuncPos } func (d *FuncDecl) End() token.Position { return d.EndPos } func (d *FuncDecl) declNode() {} // ParamDecl represents a function parameter. type ParamDecl struct { NamePos token.Position Name string ByRef bool // @param or passed by reference AsType string // optional type hint: AS NUMERIC, AS STRING, etc. } func (d *ParamDecl) Pos() token.Position { return d.NamePos } func (d *ParamDecl) End() token.Position { return d.NamePos } func (d *ParamDecl) declNode() {} // VarDecl represents LOCAL, STATIC, PRIVATE, PUBLIC, FIELD declarations. // Harbour: LOCAL must be at function top (before executable code). // PRIVATE/PUBLIC can appear anywhere (runtime memvar). type VarDecl struct { DeclPos token.Position Scope VarScope Vars []*VarInit // one or more: LOCAL a := 1, b := 2, c } func (d *VarDecl) Pos() token.Position { return d.DeclPos } func (d *VarDecl) End() token.Position { if len(d.Vars) > 0 { return d.Vars[len(d.Vars)-1].NamePos } return d.DeclPos } func (d *VarDecl) declNode() {} func (d *VarDecl) stmtNode() {} // PRIVATE/PUBLIC can appear as statements // VarScope indicates where a variable lives. type VarScope int const ( ScopeLocal VarScope = iota // LOCAL — stack, function-top only ScopeStatic // STATIC — module-level, function-top only ScopePrivate // PRIVATE — runtime memvar, anywhere ScopePublic // PUBLIC — runtime memvar, anywhere ScopeField // FIELD — database field declaration, function-top only ) // VarInit represents a single variable with optional initializer. type VarInit struct { NamePos token.Position Name string Init Expr // nil if no initializer AsType string // optional type hint } // ClassDecl represents CLASS ... ENDCLASS. type ClassDecl struct { ClassPos token.Position Name string ParentName string // INHERIT FROM parent Members []Decl // DATA, METHOD, ACCESS, ASSIGN declarations EndPos token.Position } func (d *ClassDecl) Pos() token.Position { return d.ClassPos } func (d *ClassDecl) End() token.Position { return d.EndPos } func (d *ClassDecl) declNode() {} // DataDecl represents DATA member in a class. type DataDecl struct { DataPos token.Position Name string Init Expr // INIT expression (nil if none) AsType string // AS type hint } func (d *DataDecl) Pos() token.Position { return d.DataPos } func (d *DataDecl) End() token.Position { return d.DataPos } func (d *DataDecl) declNode() {} // MethodDecl represents METHOD declaration in a class or standalone. type MethodDecl struct { MethodPos token.Position Name string ClassName string // METHOD name CLASS classname (standalone) Params []*ParamDecl IsInline bool // INLINE method InlineBody Expr // inline expression body — `RETURN ` equivalent IsOperator bool // OPERATOR overload — OperatorOp carries the slot OperatorOp int // operator slot (hbrt.Op* constant); valid only when IsOperator IsSetGet bool // METHOD name(x) SETGET — getter if no arg, setter if arg IsAccess bool // ACCESS name METHOD getterName IsAssign bool // ASSIGN name METHOD setterName AccessName string // property name for ACCESS/ASSIGN Decls []Decl Body []Stmt EndPos token.Position } func (d *MethodDecl) Pos() token.Position { return d.MethodPos } func (d *MethodDecl) End() token.Position { return d.EndPos } func (d *MethodDecl) declNode() {} // GoDumpDecl represents inline Go code from #pragma BEGINDUMP ... #pragma ENDDUMP. // Five extension: allows embedding raw Go code directly in PRG files. type GoDumpDecl struct { DumpPos token.Position Code string // raw Go source code } func (d *GoDumpDecl) Pos() token.Position { return d.DumpPos } func (d *GoDumpDecl) End() token.Position { return d.DumpPos } func (d *GoDumpDecl) declNode() {} // --- Expressions --- // LiteralExpr represents a literal value. // Harbour: HB_ET_NIL, HB_ET_NUMERIC, HB_ET_STRING, HB_ET_LOGICAL, HB_ET_DATE, HB_ET_TIMESTAMP type LiteralExpr struct { ValuePos token.Position Kind token.Kind // INT, LONG, DOUBLE, STRING, TRUE, FALSE, NIL_LIT, DATE_LIT Value string // raw literal text } func (e *LiteralExpr) Pos() token.Position { return e.ValuePos } func (e *LiteralExpr) End() token.Position { return e.ValuePos } func (e *LiteralExpr) exprNode() {} // IdentExpr represents a variable or function name. // Harbour: HB_ET_VARIABLE, HB_ET_FUNNAME type IdentExpr struct { NamePos token.Position Name string } func (e *IdentExpr) Pos() token.Position { return e.NamePos } func (e *IdentExpr) End() token.Position { return e.NamePos } func (e *IdentExpr) exprNode() {} // SelfExpr represents :: (Self access in class method). // Harbour: HB_ET_SELF type SelfExpr struct { ColonPos token.Position } func (e *SelfExpr) Pos() token.Position { return e.ColonPos } func (e *SelfExpr) End() token.Position { return e.ColonPos } func (e *SelfExpr) exprNode() {} // BinaryExpr represents a binary operation. // Harbour: HB_EO_PLUS, HB_EO_MINUS, HB_EO_EQUAL, etc. type BinaryExpr struct { Left Expr OpPos token.Position Op token.Kind Right Expr } func (e *BinaryExpr) Pos() token.Position { return e.Left.Pos() } func (e *BinaryExpr) End() token.Position { return e.Right.End() } func (e *BinaryExpr) exprNode() {} // UnaryExpr represents a prefix unary operation. // Harbour: HB_EO_NEGATE, HB_EO_NOT, HB_EO_PREINC, HB_EO_PREDEC type UnaryExpr struct { OpPos token.Position Op token.Kind // MINUS, NOT, INC, DEC X Expr } func (e *UnaryExpr) Pos() token.Position { return e.OpPos } func (e *UnaryExpr) End() token.Position { return e.X.End() } func (e *UnaryExpr) exprNode() {} // PostfixExpr represents postfix ++ or --. // Harbour: HB_EO_POSTINC, HB_EO_POSTDEC type PostfixExpr struct { X Expr OpPos token.Position Op token.Kind // INC, DEC } func (e *PostfixExpr) Pos() token.Position { return e.X.Pos() } func (e *PostfixExpr) End() token.Position { return e.OpPos } func (e *PostfixExpr) exprNode() {} // AssignExpr represents assignment: x := value, x += value, etc. // Harbour: HB_EO_ASSIGN, HB_EO_PLUSEQ, etc. type AssignExpr struct { Left Expr OpPos token.Position Op token.Kind // ASSIGN, PLUSEQ, MINUSEQ, etc. Right Expr } func (e *AssignExpr) Pos() token.Position { return e.Left.Pos() } func (e *AssignExpr) End() token.Position { return e.Right.End() } func (e *AssignExpr) exprNode() {} // CallExpr represents a function call: func(args...) // Harbour: HB_ET_FUNCALL — pFunName + pParms type CallExpr struct { Func Expr // function expression (IdentExpr, or macro) LParen token.Position Args []Expr RParen token.Position } func (e *CallExpr) Pos() token.Position { return e.Func.Pos() } func (e *CallExpr) End() token.Position { return e.RParen } func (e *CallExpr) exprNode() {} // DotExpr represents package member access: pkg.Member // Used for Go package function calls: sql.Open(), fmt.Println() type DotExpr struct { X Expr // package (IdentExpr) DotPos token.Position Member string // function/field name } func (e *DotExpr) Pos() token.Position { return e.X.Pos() } func (e *DotExpr) End() token.Position { return e.DotPos } func (e *DotExpr) exprNode() {} // SendExpr represents method call: obj:method(args...) // Harbour: HB_ET_SEND — pObject + szMessage/pMessage + pParms type SendExpr struct { Object Expr ColonPos token.Position Method string // static message name MacroMethod Expr // if ¯o message (nil for static) HasParens bool // true if () present (method call vs field access) LParen token.Position Args []Expr RParen token.Position IsAssign bool // obj:prop := value (setter) } func (e *SendExpr) Pos() token.Position { return e.Object.Pos() } func (e *SendExpr) End() token.Position { return e.RParen } func (e *SendExpr) exprNode() {} // IndexExpr represents array index: arr[index] // Harbour: HB_ET_ARRAYAT type IndexExpr struct { X Expr LBracket token.Position Index Expr RBracket token.Position } func (e *IndexExpr) Pos() token.Position { return e.X.Pos() } func (e *IndexExpr) End() token.Position { return e.RBracket } func (e *IndexExpr) exprNode() {} // AliasExpr represents field access: alias->field or (expr)->field // Harbour: HB_ET_ALIASVAR, HB_ET_ALIASEXPR type AliasExpr struct { Alias Expr // IdentExpr for static alias, any Expr for (dynamic)->field ArrowPos token.Position Field Expr // IdentExpr or MacroExpr } func (e *AliasExpr) Pos() token.Position { return e.Alias.Pos() } func (e *AliasExpr) End() token.Position { return e.Field.End() } func (e *AliasExpr) exprNode() {} // MacroExpr represents macro expansion: &variable or &(expression) // Harbour: HB_ET_MACRO with 6 subtypes type MacroExpr struct { AmpPos token.Position Expr Expr // variable or parenthesized expression } func (e *MacroExpr) Pos() token.Position { return e.AmpPos } func (e *MacroExpr) End() token.Position { return e.Expr.End() } func (e *MacroExpr) exprNode() {} // BlockExpr represents a code block: {|params| body} // Harbour: HB_ET_CODEBLOCK — pLocals + pExprList type BlockExpr struct { LBrace token.Position Params []string // parameter names (between | |) Body Expr // single expression (or comma-separated list) RBrace token.Position } func (e *BlockExpr) Pos() token.Position { return e.LBrace } func (e *BlockExpr) End() token.Position { return e.RBrace } func (e *BlockExpr) exprNode() {} // ArrayLitExpr represents a literal array: {1, 2, 3} // Harbour: HB_ET_ARRAY type ArrayLitExpr struct { LBrace token.Position Items []Expr RBrace token.Position } func (e *ArrayLitExpr) Pos() token.Position { return e.LBrace } func (e *ArrayLitExpr) End() token.Position { return e.RBrace } func (e *ArrayLitExpr) exprNode() {} // SeqExpr is a comma-separated expression list used inside code // blocks: `{|p| e1, e2, e3 }`. All sub-expressions are evaluated in // order, the last value is the block's return. Without this node the // parser kept only the last expr and silently dropped the side // effects of every preceding one — a real miscompile that bit // `SUM x, y, z TO sx, sy, sz` (only sz accumulated). type SeqExpr struct { Items []Expr StartAt token.Position EndAt token.Position } func (e *SeqExpr) Pos() token.Position { return e.StartAt } func (e *SeqExpr) End() token.Position { return e.EndAt } func (e *SeqExpr) exprNode() {} // HashLitExpr represents a literal hash: {"a" => 1, "b" => 2} // Harbour: HB_ET_HASH type HashLitExpr struct { LBrace token.Position Keys []Expr Values []Expr RBrace token.Position } func (e *HashLitExpr) Pos() token.Position { return e.LBrace } func (e *HashLitExpr) End() token.Position { return e.RBrace } func (e *HashLitExpr) exprNode() {} // IIfExpr represents inline if: IIF(cond, trueVal, falseVal) // Harbour: HB_ET_IIF type IIfExpr struct { IfPos token.Position Cond Expr True Expr False Expr } func (e *IIfExpr) Pos() token.Position { return e.IfPos } func (e *IIfExpr) End() token.Position { return e.False.End() } func (e *IIfExpr) exprNode() {} // RefExpr represents pass-by-reference: @variable // Harbour: HB_ET_REFERENCE, HB_ET_VARREF, HB_ET_FUNREF type RefExpr struct { AtPos token.Position X Expr } func (e *RefExpr) Pos() token.Position { return e.AtPos } func (e *RefExpr) End() token.Position { return e.X.End() } func (e *RefExpr) exprNode() {} // --- Statements --- // ExprStmt wraps an expression as a statement (function calls, assignments). type ExprStmt struct { X Expr } func (s *ExprStmt) Pos() token.Position { return s.X.Pos() } func (s *ExprStmt) End() token.Position { return s.X.End() } func (s *ExprStmt) stmtNode() {} // ReturnStmt represents RETURN [expr]. type ReturnStmt struct { ReturnPos token.Position Value Expr // first/only return value (nil for bare RETURN) Values []Expr // multi-return: RETURN a, b, c (nil if single) } func (s *ReturnStmt) Pos() token.Position { return s.ReturnPos } func (s *ReturnStmt) End() token.Position { if s.Value != nil { return s.Value.End() } return s.ReturnPos } func (s *ReturnStmt) stmtNode() {} // QOutStmt represents ? expr, expr, ... (shorthand for QOut). type QOutStmt struct { QPos token.Position IsQQ bool // true for ?? (QQOut) Exprs []Expr } func (s *QOutStmt) Pos() token.Position { return s.QPos } func (s *QOutStmt) End() token.Position { if len(s.Exprs) > 0 { return s.Exprs[len(s.Exprs)-1].End() } return s.QPos } func (s *QOutStmt) stmtNode() {} // IfStmt represents IF / ELSEIF / ELSE / ENDIF. // Harbour: uses PHB_ELSEIF chain for fixups. type IfStmt struct { IfPos token.Position Cond Expr Body []Stmt ElseIfs []*ElseIfClause ElseBody []Stmt // nil if no ELSE EndPos token.Position } type ElseIfClause struct { ElseIfPos token.Position Cond Expr Body []Stmt } func (s *IfStmt) Pos() token.Position { return s.IfPos } func (s *IfStmt) End() token.Position { return s.EndPos } func (s *IfStmt) stmtNode() {} // DoWhileStmt represents DO WHILE cond ... ENDDO. type DoWhileStmt struct { DoPos token.Position Cond Expr Body []Stmt EndPos token.Position } func (s *DoWhileStmt) Pos() token.Position { return s.DoPos } func (s *DoWhileStmt) End() token.Position { return s.EndPos } func (s *DoWhileStmt) stmtNode() {} // ForStmt represents FOR var := start TO end [STEP step] ... NEXT. type ForStmt struct { ForPos token.Position Var string Start Expr To Expr Step Expr // nil for default step 1 Body []Stmt NextPos token.Position } func (s *ForStmt) Pos() token.Position { return s.ForPos } func (s *ForStmt) End() token.Position { return s.NextPos } func (s *ForStmt) stmtNode() {} // ForEachStmt represents FOR EACH var IN collection ... NEXT. // Harbour: HB_ENUMERATOR structure. type ForEachStmt struct { ForPos token.Position Var string Collection Expr Descend bool // FOR EACH DESCEND Body []Stmt NextPos token.Position } func (s *ForEachStmt) Pos() token.Position { return s.ForPos } func (s *ForEachStmt) End() token.Position { return s.NextPos } func (s *ForEachStmt) stmtNode() {} // SwitchStmt represents SWITCH expr ... CASE ... OTHERWISE ... END. // Harbour: HB_SWITCHCMD structure. type SwitchStmt struct { SwitchPos token.Position Expr Expr Cases []*CaseClause Otherwise []Stmt // nil if no OTHERWISE EndPos token.Position } type CaseClause struct { CasePos token.Position Value Expr // case value Body []Stmt } func (s *SwitchStmt) Pos() token.Position { return s.SwitchPos } func (s *SwitchStmt) End() token.Position { return s.EndPos } func (s *SwitchStmt) stmtNode() {} // SeqStmt represents BEGIN SEQUENCE ... RECOVER [USING var] ... END. type SeqStmt struct { BeginPos token.Position Body []Stmt RecoverVar string // variable name after USING (empty if none) RecoverBody []Stmt // nil if no RECOVER EndPos token.Position } func (s *SeqStmt) Pos() token.Position { return s.BeginPos } func (s *SeqStmt) End() token.Position { return s.EndPos } func (s *SeqStmt) stmtNode() {} // === Five Go Extensions === // MultiAssignStmt: a, b, c := expr or a, b := Func() // Also handles: a, b := b, a (parallel swap) // Blank identifier _ discards the value. type MultiAssignStmt struct { AssignPos token.Position Targets []string // variable names ("_" = discard) Values []Expr // right-hand side expressions } func (s *MultiAssignStmt) Pos() token.Position { return s.AssignPos } func (s *MultiAssignStmt) End() token.Position { return s.AssignPos } func (s *MultiAssignStmt) stmtNode() {} // DeferStmt: DEFER expr (execute when function returns) type DeferStmt struct { DeferPos token.Position Call Expr // expression to defer (usually a method/function call) } func (s *DeferStmt) Pos() token.Position { return s.DeferPos } func (s *DeferStmt) End() token.Position { return s.DeferPos } func (s *DeferStmt) stmtNode() {} // ConstDecl: CONST block with optional auto-increment type ConstDecl struct { ConstPos token.Position Items []ConstItem } type ConstItem struct { Name string Value Expr // nil = auto-increment from previous } func (d *ConstDecl) Pos() token.Position { return d.ConstPos } func (d *ConstDecl) End() token.Position { return d.ConstPos } func (d *ConstDecl) declNode() {} // SliceExpr: a[low:high] — sub-array or sub-string type SliceExpr struct { X Expr LBracket token.Position Low Expr // nil = from start High Expr // nil = to end RBracket token.Position } func (e *SliceExpr) Pos() token.Position { return e.X.Pos() } func (e *SliceExpr) End() token.Position { return e.RBracket } func (e *SliceExpr) exprNode() {} // NilSafeExpr: obj?:Method() — returns NIL if obj is NIL type NilSafeExpr struct { X Expr QPos token.Position Method string Args []Expr HasParens bool } func (e *NilSafeExpr) Pos() token.Position { return e.X.Pos() } func (e *NilSafeExpr) End() token.Position { return e.QPos } func (e *NilSafeExpr) exprNode() {} // InterpolatedString: f"Hello {name}, age {age}" type InterpolatedString struct { FPos token.Position Parts []Expr // alternating: LiteralExpr (text), other Expr (interpolated) } func (e *InterpolatedString) Pos() token.Position { return e.FPos } func (e *InterpolatedString) End() token.Position { return e.FPos } func (e *InterpolatedString) exprNode() {} // === Five Concurrency Extensions === // ChanSendStmt: ch <- value type ChanSendStmt struct { ChanPos token.Position Chan Expr // channel expression Value Expr // value to send } func (s *ChanSendStmt) Pos() token.Position { return s.ChanPos } func (s *ChanSendStmt) End() token.Position { return s.ChanPos } func (s *ChanSendStmt) stmtNode() {} // ChanRecvExpr: <- ch (receive from channel, used as expression) type ChanRecvExpr struct { ArrowPos token.Position Chan Expr } func (e *ChanRecvExpr) Pos() token.Position { return e.ArrowPos } func (e *ChanRecvExpr) End() token.Position { return e.ArrowPos } func (e *ChanRecvExpr) exprNode() {} // WatchStmt: WATCH / CASE <- ch / CASE ch <- val / OTHERWISE / ENDWATCH type WatchStmt struct { WatchPos token.Position Cases []*WatchCase Otherwise []Stmt EndPos token.Position } type WatchCase struct { CasePos token.Position RecvChan Expr // CASE val := <- ch (receive) RecvVar string // variable name for received value ("" if none) SendChan Expr // CASE ch <- val (send) SendVal Expr // value to send Body []Stmt } func (s *WatchStmt) Pos() token.Position { return s.WatchPos } func (s *WatchStmt) End() token.Position { return s.EndPos } func (s *WatchStmt) stmtNode() {} // GoBlockStmt: GO { ... } — inline goroutine type GoBlockStmt struct { GoPos token.Position Block *BlockExpr // code block to execute } func (s *GoBlockStmt) Pos() token.Position { return s.GoPos } func (s *GoBlockStmt) End() token.Position { return s.GoPos } func (s *GoBlockStmt) stmtNode() {} // ParallelForStmt: PARALLEL FOR i := 1 TO n / body / NEXT type ParallelForStmt struct { ForPos token.Position Var string Start Expr To Expr Step Expr // nil = default 1 Body []Stmt EndPos token.Position } func (s *ParallelForStmt) Pos() token.Position { return s.ForPos } func (s *ParallelForStmt) End() token.Position { return s.EndPos } func (s *ParallelForStmt) stmtNode() {} // AsyncExpr: ASYNC expr — returns a future/channel type AsyncExpr struct { AsyncPos token.Position Call Expr } func (e *AsyncExpr) Pos() token.Position { return e.AsyncPos } func (e *AsyncExpr) End() token.Position { return e.AsyncPos } func (e *AsyncExpr) exprNode() {} // AwaitExpr: AWAIT future — blocks until result ready type AwaitExpr struct { AwaitPos token.Position Future Expr } func (e *AwaitExpr) Pos() token.Position { return e.AwaitPos } func (e *AwaitExpr) End() token.Position { return e.AwaitPos } func (e *AwaitExpr) exprNode() {} // TimeoutStmt: WITH TIMEOUT n / body / ENDWITH type TimeoutStmt struct { WithPos token.Position Duration Expr // timeout in seconds Body []Stmt EndPos token.Position } func (s *TimeoutStmt) Pos() token.Position { return s.WithPos } func (s *TimeoutStmt) End() token.Position { return s.EndPos } func (s *TimeoutStmt) stmtNode() {} // === End Five Go Extensions === // ExitStmt represents EXIT (break out of loop). type ExitStmt struct { ExitPos token.Position } func (s *ExitStmt) Pos() token.Position { return s.ExitPos } func (s *ExitStmt) End() token.Position { return s.ExitPos } func (s *ExitStmt) stmtNode() {} // LoopStmt represents LOOP (continue to next iteration). type LoopStmt struct { LoopPos token.Position } func (s *LoopStmt) Pos() token.Position { return s.LoopPos } func (s *LoopStmt) End() token.Position { return s.LoopPos } func (s *LoopStmt) stmtNode() {} // --- xBase command statements --- // UseCmd represents USE [file] [VIA driver] [ALIAS name] [EXCLUSIVE|SHARED] type UseCmd struct { UsePos token.Position File Expr // filename expression (nil = close current) Via string // RDD driver name Alias string // alias name (static) AliasExpr Expr // alias expression for ALIAS (expr) — dynamic alias Shared bool // SHARED flag ReadOnly bool // READONLY flag } func (s *UseCmd) Pos() token.Position { return s.UsePos } func (s *UseCmd) End() token.Position { return s.UsePos } func (s *UseCmd) stmtNode() {} // SelectCmd represents SELECT area type SelectCmd struct { SelectPos token.Position Area Expr // area number or alias name } func (s *SelectCmd) Pos() token.Position { return s.SelectPos } func (s *SelectCmd) End() token.Position { return s.SelectPos } func (s *SelectCmd) stmtNode() {} // GoCmd represents GO TOP / GO BOTTOM / GO recno / GOTO recno type GoCmd struct { GoPos token.Position Direction string // "TOP", "BOTTOM", or "" RecNo Expr // record number expression (nil for TOP/BOTTOM) } func (s *GoCmd) Pos() token.Position { return s.GoPos } func (s *GoCmd) End() token.Position { return s.GoPos } func (s *GoCmd) stmtNode() {} // SkipCmd represents SKIP [n] type SkipCmd struct { SkipPos token.Position Count Expr // nil for SKIP 1 } func (s *SkipCmd) Pos() token.Position { return s.SkipPos } func (s *SkipCmd) End() token.Position { return s.SkipPos } func (s *SkipCmd) stmtNode() {} // SeekCmd represents SEEK expr [SOFTSEEK] type SeekCmd struct { SeekPos token.Position Key Expr SoftSeek bool } func (s *SeekCmd) Pos() token.Position { return s.SeekPos } func (s *SeekCmd) End() token.Position { return s.SeekPos } func (s *SeekCmd) stmtNode() {} // ReplaceCmd represents REPLACE field WITH expr [, field WITH expr ...] type ReplaceCmd struct { ReplacePos token.Position Fields []ReplaceField } type ReplaceField struct { Field Expr // field expression (may include alias) Value Expr } func (s *ReplaceCmd) Pos() token.Position { return s.ReplacePos } func (s *ReplaceCmd) End() token.Position { return s.ReplacePos } func (s *ReplaceCmd) stmtNode() {} // AppendCmd represents APPEND BLANK type AppendCmd struct { AppendPos token.Position } func (s *AppendCmd) Pos() token.Position { return s.AppendPos } func (s *AppendCmd) End() token.Position { return s.AppendPos } func (s *AppendCmd) stmtNode() {} // DeleteCmd represents DELETE (mark current record for deletion) type DeleteCmd struct { DeletePos token.Position } func (s *DeleteCmd) Pos() token.Position { return s.DeletePos } func (s *DeleteCmd) End() token.Position { return s.DeletePos } func (s *DeleteCmd) stmtNode() {} // IndexCmd represents INDEX ON expr [TAG tagname] TO file [FOR cond] [UNIQUE] [DESCENDING] type IndexCmd struct { IndexPos token.Position KeyExpr Expr File Expr ForCond Expr // nil if no FOR TagName string // TAG name for CDX compound index (empty = NTX) Unique bool Descending bool } func (s *IndexCmd) Pos() token.Position { return s.IndexPos } func (s *IndexCmd) End() token.Position { return s.IndexPos } func (s *IndexCmd) stmtNode() {} // SetCmd represents SET commands: SET FILTER TO expr, SET RELATION TO expr INTO alias, etc. type SetCmd struct { SetPos token.Position Setting string // "FILTER", "RELATION", "ORDER", "INDEX", etc. Expr Expr // the value expression Extra string // extra info (INTO alias, etc.) } func (s *SetCmd) Pos() token.Position { return s.SetPos } func (s *SetCmd) End() token.Position { return s.SetPos } func (s *SetCmd) stmtNode() {} // AtSayCmd represents @ row, col SAY expr [PICTURE pic] type AtSayCmd struct { AtPos token.Position Row Expr Col Expr SayExpr Expr Picture Expr // nil if no PICTURE } func (s *AtSayCmd) Pos() token.Position { return s.AtPos } func (s *AtSayCmd) End() token.Position { return s.AtPos } func (s *AtSayCmd) stmtNode() {} // AtGetCmd represents @ row, col GET var [PICTURE pic] [VALID valid] [WHEN when] type AtGetCmd struct { AtPos token.Position Row Expr Col Expr Var Expr // the variable expression VarName string // variable name as string Picture Expr // nil if no PICTURE Valid Expr // nil if no VALID (code block) When Expr // nil if no WHEN (code block) } func (s *AtGetCmd) Pos() token.Position { return s.AtPos } func (s *AtGetCmd) End() token.Position { return s.AtPos } func (s *AtGetCmd) stmtNode() {} // AtSayGetCmd represents @ row, col SAY expr GET var [PICTURE pic] [VALID valid] [WHEN when] type AtSayGetCmd struct { AtPos token.Position Row Expr Col Expr SayExpr Expr Var Expr VarName string Picture Expr Valid Expr When Expr } func (s *AtSayGetCmd) Pos() token.Position { return s.AtPos } func (s *AtSayGetCmd) End() token.Position { return s.AtPos } func (s *AtSayGetCmd) stmtNode() {} // ReadCmd represents READ [SAVE] type ReadCmd struct { ReadPos token.Position Save bool } func (s *ReadCmd) Pos() token.Position { return s.ReadPos } func (s *ReadCmd) End() token.Position { return s.ReadPos } func (s *ReadCmd) stmtNode() {}