Files
gasm-sdk/ast/ast.go
T

162 lines
4.9 KiB
Go
Raw Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (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
ABI string // the <NAME> ABI marker, e.g. ABIInternal ("" when absent)
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"
}