From bfc64aedd91ddf023b7efc829e83ccd46ccd2cab Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 10:39:14 +0100 Subject: [PATCH 1/9] Created the Interpreter class --- Makefile | 2 +- interpreter/interpreter.go | 7 +++++++ interpreter/interpreter_test.go | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 interpreter/interpreter.go create mode 100644 interpreter/interpreter_test.go diff --git a/Makefile b/Makefile index 78cd83f..bf81b1a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BINAY_NAME=glox TESTS_DIR=./tests -TEST_SET=. ./utils ./reporting ./token ./scanner ./expression ./astprinter ./cmd/ast +TEST_SET=. ./utils ./reporting ./token ./scanner ./expression ./astprinter ./interpreter ./cmd/ast build: go build -o glox . diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go new file mode 100644 index 0000000..8e58057 --- /dev/null +++ b/interpreter/interpreter.go @@ -0,0 +1,7 @@ +package interpreter + +type Interpreter struct {} + +func NewInterpreter() *Interpreter { + return &Interpreter{} +} diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go new file mode 100644 index 0000000..3576853 --- /dev/null +++ b/interpreter/interpreter_test.go @@ -0,0 +1 @@ +package interpreter From e8477d9c23c3f02c6758676960cf1d557e0ad368 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 11:38:44 +0100 Subject: [PATCH 2/9] We start by evaluating literals and unary, with helper methods for conversion --- interpreter/interpreter.go | 61 +++++++++++++++++++++++++++- interpreter/interpreter_test.go | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index 8e58057..d1207e4 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -1,7 +1,66 @@ package interpreter -type Interpreter struct {} +import ( + "errors" + "math" + + "github.com/ByteHunter/glox/expression" + "github.com/ByteHunter/glox/reporting" + "github.com/ByteHunter/glox/token" +) + +type Interpreter struct{} func NewInterpreter() *Interpreter { return &Interpreter{} } + +func (i *Interpreter) VisitBinaryExpression(expr *expression.Binary) any { + return nil +} + +func (i *Interpreter) VisitGroupingExpression(expr *expression.Grouping) any { + return i.Evaluate(expr.Expr) +} + +func (i *Interpreter) VisitLiteralExpression(expr *expression.Literal) any { + return expr.Value +} + +func (i *Interpreter) VisitUnaryExpression(expr *expression.Unary) any { + if expr.Right == nil { + reporting.LoxError(expr.Operator.Line, "Expected an expression, nil found (InterpreterError)") + return nil + } + right := i.Evaluate(expr.Right) + + switch expr.Operator.Type { + case token.BANG: + return ! i.getBoolean(right) + case token.MINUS: + res, _ := i.getFloat(right) + return -res + } + + return nil +} + +func (i *Interpreter) Evaluate(expr expression.Expression) any { + return expr.Accept(i) +} + +func (i *Interpreter) getFloat(v any) (float64, error) { + switch t := v.(type) { + case int: + return float64(t), nil + default: + return math.NaN(), errors.New("Cannot convert to float64, unexpected type") + } +} + +func (i *Interpreter) getBoolean(v any) bool { + if v == nil || v == false { + return false + } + return true +} diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index 3576853..af9638e 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -1 +1,73 @@ package interpreter + +import ( + "fmt" + + "github.com/ByteHunter/glox/expression" + "github.com/ByteHunter/glox/token" +) + +func ExampleInterpreter_Evaluate_unary_minus() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // -42 +} + +func ExampleInterpreter_Evaluate_unary_minus2() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(-42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // 42 +} + +func ExampleInterpreter_Evaluate_unary_bang_true() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.BANG, "!", nil, 1), + expression.NewLiteral(true), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // false +} + +func ExampleInterpreter_Evaluate_unary_bang_false() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.BANG, "!", nil, 1), + expression.NewLiteral(false), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_unary_bang_other() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.BANG, "!", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // false +} From f0eb6e6e48cf00ff1030422c7059de893d4dafdd Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 11:55:14 +0100 Subject: [PATCH 3/9] Checking that unary provides a meaningful error --- interpreter/interpreter_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index af9638e..a831422 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -7,6 +7,20 @@ import ( "github.com/ByteHunter/glox/token" ) +func ExampleInterpreter_Evaluate_unary_nil() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.MINUS, "-", nil, 1), + nil, + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Expected an expression, nil found (InterpreterError) + // +} + func ExampleInterpreter_Evaluate_unary_minus() { i := NewInterpreter() expr := expression.NewUnary( From 102792bbaab97da6ac59cab4f2c3fbe3b1cc4284 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 11:59:45 +0100 Subject: [PATCH 4/9] Covering unknown unary operators --- interpreter/interpreter.go | 3 ++- interpreter/interpreter_test.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index d1207e4..24a004e 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -36,12 +36,13 @@ func (i *Interpreter) VisitUnaryExpression(expr *expression.Unary) any { switch expr.Operator.Type { case token.BANG: - return ! i.getBoolean(right) + return !i.getBoolean(right) case token.MINUS: res, _ := i.getFloat(right) return -res } + reporting.LoxError(expr.Operator.Line, "Unknown unary operator (InterpreterError)") return nil } diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index a831422..cfff9de 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -21,6 +21,20 @@ func ExampleInterpreter_Evaluate_unary_nil() { // } +func ExampleInterpreter_Evaluate_unary_unkown_token() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.PLUS, "+", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Unknown unary operator (InterpreterError) + // +} + func ExampleInterpreter_Evaluate_unary_minus() { i := NewInterpreter() expr := expression.NewUnary( From c65a03d2dad81d134890b8fd9ec2808ed1616970 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 12:06:38 +0100 Subject: [PATCH 5/9] Covering conversion errors --- interpreter/interpreter.go | 8 ++++++-- interpreter/interpreter_test.go | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index 24a004e..8af3c69 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -38,7 +38,11 @@ func (i *Interpreter) VisitUnaryExpression(expr *expression.Unary) any { case token.BANG: return !i.getBoolean(right) case token.MINUS: - res, _ := i.getFloat(right) + res, err := i.getFloat(right) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return res + } return -res } @@ -55,7 +59,7 @@ func (i *Interpreter) getFloat(v any) (float64, error) { case int: return float64(t), nil default: - return math.NaN(), errors.New("Cannot convert to float64, unexpected type") + return math.NaN(), errors.New("Cannot convert to float64, unexpected type (ConversionError)") } } diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index cfff9de..53616dc 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -35,6 +35,20 @@ func ExampleInterpreter_Evaluate_unary_unkown_token() { // } +func ExampleInterpreter_Evaluate_unary_minus_nan() { + i := NewInterpreter() + expr := expression.NewUnary( + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(true), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // NaN +} + func ExampleInterpreter_Evaluate_unary_minus() { i := NewInterpreter() expr := expression.NewUnary( From 6fc19e1cf9a70f38708cbbf83e5962570d2f93ba Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 14:26:12 +0100 Subject: [PATCH 6/9] Evaluating the binary expression --- interpreter/interpreter.go | 57 ++++++++++ interpreter/interpreter_test.go | 181 ++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index 8af3c69..6a14db9 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -16,6 +16,63 @@ func NewInterpreter() *Interpreter { } func (i *Interpreter) VisitBinaryExpression(expr *expression.Binary) any { + if expr.Left == nil { + reporting.LoxError( + expr.Operator.Line, + "Left operand expected to be an expression, nil found (InterpreterError)", + ) + return nil + } + if expr.Right == nil { + reporting.LoxError( + expr.Operator.Line, + "Right operand expected to be an expression, nil found (InterpreterError)", + ) + return nil + } + left := i.Evaluate(expr.Left) + right := i.Evaluate(expr.Right) + + switch expr.Operator.Type { + case token.MINUS: + l, err := i.getFloat(left) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + r, err := i.getFloat(right) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + return l - r + case token.SLASH: + l, err := i.getFloat(left) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + r, err := i.getFloat(right) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + return l / r + case token.STAR: + l, err := i.getFloat(left) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + r, err := i.getFloat(right) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + return l * r + } + + reporting.LoxError(expr.Operator.Line, "Unknown binary operator (InterpreterError)") return nil } diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index 53616dc..9e63c18 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -7,6 +7,8 @@ import ( "github.com/ByteHunter/glox/token" ) +// Evaluating Unary expressions + func ExampleInterpreter_Evaluate_unary_nil() { i := NewInterpreter() expr := expression.NewUnary( @@ -113,3 +115,182 @@ func ExampleInterpreter_Evaluate_unary_bang_other() { // Output: // false } + +// Evaluating Binary Expressions + +func ExampleInterpreter_Evaluate_binary_invalid_operator() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.DOT, "-", nil, 1), + expression.NewLiteral(1), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Unknown binary operator (InterpreterError) + // +} + +func ExampleInterpreter_Evaluate_binary_missing_left_operand() { + i := NewInterpreter() + expr := expression.NewBinary( + nil, + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(1), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Left operand expected to be an expression, nil found (InterpreterError) + // +} + +func ExampleInterpreter_Evaluate_binary_missing_right_operand() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.MINUS, "-", nil, 1), + nil, + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Right operand expected to be an expression, nil found (InterpreterError) + // +} + +func ExampleInterpreter_Evaluate_binary_minus() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(43), + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(1), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // 42 +} + +func ExampleInterpreter_Evaluate_binary_minus_error_left() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(43), + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_minus_error_right() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(nil), + *token.NewToken(token.MINUS, "-", nil, 1), + expression.NewLiteral(1), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_slash() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.SLASH, "/", nil, 1), + expression.NewLiteral(2), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // 21 +} + +func ExampleInterpreter_Evaluate_binary_slash_error_left() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(nil), + *token.NewToken(token.SLASH, "/", nil, 1), + expression.NewLiteral(2), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_slash_error_right() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.SLASH, "/", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_star() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(21), + *token.NewToken(token.STAR, "*", nil, 1), + expression.NewLiteral(2), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // 42 +} + +func ExampleInterpreter_Evaluate_binary_star_error_left() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(nil), + *token.NewToken(token.STAR, "*", nil, 1), + expression.NewLiteral(2), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_star_error_right() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(21), + *token.NewToken(token.STAR, "*", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} From 7dc0881cd3c14e2405261ff3324301906ce83e57 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 16:42:12 +0100 Subject: [PATCH 7/9] Evaluating the PLUS operation for numbers and strings --- interpreter/interpreter.go | 15 ++++++++++++ interpreter/interpreter_test.go | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index 6a14db9..ec67721 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -3,6 +3,7 @@ package interpreter import ( "errors" "math" + "reflect" "github.com/ByteHunter/glox/expression" "github.com/ByteHunter/glox/reporting" @@ -70,6 +71,20 @@ func (i *Interpreter) VisitBinaryExpression(expr *expression.Binary) any { return nil } return l * r + case token.PLUS: + left_type := reflect.TypeOf(left).String() + right_type := reflect.TypeOf(right).String() + if left_type == "int" && right_type == "int" { + return float64(left.(int)) + float64(right.(int)) + } + if left_type == "string" && right_type == "string" { + l := left.(string) + r := right.(string) + return l + r + } + + reporting.LoxError(expr.Operator.Line, "Incompatible types in PLUS operation (InterpreterError)") + return nil } reporting.LoxError(expr.Operator.Line, "Unknown binary operator (InterpreterError)") diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index 9e63c18..c8bb517 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -294,3 +294,46 @@ func ExampleInterpreter_Evaluate_binary_star_error_right() { // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) // } + +func ExampleInterpreter_Evaluate_binary_plus_numbers() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.PLUS, "+", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // 84 +} + +func ExampleInterpreter_Evaluate_binary_plus_string() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral("hello "), + *token.NewToken(token.PLUS, "+", nil, 1), + expression.NewLiteral("world"), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // hello world +} + +func ExampleInterpreter_Evaluate_binary_plus_incompatible_types() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral("42"), + *token.NewToken(token.PLUS, "+", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Incompatible types in PLUS operation (InterpreterError) + // +} From 166716224606eb0a960f831c3ccddf545a9a1501 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 17:04:34 +0100 Subject: [PATCH 8/9] Evaluating the comparison operations --- interpreter/interpreter.go | 49 +++++++++++--- interpreter/interpreter_test.go | 116 ++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 11 deletions(-) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index ec67721..994a156 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -35,37 +35,50 @@ func (i *Interpreter) VisitBinaryExpression(expr *expression.Binary) any { right := i.Evaluate(expr.Right) switch expr.Operator.Type { - case token.MINUS: - l, err := i.getFloat(left) + case token.GREATER: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil } - r, err := i.getFloat(right) + return l > r + case token.GREATER_EQUAL: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil } - return l - r - case token.SLASH: - l, err := i.getFloat(left) + return l >= r + case token.LESS: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil } - r, err := i.getFloat(right) + return l < r + case token.LESS_EQUAL: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil } - return l / r - case token.STAR: - l, err := i.getFloat(left) + return l <= r + case token.MINUS: + l, r, err := i.parseTwoOperands(left, right) + if err != nil { + reporting.LoxError(expr.Operator.Line, err.Error()) + return nil + } + return l - r + case token.SLASH: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil } - r, err := i.getFloat(right) + return l / r + case token.STAR: + l, r, err := i.parseTwoOperands(left, right) if err != nil { reporting.LoxError(expr.Operator.Line, err.Error()) return nil @@ -135,6 +148,20 @@ func (i *Interpreter) getFloat(v any) (float64, error) { } } +func (i *Interpreter) parseTwoOperands(left, right any) (float64, float64, error) { + l, le := i.getFloat(left) + r, re := i.getFloat(right) + + if le != nil { + return l, r, le + } + if re != nil { + return l, r, re + } + + return l, r, nil +} + func (i *Interpreter) getBoolean(v any) bool { if v == nil || v == false { return false diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index c8bb517..cef7088 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -337,3 +337,119 @@ func ExampleInterpreter_Evaluate_binary_plus_incompatible_types() { // [line 1] Error : Incompatible types in PLUS operation (InterpreterError) // } + +func ExampleInterpreter_Evaluate_binary_greater() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(43), + *token.NewToken(token.GREATER, ">", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_greater_error() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(43), + *token.NewToken(token.GREATER, ">", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_greater_equal() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.GREATER_EQUAL, ">=", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_greater_equal_error() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.GREATER_EQUAL, ">=", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_less() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(41), + *token.NewToken(token.LESS, "<", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_less_error() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(41), + *token.NewToken(token.LESS, "<", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} + +func ExampleInterpreter_Evaluate_binary_less_equal() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.LESS_EQUAL, "<=", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_less_equal_error() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.LESS_EQUAL, "<=", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) + // +} From 1f7bf7e02c292eae46980ba3dfaa0059a9f7c918 Mon Sep 17 00:00:00 2001 From: ByteHunter Date: Fri, 3 Apr 2026 17:44:41 +0100 Subject: [PATCH 9/9] Adding the EQUAL_EQUAL and BANG_EQUAL evaluation --- interpreter/interpreter.go | 26 ++++++++++ interpreter/interpreter_test.go | 84 +++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/interpreter/interpreter.go b/interpreter/interpreter.go index 994a156..b5749e4 100644 --- a/interpreter/interpreter.go +++ b/interpreter/interpreter.go @@ -63,6 +63,10 @@ func (i *Interpreter) VisitBinaryExpression(expr *expression.Binary) any { return nil } return l <= r + case token.BANQ_EQUAL: + return !i.isEqual(left, right) + case token.EQUAL_EQUAL: + return i.isEqual(left, right) case token.MINUS: l, r, err := i.parseTwoOperands(left, right) if err != nil { @@ -168,3 +172,25 @@ func (i *Interpreter) getBoolean(v any) bool { } return true } + +func (i *Interpreter) isEqual(a, b any) bool { + if a == nil && b == nil { + return true + } + if a == nil { + return false + } + atype := reflect.TypeOf(a).String() + btype := reflect.TypeOf(b).String() + + if atype != btype { + return false + } + + switch atype { + case "int", "string": + return a == b; + } + + return false +} diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index cef7088..7049073 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -453,3 +453,87 @@ func ExampleInterpreter_Evaluate_binary_less_equal_error() { // [line 1] Error : Cannot convert to float64, unexpected type (ConversionError) // } + +func ExampleInterpreter_Evaluate_binary_bang_equal() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(43), + *token.NewToken(token.BANQ_EQUAL, "!=", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_equal_equal() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.EQUAL_EQUAL, "==", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_equal_both_nil() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(nil), + *token.NewToken(token.EQUAL_EQUAL, "==", nil, 1), + expression.NewLiteral(nil), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // true +} + +func ExampleInterpreter_Evaluate_binary_equal_one_nil() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(nil), + *token.NewToken(token.EQUAL_EQUAL, "==", nil, 1), + expression.NewLiteral(42), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // false +} + +func ExampleInterpreter_Evaluate_binary_equal_not_same_types() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(42), + *token.NewToken(token.EQUAL_EQUAL, "==", nil, 1), + expression.NewLiteral(true), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // false +} + +func ExampleInterpreter_Evaluate_binary_equal_false() { + i := NewInterpreter() + expr := expression.NewBinary( + expression.NewLiteral(true), + *token.NewToken(token.EQUAL_EQUAL, "==", nil, 1), + expression.NewLiteral(false), + ) + result := i.Evaluate(expr) + fmt.Println(result) + + // Output: + // false +}