diff --git a/ast/ast.go b/ast/ast.go index a5c2686e..85fdcb7d 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -227,21 +227,14 @@ func (bs *BlockStatement) String() string { } // Represent function statement -type FunctionStatement struct { - Name *Identifier - Parameters []*ParameterLiteral +type ExpressionStatement struct { + Expr Expression } -func (fs *FunctionStatement) do() {} +func (es *ExpressionStatement) do() {} -func (fs *FunctionStatement) String() string { - var out bytes.Buffer - out.WriteString(fs.Name.String() + "(") - for _, parameter := range fs.Parameters { - out.WriteString(parameter.String()) - } - out.WriteString(")") - return out.String() +func (es *ExpressionStatement) String() string { + return es.Expr.String() } // Represent string literal diff --git a/parse/parser.go b/parse/parser.go index 3cb749ee..98c3d023 100644 --- a/parse/parser.go +++ b/parse/parser.go @@ -260,10 +260,7 @@ func parseStatement(buf TokenBuffer) (ast.Statement, error) { case Return: return parseReturnStatement(buf) default: - return nil, parseError{ - tokenType: tt, - reason: "invalid token for parsing statement", - } + return parseExpressionStatement(buf) } } @@ -648,7 +645,10 @@ func parseCallExpression(buf TokenBuffer, fn ast.Expression) (ast.Expression, er // parseCallArguments parse arguments of function call func parseCallArguments(buf TokenBuffer) ([]ast.Expression, error) { args := []ast.Expression{} - buf.Read() + if err := expectNext(buf, Lparen); err != nil { + return nil, err + } + if curTokenIs(buf, Rparen) { return args, nil } @@ -765,3 +765,23 @@ func parseBlockStatement(buf TokenBuffer) (*ast.BlockStatement, error) { } return block, nil } + +func parseExpressionStatement(buf TokenBuffer) (*ast.ExpressionStatement, error) { + stmt := &ast.ExpressionStatement{} + tok := buf.Read() + if tok.Type != Ident { + return nil, parseError{ + tok.Type, + "token is not identifier", + } + } + ident := &ast.Identifier{Value: tok.Val} + + exp, err := parseCallExpression(buf, ident) + if err != nil { + return nil, err + } + + stmt.Expr = exp + return stmt, nil +} diff --git a/parse/parser_internal_test.go b/parse/parser_internal_test.go index f3594d0c..df8337cf 100644 --- a/parse/parser_internal_test.go +++ b/parse/parser_internal_test.go @@ -1851,7 +1851,7 @@ func TestParseStatement(t *testing.T) { {Type: Rbrace, Val: "}"}, {Type: Eol, Val: "\n"}, }, - expectedErr: parseError{Int, "invalid token for parsing statement"}, + expectedErr: parseError{Int, "token is not identifier"}, expectedStmt: ``, }, { @@ -1971,7 +1971,7 @@ func TestParseStatement(t *testing.T) { tokens: []Token{ {Type: Int, Val: "1"}, }, - expectedErr: parseError{Int, "invalid token for parsing statement"}, + expectedErr: parseError{Int, "token is not identifier"}, expectedStmt: ``, }, } @@ -1992,3 +1992,96 @@ func TestParseStatement(t *testing.T) { } } } + +func TestParseExpressionStatement(t *testing.T) { + initParseFnMap() + + tests := []struct { + tokens []Token + expectedStmt string + expectedErr string + }{ + { + // add() + []Token{ + {Type: Ident, Val: "add"}, + {Type: Lparen, Val: "("}, + {Type: Rparen, Val: ")"}, + }, + "function add( )", + "", + }, + { + // read(x int) + []Token{ + {Type: Ident, Val: "read"}, + {Type: Lparen, Val: "("}, + {Type: Ident, Val: "x"}, + {Type: Rparen, Val: ")"}, + }, + "function read( x )", + "", + }, + { + // testFunction(a int, b string) + []Token{ + {Type: Ident, Val: "testFunction"}, + {Type: Lparen, Val: "("}, + {Type: Ident, Val: "a"}, + {Type: Comma, Val: ","}, + {Type: Ident, Val: "b"}, + {Type: Rparen, Val: ")"}, + }, + "function testFunction( a, b )", + "", + }, + { + // testFunction(a int b string) <= error case + []Token{ + {Type: Ident, Val: "testFunction"}, + {Type: Lparen, Val: "("}, + {Type: Ident, Val: "a"}, + {Type: IntType, Val: "int"}, + {Type: Ident, Val: "b"}, + {Type: IntType, Val: "string"}, + {Type: Rparen, Val: ")"}, + }, + "", + "INT_TYPE, expectNext() : expected [RPAREN], but got [INT_TYPE]", + }, + { + // 1() <= error case + []Token{ + {Type: Int, Val: "1"}, + {Type: Lparen, Val: "("}, + {Type: Rparen, Val: ")"}, + }, + "", + "INT, token is not identifier", + }, + { + // add) <= error case + []Token{ + {Type: Ident, Val: "add"}, + {Type: Rparen, Val: ")"}, + }, + "", + "RPAREN, expectNext() : expected [LPAREN], but got [RPAREN]", + }, + } + + for i, test := range tests { + stmt, err := parseExpressionStatement(&mockTokenBuffer{test.tokens, 0}) + if stmt != nil && stmt.String() != test.expectedStmt { + t.Fatalf("test[%d] - TestParseFunctionStatement wrong answer.\n"+ + "expected= %s\n"+ + "got= %s", i, test.expectedStmt, stmt.String()) + } + + if err != nil && err.Error() != test.expectedErr { + t.Fatalf("test[%d] - TestParseFunctionStatement wrong error.\n"+ + "expected= %s\n"+ + "got= %s", i, test.expectedErr, err.Error()) + } + } +}