From 06e99480d22cd2c4361b2d7edbd67f2030b28ecb Mon Sep 17 00:00:00 2001 From: Dmitry Panov Date: Wed, 13 Jan 2021 18:35:57 +0000 Subject: [PATCH] Added support for native functions with *Runtime as a parameter. See #243 --- runtime.go | 14 ++++++++++++++ runtime_test.go | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/runtime.go b/runtime.go index c666cde6..01110382 100644 --- a/runtime.go +++ b/runtime.go @@ -1297,6 +1297,8 @@ func(FunctionCall) Value is treated as a native JavaScript function. This increa automatic argument and return value type conversions (which involves reflect). Attempting to use the function as a constructor will result in a TypeError. +func(FunctionCall, *Runtime) Value is treated as above, except the *Runtime is also passed as a parameter. + func(ConstructorCall) *Object is treated as a native constructor, allowing to use it with the new operator: @@ -1327,6 +1329,8 @@ When a native constructor is called directly (without the new operator) its beha this value: if it's an Object, it is passed through, otherwise a new one is created exactly as if it was called with the new operator. In either case call.NewTarget will be nil. +func(ConstructorCall, *Runtime) *Object is treated as above, except the *Runtime is also passed as a parameter. + Any other Go function is wrapped so that the arguments are automatically converted into the required Go types and the return value is converted to a JavaScript value (using this method). If conversion is not possible, a TypeError is thrown. @@ -1449,9 +1453,19 @@ func (r *Runtime) ToValue(i interface{}) Value { case func(FunctionCall) Value: name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) return r.newNativeFunc(i, nil, name, nil, 0) + case func(FunctionCall, *Runtime) Value: + name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) + return r.newNativeFunc(func(call FunctionCall) Value { + return i(call, r) + }, nil, name, nil, 0) case func(ConstructorCall) *Object: name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) return r.newNativeConstructor(i, name, 0) + case func(ConstructorCall, *Runtime) *Object: + name := unistring.NewFromString(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()) + return r.newNativeConstructor(func(call ConstructorCall) *Object { + return i(call, r) + }, name, 0) case int: return intToValue(int64(i)) case int8: diff --git a/runtime_test.go b/runtime_test.go index 611115ca..40fa29fa 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -1848,6 +1848,23 @@ func TestRuntime_SetParserOptions_Eval(t *testing.T) { } } +func TestNativeCallWithRuntimeParameter(t *testing.T) { + vm := New() + vm.Set("f", func(_ FunctionCall, r *Runtime) Value { + if r == vm { + return valueTrue + } + return valueFalse + }) + ret, err := vm.RunString(`f()`) + if err != nil { + t.Fatal(err) + } + if ret != valueTrue { + t.Fatal(ret) + } +} + /* func TestArrayConcatSparse(t *testing.T) { function foo(a,b,c)