From 4b67c7d6e1fe55463981f5e777da68c6471077eb Mon Sep 17 00:00:00 2001 From: tijani Date: Mon, 8 Aug 2022 10:14:14 +0000 Subject: [PATCH] Implement the "!" evaluation operator git-svn-id: https://svn.tlawal.org/svn/monkey@46 f6afcba9-9ef1-4bdd-9b72-7484f5705bac --- evaluator/evaluator.go | 48 +++++++++++++++++++++++++++++++++++-- evaluator/evaluator_test.go | 33 +++++++++++++++++++------ repl/repl.go | 6 ++--- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 5ab22bf..632ad2b 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -5,9 +5,15 @@ import ( "monkey/object" ) +var ( + NULL = &object.Null{} + TRUE = &object.Boolean{Value: true} + FALSE = &object.Boolean{Value: false} +) + func Eval(node ast.Node) object.Object { switch node := node.(type) { - // Statements + // Statements case *ast.Program: return eval_statements(node.Statements) @@ -19,7 +25,12 @@ func Eval(node ast.Node) object.Object { return &object.Integer{Value: node.Value} case *ast.Boolean: - return &object.Boolean{Value: node.Value} + return native_bool_to_boolean_object(node.Value) + + case *ast.PrefixExpression: + right := Eval(node.Right) + return eval_prefix_expression(node.Operator, right) + } return nil @@ -33,3 +44,36 @@ func eval_statements(statements []ast.Statement) object.Object { } return result } + +func native_bool_to_boolean_object(input bool) *object.Boolean { + if input { + return TRUE + } + return FALSE +} + +func eval_prefix_expression(operator string, right object.Object) object.Object { + switch operator { + case "!": + return eval_bang_operator_expression(right) + + default: + return NULL + } +} + +func eval_bang_operator_expression(right object.Object) object.Object { + switch right { + case TRUE: + return FALSE + + case FALSE: + return TRUE + + case NULL: + return TRUE + + default: + return FALSE + } +} diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index ade6bd7..cb6e505 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -22,21 +22,40 @@ func TestEvalIntegerExpression(l_test *testing.T) { } } -func TestEvalBooleanExpression(l_test *testing.T){ +func TestEvalBooleanExpression(l_test *testing.T) { tests := []struct { - input string + input string expected bool }{ {"true", true}, {"false", false}, } - for _, tt := range tests{ - evaluated := test_eval(tt.input) - test_boolean_object(l_test, evaluated, tt.expected) - } + for _, tt := range tests { + evaluated := test_eval(tt.input) + test_boolean_object(l_test, evaluated, tt.expected) + } +} + +// Test to convert the '!' operator to boolean value and negate it +func TestBangOperator(l_test *testing.T) { + tests := []struct { + input string + expected bool + }{ + {"!true", false}, + {"!false", true}, + {"!5", false}, + {"!!true", true}, + {"!!false", false}, + {"!!5", true}, } + for _, tt := range tests { + evaluated := test_eval(tt.input) + test_boolean_object(l_test, evaluated, tt.expected) + } +} // Helpers func test_eval(input string) object.Object { @@ -60,7 +79,7 @@ func test_integer_object(l_test *testing.T, l_object object.Object, expected int return true } -func test_boolean_object(l_test *testing.T, l_object object.Object, expected bool)bool { +func test_boolean_object(l_test *testing.T, l_object object.Object, expected bool) bool { result, ok := l_object.(*object.Boolean) if !ok { l_test.Errorf("object is not Boolean, got=%T (%+v)", l_object, l_object) diff --git a/repl/repl.go b/repl/repl.go index d2f8efe..e4a3916 100644 --- a/repl/repl.go +++ b/repl/repl.go @@ -4,9 +4,9 @@ import ( "bufio" "fmt" "io" + "monkey/evaluator" "monkey/lexer" "monkey/parser" - "monkey/evaluator" ) const MONKEY_FACE = ` __,__ @@ -43,9 +43,9 @@ func Start(in io.Reader, out io.Writer) { print_parser_errors(out, l_parser.Errors()) continue } - + evaluated := evaluator.Eval(program) - if evaluated != nil{ + if evaluated != nil { io.WriteString(out, evaluated.Inspect()) io.WriteString(out, "\n") }