Skip to content

Commit 0531ea5

Browse files
committed
Add ast comments
Rename program.Opcodes() to program.DisassembleWriter()
1 parent 7244266 commit 0531ea5

File tree

3 files changed

+112
-49
lines changed

3 files changed

+112
-49
lines changed

ast/node.go

Lines changed: 105 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,179 +16,238 @@ type Node interface {
1616
String() string
1717
}
1818

19+
// Patch replaces the node with a new one.
20+
// Location information is preserved.
21+
// Type information is lost.
1922
func Patch(node *Node, newNode Node) {
2023
newNode.SetLocation((*node).Location())
2124
*node = newNode
2225
}
2326

27+
// base is a base struct for all nodes.
2428
type base struct {
2529
loc file.Location
2630
nodeType reflect.Type
2731
}
2832

33+
// Location returns the location of the node in the source code.
2934
func (n *base) Location() file.Location {
3035
return n.loc
3136
}
3237

38+
// SetLocation sets the location of the node in the source code.
3339
func (n *base) SetLocation(loc file.Location) {
3440
n.loc = loc
3541
}
3642

43+
// Type returns the type of the node.
3744
func (n *base) Type() reflect.Type {
3845
return n.nodeType
3946
}
4047

48+
// SetType sets the type of the node.
4149
func (n *base) SetType(t reflect.Type) {
4250
n.nodeType = t
4351
}
4452

53+
// NilNode represents nil.
4554
type NilNode struct {
4655
base
4756
}
4857

58+
// IdentifierNode represents an identifier.
4959
type IdentifierNode struct {
5060
base
51-
Value string
52-
FieldIndex []int
53-
Method bool // true if method, false if field
54-
MethodIndex int // index of method, set only if Method is true
61+
Value string // Name of the identifier. Like "foo" in "foo.bar".
62+
FieldIndex []int // Index of the field in the list of fields.
63+
Method bool // If true then the identifier is a method call.
64+
MethodIndex int // Index of the method in the list of methods.
5565
}
5666

67+
// SetFieldIndex sets the field index of the identifier.
5768
func (n *IdentifierNode) SetFieldIndex(field []int) {
5869
n.FieldIndex = field
5970
}
6071

72+
// SetMethodIndex sets the method index of the identifier.
6173
func (n *IdentifierNode) SetMethodIndex(methodIndex int) {
6274
n.Method = true
6375
n.MethodIndex = methodIndex
6476
}
6577

78+
// IntegerNode represents an integer.
6679
type IntegerNode struct {
6780
base
68-
Value int
81+
Value int // Value of the integer.
6982
}
7083

84+
// FloatNode represents a float.
7185
type FloatNode struct {
7286
base
73-
Value float64
87+
Value float64 // Value of the float.
7488
}
7589

90+
// BoolNode represents a boolean.
7691
type BoolNode struct {
7792
base
78-
Value bool
93+
Value bool // Value of the boolean.
7994
}
8095

96+
// StringNode represents a string.
8197
type StringNode struct {
8298
base
83-
Value string
99+
Value string // Value of the string.
84100
}
85101

102+
// ConstantNode represents a constant.
103+
// Constants are predefined values like nil, true, false, array, map, etc.
104+
// The parser.Parse will never generate ConstantNode, it is only generated
105+
// by the optimizer.
86106
type ConstantNode struct {
87107
base
88-
Value any
108+
Value any // Value of the constant.
89109
}
90110

111+
// UnaryNode represents a unary operator.
91112
type UnaryNode struct {
92113
base
93-
Operator string
94-
Node Node
114+
Operator string // Operator of the unary operator. Like "!" in "!foo" or "not" in "not foo".
115+
Node Node // Node of the unary operator. Like "foo" in "!foo".
95116
}
96117

118+
// BinaryNode represents a binary operator.
97119
type BinaryNode struct {
98120
base
99-
Regexp *regexp.Regexp
100-
Operator string
101-
Left Node
102-
Right Node
121+
Regexp *regexp.Regexp // Regexp of the "matches" operator. Like "f.+" in `foo matches "f.+"`.
122+
Operator string // Operator of the binary operator. Like "+" in "foo + bar" or "matches" in "foo matches bar".
123+
Left Node // Left node of the binary operator.
124+
Right Node // Right node of the binary operator.
103125
}
104126

127+
// ChainNode represents an optional chaining group.
128+
// A few MemberNode nodes can be chained together,
129+
// and will be wrapped in a ChainNode. Example:
130+
// ```
131+
// foo.bar?.baz?.qux
132+
// ```
133+
// The whole chain will be wrapped in a ChainNode.
105134
type ChainNode struct {
106135
base
107-
Node Node
136+
Node Node // Node of the chain.
108137
}
109138

139+
// MemberNode represents a member access.
140+
// It can be a field access, a method call,
141+
// or an array element access.
142+
// Example:
143+
// ```
144+
// foo.bar or foo["bar"]
145+
// foo.bar()
146+
// array[0]
147+
// ```
110148
type MemberNode struct {
111149
base
112-
Node Node
113-
Property Node
150+
Node Node // Node of the member access. Like "foo" in "foo.bar".
151+
Property Node // Property of the member access. For property access it is a StringNode.
114152
Name string // Name of the filed or method. Used for error reporting.
115-
Optional bool
116-
FieldIndex []int
153+
Optional bool // If true then the member access is optional. Like "foo?.bar".
154+
FieldIndex []int // Index sequence of fields. Generated by type checker.
117155

118156
// TODO: Combine Method and MethodIndex into a single MethodIndex field of &int type.
119-
Method bool
120-
MethodIndex int
157+
Method bool // If true then the member access is a method call.
158+
MethodIndex int // Index of the method in the list of methods. Generated by type checker.
121159
}
122160

161+
// SetFieldIndex sets the field index of the member access.
123162
func (n *MemberNode) SetFieldIndex(field []int) {
124163
n.FieldIndex = field
125164
}
126165

166+
// SetMethodIndex sets the method index of the member access.
127167
func (n *MemberNode) SetMethodIndex(methodIndex int) {
128168
n.Method = true
129169
n.MethodIndex = methodIndex
130170
}
131171

172+
// SliceNode represents access to a slice of an array.
173+
// Example:
174+
// ```
175+
// array[1:4]
176+
// ```
132177
type SliceNode struct {
133178
base
134-
Node Node
135-
From Node
136-
To Node
179+
Node Node // Node of the slice. Like "array" in "array[1:4]".
180+
From Node // From an index of the array. Like "1" in "array[1:4]".
181+
To Node // To an index of the array. Like "4" in "array[1:4]".
137182
}
138183

184+
// CallNode represents a function or a method call.
139185
type CallNode struct {
140186
base
141-
Callee Node
142-
Arguments []Node
143-
Typed int
144-
Fast bool
145-
Func *Function
187+
Callee Node // Node of the call. Like "foo" in "foo()".
188+
Arguments []Node // Arguments of the call.
189+
Typed int // If more than 0 then the call is one of the types from vm.FuncTypes.
190+
Fast bool // If true then the call type is "func(...any) any".
191+
Func *Function // If not nil then the func is provider via expr.Function.
146192
}
147193

194+
// BuiltinNode represents a builtin function call.
148195
type BuiltinNode struct {
149196
base
150-
Name string
151-
Arguments []Node
152-
Throws bool
153-
Map Node
197+
Name string // Name of the builtin function. Like "len" in "len(foo)".
198+
Arguments []Node // Arguments of the builtin function.
199+
Throws bool // If true then accessing a field or array index can throw an error. Used by optimizer.
200+
Map Node // Used by optimizer to fold filter() and map() builtins.
154201
}
155202

203+
// ClosureNode represents a predicate.
204+
// Example:
205+
// ```
206+
// filter(foo, .bar == 1)
207+
// ```
208+
// The predicate is `.bar == 1`.
156209
type ClosureNode struct {
157210
base
158-
Node Node
211+
Node Node // Node of the predicate body.
159212
}
160213

214+
// PointerNode represents a pointer to a current value in predicate.
161215
type PointerNode struct {
162216
base
163-
Name string
217+
Name string // Name of the pointer. Like "index" in "#index".
164218
}
165219

220+
// ConditionalNode represents a ternary operator.
166221
type ConditionalNode struct {
167222
base
168-
Cond Node
169-
Exp1 Node
170-
Exp2 Node
223+
Cond Node // Condition of the ternary operator. Like "foo" in "foo ? bar : baz".
224+
Exp1 Node // Expression 1 of the ternary operator. Like "bar" in "foo ? bar : baz".
225+
Exp2 Node // Expression 2 of the ternary operator. Like "baz" in "foo ? bar : baz".
171226
}
172227

228+
// VariableDeclaratorNode represents a variable declaration.
173229
type VariableDeclaratorNode struct {
174230
base
175-
Name string
176-
Value Node
177-
Expr Node
231+
Name string // Name of the variable. Like "foo" in "let foo = 1; foo + 1".
232+
Value Node // Value of the variable. Like "1" in "let foo = 1; foo + 1".
233+
Expr Node // Expression of the variable. Like "foo + 1" in "let foo = 1; foo + 1".
178234
}
179235

236+
// ArrayNode represents an array.
180237
type ArrayNode struct {
181238
base
182-
Nodes []Node
239+
Nodes []Node // Nodes of the array.
183240
}
184241

242+
// MapNode represents a map.
185243
type MapNode struct {
186244
base
187-
Pairs []Node
245+
Pairs []Node // PairNode nodes.
188246
}
189247

248+
// PairNode represents a key-value pair of a map.
190249
type PairNode struct {
191250
base
192-
Key Node
193-
Value Node
251+
Key Node // Key of the pair.
252+
Value Node // Value of the pair.
194253
}

debug/debugger.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func StartDebugger(program *Program, env any) {
5959

6060
index := make(map[int]int)
6161
var buf strings.Builder
62-
program.Opcodes(&buf)
62+
program.DisassembleWriter(&buf)
6363

6464
for row, line := range strings.Split(buf.String(), "\n") {
6565
if line == "" {

vm/program.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/antonmedv/expr/vm/runtime"
1515
)
1616

17+
// Program represents a compiled expression.
1718
type Program struct {
1819
Bytecode []Opcode
1920
Arguments []int
@@ -26,6 +27,7 @@ type Program struct {
2627
debugInfo map[string]string
2728
}
2829

30+
// NewProgram returns a new Program. It's used by the compiler.
2931
func NewProgram(
3032
source *file.Source,
3133
locations []file.Location,
@@ -48,15 +50,17 @@ func NewProgram(
4850
}
4951
}
5052

53+
// Disassemble returns opcodes as a string.
5154
func (program *Program) Disassemble() string {
5255
var buf bytes.Buffer
5356
w := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0)
54-
program.Opcodes(w)
57+
program.DisassembleWriter(w)
5558
_ = w.Flush()
5659
return buf.String()
5760
}
5861

59-
func (program *Program) Opcodes(w io.Writer) {
62+
// DisassembleWriter takes a writer and writes opcodes to it.
63+
func (program *Program) DisassembleWriter(w io.Writer) {
6064
ip := 0
6165
for ip < len(program.Bytecode) {
6266
pp := ip

0 commit comments

Comments
 (0)