From 6dd573c3f60f68fff6bde9d2c67638cdcb138d73 Mon Sep 17 00:00:00 2001 From: earncef Date: Fri, 22 Feb 2019 22:39:07 +0100 Subject: [PATCH] Runtime error trace format (#111) * Runtime error format * Parser and Compiler error formats updated --- cmd/tengo/main.go | 10 +- compiler/compiler_error_report_test.go | 16 +- compiler/error.go | 2 +- compiler/parser/error.go | 10 +- compiler/parser/error_list_test.go | 2 +- compiler/parser/error_test.go | 2 +- runtime/vm.go | 221 +++++++++++++------------ runtime/vm_call_test.go | 4 +- runtime/vm_error_report_test.go | 14 +- runtime/vm_module_test.go | 15 +- 10 files changed, 148 insertions(+), 148 deletions(-) diff --git a/cmd/tengo/main.go b/cmd/tengo/main.go index 4a6e12e..470c687 100644 --- a/cmd/tengo/main.go +++ b/cmd/tengo/main.go @@ -201,7 +201,7 @@ func runREPL(in io.Reader, out io.Writer) { srcFile := fileSet.AddFile("repl", -1, len(line)) file, err := parser.ParseFile(srcFile, []byte(line), nil) if err != nil { - _, _ = fmt.Fprintf(out, "error: %s\n", err.Error()) + _, _ = fmt.Fprintln(out, err.Error()) continue } @@ -209,19 +209,15 @@ func runREPL(in io.Reader, out io.Writer) { c := compiler.NewCompiler(srcFile, symbolTable, constants, nil, nil) if err := c.Compile(file); err != nil { - _, _ = fmt.Fprintf(out, "Compilation error:\n %s\n", err.Error()) + _, _ = fmt.Fprintln(out, err.Error()) continue } bytecode := c.Bytecode() machine := runtime.NewVM(bytecode, globals, nil) - if err != nil { - _, _ = fmt.Fprintf(out, "VM error:\n %s\n", err.Error()) - continue - } if err := machine.Run(); err != nil { - _, _ = fmt.Fprintf(out, "Execution error:\n %s\n", err.Error()) + _, _ = fmt.Fprintln(out, err.Error()) continue } diff --git a/compiler/compiler_error_report_test.go b/compiler/compiler_error_report_test.go index 27191c5..6307195 100644 --- a/compiler/compiler_error_report_test.go +++ b/compiler/compiler_error_report_test.go @@ -3,15 +3,15 @@ package compiler_test import "testing" func TestCompilerErrorReport(t *testing.T) { - expectError(t, `import("user1")`, "test:1:1: module file read error: open user1.tengo: no such file or directory") + expectError(t, `import("user1")`, "Compile Error: module file read error: open user1.tengo: no such file or directory\n\tat test:1:1") - expectError(t, `a = 1`, "test:1:1: unresolved reference 'a'") - expectError(t, `a, b := 1, 2`, "test:1:1: tuple assignment not allowed") + expectError(t, `a = 1`, "Compile Error: unresolved reference 'a'\n\tat test:1:1") + expectError(t, `a, b := 1, 2`, "Compile Error: tuple assignment not allowed\n\tat test:1:1") expectError(t, `a.b := 1`, "not allowed with selector") - expectError(t, `a:=1; a:=3`, "test:1:7: 'a' redeclared in this block") + expectError(t, `a:=1; a:=3`, "Compile Error: 'a' redeclared in this block\n\tat test:1:7") - expectError(t, `return 5`, "test:1:1: return not allowed outside function") - expectError(t, `func() { break }`, "test:1:10: break not allowed outside loop") - expectError(t, `func() { continue }`, "test:1:10: continue not allowed outside loop") - expectError(t, `func() { export 5 }`, "test:1:10: export not allowed inside function") + expectError(t, `return 5`, "Compile Error: return not allowed outside function\n\tat test:1:1") + expectError(t, `func() { break }`, "Compile Error: break not allowed outside loop\n\tat test:1:10") + expectError(t, `func() { continue }`, "Compile Error: continue not allowed outside loop\n\tat test:1:10") + expectError(t, `func() { export 5 }`, "Compile Error: export not allowed inside function\n\tat test:1:10") } diff --git a/compiler/error.go b/compiler/error.go index b0697f9..6ac33d4 100644 --- a/compiler/error.go +++ b/compiler/error.go @@ -16,5 +16,5 @@ type Error struct { func (e *Error) Error() string { filePos := e.fileSet.Position(e.node.Pos()) - return fmt.Sprintf("%s: %s", filePos, e.error.Error()) + return fmt.Sprintf("Compile Error: %s\n\tat %s", e.error.Error(), filePos) } diff --git a/compiler/parser/error.go b/compiler/parser/error.go index dd72e58..80544fb 100644 --- a/compiler/parser/error.go +++ b/compiler/parser/error.go @@ -1,6 +1,10 @@ package parser -import "github.com/d5/tengo/compiler/source" +import ( + "fmt" + + "github.com/d5/tengo/compiler/source" +) // Error represents a parser error. type Error struct { @@ -10,8 +14,8 @@ type Error struct { func (e Error) Error() string { if e.Pos.Filename != "" || e.Pos.IsValid() { - return e.Pos.String() + ": " + e.Msg + return fmt.Sprintf("Parse Error: %s\n\tat %s", e.Msg, e.Pos) } - return e.Msg + return fmt.Sprintf("Parse Error: %s", e.Msg) } diff --git a/compiler/parser/error_list_test.go b/compiler/parser/error_list_test.go index 205dbc2..926dfdb 100644 --- a/compiler/parser/error_list_test.go +++ b/compiler/parser/error_list_test.go @@ -14,5 +14,5 @@ func TestErrorList_Sort(t *testing.T) { list.Add(source.FilePos{Offset: 30, Line: 3, Column: 10}, "error 3") list.Add(source.FilePos{Offset: 10, Line: 1, Column: 10}, "error 1") list.Sort() - assert.Equal(t, "1:10: error 1 (and 2 more errors)", list.Error()) + assert.Equal(t, "Parse Error: error 1\n\tat 1:10 (and 2 more errors)", list.Error()) } diff --git a/compiler/parser/error_test.go b/compiler/parser/error_test.go index b8bf687..a86c0e5 100644 --- a/compiler/parser/error_test.go +++ b/compiler/parser/error_test.go @@ -10,5 +10,5 @@ import ( func TestError_Error(t *testing.T) { err := &parser.Error{Pos: source.FilePos{Offset: 10, Line: 1, Column: 10}, Msg: "test"} - assert.Equal(t, "1:10: test", err.Error()) + assert.Equal(t, "Parse Error: test\n\tat 1:10", err.Error()) } diff --git a/runtime/vm.go b/runtime/vm.go index 5bbcf94..2708fde 100644 --- a/runtime/vm.go +++ b/runtime/vm.go @@ -94,6 +94,8 @@ func (v *VM) Run() (err error) { v.ip = -1 atomic.StoreInt64(&v.aborting, 0) + var filePos source.FilePos + mainloop: for v.ip < v.curIPLimit && (atomic.LoadInt64(&v.aborting) == 0) { v.ip++ @@ -127,14 +129,14 @@ mainloop: res, e := (*left).BinaryOp(token.Add, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s + %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s + %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -153,14 +155,14 @@ mainloop: res, e := (*left).BinaryOp(token.Sub, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s - %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s - %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -179,14 +181,14 @@ mainloop: res, e := (*left).BinaryOp(token.Mul, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s * %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s * %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -205,14 +207,14 @@ mainloop: res, e := (*left).BinaryOp(token.Quo, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s / %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s / %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -231,14 +233,14 @@ mainloop: res, e := (*left).BinaryOp(token.Rem, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s %% %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s %% %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -257,14 +259,14 @@ mainloop: res, e := (*left).BinaryOp(token.And, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s & %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s & %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -283,14 +285,14 @@ mainloop: res, e := (*left).BinaryOp(token.Or, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s | %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s | %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -309,14 +311,14 @@ mainloop: res, e := (*left).BinaryOp(token.Xor, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s ^ %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s ^ %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -335,14 +337,14 @@ mainloop: res, e := (*left).BinaryOp(token.AndNot, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s &^ %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s &^ %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -361,14 +363,14 @@ mainloop: res, e := (*left).BinaryOp(token.Shl, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s << %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s << %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -387,14 +389,14 @@ mainloop: res, e := (*left).BinaryOp(token.Shr, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s >> %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s >> %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -447,14 +449,14 @@ mainloop: res, e := (*left).BinaryOp(token.Greater, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s > %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s > %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -473,14 +475,14 @@ mainloop: res, e := (*left).BinaryOp(token.GreaterEq, *right) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidOperator { - err = fmt.Errorf("%s: invalid operation: %s >= %s", - filePos, (*left).TypeName(), (*right).TypeName()) + err = fmt.Errorf("invalid operation: %s >= %s", + (*left).TypeName(), (*right).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -545,8 +547,8 @@ mainloop: v.stack[v.sp] = &res v.sp++ default: - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid operation: ^%s", filePos, (*operand).TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid operation: ^%s", (*operand).TypeName()) break mainloop } @@ -576,8 +578,8 @@ mainloop: v.stack[v.sp] = &res v.sp++ default: - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid operation: -%s", filePos, (*operand).TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid operation: -%s", (*operand).TypeName()) break mainloop } @@ -637,8 +639,8 @@ mainloop: v.sp -= numSelectors + 1 if e := indexAssign(v.globals[globalIndex], val, selectors); e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = fmt.Errorf("%s: %s", filePos, e.Error()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) + err = e break mainloop } @@ -732,14 +734,14 @@ mainloop: case objects.Indexable: val, e := left.IndexGet(*index) if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) if e == objects.ErrInvalidIndexType { - err = fmt.Errorf("%s: invalid index type: %s", filePos, (*index).TypeName()) + err = fmt.Errorf("invalid index type: %s", (*index).TypeName()) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } if val == nil { @@ -757,8 +759,8 @@ mainloop: case *objects.Error: // e.value key, ok := (*index).(*objects.String) if !ok || key.Value != "value" { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid index on error", filePos) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid index on error") break mainloop } @@ -771,8 +773,8 @@ mainloop: v.sp++ default: - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: not indexable: %s", filePos, left.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("not indexable: %s", left.TypeName()) break mainloop } @@ -787,8 +789,8 @@ mainloop: if low, ok := (*low).(*objects.Int); ok { lowIdx = low.Value } else { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index type: %s", filePos, low.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index type: %s", low.TypeName()) break mainloop } } @@ -802,14 +804,14 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index type: %s", filePos, high.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) break mainloop } if lowIdx > highIdx { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index: %d > %d", filePos, lowIdx, highIdx) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) break mainloop } @@ -842,14 +844,14 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index type: %s", filePos, high.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) break mainloop } if lowIdx > highIdx { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index: %d > %d", filePos, lowIdx, highIdx) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) break mainloop } @@ -883,14 +885,14 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index type: %s", filePos, high.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) break mainloop } if lowIdx > highIdx { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index: %d > %d", filePos, lowIdx, highIdx) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) break mainloop } @@ -924,14 +926,14 @@ mainloop: } else if high, ok := (*high).(*objects.Int); ok { highIdx = high.Value } else { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index type: %s", filePos, high.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index type: %s", high.TypeName()) break mainloop } if lowIdx > highIdx { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: invalid slice index: %d > %d", filePos, lowIdx, highIdx) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("invalid slice index: %d > %d", lowIdx, highIdx) break mainloop } @@ -967,9 +969,9 @@ mainloop: switch callee := value.(type) { case *objects.Closure: if numArgs != callee.Fn.NumParameters { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("%s: wrong number of arguments: want=%d, got=%d", - filePos, callee.Fn.NumParameters, numArgs) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) + err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", + callee.Fn.NumParameters, numArgs) break mainloop } @@ -1001,9 +1003,9 @@ mainloop: case *objects.CompiledFunction: if numArgs != callee.NumParameters { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("%s: wrong number of arguments: want=%d, got=%d", - filePos, callee.NumParameters, numArgs) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) + err = fmt.Errorf("wrong number of arguments: want=%d, got=%d", + callee.NumParameters, numArgs) break mainloop } @@ -1044,21 +1046,21 @@ mainloop: // runtime error if e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) if e == objects.ErrWrongNumArguments { - err = fmt.Errorf("%s: wrong number of arguments in call to '%s'", - filePos, value.TypeName()) + err = fmt.Errorf("wrong number of arguments in call to '%s'", + value.TypeName()) break mainloop } if e, ok := e.(objects.ErrInvalidArgumentType); ok { - err = fmt.Errorf("%s: invalid type for argument '%s' in call to '%s': expected %s, found %s", - filePos, e.Name, value.TypeName(), e.Expected, e.Found) + err = fmt.Errorf("invalid type for argument '%s' in call to '%s': expected %s, found %s", + e.Name, value.TypeName(), e.Expected, e.Found) break mainloop } - err = fmt.Errorf("%s: %s", filePos, e.Error()) + err = e break mainloop } @@ -1076,8 +1078,8 @@ mainloop: v.sp++ default: - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) - err = fmt.Errorf("%s: not callable: %s", filePos, callee.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-1]) + err = fmt.Errorf("not callable: %s", callee.TypeName()) break mainloop } @@ -1153,8 +1155,8 @@ mainloop: sp := v.curFrame.basePointer + localIndex if e := indexAssign(v.stack[sp], val, selectors); e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) - err = fmt.Errorf("%s: %s", filePos, e.Error()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) + err = e break mainloop } @@ -1192,8 +1194,8 @@ mainloop: module, ok := v.builtinModules[moduleName] if !ok { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = fmt.Errorf("%s: module '%s' not found", filePos, moduleName) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) + err = fmt.Errorf("module '%s' not found", moduleName) break mainloop } @@ -1212,8 +1214,8 @@ mainloop: fn, ok := v.constants[constIndex].(*objects.CompiledFunction) if !ok { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) - err = fmt.Errorf("%s: not function: %s", filePos, fn.TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-3]) + err = fmt.Errorf("not function: %s", fn.TypeName()) break mainloop } @@ -1261,8 +1263,8 @@ mainloop: v.sp -= numSelectors + 1 if e := indexAssign(v.curFrame.freeVars[freeIndex], val, selectors); e != nil { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) - err = fmt.Errorf("%s: %s", filePos, e.Error()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip-2]) + err = e break mainloop } @@ -1283,8 +1285,8 @@ mainloop: iterable, ok := (*dst).(objects.Iterable) if !ok { - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) - err = fmt.Errorf("%s: not iterable: %s", filePos, (*dst).TypeName()) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.ip]) + err = fmt.Errorf("not iterable: %s", (*dst).TypeName()) break mainloop } @@ -1350,12 +1352,13 @@ mainloop: } if err != nil { + err = fmt.Errorf("Runtime Error: %s\n\tat %s", err.Error(), filePos) for v.framesIndex > 1 { v.framesIndex-- v.curFrame = &v.frames[v.framesIndex-1] - filePos := v.fileSet.Position(v.curFrame.fn.SourceMap[v.curFrame.ip-1]) - err = fmt.Errorf("%s\nin %s", err.Error(), filePos) + filePos = v.fileSet.Position(v.curFrame.fn.SourceMap[v.curFrame.ip-1]) + err = fmt.Errorf("%s\n\tat %s", err.Error(), filePos) } return err } diff --git a/runtime/vm_call_test.go b/runtime/vm_call_test.go index 1bec423..c93e773 100644 --- a/runtime/vm_call_test.go +++ b/runtime/vm_call_test.go @@ -15,7 +15,5 @@ c := func(a) { a() } b(a, c) -`, `test:7:4: not callable: int -in test:3:4 -in test:9:1`) +`, "Runtime Error: not callable: int\n\tat test:7:4\n\tat test:3:4\n\tat test:9:1") } diff --git a/runtime/vm_error_report_test.go b/runtime/vm_error_report_test.go index 49bfc32..a25219a 100644 --- a/runtime/vm_error_report_test.go +++ b/runtime/vm_error_report_test.go @@ -5,16 +5,16 @@ import "testing" func TestVMErrorInfo(t *testing.T) { expectError(t, `a := 5 a + "boo"`, - "test:2:1: invalid operation: int + string") + "Runtime Error: invalid operation: int + string\n\tat test:2:1") expectError(t, `a := 5 b := a(5)`, - "test:2:6: not callable: int") + "Runtime Error: not callable: int\n\tat test:2:6") expectError(t, `a := 5 b := {} b.x.y = 10`, - "test:3:1: not index-assignable: undefined") + "Runtime Error: not index-assignable: undefined\n\tat test:3:1") expectError(t, ` a := func() { @@ -22,12 +22,12 @@ a := func() { b += "foo" } a()`, - "test:4:2: invalid operation: int + string") + "Runtime Error: invalid operation: int + string\n\tat test:4:2") expectErrorWithUserModules(t, `a := 5 a + import("mod1")`, map[string]string{ "mod1": `export "foo"`, - }, "test:2:2: invalid operation: int + string") + }, ": invalid operation: int + string\n\tat test:2:2") expectErrorWithUserModules(t, `a := import("mod1")()`, map[string]string{ "mod1": ` @@ -35,7 +35,7 @@ export func() { b := 5 return b + "foo" }`, - }, "mod1:4:9: invalid operation: int + string") + }, "Runtime Error: invalid operation: int + string\n\tat mod1:4:9") expectErrorWithUserModules(t, `a := import("mod1")()`, map[string]string{ "mod1": `export import("mod2")()`, @@ -44,5 +44,5 @@ export func() { b := 5 return b + "foo" }`, - }, "mod2:4:9: invalid operation: int + string") + }, "Runtime Error: invalid operation: int + string\n\tat mod2:4:9") } diff --git a/runtime/vm_module_test.go b/runtime/vm_module_test.go index 4e6c3dc..d8fac1d 100644 --- a/runtime/vm_module_test.go +++ b/runtime/vm_module_test.go @@ -160,19 +160,19 @@ export func() { expectErrorWithUserModules(t, `import("mod1")`, map[string]string{ "mod1": `import("mod2")`, "mod2": `import("mod1")`, - }, "mod2:1:1: cyclic module import") + }, "Compile Error: cyclic module import: mod1\n\tat mod2:1:1") // (main) -> mod1 -> mod2 -> mod3 -> mod1 expectErrorWithUserModules(t, `import("mod1")`, map[string]string{ "mod1": `import("mod2")`, "mod2": `import("mod3")`, "mod3": `import("mod1")`, - }, "mod3:1:1: cyclic module import") + }, "Compile Error: cyclic module import: mod1\n\tat mod3:1:1") // (main) -> mod1 -> mod2 -> mod3 -> mod2 expectErrorWithUserModules(t, `import("mod1")`, map[string]string{ "mod1": `import("mod2")`, "mod2": `import("mod3")`, "mod3": `import("mod2")`, - }, "mod3:1:1: cyclic module import") + }, "Compile Error: cyclic module import: mod2\n\tat mod3:1:1") // unknown modules expectErrorWithUserModules(t, `import("mod0")`, map[string]string{ @@ -198,15 +198,15 @@ export func() { // 'export' must be in the top-level expectErrorWithUserModules(t, `import("mod1")`, map[string]string{ "mod1": `func() { export 5 }()`, - }, "mod1:1:10: export not allowed inside function") + }, "Compile Error: export not allowed inside function\n\tat mod1:1:10") expectErrorWithUserModules(t, `import("mod1")`, map[string]string{ "mod1": `func() { func() { export 5 }() }()`, - }, "mod1:1:19: export not allowed inside function") + }, "Compile Error: export not allowed inside function\n\tat mod1:1:19") // module cannot access outer scope expectErrorWithUserModules(t, `a := 5; import("mod1")`, map[string]string{ "mod1": `export a`, - }, "mod1:1:8: unresolved reference 'a'") + }, "Compile Error: unresolved reference 'a'\n\tat mod1:1:8") // runtime error within modules expectErrorWithUserModules(t, ` @@ -218,8 +218,7 @@ export func(a) { a() } `, - }, `mod1:3:4: not callable: int -in test:4:1`) + }, "Runtime Error: not callable: int\n\tat mod1:3:4\n\tat test:4:1") } func TestModuleBlockScopes(t *testing.T) {