Documentation
¶
Overview ¶
Package ast defines the Phase 0 abstract syntax tree.
Everything in Ruby is an expression, so there is no statement/expression split: a body is a slice of Node and its value is the value of its last node.
Index ¶
- type Alias
- type AltPattern
- type ArrayLit
- type ArrayPattern
- type Assign
- type Begin
- type BignumLit
- type BinaryExpr
- type BindPattern
- type BindingPattern
- type Block
- type BlockPass
- type BoolLit
- type Break
- type CVarAssign
- type CVarRef
- type Call
- type Case
- type CaseIn
- type ClassDef
- type ConstAssign
- type ConstPattern
- type ConstRef
- type Elsif
- type FindPattern
- type FloatLit
- type For
- type ForwardArgs
- type GVarAssign
- type GVarRef
- type HashLit
- type HashPattern
- type If
- type ImaginaryLit
- type InClause
- type IntLit
- type IvarAssign
- type IvarRef
- type KwParam
- type MatchPattern
- type MethodDef
- type ModuleDef
- type MultiAssign
- type Next
- type NilLit
- type Node
- type OpAssign
- type Pattern
- type Program
- type RangeLit
- type RationalLit
- type RegexpLit
- type RescueClause
- type Retry
- type Return
- type ScopedConst
- type ScopedConstAssign
- type SelfLit
- type SingletonClassDef
- type SplatArg
- type StrInterp
- type StringLit
- type Super
- type SymbolLit
- type UnaryExpr
- type Undef
- type ValuePattern
- type VarRef
- type WhenClause
- type While
- type XStr
- type Yield
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Alias ¶
Alias is `alias NewName OldName` — it makes NewName an alias of an existing method (or global variable). Each name is the bare method/symbol/global text without a leading colon.
MRI's `fitem` admits a dynamic symbol (`alias :"#{x}" y`), whose name is only known at run time. Such a name arrives in NewNameExpr/OldNameExpr, with the matching string field empty; the expression evaluates to the symbol. Both Expr fields are nil for the ordinary all-static form.
type AltPattern ¶
type AltPattern struct{ Alts []Pattern }
AltPattern is `p1 | p2 | …`: it matches when any alternative matches. Ruby forbids variable bindings inside alternatives, so the alternatives are value/ constant/structural patterns tested without binding.
type ArrayPattern ¶
ArrayPattern matches an array-like subject via the deconstruct protocol. Pre are the patterns before the splat, Post those after; HasSplat indicates a `*[name]` is present, with SplatName the (possibly empty) capture name. Const, when non-nil, additionally requires `subject.is_a?(Const)` (`in Point[x, y]`).
type Begin ¶
type Begin struct {
Body []Node
Rescues []RescueClause
ElseBody []Node // nil if no else
EnsureBody []Node // nil if no ensure
}
Begin is `begin BODY (rescue …)* [else …] [ensure …] end`.
type BinaryExpr ¶
BinaryExpr is `Left Op Right` for the Phase 0 fast-path operators.
type BindPattern ¶
type BindPattern struct{ Name string }
BindPattern binds the whole subject to a local (`in x`, the wildcard `in _`).
type BindingPattern ¶
BindingPattern is `SubPattern => name`: it matches SubPattern, then binds the subject to name.
type Block ¶
type Block struct {
// Line is the 1-based source line the block's OPENER sits on -- its `{`, its
// `do`, or the `->` of an arrow lambda. It lives here rather than in
// Program.Lines because a Block is not a Node (it is a field of Call), so
// that map cannot key on it.
//
// It is observable as MRI's location.first_lineno: Proc#source_location,
// Method#source_location for a define_method, and the line a Proc prints
// when it inspects itself. A consumer previously had to take the line of the
// enclosing STATEMENT, which is the same only when the block opens on that
// statement's first line. Measured against ruby 4.0.5:
//
// h = { # line 1
// :a => proc { # line 2
// 1
// },
// :b => proc { 2 }, # line 5
// }
// h[:a].source_location[1] # ruby 2 from the statement, 1
// h[:b].source_location[1] # ruby 5 from the statement, 1
//
// The body's first line is not a substitute either: ruby answers 2 for :a,
// whose first statement is on line 3, and an empty block has no statement at
// all.
//
// 0 means "not recorded" -- read it as unknown, not as line 0.
Line int
Params []string
Defaults []Node // parallel to Params; nil for a required or *splat param
SplatIndex int // index of the top-level *splat param in Params, or -1
BlockParam string // name of the &block param, or "" if none (parallels MethodDef.BlockParam)
// Locals are the block-local variables declared after a `;` in the parameter
// list (`{ |a; x, y| … }`): fresh, nil-valued locals of this block that shadow
// any enclosing binding of the same name. MRI: `opt_bv_decl: '\n'? ';'
// bv_decls '\n'?` with `bvar: tIDENTIFIER { new_bv(p, $1); }`. Empty when the
// list has no `;` part.
Locals []string
Body []Node
}
Block is a literal block: parameters and a body. It is a closure over the scope in which it appears. Defaults parallels Params (nil for a required or *splat param; non-nil for an optional `name = expr` param), exactly as MethodDef records its method-parameter defaults.
type BlockPass ¶
type BlockPass struct{ Value Node }
BlockPass is a `&expr` argument: its value is coerced to a Proc (via to_proc) and passed as the call's block. It only ever appears last in a Call's args.
type Break ¶
type Break struct{ Value Node }
Break exits the innermost block (terminating its iterator) or loop. Value may be nil.
type Call ¶
type Call struct {
Recv Node
Name string
Args []Node
Block *Block
Safe bool // &. safe navigation: nil receiver short-circuits to nil
// Paren records one bit of WRITTEN FORM: the call site had a parenthesised
// argument list, `foo(…)`, rather than none. It is what separates MRI's
// FCALL from its VCALL, which are different nodes built by different
// productions — `fcall: operation` feeding `method_call: fcall paren_args`
// (parse.y-ruby_4_0:3572-3577 and 5242-5248) makes an FCALL, while a bare
// name reaching `gettable` makes a VCALL (parse.y-ruby_4_0:13086). The
// difference is observable: `nope` raises NameError, `nope()` raises
// NoMethodError.
//
// It is written form and nothing else. It is true for an empty list
// (`foo()`, where Args is nil) and false for every call written without
// parentheses whatever else is there — `puts 1`, `obj.m`, and `a[0]`,
// since brackets are not parentheses. It is also false on the Calls the
// parser synthesises with no source of their own, such as the read half
// of an op-assign.
//
// Deciding VCALL takes more than this one bit, because MRI's `operation`
// admits tFID: `foo!` and `foo?` are FCALLs with no parentheses
// (parse.y-ruby_4_0:4370-4374 and 6696-6698), and a literal block makes an
// FCALL too (`primary: fcall brace_block`, parse.y-ruby_4_0:4458-4463). A
// consumer wanting VCALL should ask for Recv == nil && !Paren &&
// len(Args) == 0 && Block == nil && a Name that is a plain identifier
// (no trailing ! or ?).
Paren bool
}
Call is a method call. Recv is nil for a self/funcall (e.g. `puts x`, `fib(n)`). Block is an optional literal block ({…} or do…end) attached to the call.
type Case ¶
type Case struct {
Subject Node // nil for the condition form
Whens []WhenClause
Else []Node // nil if no else
}
Case is `case [Subject] (when …)* [else …] end`. With a Subject each `when` matches via `cond === Subject`; without one, each `when` is a boolean test.
type CaseIn ¶
CaseIn is `case Subject (in PATTERN [guard]; BODY)* [else BODY] end` — Ruby pattern matching. Unlike Case, each clause matches the subject against a structural Pattern (deconstruction + binding), and a failed match with no else raises NoMatchingPatternError.
type ClassDef ¶
type ClassDef struct {
Name string
NamePath Node // *ScopedConst for `class A::B` / `class ::B`, else nil
Super string // "" if none and SuperExpr is nil
SuperExpr Node // non-nil superclass expression (e.g. a `::`-path), else nil
Body []Node
}
ClassDef defines or reopens a class. Super is the optional superclass name.
Name carries the simple constant name; for a scope-resolution path (`class Foo::Bar`) or a leading-`::` name (`class ::Bar`) NamePath holds the full ScopedConst and Name is the trailing segment. SuperExpr, when non-nil, holds a superclass that is a `::`-path or otherwise not a bare constant; for a bare-constant superclass Super holds its name and SuperExpr is nil.
type ConstAssign ¶
ConstAssign assigns to a constant: NAME = value.
type ConstPattern ¶
type ConstPattern struct{ Const Node }
ConstPattern matches when `subject.is_a?(Const)` (`in Integer`, `in String`).
type ConstRef ¶
type ConstRef struct{ Name string }
ConstRef references a constant (e.g. a class name) by name.
type FindPattern ¶
FindPattern is the array find pattern `[*pre, mid…, *post]`: it scans the deconstructed array for the first window where every Mid sub-pattern matches consecutively, binding PreName to the elements before it and PostName to those after. Const, when non-nil, additionally requires subject.is_a?(Const).
type For ¶
For is a `for VARS in ITER ... end` loop. Unlike a block, a `for` does not introduce a new scope, so its variables remain visible after the loop.
MRI's loop variable is `for_var: lhs | mlhs`, i.e. any assignment target or any multiple-assignment target list. The common shapes — one local, or a comma-separated list of locals — are in Vars, which is what they have always been. Everything else needs a node, and then Target is non-nil and Vars is EMPTY, so there is only ever one place to read the loop variable from:
- a single non-local target (`for @v in …`, `for $v in …`, `for C in …`, `for o.a in …`, `for a[0] in …`): Target is that target, already in its assignable form (a setter call for the attribute and index forms).
- any list that Vars cannot spell — one holding a `*rest` (`for a, *b in …`), a nested group (`for a, (b, c) in …`), a non-local (`for @a, b in …`), or a trailing comma (`for a, in …`, which destructures where `for a in …` does not): Target is a *MultiAssign with Values nil, the same shape a nested masgn target has.
type ForwardArgs ¶
type ForwardArgs struct{}
ForwardArgs is the `...` forwarding argument inside a call (`g(...)`): it splices the enclosing method's forwarded positional, keyword, and block arguments into this call. It only appears in a method that declared `...`.
type GVarRef ¶
type GVarRef struct{ Name string }
GVarRef references a global variable by name ("$~", "$1", "$stdout", …).
type HashLit ¶
type HashLit struct {
Keys []Node
Values []Node
// Braced is true when the hash was written as `{…}`, and false when the
// parser collected it from bare `k: v` pairs in an argument list.
Braced bool
}
HashLit is a hash literal {k => v, …}; Keys[i] maps to Values[i].
Braced records one bit of WRITTEN FORM, exactly as MRI's own parser does: `primary: tLBRACE assoc_list '}'` sets `RNODE_HASH($$)->nd_brace = TRUE` (parse.y-ruby_4_0:4415-4419), while `rb_node_hash_new` leaves it 0 for every hash the grammar assembles itself (parse.y-ruby_4_0:11784-11791). The two spellings mean different things at a call site: `f({k: 1})` passes a POSITIONAL Hash and `f(k: 1)` passes KEYWORDS. MRI reads the bit back for exactly that question (aryset_check, parse.y-ruby_4_0:13669).
The bit says only "written with braces". It is NOT conditional on being an argument, again as in MRI: `x = {a: 1}` is Braced too. A consumer that wants "positional Hash argument" asks Braced of a node it already found in Call.Args. A `{` that opens a BLOCK never reaches the hash-literal production at all — that disambiguation is the lexer's (parse.y-ruby_4_0:11141-11153) and ours (see parseHashLiteral) — so `obj.m {}` builds no HashLit to ask.
type HashPattern ¶
type HashPattern struct {
Const Node
Keys []string
Values []Pattern
HasRest bool
RestName string
RestNil bool
}
HashPattern matches a hash-like subject via the deconstruct_keys protocol. Keys[i] is the symbol key; Values[i] is its sub-pattern, or nil for the shorthand `{name:}` that binds local `name`. RestNil requires no extra keys (`**nil`); RestName captures the remaining keys into a Hash (`**rest`); HasRest distinguishes `**rest` from no double-splat. Const, when non-nil, additionally requires `subject.is_a?(Const)` (`in Point(x:, y:)`).
type ImaginaryLit ¶
type ImaginaryLit struct{ Value Node }
ImaginaryLit is an imaginary literal (`3i`, `2.5i`, and the combined `2ri` rational-imaginary): Value is the underlying numeric literal the `i` suffix promotes (itself possibly a RationalLit for the `ri` form).
type InClause ¶
InClause is one `in PATTERN [if cond | unless cond] [then] BODY`. GuardNeg is true for an `unless` guard. Guard is nil when there is no guard.
type IvarRef ¶
type IvarRef struct{ Name string }
IvarRef reads an instance variable (@name) of self.
type KwParam ¶
KwParam is a single keyword parameter. Default is nil for a required keyword (`a:`); non-nil for an optional one (`a: expr`).
type MatchPattern ¶
MatchPattern is a one-line pattern match: `Subject => Pattern` (Bool false: rightward assignment — binds on success, raises NoMatchingPatternError on failure) or `Subject in Pattern` (Bool true: a boolean test — true/false, binding on success).
type MethodDef ¶
type MethodDef struct {
Name string
Params []string
Defaults []Node // parallel to Params; nil for a required param
SplatIndex int // index of the *splat param in Params, or -1
KwParams []KwParam // keyword parameters (a:, b: default), after positionals
KwRest string // name of the **rest keyword-splat param, or "" if none
BlockParam string // name of the &block param, or "" if none
Singleton bool // def self.foo — a singleton (class) method
Recv Node // def recv.foo — explicit non-self receiver (nil otherwise)
Forward bool // def f(...) / def f(a, ...) — accepts forwarded arguments
Body []Node
}
MethodDef defines a method on the current self.
type ModuleDef ¶
type ModuleDef struct {
Name string
NamePath Node // *ScopedConst for `module A::B` / `module ::B`, else nil
Body []Node
}
ModuleDef defines or reopens a module. NamePath mirrors ClassDef.NamePath: it is non-nil for a scope-resolution or leading-`::` module name, in which case Name is the trailing segment.
type MultiAssign ¶
type MultiAssign struct {
Names []string
Targets []Node // nil for all-locals; else parallel to Names
SplatIndex int
Values []Node
}
MultiAssign is a destructuring assignment to local targets: a, b = 1, 2 or a, *b = list. SplatIndex is the index of the *splat target in Names, or -1.
Targets, when non-nil, is parallel to Names and holds the general LHS target node for each position (e.g. a *ConstRef for a constant target `A, B = …`). It is left nil for the all-locals case so consumers that only understand local targets keep working; when any target is not a plain local, Targets is populated for every position and Names mirrors it (the local name, or "" for a non-local target whose splat capture, if any, has no local name).
type Next ¶
type Next struct{ Value Node }
Next skips to the next iteration of the innermost block or loop. Value may be nil.
type Node ¶
type Node interface {
// contains filtered or unexported methods
}
Node is any AST node.
type OpAssign ¶
OpAssign is compound assignment to a local: `Name Op= Value` (e.g. x += 1, x ||= 5). Compiled so a fresh local is allocated before its read.
type Pattern ¶
type Pattern interface {
// contains filtered or unexported methods
}
Pattern is any case/in pattern node.
type Program ¶
Program is the top-level sequence of expressions.
Lines gives the 1-based source line each STATEMENT node in the tree began on, keyed by the node itself (every Node is a distinct pointer, so the map is exact). It is how a consumer says WHERE something is: a backtrace, Ruby's __LINE__, Module#const_source_location. A node with no entry reads back as line 0, which is what MRI's rb_iseq_line_no returns for a pc its own table cannot place (iseq.c v3_4_0:2314).
The granularity is deliberate. MRI attaches a line to every node and compiles a per-instruction table from it (compile.c v3_4_0: ADD_INSN records nd_line(node); iseq.c:673 rb_iseq_insns_info_encode_positions builds insns_info + positions), but that table is COMPRESSED — one entry per line CHANGE, not per instruction — and every reader resolves a pc to the nearest preceding entry. Statement boundaries are where the line changes in all but pathological source, so this map holds the same information at the granularity a consumer can observe, without a position field on every node type.
("55" stood here and the count is 56 as of parser v0.11.0. A count of something the file itself defines rots on the next addition and says nothing the reader needs, so it is gone rather than corrected.)
type RationalLit ¶
type RationalLit struct{ Value Node }
RationalLit is a rational literal (`2r`, `0.5r`): Value is the underlying numeric literal (an IntLit, BignumLit, or FloatLit) the `r` suffix promotes.
type RegexpLit ¶
RegexpLit is a regexp literal /source/flags. Flags holds, in source order, the subset of the flag letters i, m, x, o and the encoding flags n (ASCII-8BIT), u (UTF-8), e (EUC-JP) and s (Windows-31J) that were present.
type RescueClause ¶
type RescueClause struct {
Classes []Node
Var string // plain-local capture name (`rescue => e`), or "" — see VarTarget
// VarTarget is the general capture target when it is not a plain local —
// an instance/class/global variable, a constant, or an attribute/index
// (`rescue => @error`, `rescue => $g`, `rescue => obj.err`). It is the LHS
// node the caught exception is assigned to; nil when Var carries a local.
VarTarget Node
Body []Node
}
RescueClause is one `rescue [Classes] [=> Var] BODY`. Empty Classes means rescue StandardError.
type Retry ¶
type Retry struct{}
Retry restarts the enclosing begin body from inside a rescue clause.
type ScopedConst ¶
type ScopedConst struct {
Recv Node
Name string
Global bool // true for a leading `::Name` (top-level constant lookup)
}
ScopedConst is a constant looked up through ::, e.g. Math::PI or Foo::BAR. Recv evaluates to the module/class whose constant table is consulted. A nil Recv with Global true is a leading-`::` top-level lookup (`::Foo`).
type ScopedConstAssign ¶
ScopedConstAssign assigns to a scope-resolved constant: `A::B = value` or the top-level `::A = value`. Target is the *ScopedConst that names the constant.
type SingletonClassDef ¶
SingletonClassDef opens the singleton (metaclass) of Target: `class << Target; Body; end`. Methods and constants defined in Body attach to Target's singleton class. `class << self` (Target is *SelfLit) is the idiomatic form for defining class methods; `class << obj` opens an arbitrary object's singleton class.
type SplatArg ¶
type SplatArg struct{ Value Node }
SplatArg is a `*expr` argument or array element: its (array) value is spliced into the surrounding argument list / array.
type StrInterp ¶
type StrInterp struct{ Parts []Node }
StrInterp is an interpolated double-quoted string: the parts alternate string literals and embedded expressions, all coerced with to_s and concatenated.
type StringLit ¶
type StringLit struct{ Value string }
StringLit is a (Phase 0: non-interpolated) string literal.
type Super ¶
type Super struct {
Args []Node
Forward bool
Block *Block // a `do…end` / `{…}` block passed to super, or nil
}
Super calls the same-named method in the ancestor chain. Forward is true for a bare `super` (passes the enclosing method's own arguments); otherwise Args are the explicit arguments of `super(...)`.
type SymbolLit ¶
type SymbolLit struct{ Name string }
SymbolLit is a symbol literal (:name); Name excludes the leading colon.
type Undef ¶
Undef is `undef name [, name…]` — it removes the named method(s) from the current class/module. Names hold the bare method names.
A dynamic symbol (`undef :"#{x}"`) has an empty string at its position in Names and its expression at the same index of Exprs. Exprs is nil when every name is static, and otherwise has exactly len(Names) entries, nil at each static position.
type ValuePattern ¶
type ValuePattern struct{ Value Node }
ValuePattern matches when `Value === subject` (literals, ranges, pinned expressions): the subject is tested but not destructured.
type VarRef ¶
type VarRef struct{ Name string }
VarRef references a local variable known to the current scope.
type WhenClause ¶
WhenClause is one `when COND[, COND…] [then] BODY`.