Runtime error trace format (#111)
* Runtime error format * Parser and Compiler error formats updated
This commit is contained in:
parent
f265f1702b
commit
6dd573c3f6
10 changed files with 148 additions and 148 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
221
runtime/vm.go
221
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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue