瀏覽代碼

Added support for variadic Go functions in ExportTo(). Closes #582

Dmitry Panov 1 年之前
父節點
當前提交
6639a88c21
共有 2 個文件被更改,包括 71 次插入6 次删除
  1. 18 3
      runtime.go
  2. 53 3
      runtime_test.go

+ 18 - 3
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()

+ 53 - 3
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) {