aboutsummaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
Diffstat (limited to 'parser')
-rw-r--r--parser/parser.go17
-rw-r--r--parser/parser_test.go132
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
+}