-
Notifications
You must be signed in to change notification settings - Fork 216
/
ast_print.go
325 lines (284 loc) · 7.39 KB
/
ast_print.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
// ================================================================
// Print routines for AST and ASTNode
// ================================================================
package dsl
import (
"fmt"
"strings"
)
// ================================================================
// Print is indent-style multiline print.
// Example, given parse of '$y = 2 * $x + 1':
//
// * statement block
// * assignment "="
// * direct field value "y"
// * operator "+"
// * operator "*"
// * int literal "2"
// * direct field value "x"
// * int literal "1"
func (ast *AST) Print() {
ast.RootNode.Print()
}
// PrintParex is parenthesized-expression print.
// Example, given parse of '$y = 2 * $x + 1':
//
// (statement-block
// (=
// $y
// (+
// (* 2 $x)
// 1
// )
// )
// )
func (ast *AST) PrintParex() {
ast.RootNode.PrintParex()
}
// PrintParexOneLine is parenthesized-expression print, all on one line.
// Example, given parse of '$y = 2 * $x + 1':
//
// (statement-block (= $y (+ (* 2 $x) 1)))
func (ast *AST) PrintParexOneLine() {
ast.RootNode.PrintParexOneLine()
}
// ================================================================
// Print is indent-style multiline print.
func (node *ASTNode) Print() {
node.printAux(0)
}
// printAux is a recursion-helper for Print.
func (node *ASTNode) printAux(depth int) {
// Indent
for i := 0; i < depth; i++ {
fmt.Print(" ")
}
// Token text (if non-nil) and token type
tok := node.Token
fmt.Print("* " + node.Type)
if tok != nil {
fmt.Printf(" \"%s\"", string(tok.Lit))
}
fmt.Println()
// Children, indented one level further
for _, child := range node.Children {
child.printAux(depth + 1)
}
}
// ----------------------------------------------------------------
// PrintParex is parenthesized-expression print.
func (node *ASTNode) PrintParex() {
node.printParexAux(0)
}
// printParexAux is a recursion-helper for PrintParex.
func (node *ASTNode) printParexAux(depth int) {
if node.IsLeaf() {
for i := 0; i < depth; i++ {
fmt.Print(" ")
}
fmt.Println(node.Text())
} else if node.ChildrenAreAllLeaves() {
// E.g. (= sum 0) or (+ 1 2)
for i := 0; i < depth; i++ {
fmt.Print(" ")
}
fmt.Print("(")
fmt.Print(node.Text())
for _, child := range node.Children {
fmt.Print(" ")
fmt.Print(child.Text())
}
fmt.Println(")")
} else {
// Parent and opening parenthesis on first line
for i := 0; i < depth; i++ {
fmt.Print(" ")
}
fmt.Print("(")
fmt.Println(node.Text())
// Children on their own lines
for _, child := range node.Children {
child.printParexAux(depth + 1)
}
// Closing parenthesis on last line
for i := 0; i < depth; i++ {
fmt.Print(" ")
}
fmt.Println(")")
}
}
// ----------------------------------------------------------------
// PrintParexOneLine is parenthesized-expression print, all on one line.
func (node *ASTNode) PrintParexOneLine() {
node.printParexOneLineAux()
fmt.Println()
}
// printParexOneLineAux is a recursion-helper for PrintParexOneLine.
func (node *ASTNode) printParexOneLineAux() {
if node.IsLeaf() {
fmt.Print(node.Text())
} else {
fmt.Print("(")
fmt.Print(node.Text())
for _, child := range node.Children {
fmt.Print(" ")
child.printParexOneLineAux()
}
fmt.Print(")")
}
}
// ----------------------------------------------------------------
// IsLeaf determines if an AST node is a leaf node.
func (node *ASTNode) IsLeaf() bool {
return len(node.Children) == 0
}
// ChildrenAreAllLeaves determines if an AST node's children are all leaf nodes.
func (node *ASTNode) ChildrenAreAllLeaves() bool {
for _, child := range node.Children {
if !child.IsLeaf() {
return false
}
}
return true
}
// ----------------------------------------------------------------
// Text makes a human-readable, whitespace-free name for an AST node. Some
// nodes have non-nil tokens; other, nil. And token-types can have spaces in
// them. In this method we use custom mappings to always get a whitespace-free
// representation of the content of a single AST node.
func (node *ASTNode) Text() string {
tokenText := ""
if node.Token != nil {
tokenText = string(node.Token.Lit)
}
switch node.Type {
case NodeTypeStringLiteral:
return "\"" + strings.ReplaceAll(tokenText, "\"", "\\\"") + "\""
case NodeTypeIntLiteral:
return tokenText
case NodeTypeFloatLiteral:
return tokenText
case NodeTypeBoolLiteral:
return tokenText
case NodeTypeNullLiteral:
return tokenText
case NodeTypeArrayLiteral:
return tokenText
case NodeTypeMapLiteral:
return tokenText
case NodeTypeMapLiteralKeyValuePair:
return tokenText
case NodeTypeArrayOrMapIndexAccess:
return "[]"
case NodeTypeArraySliceAccess:
return "[:]"
case NodeTypeArraySliceEmptyLowerIndex:
return "array-slice-empty-lower-index"
case NodeTypeArraySliceEmptyUpperIndex:
return "array-slice-empty-upper-index"
case NodeTypeContextVariable:
return tokenText
case NodeTypeConstant:
return tokenText
case NodeTypeEnvironmentVariable:
return "ENV[\"" + tokenText + "\"]"
case NodeTypeDirectFieldValue:
return "$" + tokenText
case NodeTypeIndirectFieldValue:
return "$[" + tokenText + "]"
case NodeTypeFullSrec:
return tokenText
case NodeTypeDirectOosvarValue:
return "@" + tokenText
case NodeTypeIndirectOosvarValue:
return "@[" + tokenText + "]"
case NodeTypeFullOosvar:
return tokenText
case NodeTypeLocalVariable:
return tokenText
case NodeTypeTypedecl:
return tokenText
case NodeTypeStatementBlock:
return "statement-block"
case NodeTypeAssignment:
return tokenText
case NodeTypeUnset:
return tokenText
case NodeTypeBareBoolean:
return "bare-boolean"
case NodeTypeFilterStatement:
return tokenText
case NodeTypeEmit1Statement:
return tokenText
case NodeTypeEmitStatement:
return tokenText
case NodeTypeEmitPStatement:
return tokenText
case NodeTypeEmitFStatement:
return tokenText
case NodeTypeDumpStatement:
return tokenText
case NodeTypeEdumpStatement:
return tokenText
case NodeTypePrintStatement:
return tokenText
case NodeTypeEprintStatement:
return tokenText
case NodeTypePrintnStatement:
return tokenText
case NodeTypeEprintnStatement:
return tokenText
case NodeTypeNoOp:
return "no-op"
case NodeTypeOperator:
return tokenText
case NodeTypeDotOperator:
return tokenText
case NodeTypeFunctionCallsite:
return tokenText
case NodeTypeBeginBlock:
return "begin"
case NodeTypeEndBlock:
return "end"
case NodeTypeIfChain:
return "if-chain"
case NodeTypeIfItem:
return tokenText
case NodeTypeCondBlock:
return "cond"
case NodeTypeWhileLoop:
return tokenText
case NodeTypeDoWhileLoop:
return tokenText
case NodeTypeForLoopOneVariable:
return tokenText
case NodeTypeForLoopTwoVariable:
return tokenText
case NodeTypeForLoopMultivariable:
return tokenText
case NodeTypeTripleForLoop:
return tokenText
case NodeTypeBreak:
return tokenText
case NodeTypeContinue:
return tokenText
case NodeTypeNamedFunctionDefinition:
return "named-udf"
case NodeTypeUnnamedFunctionDefinition:
return "unnamed-udf"
case NodeTypeSubroutineDefinition:
return "subr"
case NodeTypeParameterList:
return "parameters"
case NodeTypeParameter:
return "parameter"
case NodeTypeParameterName:
return tokenText
case NodeTypeReturn:
return tokenText
case NodeTypePanic:
return tokenText
}
return "[ERROR]"
}