Skip to content

Commit

Permalink
Merge pull request #333 from MichaelS11/recoverFunc
Browse files Browse the repository at this point in the history
Added recoverFunc & runVMConvertFunction panic VM error
  • Loading branch information
mattn authored Apr 9, 2020
2 parents 716730c + 3996484 commit 3921fdd
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 37 deletions.
2 changes: 1 addition & 1 deletion anko.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/mattn/anko/vm"
)

const version = "0.1.6"
const version = "0.1.7"

var (
flagExecute string
Expand Down
6 changes: 3 additions & 3 deletions vm/packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ func TestImport(t *testing.T) {
envPackages := env.Packages
envPackageTypes := env.PackageTypes

env.Packages = map[string]map[string]reflect.Value{"testPackage": map[string]reflect.Value{"a.b": reflect.ValueOf(1)}}
env.Packages = map[string]map[string]reflect.Value{"testPackage": {"a.b": reflect.ValueOf(1)}}
tests = []Test{
{Script: `a = import("testPackage")`, RunError: fmt.Errorf("import DefineValue error: symbol contains '.'")},
}
runTests(t, tests, nil, &Options{Debug: true})

env.Packages = map[string]map[string]reflect.Value{"testPackage": map[string]reflect.Value{"a": reflect.ValueOf(1)}}
env.PackageTypes = map[string]map[string]reflect.Type{"testPackage": map[string]reflect.Type{"a.b": reflect.TypeOf(1)}}
env.Packages = map[string]map[string]reflect.Value{"testPackage": {"a": reflect.ValueOf(1)}}
env.PackageTypes = map[string]map[string]reflect.Type{"testPackage": {"a.b": reflect.TypeOf(1)}}
tests = []Test{
{Script: `a = import("testPackage")`, RunError: fmt.Errorf("import DefineReflectType error: symbol contains '.'")},
}
Expand Down
30 changes: 18 additions & 12 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ func newStringError(pos ast.Pos, err string) error {
return &Error{Message: err, Pos: pos.Position()}
}

// recoverFunc generic recover function
func recoverFunc(runInfo *runInfoStruct) {
recoverInterface := recover()
if recoverInterface == nil {
return
}
switch value := recoverInterface.(type) {
case *Error:
runInfo.err = value
case error:
runInfo.err = value
default:
runInfo.err = fmt.Errorf("%v", recoverInterface)
}
}

func isNil(v reflect.Value) bool {
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
Expand Down Expand Up @@ -320,12 +336,7 @@ func makeType(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type {
}
if !runInfo.options.Debug {
// captures panic
defer func() {
if recoverResult := recover(); recoverResult != nil {
runInfo.err = fmt.Errorf("%v", recoverResult)
t = nil
}
}()
defer recoverFunc(runInfo)
}
t = reflect.MapOf(key, t)
return t
Expand Down Expand Up @@ -358,12 +369,7 @@ func makeType(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type {
}
if !runInfo.options.Debug {
// captures panic
defer func() {
if recoverResult := recover(); recoverResult != nil {
runInfo.err = fmt.Errorf("%v", recoverResult)
t = nil
}
}()
defer recoverFunc(runInfo)
}
t = reflect.StructOf(fields)
return t
Expand Down
1 change: 1 addition & 0 deletions vm/vmContainers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ func TestSliceAppendSlices(t *testing.T) {

{Script: `a = make([][]bool); a += [true, false];`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{}}},
{Script: `a = make([][]bool); a += [[true, false]]; b = make([]bool); b += [true, false]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{{true, false}}, "b": []bool{true, false}}},
{Script: `a = make([][]bool); a += [[true, false]]; b = [[1.1]]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{[]bool{true, false}}, "b": []interface{}{[]interface{}{1.1}}}},
{Script: `a = make([]bool); a += [true, false]; b = make([][]bool); b += [[true, false]]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true, false}, "b": [][]bool{{true, false}}}},

{Script: `a = make([][]interface); a += [[1, 2]]`, RunOutput: [][]interface{}{{int64(1), int64(2)}}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1), int64(2)}}}},
Expand Down
2 changes: 1 addition & 1 deletion vm/vmConvertToX.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func convertVMFunctionToType(rv reflect.Value, rt reflect.Type) (reflect.Value,
// returns normal VM reflect.Value form
rv, err := processCallReturnValues(rvs, true, false)
if err != nil {
panic("function run error: " + err.Error())
panic(err)
}

if rt.NumOut() < 1 {
Expand Down
7 changes: 1 addition & 6 deletions vm/vmExpr.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package vm

import (
"fmt"
"reflect"

"github.com/mattn/anko/ast"
Expand Down Expand Up @@ -703,11 +702,7 @@ func (runInfo *runInfoStruct) invokeExpr() {
}}
if !runInfo.options.Debug {
// captures panic
defer func() {
if recoverResult := recover(); recoverResult != nil {
runInfo.err = fmt.Errorf("%v", recoverResult)
}
}()
defer recoverFunc(runInfo)
}
chosen, _, _ = reflect.Select(cases)
if chosen == 0 {
Expand Down
9 changes: 3 additions & 6 deletions vm/vmExprFunction.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,11 @@ func (runInfo *runInfoStruct) callExpr() {

if !runInfo.options.Debug {
// captures panic
defer func() {
if recoverResult := recover(); recoverResult != nil {
runInfo.err = fmt.Errorf("%v", recoverResult)
runInfo.rv = nilValue
}
}()
defer recoverFunc(runInfo)
}

runInfo.rv = nilValue

// useCallSlice lets us know to use CallSlice instead of Call because of the format of the args
if useCallSlice {
if callExpr.Go {
Expand Down
2 changes: 1 addition & 1 deletion vm/vmFunctions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ func TestFunctionConversions(t *testing.T) {
{Script: `b = func(){ return 1++ }; c = a(b)`,
Input: map[string]interface{}{"a": func(b func() bool) bool {
return b()
}}, RunError: fmt.Errorf("function run error: invalid operation")},
}}, RunError: fmt.Errorf("invalid operation")},
{Script: `b = func(){ return true }; c = a(b)`,
Input: map[string]interface{}{"a": func(b func() string) string {
return b()
Expand Down
19 changes: 12 additions & 7 deletions vm/vmOperators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func TestBasicOperators(t *testing.T) {
{Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": "b"}, RunOutput: "ab"},
{Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": int64(1)}, RunOutput: "a1"},
{Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": float64(1.1)}, RunOutput: "a1.1"},
{Script: `a + b`, Input: map[string]interface{}{"a": int64(2), "b": "b"}, RunOutput: "2b"},
{Script: `a + b`, Input: map[string]interface{}{"a": float64(2.5), "b": "b"}, RunOutput: "2.5b"},

{Script: `a + z`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil},
{Script: `z + b`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil},

Expand Down Expand Up @@ -432,10 +435,15 @@ func TestTernaryOperator(t *testing.T) {
t.Parallel()

tests := []Test{
{Script: `a = 1 ? 2 : panic(2)`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = c ? a : b`, RunError: fmt.Errorf("undefined symbol 'c'")},
{Script: `a = a ? a : b`, RunError: fmt.Errorf("undefined symbol 'a'")},
{Script: `a = 0; a = a ? a : b`, RunError: fmt.Errorf("undefined symbol 'b'")},
{Script: `a = a ? 1 : 2`, RunError: fmt.Errorf("undefined symbol 'a'")},
{Script: `a = z ? 1 : 2`, RunError: fmt.Errorf("undefined symbol 'z'")},
{Script: `a = 0; a = a ? 1 : z`, RunError: fmt.Errorf("undefined symbol 'z'")},
{Script: `a = 1; a = a ? z : 1`, RunError: fmt.Errorf("undefined symbol 'z'")},
{Script: `a = b[1] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")},
{Script: `a = b[1][2] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")},
{Script: `a = b["test"][1] ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": 2}}, RunError: fmt.Errorf("type int does not support index operation")},

{Script: `a = 1 ? 2 : z`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = -1 ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = true ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = false ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}},
Expand All @@ -455,13 +463,10 @@ func TestTernaryOperator(t *testing.T) {
{Script: `a = nil ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}},
{Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}},
{Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}},
{Script: `a = b[1] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")},
{Script: `a = b[1][2] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")},
{Script: `a = [] ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}},
{Script: `a = [2] ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": int64(2)}}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = b["test"] ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": int64(2)}}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `a = b["test"][1] ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": 2}}, RunError: fmt.Errorf("type int does not support index operation")},
{Script: `b = "test"; a = b ? 2 : "empty"`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `b = "test"; a = b[1:3] ? 2 : "empty"`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}},
{Script: `b = "test"; a = b[2:2] ? 2 : "empty"`, RunOutput: "empty", Output: map[string]interface{}{"a": "empty"}},
Expand Down

0 comments on commit 3921fdd

Please sign in to comment.