umx_compiler

UMX virtual machine "Monkey" interpreter / bytecode compiler
git clone git://bsandro.tech/umx_compiler
Log | Files | Refs

commit bfcf0bffcc71d9f795de9f86033b844b12931378
parent c197eb43b8f485f0c9874a208e2eaf8d91eae6bd
Author: bsandro <email@bsandro.tech>
Date:   Mon, 27 Jun 2022 22:07:56 +0300

basic arrays support

Diffstat:
Mast/ast.go | 21+++++++++++++++++++++
Mlexer/lexer.go | 4++++
Mlexer/lexer_test.go | 9+++++++++
Mparser/parser.go | 19++++++++++++-------
Mparser/parser_test.go | 19+++++++++++++++++++
Mtoken/token.go | 2++
6 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/ast/ast.go b/ast/ast.go @@ -278,3 +278,24 @@ func (sl *StringLiteral) TokenLiteral() string { func (sl *StringLiteral) String() string { return sl.Token.Literal } + +type ArrayLiteral struct { + Token token.Token + Elements []Expression +} + +func (al *ArrayLiteral) expressionNode() {} +func (al *ArrayLiteral) TokenLiteral() string { + return al.Token.Literal +} +func (al *ArrayLiteral) String() string { + var out bytes.Buffer + elements := []string{} + for _, el := range al.Elements { + elements = append(elements, el.String()) + } + out.WriteString("[") + out.WriteString(strings.Join(elements, ", ")) + out.WriteString("]") + return out.String() +} diff --git a/lexer/lexer.go b/lexer/lexer.go @@ -54,6 +54,10 @@ func (l *Lexer) NextToken() token.Token { tok = newToken(token.LCURLY, l.ch) case '}': tok = newToken(token.RCURLY, l.ch) + case '[': + tok = newToken(token.LBRACKET, l.ch) + case ']': + tok = newToken(token.RBRACKET, l.ch) case '+': tok = newToken(token.PLUS, l.ch) case '-': diff --git a/lexer/lexer_test.go b/lexer/lexer_test.go @@ -25,6 +25,8 @@ if (5 < 10) { "foo123"; "foo bar"; + +[1, 2]; ` tests := []struct { @@ -113,6 +115,13 @@ if (5 < 10) { {token.STRING, "foo bar"}, {token.SEMICOLON, ";"}, + {token.LBRACKET, "["}, + {token.INT, "1"}, + {token.COMMA, ","}, + {token.INT, "2"}, + {token.RBRACKET, "]"}, + {token.SEMICOLON, ";"}, + {token.EOF, ""}, } diff --git a/parser/parser.go b/parser/parser.go @@ -70,15 +70,14 @@ func New(l *lexer.Lexer) *Parser { p.registerPrefix(token.TRUE, p.parseBoolean) p.registerPrefix(token.FALSE, p.parseBoolean) - p.registerPrefix(token.LPAREN, p.parseGroupedExpression) - p.registerPrefix(token.IF, p.parseIfExpression) - p.registerPrefix(token.FUNCTION, p.parseFunctionLiteral) + p.registerInfix(token.LPAREN, p.parseCallExpression) p.registerPrefix(token.STRING, p.parseStringLiteral) + p.registerPrefix(token.LBRACKET, p.parseArrayLiteral) return p } @@ -348,13 +347,13 @@ func (p *Parser) parseFunctionParameters() []*ast.Identifier { func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression { expr := &ast.CallExpression{Token: p.curToken, Function: function} - expr.Arguments = p.parseCallArguments() + expr.Arguments = p.parseExpressionList(token.RPAREN) return expr } -func (p *Parser) parseCallArguments() []ast.Expression { +func (p *Parser) parseExpressionList(end token.TokenType) []ast.Expression { args := []ast.Expression{} - if p.peekTokenIs(token.RPAREN) { + if p.peekTokenIs(end) { p.nextToken() return args } @@ -365,7 +364,7 @@ func (p *Parser) parseCallArguments() []ast.Expression { p.nextToken() args = append(args, p.parseExpression(LOWEST)) } - if !p.expectPeek(token.RPAREN) { + if !p.expectPeek(end) { return nil } return args @@ -374,3 +373,9 @@ func (p *Parser) parseCallArguments() []ast.Expression { func (p *Parser) parseStringLiteral() ast.Expression { return &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal} } + +func (p *Parser) parseArrayLiteral() ast.Expression { + array := &ast.ArrayLiteral{Token: p.curToken} + array.Elements = p.parseExpressionList(token.RBRACKET) + return array +} diff --git a/parser/parser_test.go b/parser/parser_test.go @@ -587,3 +587,22 @@ func TestStringLiteralExpression(t *testing.T) { t.Errorf("literal string value is wrong") } } + +func TestParsingArrayLiterals(t *testing.T) { + input := "[10,20*30,40+50]" + l := lexer.New(input) + p := New(l) + prg := p.ParseProgram() + checkParserErrors(t, p) + statement, ok := prg.Statements[0].(*ast.ExpressionStatement) + array, ok := statement.Expression.(*ast.ArrayLiteral) + if !ok { + t.Fatalf("expression is not ArrayLiteral") + } + if len(array.Elements) != 3 { + t.Fatalf("array Elements count is wrong") + } + testIntegerLiteral(t, array.Elements[0], 10) + testInfixExpression(t, array.Elements[1], 20, "*", 30) + testInfixExpression(t, array.Elements[2], 40, "+", 50) +} diff --git a/token/token.go b/token/token.go @@ -26,6 +26,8 @@ const ( RPAREN = ")" LCURLY = "{" RCURLY = "}" + LBRACKET = "[" + RBRACKET = "]" FUNCTION = "FUNCTION" LET = "LET" TRUE = "TRUE"