diff options
Diffstat (limited to 'parser/parser_test.go')
| -rw-r--r-- | parser/parser_test.go | 171 |
1 files changed, 170 insertions, 1 deletions
diff --git a/parser/parser_test.go b/parser/parser_test.go index f7158bf..be49bf5 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -1,9 +1,11 @@ package parser import ( + "fmt" + "testing" + "github.com/mewsen/interpreter/ast" "github.com/mewsen/interpreter/lexer" - "testing" ) func TestLetStatements(t *testing.T) { @@ -64,3 +66,170 @@ func testLetStatement(t *testing.T, s ast.Statement, name string) bool { return true } + +func TestReturnStatement(t *testing.T) { + input := ` +return 5; +return 10; +return 993322; + ` + + l := lexer.New(input) + p := New(l) + + program := p.ParseProgram() + + checkParserErrors(t, p) + + if len(program.Statements) != 3 { + t.Fatalf("program.Statements does not contain 3 statement. got=%d", len(program.Statements)) + } + + for _, stmt := range program.Statements { + returnStmt, ok := stmt.(*ast.ReturnStatement) + if !ok { + t.Errorf("stmt not *ast.returnStatement, got=%T", stmt) + continue + } + if returnStmt.TokenLiteral() != "return" { + t.Errorf("returnStmt.TokenLiteral not 'return', got=%q", returnStmt.TokenLiteral()) + } + } +} + +func TestIdentifierExpression(t *testing.T) { + input := "foobar;" + + l := lexer.New(input) + p := New(l) + program := p.ParseProgram() + + checkParserErrors(t, p) + + if len(program.Statements) != 1 { + t.Fatalf("program has not enough statements. got=%d", + len(program.Statements)) + } + + stmt, ok := program.Statements[0].(*ast.ExpressionStatement) + if !ok { + t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", + program.Statements[0]) + } + + ident, ok := stmt.Expression.(*ast.Identifier) + if !ok { + t.Fatalf("exp not *ast.Identifier. got=%T", stmt.Expression) + } + + if ident.Value != "foobar" { + t.Errorf("ident.Value not %s. got=%s", "foobar", ident.Value) + } + + if ident.TokenLiteral() != "foobar" { + t.Errorf("ident.TokenLiteral not %s. got=%s", "foobar", + ident.TokenLiteral()) + } +} + +func checkParserErrors(t *testing.T, p *Parser) { + for _, err := range p.errors { + t.Fatal(err) + } +} + +func TestIntegerLiteralExpression(t *testing.T) { + input := "5;" + + l := lexer.New(input) + p := New(l) + program := p.ParseProgram() + checkParserErrors(t, p) + + if len(program.Statements) != 1 { + t.Fatalf("program has not enough statements. got=%d", + len(program.Statements)) + } + stmt, ok := program.Statements[0].(*ast.ExpressionStatement) + if !ok { + t.Fatalf("exp not *ast.IntergerLiteral. got=%T", program.Statements[0]) + } + + literal, ok := stmt.Expression.(*ast.IntegerLiteral) + if !ok { + t.Fatalf("literal.Value not %d, got=%d", 5, stmt.Expression) + } + + if literal.Value != 5 { + t.Errorf("literal.Value not %d. got=%d", 5, literal.Value) + } + + if literal.TokenLiteral() != "5" { + t.Errorf("literal.TokenLiteral not %s. got=%s", "5", + literal.TokenLiteral()) + } +} + +func TestParsingPrefixExpressions(t *testing.T) { + prefixTests := []struct { + input string + operator string + integerValue int64 + }{ + {"!5", "!", 5}, + {"-15", "-", 15}, + } + + for _, tt := range prefixTests { + l := lexer.New(tt.input) + p := New(l) + program := p.ParseProgram() + checkParserErrors(t, p) + + if len(program.Statements) != 1 { + t.Fatalf("program.Statements does not contain %d statements. got=%d\n", + 1, len(program.Statements)) + } + + stmt, ok := program.Statements[0].(*ast.ExpressionStatement) + if !ok { + t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", + program.Statements[0]) + } + + exp, ok := stmt.Expression.(*ast.PrefixExpression) + if !ok { + t.Fatalf("stmt is not ast.PrefixExpression. got=%T", stmt.Expression) + } + + if exp.Operator != tt.operator { + t.Fatalf("exp.Operator is not %s. got=%s", + tt.operator, exp.Operator) + } + + if !testIntegerLiteral(t, exp.Right, tt.integerValue) { + return + } + } +} + +func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool { + integ, ok := il.(*ast.IntegerLiteral) + if !ok { + t.Errorf("il not *ast.IntegerLiteral. got=%T", il) + return false + } + + if integ.Value != value { + t.Errorf("integ.Value not %d. got=%d", value, integ.Value) + return false + } + + if integ.TokenLiteral() != fmt.Sprintf("%d", value) { + t.Errorf("integ.TokenLiteral not %d. got=%s", value, + integ.TokenLiteral()) + return false + } + + return true +} |
