Skip to content

Commit b851821

Browse files
committed
3.5 Evaluation (literals)
* Boolean literals * Null
1 parent ced9b41 commit b851821

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

evaluator/evaluator.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ import (
99
"github.com/cedrickchee/hou/object"
1010
)
1111

12+
var (
13+
// TRUE is a cached Boolean object holding the `true` value.
14+
TRUE = &object.Boolean{Value: true}
15+
16+
// FALSE is a cached Boolean object holding the `false` value.
17+
FALSE = &object.Boolean{Value: false}
18+
19+
// NULL is a cached Null object. There should only be one reference to a
20+
// null value, just as there's only one 'true' and one 'false'.
21+
// No kinda-but-not-quite-null, no half-null and no
22+
// basically-thesame-as-the-other-null.
23+
NULL = &object.Null{}
24+
)
25+
1226
// Eval evaluates the node and returns an object.
1327
func Eval(node ast.Node) object.Object {
1428
// Traverse the AST by starting at the top of the tree, receiving an
@@ -30,6 +44,9 @@ func Eval(node ast.Node) object.Object {
3044
// Expressions
3145
case *ast.IntegerLiteral:
3246
return &object.Integer{Value: node.Value}
47+
48+
case *ast.Boolean:
49+
return nativeBoolToBooleanObject(node.Value)
3350
}
3451

3552
return nil
@@ -44,3 +61,19 @@ func evalStatements(stmts []ast.Statement) object.Object {
4461

4562
return result
4663
}
64+
65+
// Helper function to reference true or false to only two instances of
66+
// object.Boolean: TRUE and FALSE.
67+
func nativeBoolToBooleanObject(input bool) *object.Boolean {
68+
// We shouldn't create a new object.Boolean every time we encounter a true
69+
// or false. There is no difference between two trues. The same goes for
70+
// false. We shouldn't use new instances every time. There are only two
71+
// possible values, so let's reference them instead of allocating new
72+
// object.Booleans (creating new ones). That is a small performance
73+
// improvement we get without a lot of work.
74+
75+
if input {
76+
return TRUE
77+
}
78+
return FALSE
79+
}

evaluator/evaluator_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ func TestEvalIntegerExpression(t *testing.T) {
2323
}
2424
}
2525

26+
func TestEvalBooleanExpression(t *testing.T) {
27+
tests := []struct {
28+
input string
29+
expected bool
30+
}{
31+
{"true", true},
32+
{"false", false},
33+
}
34+
35+
for _, tt := range tests {
36+
evaluated := testEval(tt.input)
37+
testBooleanObject(t, evaluated, tt.expected)
38+
}
39+
}
40+
2641
func testEval(input string) object.Object {
2742
l := lexer.New(input)
2843
p := parser.New(l)
@@ -45,3 +60,17 @@ func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
4560

4661
return true
4762
}
63+
64+
func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
65+
result, ok := obj.(*object.Boolean)
66+
if !ok {
67+
t.Errorf("object is not Boolean. got=%T (%+v)", obj, obj)
68+
return false
69+
}
70+
if result.Value != expected {
71+
t.Errorf("object has wrong value. got=%t, want=%t",
72+
result.Value, expected)
73+
return false
74+
}
75+
return true
76+
}

0 commit comments

Comments
 (0)