diff --git a/runtime.go b/runtime.go index e9a500da..c240ddea 100644 --- a/runtime.go +++ b/runtime.go @@ -2206,9 +2206,24 @@ func (r *Runtime) toReflectValue(v Value, dst reflect.Value, ctx *objectExportCt func (r *Runtime) wrapJSFunc(fn Callable, typ reflect.Type) func(args []reflect.Value) (results []reflect.Value) { return func(args []reflect.Value) (results []reflect.Value) { - jsArgs := make([]Value, len(args)) - for i, arg := range args { - jsArgs[i] = r.ToValue(arg.Interface()) + var jsArgs []Value + if len(args) > 0 { + if typ.IsVariadic() { + varArg := args[len(args)-1] + args = args[:len(args)-1] + jsArgs = make([]Value, 0, len(args)+varArg.Len()) + for _, arg := range args { + jsArgs = append(jsArgs, r.ToValue(arg.Interface())) + } + for i := 0; i < varArg.Len(); i++ { + jsArgs = append(jsArgs, r.ToValue(varArg.Index(i).Interface())) + } + } else { + jsArgs = make([]Value, len(args)) + for i, arg := range args { + jsArgs[i] = r.ToValue(arg.Interface()) + } + } } numOut := typ.NumOut() diff --git a/runtime_test.go b/runtime_test.go index a834428d..708ce7f0 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -941,8 +941,8 @@ func ExampleRuntime_ExportTo_funcThrow() { func ExampleRuntime_ExportTo_funcVariadic() { const SCRIPT = ` - function f() { - return Array.prototype.join.call(arguments, ","); + function f(...args) { + return args.join("#"); } ` vm := New() @@ -957,7 +957,57 @@ func ExampleRuntime_ExportTo_funcVariadic() { panic(err) } fmt.Println(fn("a", "b", 42)) - // Output: a,b,42 + // Output: a#b#42 +} + +func TestRuntime_ExportTo_funcVariadic(t *testing.T) { + const SCRIPT = ` + function f(...args) { + return args.join("#"); + } + ` + vm := New() + _, err := vm.RunString(SCRIPT) + if err != nil { + panic(err) + } + + t.Run("no args", func(t *testing.T) { + var fn func(args ...any) string + err = vm.ExportTo(vm.Get("f"), &fn) + if err != nil { + panic(err) + } + res := fn() + if res != "" { + t.Fatal(res) + } + }) + + t.Run("non-variadic args", func(t *testing.T) { + var fn func(firstArg any, args ...any) string + err = vm.ExportTo(vm.Get("f"), &fn) + if err != nil { + panic(err) + } + res := fn("first") + if res != "first" { + t.Fatal(res) + } + }) + + t.Run("non-variadic and variadic args", func(t *testing.T) { + var fn func(firstArg any, args ...any) string + err = vm.ExportTo(vm.Get("f"), &fn) + if err != nil { + panic(err) + } + res := fn("first", "second") + if res != "first#second" { + t.Fatal(res) + } + }) + } func TestRuntime_ExportToFuncFail(t *testing.T) {