arrays + builtins
This commit is contained in:
@@ -30,6 +30,7 @@ var precedences = map[token.TokenType]int{
|
||||
token.SLASH: PRODUCT,
|
||||
token.ASTERISK: PRODUCT,
|
||||
token.LPAREN: CALL,
|
||||
token.LBRACKET: INDEX,
|
||||
}
|
||||
|
||||
type (
|
||||
@@ -65,6 +66,7 @@ func New(l *lexer.Lexer) *Parser {
|
||||
p.registerPrefix(token.IF, p.parseIfExpression)
|
||||
p.registerPrefix(token.FUNCTION, p.parseFunctionLiteral)
|
||||
p.registerPrefix(token.STRING, p.parseStringLiteral)
|
||||
p.registerPrefix(token.LBRACKET, p.parseArrayLiteral)
|
||||
|
||||
p.infixParseFns = make(map[token.TokenType]infixParseFn)
|
||||
p.registerInfix(token.PLUS, p.parseInfixExpression)
|
||||
@@ -75,8 +77,8 @@ func New(l *lexer.Lexer) *Parser {
|
||||
p.registerInfix(token.NOT_EQ, p.parseInfixExpression)
|
||||
p.registerInfix(token.LT, p.parseInfixExpression)
|
||||
p.registerInfix(token.GT, p.parseInfixExpression)
|
||||
|
||||
p.registerInfix(token.LPAREN, p.parseCallExpression)
|
||||
p.registerInfix(token.LBRACKET, p.parseIndexExpression)
|
||||
|
||||
// Read two tokens, so curToken and peekToken are both set
|
||||
p.nextToken()
|
||||
@@ -435,3 +437,24 @@ func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {
|
||||
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
|
||||
}
|
||||
|
||||
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(token.RBRACKET) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return exp
|
||||
}
|
||||
|
||||
@@ -341,6 +341,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 {
|
||||
@@ -689,6 +697,52 @@ func TestStringLiteralExpression(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingArrayLiterals(t *testing.T) {
|
||||
input := "[1, 2 * 2, 3 + 3]"
|
||||
|
||||
l := lexer.New(input)
|
||||
p := New(l)
|
||||
program := p.ParseProgram()
|
||||
checkParserErrors(t, p)
|
||||
|
||||
stmt := program.Statements[0].(*ast.ExpressionStatement)
|
||||
array, ok := stmt.Expression.(*ast.ArrayLiteral)
|
||||
if !ok {
|
||||
t.Fatalf("exp not *ast.ArrayLiteral. got=%T", stmt.Expression)
|
||||
}
|
||||
|
||||
if len(array.Elements) != 3 {
|
||||
t.Fatalf("len(array.Elements) not 3. got=%d", len(array.Elements))
|
||||
}
|
||||
|
||||
testIntegerLiteral(t, array.Elements[0], 1)
|
||||
testInfixExpression(t, array.Elements[1], 2, "*", 2)
|
||||
testInfixExpression(t, array.Elements[2], 3, "+", 3)
|
||||
}
|
||||
|
||||
func TestParsingIndexExpressions(t *testing.T) {
|
||||
input := "myArray[1 + 1]"
|
||||
|
||||
l := lexer.New(input)
|
||||
p := New(l)
|
||||
program := p.ParseProgram()
|
||||
checkParserErrors(t, p)
|
||||
|
||||
stmt := program.Statements[0].(*ast.ExpressionStatement)
|
||||
indexExp, ok := stmt.Expression.(*ast.IndexExpression)
|
||||
if !ok {
|
||||
t.Fatalf("exp not *ast.IndexExpression. got=%T", stmt.Expression)
|
||||
}
|
||||
|
||||
if !testIdentifier(t, indexExp.Left, "myArray") {
|
||||
return
|
||||
}
|
||||
|
||||
if !testInfixExpression(t, indexExp.Index, 1, "+", 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
|
||||
if s.TokenLiteral() != "let" {
|
||||
t.Errorf("s.TokenLiteral not 'let'. got=%q", s.TokenLiteral())
|
||||
|
||||
Reference in New Issue
Block a user