Runtime error trace format (#111)

* Runtime error format

* Parser and Compiler error formats updated
This commit is contained in:
earncef 2019-02-22 22:39:07 +01:00 committed by Daniel
parent f265f1702b
commit 6dd573c3f6
10 changed files with 148 additions and 148 deletions

View file

@ -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
}

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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())
}

View file

@ -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())
}

View file

@ -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
}

View file

@ -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")
}

View file

@ -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")
}

View file

@ -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) {