aboutsummaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-04-04 16:25:56 +0000
committerBobby <[email protected]>2024-04-04 16:25:56 +0000
commit77d0ea46b3f1de99357c7706c4c05eb44c237412 (patch)
treed6fa8ca0a89233b26591eaed72c1017ad6190dba /parser
parent3d4f24f7c4ea05471109c0b13abbc95e70c6924b (diff)
downloadmana-77d0ea46b3f1de99357c7706c4c05eb44c237412.tar.xz
mana-77d0ea46b3f1de99357c7706c4c05eb44c237412.zip
arrays and array indexes
Diffstat (limited to 'parser')
-rw-r--r--parser/parser.go64
-rw-r--r--parser/parser_test.go43
-rw-r--r--parser/parser_tracing.go54
3 files changed, 110 insertions, 51 deletions
diff --git a/parser/parser.go b/parser/parser.go
index a4472b2..4fa36b1 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -18,6 +18,7 @@ const (
PRODUCT // *
PREFIX // -X or !X
CALL // myFunction(X)
+ INDEX // array[index]
)
var precedences = map[tokens.TokenType]int{
@@ -30,6 +31,7 @@ var precedences = map[tokens.TokenType]int{
tokens.SLASH: PRODUCT,
tokens.ASTERISK: PRODUCT,
tokens.LPAREN: CALL,
+ tokens.LBRACKET: INDEX,
}
type (
@@ -85,6 +87,7 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(tokens.LT, p.parseInfixExpression)
p.registerInfix(tokens.GT, p.parseInfixExpression)
p.registerInfix(tokens.LPAREN, p.parseCallExpression)
+ p.registerInfix(tokens.LBRACKET, p.parseIndexExpression)
return p
}
@@ -117,9 +120,9 @@ func (p *Parser) ParseProgram() *ast.Program {
// Parse the statement and append it to the program.
var stmt ast.Statement = p.parseStatement()
- if stmt != nil {
- program.Statements = append(program.Statements, stmt)
- }
+ // if stmt != nil {
+ program.Statements = append(program.Statements, stmt)
+ // }
// Advance to the next token.
p.nextToken()
@@ -334,9 +337,9 @@ func (p *Parser) parseBlockStatement() *ast.BlockStatement {
for !p.curTokenIs(tokens.RBRACE) && !p.curTokenIs(tokens.EOF) {
stmt := p.parseStatement()
- if stmt != nil {
- block.Statements = append(block.Statements, stmt)
- }
+ // if stmt != nil {
+ block.Statements = append(block.Statements, stmt)
+ // }
p.nextToken()
}
@@ -414,29 +417,29 @@ func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression {
}
// parseCallArguments parses call arguments.
-func (p *Parser) parseCallArguments() []ast.Expression {
- args := []ast.Expression{}
+// func (p *Parser) parseCallArguments() []ast.Expression {
+// args := []ast.Expression{}
- if p.peekTokenIs(tokens.RPAREN) {
- p.nextToken()
- return args
- }
+// if p.peekTokenIs(tokens.RPAREN) {
+// p.nextToken()
+// return args
+// }
- p.nextToken()
- args = append(args, p.parseExpression(LOWEST))
+// p.nextToken()
+// args = append(args, p.parseExpression(LOWEST))
- for p.peekTokenIs(tokens.COMMA) {
- p.nextToken()
- p.nextToken()
- args = append(args, p.parseExpression(LOWEST))
- }
+// for p.peekTokenIs(tokens.COMMA) {
+// p.nextToken()
+// p.nextToken()
+// args = append(args, p.parseExpression(LOWEST))
+// }
- if !p.expectPeek(tokens.RPAREN) {
- return nil
- }
+// if !p.expectPeek(tokens.RPAREN) {
+// return nil
+// }
- return args
-}
+// return args
+// }
func (p *Parser) parseStringLiteral() ast.Expression {
return &ast.StringLiteral{
@@ -478,6 +481,19 @@ func (p *Parser) parseExpressionList(end tokens.TokenType) []ast.Expression {
return list
}
+func (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression {
+ exp := &ast.IndexExpression{Token: p.curToken, Left: left}
+
+ p.nextToken()
+ exp.Index = p.parseExpression(LOWEST)
+
+ if !p.expectPeek(tokens.RBRACKET) {
+ return nil
+ }
+
+ return exp
+}
+
// curTokenIs returns true if the current token is of the given type.
func (p *Parser) curTokenIs(t tokens.TokenType) bool {
return p.curToken.Type == t
diff --git a/parser/parser_test.go b/parser/parser_test.go
index f1b8b8c..7b347f5 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -519,6 +519,14 @@ func TestOperatorPrecedenceParsing(t *testing.T) {
"add(a + b + c * d / f + g)",
"add((((a + b) + ((c * d) / f)) + g))",
},
+ {
+ "a * [1, 2, 3, 4][b * c] * d",
+ "((a * ([1, 2, 3, 4][(b * c)])) * d)",
+ },
+ {
+ "add(a * b[2], b[1], 2 * [1, 2][1])",
+ "add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))",
+ },
}
for _, tt := range tests {
@@ -802,6 +810,11 @@ func TestParsingArrayLiterals(t *testing.T) {
checkParserErrors(t, p)
stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
+
+ if !ok {
+ t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", program.Statements[0])
+ }
+
array, ok := stmt.Expression.(*ast.ArrayLiteral)
if !ok {
@@ -816,3 +829,33 @@ func TestParsingArrayLiterals(t *testing.T) {
testInfixExpression(t, array.Elements[1], 2, "*", 2)
testInfixExpression(t, array.Elements[2], 3, "+", 3)
}
+
+func TestParsingIndexExpressions(t *testing.T) {
+ input := "myArray[1 + 1]"
+
+ var l *lexer.Lexer = lexer.New(input)
+ var p *Parser = New(l)
+
+ var program *ast.Program = p.ParseProgram()
+ checkParserErrors(t, p)
+
+ stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
+
+ if !ok {
+ t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", program.Statements[0])
+ }
+
+ indexExp, ok := stmt.Expression.(*ast.IndexExpression)
+
+ if !ok {
+ t.Fatalf("exp is not ast.IndexExpression. got=%T", stmt.Expression)
+ }
+
+ if !testIdentifier(t, indexExp.Left, "myArray") {
+ return
+ }
+
+ if !testInfixExpression(t, indexExp.Index, 1, "+", 1) {
+ return
+ }
+}
diff --git a/parser/parser_tracing.go b/parser/parser_tracing.go
index 2f3fcdb..76a8c45 100644
--- a/parser/parser_tracing.go
+++ b/parser/parser_tracing.go
@@ -1,37 +1,37 @@
package parser
-import (
- "fmt"
- "strings"
-)
+// import (
+// "fmt"
+// "strings"
+// )
-var traceLevel int = 0
+// var traceLevel int = 0
-const traceIdentPlaceholder string = "\t"
+// const traceIdentPlaceholder string = "\t"
-func identLevel() string {
- return strings.Repeat(traceIdentPlaceholder, traceLevel-1)
-}
+// func identLevel() string {
+// return strings.Repeat(traceIdentPlaceholder, traceLevel-1)
+// }
-func tracePrint(fs string) {
- fmt.Printf("%s%s\n", identLevel(), fs)
-}
+// func tracePrint(fs string) {
+// fmt.Printf("%s%s\n", identLevel(), fs)
+// }
-func incIdent() {
- traceLevel = traceLevel + 1
-}
+// func incIdent() {
+// traceLevel = traceLevel + 1
+// }
-func decIdent() {
- traceLevel = traceLevel - 1
-}
+// func decIdent() {
+// traceLevel = traceLevel - 1
+// }
-func trace(msg string) string {
- incIdent()
- tracePrint("BEGIN " + msg)
- return msg
-}
+// func trace(msg string) string {
+// incIdent()
+// tracePrint("BEGIN " + msg)
+// return msg
+// }
-func untrace(msg string) {
- tracePrint("END " + msg)
- decIdent()
-}
+// func untrace(msg string) {
+// tracePrint("END " + msg)
+// decIdent()
+// }