commit bfcf0bffcc71d9f795de9f86033b844b12931378
parent c197eb43b8f485f0c9874a208e2eaf8d91eae6bd
Author: bsandro <email@bsandro.tech>
Date: Mon, 27 Jun 2022 22:07:56 +0300
basic arrays support
Diffstat:
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"