Browse Source

Merge pull request #97 from postromantic/feature/params

Adding params argument support
Sébastien Ros 10 years ago
parent
commit
3aba2912a7

+ 10 - 0
Jint.Tests/Runtime/Domain/A.cs

@@ -75,5 +75,15 @@ namespace Jint.Tests.Runtime.Domain
         {
             return map(value);
         }
+
+        public string Call13(params object[] values)
+        {
+            return String.Join(",", values);
+        }
+
+        public string Call14(string firstParam, params object[] values)
+        {
+            return String.Format("{0}:{1}", firstParam, String.Join(",", values));
+        }
     }
 }

+ 21 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -1031,5 +1031,26 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void ShouldCallInstanceMethodWithParams()
+        {
+            _engine.SetValue("a", new A());
+
+            RunTest(@"
+                assert(a.Call13('1','2','3') === '1,2,3');
+                assert(a.Call13('1') === '1');
+                assert(a.Call13() === '');
+
+                assert(a.Call14('a','1','2','3') === 'a:1,2,3');
+                assert(a.Call14('a','1') === 'a:1');
+                assert(a.Call14('a') === 'a:');
+
+                function call13wrapper(){ return a.Call13.apply(a, Array.prototype.slice.call(arguments)); }
+                assert(call13wrapper('1','2','3') === '1,2,3');
+
+                assert(a.Call13('1','2','3') === a.Call13(['1','2','3']));
+            ");
+        }
+
     }
 }

+ 32 - 2
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -1,7 +1,10 @@
-using System.Globalization;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Reflection;
 using Jint.Native;
+using Jint.Native.Array;
 using Jint.Native.Function;
 
 namespace Jint.Runtime.Interop
@@ -22,8 +25,9 @@ namespace Jint.Runtime.Interop
             return Invoke(_methods, thisObject, arguments);
         }
 
-        public JsValue Invoke(MethodInfo[] methodInfos, JsValue thisObject, JsValue[] arguments)
+        public JsValue Invoke(MethodInfo[] methodInfos, JsValue thisObject, JsValue[] jsArguments)
         {
+            var arguments = ProcessParamsArrays(jsArguments, methodInfos);
             var methods = TypeConverter.FindBestMatch(Engine, methodInfos, arguments).ToList();
             var converter = Engine.ClrTypeConverter;
 
@@ -67,5 +71,31 @@ namespace Jint.Runtime.Interop
             throw new JavaScriptException(Engine.TypeError, "No public methods with the specified arguments were found.");
         }
 
+        private JsValue[] ProcessParamsArrays(JsValue[] jsArguments, IEnumerable<MethodInfo> methodInfos)
+        {
+            foreach (var methodInfo in methodInfos)
+            {
+                var parameters = methodInfo.GetParameters();
+                if (!parameters.Any(p => Attribute.IsDefined(p, typeof(ParamArrayAttribute))))
+                    continue;
+
+                var nonParamsArgumentsCount = parameters.Length - 1;
+                if (jsArguments.Length < nonParamsArgumentsCount)
+                    continue;
+
+                var newArgumentsCollection = jsArguments.Take(nonParamsArgumentsCount).ToList();
+                var argsToTransform = jsArguments.Skip(nonParamsArgumentsCount).ToList();
+
+                if (argsToTransform.Count == 1 && argsToTransform.FirstOrDefault().IsArray())
+                    continue;
+
+                var arrayInstance = ArrayConstructor.CreateArrayConstructor(Engine).Construct(argsToTransform.ToArray());
+                newArgumentsCollection.Add(new JsValue(arrayInstance));
+                return newArgumentsCollection.ToArray();
+            }
+
+            return jsArguments;
+        }
+
     }
 }