// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause // Package ast defines the abstract syntax tree of a GAsm source file. The // tree is produced by the parser and consumed by the formatter, linter and // language server. Operand classification that depends on the target // architecture (is this bare name a register or a label?) is deliberately left // to the arch package; the AST records syntax only. package ast import "sourcedock.dev/petrbalvin/gasm-devkit/token" // File is the parsed representation of one .s source file. type File struct { Path string Decls []Decl Orphans []Stmt // labels/instructions seen before any TEXT directive // Macros holds the names introduced by #define directives in this file. // The linter uses it to avoid flagging macro invocations as unknown // instructions (macro expansion itself is out of scope, see the docs). Macros map[string]bool } // Decl is a top-level declaration. type Decl interface { declNode() // Pos returns the position of the declaration's first token. Pos() token.Position } // Stmt is a statement inside a TEXT body. type Stmt interface { stmtNode() Pos() token.Position } // Include is a #include "header" line. type Include struct { Hash token.Token Name token.Token // the directive name, usually "include" Header token.Token // the string literal, quotes included } func (*Include) declNode() {} func (d *Include) Pos() token.Position { return d.Hash.Pos } // Preproc is any other preprocessor line (#define, #undef, …) captured loosely. type Preproc struct { Hash token.Token Raw string // verbatim text after the '#' } func (*Preproc) declNode() {} func (d *Preproc) Pos() token.Position { return d.Hash.Pos } // Text is a TEXT function definition and its body. type Text struct { Keyword token.Token // the TEXT token Name *Symbol // ·funcName(SB) Flags []string // NOSPLIT, DUPOK, … Frame *Operand // $0 Args *Operand // the -65 part; nil when absent Body []Stmt Doc string // preceding comment block (typically the Go signature) } func (*Text) declNode() {} func (d *Text) Pos() token.Position { return d.Keyword.Pos } // Globl is a GLOBL symbol declaration. type Globl struct { Keyword token.Token Name *Symbol Flags []string Size *Operand } func (*Globl) declNode() {} func (d *Globl) Pos() token.Position { return d.Keyword.Pos } // Data is a DATA symbol initialiser. type Data struct { Keyword token.Token Name *Symbol // includes any +offset Width int // the /width suffix; 0 when absent Value *Operand } func (*Data) declNode() {} func (d *Data) Pos() token.Position { return d.Keyword.Pos } // Label is a local label definition such as vec1:. type Label struct { Name token.Token Colon token.Token } func (*Label) stmtNode() {} func (s *Label) Pos() token.Position { return s.Name.Pos } // Instr is a single machine instruction with zero or more operands. type Instr struct { Mnemonic token.Token Operands []*Operand Comment string // trailing comment text, without the leading // } func (*Instr) stmtNode() {} func (s *Instr) Pos() token.Position { return s.Mnemonic.Pos } // Symbol is a symbol reference: ·name(SB), name<>(SB), name+8(FP), … type Symbol struct { Raw string // verbatim text Pkg string // package prefix before the middle dot ("" = current package) Name string // identifier without the middle dot or <> Static bool // the <> marker is present Pseudo string // FP, SP, SB or PC ("" for a bare name) Offset int64 HasOff bool Pos token.Position } // OpKind classifies an operand syntactically. type OpKind int const ( OpImmediate = iota // $value OpAddr // register, memory reference, symbol or label ) // Operand is one instruction operand. type Operand struct { Raw string Kind OpKind Imm Immediate Addr Address Pos token.Position } // Immediate is a $ value. type Immediate struct { Neg bool Val int64 HasVal bool // a simple integer immediate was parsed Float string // non-empty for a floating-point immediate Str string // non-empty for a string/rune immediate Sym *Symbol // non-nil for $sym(…) } // Address is a non-immediate operand: a register, a memory reference, a symbol // reference or a label. Fields are populated best-effort from the syntax. type Address struct { Sym *Symbol // name reference (bare ident, or name+off(pseudo)) Base string // base register, from (base) Index string // index register, from (index*scale) Scale int // index scale; 0 when absent Offset int64 // leading displacement, from off(base) HasOff bool // a leading displacement is present Shift string // verbatim arm64 shift suffix, e.g. "<<2" }