Skip to content

Commit

Permalink
Implement parseFunctionStatement and test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
boohyunsik committed Jan 22, 2019
1 parent fb18766 commit 9de42be
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 19 deletions.
17 changes: 5 additions & 12 deletions ast/ast.go
Expand Up @@ -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
Expand Down
30 changes: 25 additions & 5 deletions parse/parser.go
Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
97 changes: 95 additions & 2 deletions parse/parser_internal_test.go
Expand Up @@ -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: ``,
},
{
Expand Down Expand Up @@ -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: ``,
},
}
Expand All @@ -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())
}
}
}

0 comments on commit 9de42be

Please sign in to comment.