-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparsers.go
564 lines (472 loc) · 15.6 KB
/
parsers.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
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
package parser
import (
"fmt"
"strconv"
"github.com/manishmeganathan/tunalang/lexer"
"github.com/manishmeganathan/tunalang/syntaxtree"
)
const (
_ int = iota
LOWEST
EQUALS // ==
LESSGREATER // > or <
SUM // +
PRODUCT // *
PREFIX // -X or !X
CALL // myFunction(X)
INDEX // myList[X]
)
var precedences = map[lexer.TokenType]int{
lexer.EQ: EQUALS,
lexer.NOT_EQ: EQUALS,
lexer.LT: LESSGREATER,
lexer.GT: LESSGREATER,
lexer.PLUS: SUM,
lexer.MINUS: SUM,
lexer.SLASH: PRODUCT,
lexer.ASTERISK: PRODUCT,
lexer.LPAREN: CALL,
lexer.LBRACK: INDEX,
}
var traceON = false
// A function that returns the precedence value
// for the given lexilogical token type
func GetPrecedence(tokentype lexer.TokenType) int {
// Check the precedence table for the token type
if p, ok := precedences[tokentype]; ok {
// Return the precedence value
return p
}
// Return the lowest precedence if not found in the map
return LOWEST
}
// A method of Parser that parses the lexer input
// into an abstract syntax tree Program
func (p *Parser) ParseProgram() *syntaxtree.Program {
// Create a syntax tree program
program := &syntaxtree.Program{}
// Initialize the syntax tree statements slice
program.Statements = []syntaxtree.Statement{}
// Iterate until the lexer returns an EOF token
for !p.isCursorToken(lexer.EOF) {
// Parse the current token into a statement
stmt := p.parseStatement()
// Add the statement to the syntax tree program statements
program.Statements = append(program.Statements, stmt)
// Advance the parse cursor
p.NextToken()
}
// Return the parsed syntax tree program
return program
}
// A method of Parser that parses the token in the
// parse cursor into an syntax tree statement node
func (p *Parser) parseStatement() syntaxtree.Statement {
// Check the value of the token in the parse cursor
switch p.cursorToken.Type {
// Let Statement
case lexer.LET:
// Parse the statement into a 'let' statement
return p.parseLetStatement()
// Return Statement
case lexer.RETURN:
// Parse the statement into a 'return' statement
return p.parseReturnStatement()
// Expression Statement
default:
// Parse the statement into an 'expression' statement
return p.parseExpressionStatement()
}
}
// A method of Parser that parses the token in the parse
// cursor into a LET statement node for the syntax tree
func (p *Parser) parseLetStatement() *syntaxtree.LetStatement {
// Create a LET statement node with the token
stmt := &syntaxtree.LetStatement{Token: p.cursorToken}
// Check the peek cursor for an identfier token and move to it
if !p.expectPeek(lexer.IDENT) {
// no identifier token detected i.e invalid let statement
return nil
}
// Assign the statement identifier to the statement node
stmt.Name = &syntaxtree.Identifier{Token: p.cursorToken, Value: p.cursorToken.Literal}
// Check the peek cursor for assignment token and move to it
if !p.expectPeek(lexer.ASSIGN) {
// no assign token detcted i.e invalid let statement
return nil
}
// Advance the parse cursor
p.NextToken()
// Assign the parsed let value expression
stmt.Value = p.parseExpression(LOWEST)
// Advance until semicolon in encountered
if p.isPeekToken(lexer.SEMICOLON) {
// Advance the parse cursor
p.NextToken()
}
// Return the parsed let statement
return stmt
}
// A method of Parser that parses the token in the parse
// cursor into a RETURN statement node for the syntax tree
func (p *Parser) parseReturnStatement() *syntaxtree.ReturnStatement {
// Create a RETURN statement node with the token
stmt := &syntaxtree.ReturnStatement{Token: p.cursorToken}
// Advance the parse cursor
p.NextToken()
// Assign the parsed return value
stmt.ReturnValue = p.parseExpression(LOWEST)
// Advance until semicolon in encountered
if p.isPeekToken(lexer.SEMICOLON) {
p.NextToken()
}
// Return the parsed return statement
return stmt
}
// A method of Parser that parses the token in the parse
// cursor into an expression statement node for the syntax tree
func (p *Parser) parseExpressionStatement() *syntaxtree.ExpressionStatement {
if traceON {
// Print parser trace
defer untrace(trace("parseExpressionStatement"))
}
// Create an expression statement node with the token
stmt := &syntaxtree.ExpressionStatement{Token: p.cursorToken}
// Parse the full expression
stmt.Expression = p.parseExpression(LOWEST)
// Check if the next token is a semicolon
// (expressions do not have to end with a semicolon)
if p.isPeekToken(lexer.SEMICOLON) {
// Advance the parse cursor
p.NextToken()
}
// Returned the parsed expression statement
return stmt
}
// A method of Parser that parses a full expression given a precedence value
func (p *Parser) parseExpression(precedence int) syntaxtree.Expression {
if traceON {
// Print parser trace
defer untrace(trace("parseExpression"))
}
// Retrive the prefix parser function
prefix := p.prefixParseFns[p.cursorToken.Type]
// Check if the prefix parser is null
if prefix == nil {
p.noPrefixParseFnError(p.cursorToken.Type)
// Return a nil
return nil
}
// Call the prefix parser
leftExp := prefix()
// Iterate on the token and check if the next token is neither a
// semicolon and hash a precedence below the the given precedence
for !p.isPeekToken(lexer.SEMICOLON) && precedence < GetPrecedence(p.peekToken.Type) {
// Retrive the infix parser function
infix := p.infixParseFns[p.peekToken.Type]
// Check if the infix parser is null
if infix == nil {
// Return the left expression as is
return leftExp
}
// Advance the parse cursor
p.NextToken()
// Call the infix parser on left expression and update it
leftExp = infix(leftExp)
}
// Return the left expression
return leftExp
}
// A method of Parser that parses an Identifier literal
func (p *Parser) parseIdentifier() syntaxtree.Expression {
return &syntaxtree.Identifier{Token: p.cursorToken, Value: p.cursorToken.Literal}
}
// A method of Parser that parses an Integer literal
func (p *Parser) parseIntegerLiteral() syntaxtree.Expression {
if traceON {
// Print parser trace
defer untrace(trace("parseIntegerLiteral"))
}
// Create an integer literal node with the token
lit := &syntaxtree.IntegerLiteral{Token: p.cursorToken}
// Parse the literal to int64
value, err := strconv.ParseInt(p.cursorToken.Literal, 0, 64)
// Check the error
if err != nil {
// Construct an error message
msg := fmt.Sprintf("could not parse %q as integer", p.cursorToken.Literal)
// Add the error to parser's errors
p.Errors = append(p.Errors, msg)
// Return a nil
return nil
}
// Assign the integer literal node's value
lit.Value = value
// Return the integer literal node
return lit
}
// A method of Parser that parses a Prefix Expression
func (p *Parser) parsePrefixExpression() syntaxtree.Expression {
if traceON {
// Print parser trace
defer untrace(trace("parsePrefixExpression"))
}
// Create a prefix expression node with the token and operator literal
expression := &syntaxtree.PrefixExpression{
Token: p.cursorToken,
Operator: p.cursorToken.Literal,
}
// Advance the parse cursor
p.NextToken()
// Assign the prefix expression node's expression value
expression.Right = p.parseExpression(PREFIX)
// Return the prefix expression node
return expression
}
// A method of Parser that parses an Infix Expression
func (p *Parser) parseInfixExpression(left syntaxtree.Expression) syntaxtree.Expression {
if traceON {
// Print parser trace
defer untrace(trace("parseInfixExpression"))
}
// Create an infix expression node with the token, operator literal and left expression
expression := &syntaxtree.InfixExpression{
Token: p.cursorToken,
Operator: p.cursorToken.Literal,
Left: left,
}
// Determine the precedence of the cursor token
precedence := GetPrecedence(p.cursorToken.Type)
// Advance the parse cursor
p.NextToken()
// Assign the right expression to the parsed value of
// the right expression with the given precedence
expression.Right = p.parseExpression(precedence)
// Return the infix expression node
return expression
}
// A method of Parser that parses a Boolean Literal
func (p *Parser) parseBooleanLiteral() syntaxtree.Expression {
return &syntaxtree.BooleanLiteral{Token: p.cursorToken, Value: p.isCursorToken(lexer.TRUE)}
}
// A method of Parser that parses a String Literal
func (p *Parser) parseStringLiteral() syntaxtree.Expression {
return &syntaxtree.StringLiteral{Token: p.cursorToken, Value: p.cursorToken.Literal}
}
// A method of Parser that parses Grouped Expressions
func (p *Parser) parseGroupedExpression() syntaxtree.Expression {
// Advance the parse cursor
p.NextToken()
// Parse the expression in the parentheses
exp := p.parseExpression(LOWEST)
// Check for closing parentheses
if !p.expectPeek(lexer.RPAREN) {
return nil
}
// Return the parsed parentheses
return exp
}
// A method of Parser that parses Block Statements
func (p *Parser) parseBlockStatement() *syntaxtree.BlockStatement {
// Create a block statement node for the syntax tree
block := &syntaxtree.BlockStatement{Token: p.cursorToken}
// Initialze the block statements slice
block.Statements = []syntaxtree.Statement{}
// Advance the parse cursor
p.NextToken()
// Iterate until an } or EOF token is encountered
for !p.isCursorToken(lexer.RBRACE) && !p.isCursorToken(lexer.EOF) {
// Parse the statement
stmt := p.parseStatement()
// Add it the to block statements
block.Statements = append(block.Statements, stmt)
// Advance the parse cursor
p.NextToken()
}
// Return the parsed block statement
return block
}
// A method of Parser that parses If Expressions
func (p *Parser) parseIfExpression() syntaxtree.Expression {
// Create an if expression node for the syntax tree
expression := &syntaxtree.IfExpression{Token: p.cursorToken}
// Check for the conditional opening ( token
if !p.expectPeek(lexer.LPAREN) {
return nil
}
// Advance the parse cursor
p.NextToken()
// Parse the condition expression
expression.Condition = p.parseExpression(LOWEST)
// Check for the conditional ending ) token
if !p.expectPeek(lexer.RPAREN) {
return nil
}
// Check for the block opening { token
if !p.expectPeek(lexer.LBRACE) {
return nil
}
// Parse the consequence block statement
expression.Consequence = p.parseBlockStatement()
// Check the ELSE token
if p.isPeekToken(lexer.ELSE) {
// Advance the parse cursor
p.NextToken()
// Check for the block opening { token
if !p.expectPeek(lexer.LBRACE) {
return nil
}
// Parse the alternate consequence block statement
expression.Alternative = p.parseBlockStatement()
}
// Return the parsed if expression
return expression
}
// A method of Parser that parses Function parameters
func (p *Parser) parseFunctionParameters() []*syntaxtree.Identifier {
// Initialize a slice of identifier nodes
identifiers := []*syntaxtree.Identifier{}
// Check if the next token is ) token
if p.isPeekToken(lexer.RPAREN) {
// Advance the parse cursor
p.NextToken()
// Return the empty list of identifiers
return identifiers
}
// Advance the parse cursor
p.NextToken()
// Create an identifer node for the syntax tree and add it to the list
ident := &syntaxtree.Identifier{Token: p.cursorToken, Value: p.cursorToken.Literal}
identifiers = append(identifiers, ident)
// Iterate as long as the next token is comma
for p.isPeekToken(lexer.COMMA) {
// Advance the parse cursor twice (skip the over the comma)
p.NextToken()
p.NextToken()
// Create an identifer node for the syntax tree and add it to the list
ident := &syntaxtree.Identifier{Token: p.cursorToken, Value: p.cursorToken.Literal}
identifiers = append(identifiers, ident)
}
// Check for the ) token
if !p.expectPeek(lexer.RPAREN) {
return nil
}
// Return the list of idenfier nodes for the function parameters
return identifiers
}
// A method of Parser that parses Function literals
func (p *Parser) parseFunctionLiteral() syntaxtree.Expression {
// Create a function literal node
lit := &syntaxtree.FunctionLiteral{Token: p.cursorToken}
// Check for the function parameter begin ( token
if !p.expectPeek(lexer.LPAREN) {
return nil
}
// Assign the fn paramters after parsing them
lit.Parameters = p.parseFunctionParameters()
// Check for the function block begin { token
if !p.expectPeek(lexer.LBRACE) {
return nil
}
// Assign the fn body after parsing it
lit.Body = p.parseBlockStatement()
// Return the parsed function literal node
return lit
}
// A method of Parser that parses a list of expressions
func (p *Parser) parseExpressionList(end lexer.TokenType) []syntaxtree.Expression {
// Initialize a slice of expression nodes
list := []syntaxtree.Expression{}
// Check if the next token is the end token
if p.isPeekToken(end) {
// Advance the parse cursor
p.NextToken()
// Return the empty list of expressions
return list
}
// Advance the parse cursor
p.NextToken()
// Append the parsed expression to the list
list = append(list, p.parseExpression(LOWEST))
// Iterate as long as the next token is not the end token
for p.isPeekToken(lexer.COMMA) {
// Advance the parse cursor twice (skip over the comma)
p.NextToken()
p.NextToken()
// Append the parsed expression to the list
list = append(list, p.parseExpression(LOWEST))
}
// Check if the next token is the end token
if !p.expectPeek(end) {
return nil
}
// Return the parsed list of expressions
return list
}
// A method of Parser that parses Call expressions
func (p *Parser) parseCallExpression(function syntaxtree.Expression) syntaxtree.Expression {
// Create a call expression node for the syntax tree
exp := &syntaxtree.CallExpression{Token: p.cursorToken, Function: function}
// Parse the call arguments
exp.Arguments = p.parseExpressionList(lexer.RPAREN)
// Return the parsed call expression
return exp
}
// A method of Parser that parses List literals
func (p *Parser) parseListLiteral() syntaxtree.Expression {
// Create a list literal node for the syntax tree
list := &syntaxtree.ListLiteral{Token: p.cursorToken}
// Parse the expression for the list elements
list.Elements = p.parseExpressionList(lexer.RBRACK)
// Return the parsed list literal
return list
}
// A method of Parser that parses Index expressions
func (p *Parser) parseIndexExpression(left syntaxtree.Expression) syntaxtree.Expression {
// Create an index expression node for the syntax tree
exp := &syntaxtree.IndexExpression{Token: p.cursorToken, Left: left}
// Advance the parse cursor
p.NextToken()
// Parse the expression for the index
exp.Index = p.parseExpression(LOWEST)
// Check for the ] token
if !p.expectPeek(lexer.RBRACK) {
return nil
}
// Return the parsed index expression
return exp
}
// A method of Parser that parses Map literals
func (p *Parser) parseMapLiteral() syntaxtree.Expression {
// Create a map literal node for the syntax tree
hash := &syntaxtree.MapLiteral{Token: p.cursorToken}
// Initialize a map for key value pairs
hash.Pairs = make(map[syntaxtree.Expression]syntaxtree.Expression)
// Iterate until the next token is the } token
for !p.isPeekToken(lexer.RBRACE) {
// Advance the parse cursor
p.NextToken()
// Parse the key expression
key := p.parseExpression(LOWEST)
// Assert the colon token expected
if !p.expectPeek(lexer.COLON) {
return nil
}
// Advance the parse cursor
p.NextToken()
// Parse the value expression
value := p.parseExpression(LOWEST)
// Assign the key value pair
hash.Pairs[key] = value
// Check if the map either continues or ends
if !p.isPeekToken(lexer.RBRACE) && !p.expectPeek(lexer.COMMA) {
return nil
}
}
// Check if the next token is the } token
if !p.expectPeek(lexer.RBRACE) {
return nil
}
// Return the parsed map literal
return hash
}