Skip to content

Commit

Permalink
better error message
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jul 7, 2022
1 parent 8640be5 commit 28585fa
Show file tree
Hide file tree
Showing 22 changed files with 133 additions and 96 deletions.
24 changes: 13 additions & 11 deletions evaluator/array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func TestErrorArrayHandling(t *testing.T) {
}{
{
"-[];",
"unknown operator: -ARRAY",
"unknown operator: -ARRAY - at [Line: 1, Offset: 1]",
},
{
"[] + [];",
Expand Down Expand Up @@ -188,18 +188,20 @@ func TestErrorArrayHandling(t *testing.T) {
},
}

for _, tt := range tests {
evaluated := testEval(tt.input, t)
for i, tt := range tests {
t.Run(fmt.Sprintf("TestErrorArrayHandling[%d]", i), func(t *testing.T) {
evaluated := testEval(tt.input, t)

errObj, ok := evaluated.(*object.Error)
if !ok {
t.Errorf("no error object returned. got=%T(%+v)", evaluated, evaluated)
continue
}
errObj, ok := evaluated.(*object.Error)
if !ok {
t.Fatalf("no error object returned. got=%T(%+v)", evaluated, evaluated)
}

if errObj.Message != tt.expectedMessage {
t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMessage, errObj.Message)
}
})

if errObj.Message != tt.expectedMessage {
t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMessage, errObj.Message)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion evaluator/boolean_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestErrorBooleanHandling(t *testing.T) {
}{
{
"-true",
"unknown operator: -BOOLEAN",
"unknown operator: -BOOLEAN - at [Line: 1, Offset: 1]",
},
{
"true + false;",
Expand Down
9 changes: 6 additions & 3 deletions evaluator/digit.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package evaluator

import "ninja/object"
import (
"ninja/ast"
"ninja/object"
)

func evalFloatOrIntegerInfixExpression(
operator string,
Expand Down Expand Up @@ -31,7 +34,7 @@ func evalFloatOrIntegerInfixExpression(
return evalFloatInfixExpression(operator, leftValFloat, rightValFloat)
}

func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
func evalMinusPrefixOperatorExpression(node *ast.PrefixExpression, right object.Object) object.Object {
if right.Type() == object.INTEGER_OBJ {
value := right.(*object.Integer).Value
return &object.Integer{Value: -value}
Expand All @@ -42,7 +45,7 @@ func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
return &object.Float{Value: -value}
}

return object.NewErrorFormat("unknown operator: -%s", right.Type())
return object.NewErrorFormat("unknown operator: -%s %s", right.Type(), node.Token)
}

func evalIncrementExpression(right object.Object) object.Object {
Expand Down
19 changes: 11 additions & 8 deletions evaluator/for_statement_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"fmt"
"ninja/object"
"testing"
)
Expand Down Expand Up @@ -32,15 +33,17 @@ func TestForStatement(t *testing.T) {
},
}

for _, tt := range tests {
evaluated := testEval(tt.input, t)
for i, tt := range tests {
t.Run(fmt.Sprintf("TestForStatement[%d]", i), func(t *testing.T) {
evaluated := testEval(tt.input, t)

integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else if evaluated != nil {
t.Errorf("result isnt nil. Got %v", evaluated)
}
integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else if evaluated != nil {
t.Errorf("result isnt nil. Got %v", evaluated)
}
})
}
}

Expand Down
4 changes: 2 additions & 2 deletions evaluator/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ func applyFunction(fn object.Object, args []object.Object) object.Object {
switch fn := fn.(type) {
case *object.FunctionLiteral:
if len(fn.Parameters) != len(args) {
return object.NewErrorFormat("Function expected %d arguments, got %d", len(fn.Parameters), len(args))
return object.NewErrorFormat("Function expected %d arguments, got %d at %s", len(fn.Parameters), len(args), fn.Body.Token)
}
extendedEnv := extendFunctionEnv(fn.Env, fn.Parameters, args)
evaluated := Eval(fn.Body, extendedEnv)
return unwrapReturnValue(evaluated)
case *object.Function:
if len(fn.Parameters) != len(args) {
return object.NewErrorFormat("Function expected %d arguments, got %d", len(fn.Parameters), len(args))
return object.NewErrorFormat("Function expected %d arguments, got %d at %s", len(fn.Parameters), len(args), fn.Body.Token)
}
extendedEnv := extendFunctionEnv(fn.Env, fn.Parameters, args)
evaluated := Eval(fn.Body, extendedEnv)
Expand Down
45 changes: 28 additions & 17 deletions evaluator/function_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"fmt"
"ninja/object"
"testing"
)
Expand Down Expand Up @@ -109,14 +110,21 @@ func TestCallFunction(t *testing.T) {
"function add(a, b) { return function test(x, y) { return a + b + x + y }; } add(10, 10)(10, 10);",
40,
},
//{
// "var a = 0; function add() { return function increment() { a++; return a; }}; var b = add()(); add()();",
// 2,
// },
}

for _, tt := range tests {
evaluated := testEval(tt.expression, t)
for i, tt := range tests {
t.Run(fmt.Sprintf("TestCallFunction[%d]", i), func(t *testing.T) {
evaluated := testEval(tt.expression, t)

if !testObjectLiteral(t, evaluated, tt.rs) {
t.Errorf("TestCallFunction unable to test")
}
})

if !testObjectLiteral(t, evaluated, tt.rs) {
t.Errorf("TestCallFunction unable to test")
}
}
}

Expand Down Expand Up @@ -145,21 +153,24 @@ func TestCallWrongParameters(t *testing.T) {
input string
expectedErrorMessage string
}{
{"function (x) {}();", "Function expected 1 arguments, got 0"},
{"function () {}(0);", "Function expected 0 arguments, got 1"},
{"function (x) {}();", "Function expected 1 arguments, got 0 at { at [Line: 1, Offset: 14]"},
{"function () {}(0);", "Function expected 0 arguments, got 1 at { at [Line: 1, Offset: 13]"},
{"function () { return add(); }();", "identifier not found: add IDENT at [Line: 1, Offset: 25]"},
}

for _, tt := range tests {
evaluated := testEval(tt.input, t)
for i, tt := range tests {
t.Run(fmt.Sprintf("TestCallWrongParameters[%d]", i), func(t *testing.T) {
evaluated := testEval(tt.input, t)

errObj, ok := evaluated.(*object.Error)
if !ok {
t.Fatalf("no error object returned. got=%T(%+v)", evaluated, evaluated)
}

errObj, ok := evaluated.(*object.Error)
if !ok {
t.Errorf("no error object returned. got=%T(%+v)", evaluated, evaluated)
continue
}
if errObj.Message != tt.expectedErrorMessage {
t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedErrorMessage, errObj.Message)
}
})

if errObj.Message != tt.expectedErrorMessage {
t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedErrorMessage, errObj.Message)
}
}
}
2 changes: 1 addition & 1 deletion evaluator/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestErrorHashHandling(t *testing.T) {
}{
{
"-{};",
"unknown operator: -HASH",
"unknown operator: -HASH - at [Line: 1, Offset: 1]",
},
{
"{} + {}",
Expand Down
6 changes: 3 additions & 3 deletions evaluator/identifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func evalIdentifier(
return builtin
}

return object.NewErrorFormat("identifier not found: " + node.Value)
return object.NewErrorFormat("identifier not found: %s %s", node.Value, node.Token)
}

func evalAssignStatement(node *ast.AssignStatement, env *object.Environment) object.Object {
Expand All @@ -42,12 +42,12 @@ func evalAssignIdentifier(node *ast.AssignStatement, env *object.Environment) ob

// Unecessary check..
if !ok {
return object.NewErrorFormat("node.Name is not type of identifier. Got %T", node.Name)
return object.NewErrorFormat("node.Name is not type of identifier. Got %T %s", node.Name, node.Token)
}

_, ok = env.Get(identifier.Value)
if !ok {
return object.NewErrorFormat("identifier not found: %s", identifier.Value)
return object.NewErrorFormat("identifier not found: %s %s", identifier.Value, node.Token)
}

val := Eval(node.Value, env)
Expand Down
31 changes: 17 additions & 14 deletions evaluator/identifier_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"fmt"
"ninja/object"
"testing"
)
Expand Down Expand Up @@ -47,15 +48,15 @@ func TestErrorIdentifierHandling(t *testing.T) {
}{
{
"foobar",
"identifier not found: foobar",
"identifier not found: foobar IDENT at [Line: 1, Offset: 7]",
},
{
"foobar = 1 + 1;",
"identifier not found: foobar",
"identifier not found: foobar IDENT at [Line: 1, Offset: 7]",
},
{
"var b = a + 1;",
"identifier not found: a",
"identifier not found: a IDENT at [Line: 1, Offset: 10]",
},
{
`"Hello" - "World"`,
Expand All @@ -79,18 +80,20 @@ func TestErrorIdentifierHandling(t *testing.T) {
},
}

for _, tt := range tests {
evaluated := testEval(tt.input, t)
for i, tt := range tests {
t.Run(fmt.Sprintf("TestErrorIdentifierHandling[%d]", i), func(t *testing.T) {
evaluated := testEval(tt.input, t)

errObj, ok := evaluated.(*object.Error)
if !ok {
t.Fatalf("no error object returned. got=%T(%+v)", evaluated, evaluated)
}

errObj, ok := evaluated.(*object.Error)
if !ok {
t.Errorf("no error object returned. got=%T(%+v)", evaluated, evaluated)
continue
}
if errObj.Message != tt.expectedMessage {
t.Errorf("wrong error message. expected=%q, got=%q",
tt.expectedMessage, errObj.Message)
}
})

if errObj.Message != tt.expectedMessage {
t.Errorf("wrong error message. expected=%q, got=%q",
tt.expectedMessage, errObj.Message)
}
}
}
2 changes: 1 addition & 1 deletion evaluator/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func evalImport(node ast.Node, env *object.Environment) object.Object {
readFile, err := os.Open(filename.Value)

if err != nil {
return object.NewErrorFormat("IO Error: error reading file '%s': %s", filename.Value, err)
return object.NewErrorFormat("IO Error: error reading file '%s': %s %s", filename.Value, err, astImport.Token)
}

l := lexer.New(readFile)
Expand Down
6 changes: 3 additions & 3 deletions evaluator/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func TestErrorImportHandling(t *testing.T) {
}{
{
`import "non-exists-file"`,
"IO Error: error reading file 'non-exists-file': open non-exists-file: no such file or directory",
"IO Error: error reading file 'non-exists-file': open non-exists-file: no such file or directory IMPORT at [Line: 1, Offset: 7]",
},
{
`import "../fixtures/stub-with-error.nj"`,
"../fixtures/stub-with-error.nj: expected next token to be (, got EOF (\x00) at [Line: 1, Offset: 13] instead.",
"../fixtures/stub-with-error.nj: expected next token to be (, got EOF at [Line: 1, Offset: 13] instead.",
},
{
`import "../fixtures/stub-with-error-in-function.nj"`,
"../fixtures/stub-with-error-in-function.nj: Function expected 2 arguments, got 3",
"../fixtures/stub-with-error-in-function.nj: Function expected 2 arguments, got 3 at { at [Line: 16, Offset: 38]",
},
}

Expand Down
5 changes: 3 additions & 2 deletions evaluator/prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ func evalPrefixExpression(node *ast.PrefixExpression, env *object.Environment) o
case "!":
return evalBangOperatorExpression(right)
case "-":
return evalMinusPrefixOperatorExpression(right)
return evalMinusPrefixOperatorExpression(node, right)
}
return object.NewErrorFormat("unknown operator: %s%s", node.Operator, right.Type())

return object.NewErrorFormat("unknown operator: %s%s %s", node.Operator, right.Type(), node.Token)
}

func evalPrefixExpressionAndAssing(node *ast.PrefixExpression, right object.Object, env *object.Environment) object.Object {
Expand Down
2 changes: 1 addition & 1 deletion evaluator/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestErrorStringHandling(t *testing.T) {
}{
{
"-\"hello\"",
"unknown operator: -STRING",
"unknown operator: -STRING - at [Line: 1, Offset: 1]",
},
{
`"Hello" - "Nice"`,
Expand Down
Binary file removed main
Binary file not shown.
3 changes: 2 additions & 1 deletion object/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import "testing"

func TestEnvironment_Get(t *testing.T) {
env := NewEnvironment()
env.Set("name", &String{Value: "Hello"})
str := &String{Value: "Hello"}
env.Set("name", str)

v, ok := env.Get("name")
if !ok {
Expand Down
10 changes: 5 additions & 5 deletions parser/assign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ i = i = 1;
tests := []struct {
expectedError string
}{
{fmt.Sprintf("expected next token to be %s, got %s (true) at [Line: 2, Offset: 11] instead.", token.ASSIGN, token.TRUE)},
{fmt.Sprintf("expected next token to be %s, got %s (=) at [Line: 3, Offset: 5] instead.", token.IDENT, token.ASSIGN)},
{fmt.Sprintf("expected next token to be %s, got %s (var) at [Line: 4, Offset: 8] instead.", token.IDENT, token.VAR)},
{fmt.Sprintf("expected next token to be %s, got %s (=) at [Line: 5, Offset: 5] instead.", token.IDENT, token.ASSIGN)},
{fmt.Sprintf("expected next token to be %s, got %s (=) at [Line: 6, Offset: 7] instead.", token.IDENT, token.ASSIGN)},
{fmt.Sprintf("expected next token to be %s, got %s at [Line: 2, Offset: 11] instead.", token.ASSIGN, token.TRUE)},
{fmt.Sprintf("expected next token to be %s, got %s at [Line: 3, Offset: 5] instead.", token.IDENT, token.ASSIGN)},
{fmt.Sprintf("expected next token to be %s, got %s at [Line: 4, Offset: 8] instead.", token.IDENT, token.VAR)},
{fmt.Sprintf("expected next token to be %s, got %s at [Line: 5, Offset: 5] instead.", token.IDENT, token.ASSIGN)},
{fmt.Sprintf("expected next token to be %s, got %s at [Line: 6, Offset: 7] instead.", token.IDENT, token.ASSIGN)},
}

errors := p.Errors()
Expand Down
Loading

0 comments on commit 28585fa

Please sign in to comment.