Can now parse FunctionLiteral and its parameters. Tests are also included.
git-svn-id: https://svn.tlawal.org/svn/monkey@38 f6afcba9-9ef1-4bdd-9b72-7484f5705bac
This commit is contained in:
parent
c1d53c5101
commit
c421b040d5
@ -106,6 +106,9 @@ func New(l_lexer *lexer.Lexer) *Parser {
|
||||
// IF Expression
|
||||
l_parser.register_prefix(token.IF, l_parser.parse_if_expression)
|
||||
|
||||
// Function Literals
|
||||
l_parser.register_prefix(token.FUNCTION, l_parser.parse_function_literal)
|
||||
|
||||
return l_parser
|
||||
}
|
||||
|
||||
@ -344,3 +347,42 @@ func (l_parser *Parser) parse_block_statement() *ast.BlockStatement {
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
func (l_parser *Parser) parse_function_literal() ast.Expression {
|
||||
literal := &ast.FunctionLiteral{ Token: l_parser.current_token }
|
||||
if !l_parser.expect_peek(token.LPAREN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
literal.Parameters = l_parser.parse_function_parameters()
|
||||
if !l_parser.expect_peek(token.LBRACE) {
|
||||
return nil
|
||||
}
|
||||
literal.Body = l_parser.parse_block_statement()
|
||||
return literal
|
||||
}
|
||||
|
||||
func (l_parser *Parser) parse_function_parameters() []*ast.Identifier {
|
||||
identifiers := []*ast.Identifier{}
|
||||
|
||||
if l_parser.peek_token_is(token.RPAREN) {
|
||||
l_parser.next_token()
|
||||
return identifiers
|
||||
}
|
||||
|
||||
l_parser.next_token()
|
||||
|
||||
ident := &ast.Identifier{Token: l_parser.current_token, Value: l_parser.current_token.Literal}
|
||||
identifiers = append(identifiers, ident)
|
||||
|
||||
for l_parser.peek_token_is(token.COMMA) {
|
||||
l_parser.next_token()
|
||||
l_parser.next_token()
|
||||
ident := &ast.Identifier{Token: l_parser.current_token, Value: l_parser.current_token.Literal}
|
||||
identifiers = append(identifiers, ident)
|
||||
}
|
||||
if !l_parser.expect_peek(token.RPAREN) {
|
||||
return nil
|
||||
}
|
||||
return identifiers
|
||||
}
|
||||
|
@ -453,6 +453,76 @@ func TestIfElseExpression(l_test *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunctionLiteralParsing(l_test *testing.T) {
|
||||
input := `fn(x, y) { x + y; }`
|
||||
|
||||
l_lexer := lexer.New(input)
|
||||
l_parser := New(l_lexer)
|
||||
program := l_parser.ParseProgram()
|
||||
check_parser_errors(l_test, l_parser)
|
||||
|
||||
if len(program.Statements) != 1 {
|
||||
l_test.Fatalf("program.Statements does not contain %d statements, got=%d\n", 1, len(program.Statements))
|
||||
}
|
||||
|
||||
statement, ok := program.Statements[0].(*ast.ExpressionStatement)
|
||||
if !ok {
|
||||
l_test.Fatalf("program.Statements[0] is not ast.ExpressionStatement, got=%T", program.Statements[0])
|
||||
}
|
||||
|
||||
function, ok := statement.Expression.(*ast.FunctionLiteral)
|
||||
if !ok {
|
||||
l_test.Fatalf("statement.Expression is not ast.FunctionLiteral, got=%T", statement.Expression)
|
||||
}
|
||||
|
||||
if len(function.Parameters) != 2 {
|
||||
l_test.Fatalf("function literal parameters wrong, want 2, got=%d\n", len(function.Parameters))
|
||||
}
|
||||
testLiteralExpression(l_test, function.Parameters[0], "x")
|
||||
testLiteralExpression(l_test, function.Parameters[1], "y")
|
||||
|
||||
if len(function.Body.Statements) != 1 {
|
||||
l_test.Fatalf("function.Body.Statements does not have 1 statement, got=%d\n", len(function.Body.Statements))
|
||||
}
|
||||
|
||||
body_statement, ok := function.Body.Statements[0].(*ast.ExpressionStatement)
|
||||
if !ok {
|
||||
l_test.Fatalf("function body statement is not ast.ExpressionStatemes, got=%T", function.Body.Statements[0])
|
||||
}
|
||||
testInfixExpression(l_test, body_statement.Expression, "x", "+", "y")
|
||||
|
||||
}
|
||||
|
||||
func TestFunctionParameterParsing(l_test *testing.T){
|
||||
tests := []struct {
|
||||
input string
|
||||
expected_params []string
|
||||
}{
|
||||
{ input: "fn() {};", expected_params: []string{}},
|
||||
{ input: "fn(x) {};", expected_params: []string{"x"}},
|
||||
{ input: "fn(x, y, z) {};", expected_params: []string{"x", "y", "z"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
l_lexer := lexer.New(tt.input)
|
||||
l_parser := New(l_lexer)
|
||||
program := l_parser.ParseProgram()
|
||||
check_parser_errors(l_test, l_parser)
|
||||
|
||||
statement := program.Statements[0].(*ast.ExpressionStatement)
|
||||
function := statement.Expression.(*ast.FunctionLiteral)
|
||||
|
||||
if len(function.Parameters) != len(tt.expected_params){
|
||||
l_test.Errorf("length of parameters is wrong, want %d, got=%d\n",
|
||||
len(tt.expected_params), len(function.Parameters))
|
||||
}
|
||||
|
||||
for i, identifier := range tt.expected_params {
|
||||
testLiteralExpression(l_test, function.Parameters[i], identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
func check_parser_errors(l_test *testing.T, l_parser *Parser) {
|
||||
|
Loading…
Reference in New Issue
Block a user