diff options
Diffstat (limited to 'parser')
| -rw-r--r-- | parser/parser.go | 17 | ||||
| -rw-r--r-- | parser/parser_test.go | 132 |
2 files changed, 122 insertions, 27 deletions
diff --git a/parser/parser.go b/parser/parser.go index a2ea590..310acee 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -65,6 +65,8 @@ func New(l *lexer.Lexer) *Parser { p.registerPrefix(tokens.INT, p.parseIntegerLiteral) p.registerPrefix(tokens.BANG, p.parsePrefixExpression) p.registerPrefix(tokens.MINUS, p.parsePrefixExpression) + p.registerPrefix(tokens.TRUE, p.parseBoolean) + p.registerPrefix(tokens.FALSE, p.parseBoolean) // Initialize the infix parse functions. p.infixParseFns = make(map[tokens.TokenType]infixParseFn) @@ -137,9 +139,14 @@ func (p *Parser) parseIdentifier() ast.Expression { return &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} } +// parseBoolean parses a boolean. +func (p *Parser) parseBoolean() ast.Expression { + return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(tokens.TRUE)} +} + // parseIntegerLiteral parses an integer literal. func (p *Parser) parseIntegerLiteral() ast.Expression { - defer untrace(trace("parseIntegerLiteral")) + // defer untrace(trace("parseIntegerLiteral")) var lit *ast.IntegerLiteral = &ast.IntegerLiteral{Token: p.curToken} @@ -197,7 +204,7 @@ func (p *Parser) parseReturnStatement() *ast.ReturnStatement { // parseExpressionStatement parses an expression statement. func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement { - defer untrace(trace("parseExpressionStatement")) + // defer untrace(trace("parseExpressionStatement")) var stmt *ast.ExpressionStatement = &ast.ExpressionStatement{Token: p.curToken} @@ -219,7 +226,7 @@ func (p *Parser) noPrefixParseFnError(t tokens.TokenType) { // parseExpression parses an expression. func (p *Parser) parseExpression(precedence int) ast.Expression { - defer untrace(trace("parseExpression")) + // defer untrace(trace("parseExpression")) prefix := p.prefixParseFns[p.curToken.Type] @@ -248,7 +255,7 @@ func (p *Parser) parseExpression(precedence int) ast.Expression { // parsePrefixExpression parses a prefix expression. func (p *Parser) parsePrefixExpression() ast.Expression { - defer untrace(trace("parsePrefixExpression")) + // defer untrace(trace("parsePrefixExpression")) var expression *ast.PrefixExpression = &ast.PrefixExpression{ Token: p.curToken, @@ -264,7 +271,7 @@ func (p *Parser) parsePrefixExpression() ast.Expression { // parseInfixExpression parses an infix expression. func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression { - defer untrace(trace("parseInfixExpression")) + // defer untrace(trace("parseInfixExpression")) expression := &ast.InfixExpression{ Token: p.curToken, diff --git a/parser/parser_test.go b/parser/parser_test.go index 4d76935..d2a8c8f 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -154,13 +154,14 @@ func testLiteralExpression( switch v := expected.(type) { case int: return testIntegerLiteral(t, exp, int64(v)) - case int64: return testIntegerLiteral(t, exp, v) case string: return testIdentifier(t, exp, v) + case bool: + return testBooleanLiteral(t, exp, v) } - + t.Errorf("type of exp not handled. got=%T", exp) return false } @@ -175,7 +176,7 @@ func testInfixExpression( opExp, ok := exp.(*ast.InfixExpression) if !ok { - t.Errorf("exp is not ast.InfixExpression. got =%T(%s)", exp, exp) + t.Errorf("exp is not ast.InfixExpression. got =%T(%s)", exp, exp) return false } @@ -263,16 +264,56 @@ func TestIntegerLiteralExpression(t *testing.T) { } } -// Prefix expression tests. +// Boolean expression tests. + +func TestBooleanExpression(t *testing.T) { + tests := []struct { + input string + expectedBoolean bool + }{ + {"true;", true}, + {"false;", false}, + } + + for _, tt := range tests { + var l *lexer.Lexer = lexer.New(tt.input) + var p *Parser = New(l) + var program *ast.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]) + } + + boolean, ok := stmt.Expression.(*ast.Boolean) + + if !ok { + t.Fatalf("exp not *ast.Boolean. got=%T", stmt.Expression) + } + + if boolean.Value != tt.expectedBoolean { + t.Errorf("boolean.Value not %t. got=%t", tt.expectedBoolean, boolean.Value) + } + } +} + +// Prefix expression tests. func TestParsingPrefixExpressions(t *testing.T) { var prefixTests = []struct { input string operator string - integerValue int64 + value interface{} }{ {"!5;", "!", 5}, {"-15;", "-", 15}, + {"!true;", "!", true}, + {"!false;", "!", false}, } for _, tt := range prefixTests { @@ -301,7 +342,11 @@ func TestParsingPrefixExpressions(t *testing.T) { t.Fatalf("exp.Operator is not '%s'. got=%s", tt.operator, exp.Operator) } - if !testIntegerLiteral(t, exp.Right, tt.integerValue) { + // if !testIntegerLiteral(t, exp.Right, tt.integerValue) { + // return + // } + + if !testLiteralExpression(t, exp.Right, tt.value) { return } } @@ -335,10 +380,10 @@ func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool { func TestParsingInfixExpressions(t *testing.T) { var infixTests = []struct { - input string - leftValue int64 - operator string - rightValue int64 + input string + leftValue interface{} + operator string + rightValue interface{} }{ {"5 + 5;", 5, "+", 5}, {"5 - 5;", 5, "-", 5}, @@ -348,6 +393,9 @@ func TestParsingInfixExpressions(t *testing.T) { {"5 < 5;", 5, "<", 5}, {"5 == 5;", 5, "==", 5}, {"5 != 5;", 5, "!=", 5}, + {"true == true", true, "==", true}, + {"true != false", true, "!=", false}, + {"false == false", false, "==", false}, } for _, tt := range infixTests { @@ -357,7 +405,6 @@ func TestParsingInfixExpressions(t *testing.T) { var program *ast.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)) } @@ -368,21 +415,25 @@ func TestParsingInfixExpressions(t *testing.T) { t.Fatalf("program.Statements[0] is not ast.ExpressionStatement, got=%T", program.Statements[0]) } - exp, ok := stmt.Expression.(*ast.InfixExpression) + // exp, ok := stmt.Expression.(*ast.InfixExpression) - if !ok { - t.Fatalf("exp is not ast.InfixExpression. got=%T", stmt.Expression) - } + // if !ok { + // t.Fatalf("exp is not ast.InfixExpression. got=%T", stmt.Expression) + // } - if !testIntegerLiteral(t, exp.Left, tt.leftValue) { - return - } + // if !testIntegerLiteral(t, exp.Left, tt.leftValue) { + // return + // } - if exp.Operator != tt.operator { - t.Fatalf("exp.Operator is not '%s', got=%s", tt.operator, exp.Operator) - } + // if exp.Operator != tt.operator { + // t.Fatalf("exp.Operator is not '%s', got=%s", tt.operator, exp.Operator) + // } + + // if !testIntegerLiteral(t, exp.Right, tt.rightValue) { + // return + // } - if !testIntegerLiteral(t, exp.Right, tt.rightValue) { + if !testInfixExpression(t, stmt.Expression, tt.leftValue, tt.operator, tt.rightValue) { return } } @@ -443,6 +494,22 @@ func TestOperatorPrecedenceParsing(t *testing.T) { "3 + 4 * 5 == 3 * 1 + 4 * 5", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))", }, + { + "true", + "true", + }, + { + "false", + "false", + }, + { + "3 > 5 == false", + "((3 > 5) == false)", + }, + { + "3 < 5 == true", + "((3 < 5) == true)", + }, } for _, tt := range tests { @@ -458,3 +525,24 @@ func TestOperatorPrecedenceParsing(t *testing.T) { } } } + +func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool { + boo, ok := exp.(*ast.Boolean) + + if !ok { + t.Errorf("exp not *ast.Boolean. got=%T", exp) + return false + } + + if boo.Value != value { + t.Errorf("boo.Value not %t. got=%t", value, boo.Value) + return false + } + + if boo.TokenLiteral() != fmt.Sprintf("%t", value) { + t.Errorf("boo.TokenLiteral not %t. got=%s", value, boo.TokenLiteral()) + return false + } + + return true +} |
