Forráskód Böngészése

boolean literal parse

runningwater 3 éve
szülő
commit
1fd2b580e8
4 módosított fájl, 121 hozzáadás és 9 törlés
  1. 15 0
      ast/ast.go
  2. 6 0
      parser/parser.go
  3. 91 0
      parser/parser_test.go
  4. 9 9
      parser/parser_tracing.go

+ 15 - 0
ast/ast.go

@@ -205,3 +205,18 @@ func (oe *InfixExpression) String() string {
 }
 
 func (oe *InfixExpression) expressionNode() {}
+
+type Boolean struct {
+	Token token.Token
+	Value bool
+}
+
+func (b *Boolean) TokenLiteral() string {
+	return b.Token.Literal
+}
+
+func (b *Boolean) String() string {
+	return b.Token.Literal
+}
+
+func (b *Boolean) expressionNode() {}

+ 6 - 0
parser/parser.go

@@ -66,6 +66,8 @@ func New(l *lexer.Lexer) *Parser {
 	p.registerPrefix(token.INT, p.parseIntegerLiteral)
 	p.registerPrefix(token.BANG, p.parsePrefixExpression)
 	p.registerPrefix(token.MINUS, p.parsePrefixExpression)
+	p.registerPrefix(token.TRUE, p.parseBoolean)
+	p.registerPrefix(token.FALSE, p.parseBoolean)
 
 	p.infixParseFns = make(map[token.TypeToken]infixParseFn)
 	p.registerInfix(token.PLUS, p.parseInfixExpression)
@@ -87,6 +89,10 @@ func New(l *lexer.Lexer) *Parser {
 func (p *Parser) parseIdentifier() ast.Expression {
 	return &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
 }
+
+func (p *Parser) parseBoolean() ast.Expression {
+	return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)}
+}
 func (p *Parser) parseIntegerLiteral() ast.Expression {
 	defer untrace(trace("parseIntegerLiteral"))
 

+ 91 - 0
parser/parser_test.go

@@ -239,6 +239,56 @@ func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
 	return true
 }
 
+func testLiteralExpression(t *testing.T, exp ast.Expression, expected interface{}) bool {
+	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 hand. got=%T", exp)
+	return false
+}
+
+func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bool {
+	bo, ok := exp.(*ast.Boolean)
+	if !ok {
+		t.Errorf("exp not *ast.Boolean. got=%T", exp)
+		return false
+	}
+	if bo.Value != value {
+		t.Errorf("bo.Value not %t. got=%t", value, bo.Value)
+		return false
+	}
+	if bo.TokenLiteral() != fmt.Sprintf("%t", value) {
+		t.Errorf("bo.TokenLiteral not %t. got=%s", value, bo.TokenLiteral())
+		return false
+	}
+	return true
+}
+
+func testIdentifier(t *testing.T, exp ast.Expression, v string) bool {
+	ident, ok := exp.(*ast.Identifier)
+	if !ok {
+		t.Errorf("exp not *ast.Identifier. got=%T", exp)
+		return false
+	}
+	if ident.Value != v {
+		t.Errorf("ident.Value not %s. got=%s", v, ident.Value)
+		return false
+	}
+	if ident.TokenLiteral() != v {
+		t.Errorf("ident.TokenLiteral not %s. got=%s", v,
+			ident.TokenLiteral())
+		return false
+	}
+	return true
+}
+
 // <expression> <infix operator> <expression>
 func TestParsingInfixExpressions(t *testing.T) {
 	infixTests := []struct {
@@ -345,6 +395,10 @@ func TestOperatorPrecedenceParsing(t *testing.T) {
 			"3 + 4 * 5 == 3 * 1 + 4 * 5",
 			"((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))",
 		},
+		{
+			"3 > 5 == false",
+			"((3 > 5) == false)",
+		},
 	}
 
 	for _, tt := range tests {
@@ -361,3 +415,40 @@ func TestOperatorPrecedenceParsing(t *testing.T) {
 		fmt.Printf("=====================================parse %s, end============================\n", tt.input)
 	}
 }
+
+func TestBooleanExpression(t *testing.T) {
+	tests := []struct {
+		input           string
+		expectedBoolean bool
+	}{
+		{"true;", true},
+		{"false;", false},
+	}
+
+	for _, tt := range tests {
+		l := lexer.New(tt.input)
+		p := New(l)
+		program := p.ParseProgram()
+		checkParseErrors(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)
+		}
+	}
+}

+ 9 - 9
parser/parser_tracing.go

@@ -1,8 +1,8 @@
 package parser
 
 import (
-    "fmt"
-    "strings"
+	"fmt"
+	"strings"
 )
 
 var traceLevel = 0
@@ -10,23 +10,23 @@ var traceLevel = 0
 const traceIdentPlaceholder string = "\t"
 
 func identLevel() string {
-    return strings.Repeat(traceIdentPlaceholder, traceLevel-1)
+	return strings.Repeat(traceIdentPlaceholder, traceLevel-1)
 }
 
 func tracePrint(fs string) {
-    fmt.Printf("%s%s\n", identLevel(), fs)
+	fmt.Printf("%s%s\n", identLevel(), fs)
 }
 
 func incIdent() { traceLevel = traceLevel + 1 }
 func decIdent() { traceLevel = traceLevel - 1 }
 
 func trace(msg string) string {
-    incIdent()
-    tracePrint("BEGIN " + msg)
-    return msg
+	incIdent()
+	tracePrint("BEGIN " + msg)
+	return msg
 }
 
 func untrace(msg string) {
-    tracePrint("END " + msg)
-    decIdent()
+	tracePrint("END " + msg)
+	decIdent()
 }