Browse Source

Merge remote-tracking branch 'upstream/master'

Brian Beard 11 years ago
parent
commit
19712c9887

+ 2 - 0
Jint.Tests/Jint.Tests.csproj

@@ -59,6 +59,8 @@
     <Compile Include="Runtime\Domain\ClassWithField.cs" />
     <Compile Include="Runtime\Domain\ClassWithField.cs" />
     <Compile Include="Runtime\Domain\ClassWithStaticFields.cs" />
     <Compile Include="Runtime\Domain\ClassWithStaticFields.cs" />
     <Compile Include="Runtime\Domain\Colors.cs" />
     <Compile Include="Runtime\Domain\Colors.cs" />
+    <Compile Include="Runtime\Domain\Company.cs" />
+    <Compile Include="Runtime\Domain\ICompany.cs" />
     <Compile Include="Runtime\Domain\IPerson.cs" />
     <Compile Include="Runtime\Domain\IPerson.cs" />
     <Compile Include="Runtime\Domain\Person.cs" />
     <Compile Include="Runtime\Domain\Person.cs" />
     <Compile Include="Runtime\Domain\Shape.cs" />
     <Compile Include="Runtime\Domain\Shape.cs" />

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

@@ -45,5 +45,29 @@ namespace Jint.Tests.Runtime.Domain
 
 
             return callback(thisArg, arguments).ToString();
             return callback(thisArg, arguments).ToString();
         }
         }
+
+        public bool Call7(string str, Func<string, bool> predicate)
+        {
+            return predicate(str);
+        }
+
+        public string Call8(Func<string> predicate)
+        {
+            return predicate();
+        }
+
+        public void Call9(Action predicate)
+        {
+            predicate();
+        }
+        public void Call10(string str, Action<string> predicate)
+        {
+            predicate(str);
+        }
+        public void Call11(string str, string str2, Action<string, string> predicate)
+        {
+            predicate(str, str2);
+        }
+
     }
     }
 }
 }

+ 36 - 0
Jint.Tests/Runtime/Domain/Company.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    public class Company : ICompany, IComparable<ICompany>
+    {
+        private string _name;
+        private readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>();
+
+        public Company(string name)
+        {
+            _name = name;
+        }
+
+        string ICompany.Name
+        {
+            get { return _name; }
+            set { _name = value; }
+        }
+
+        string ICompany.this[string key]
+        {
+            get { return _dictionary[key]; }
+            set { _dictionary[key] = value; }
+        }
+
+        int IComparable<ICompany>.CompareTo(ICompany other)
+        {
+            return string.Compare(_name, other.Name, StringComparison.CurrentCulture);
+        }
+    }
+}

+ 8 - 0
Jint.Tests/Runtime/Domain/ICompany.cs

@@ -0,0 +1,8 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public interface ICompany
+    {
+        string Name { get; set; }
+        string this[string key] { get; set; }
+    }
+}

+ 38 - 37
Jint.Tests/Runtime/EngineTests.cs

@@ -594,9 +594,9 @@ namespace Jint.Tests.Runtime
         [Fact]
         [Fact]
         public void ShouldNotExecuteDebuggerStatement()
         public void ShouldNotExecuteDebuggerStatement()
         {
         {
-            new Engine().Execute("debugger"); 
+            new Engine().Execute("debugger");
         }
         }
-       
+
         [Fact]
         [Fact]
         public void ShouldThrowStatementCountOverflow()
         public void ShouldThrowStatementCountOverflow()
         {
         {
@@ -609,7 +609,7 @@ namespace Jint.Tests.Runtime
         public void ShouldThrowTimeout()
         public void ShouldThrowTimeout()
         {
         {
             Assert.Throws<TimeoutException>(
             Assert.Throws<TimeoutException>(
-                () => new Engine(cfg => cfg.TimeoutInterval(new TimeSpan(0,0,0,0,500))).Execute("while(true);")
+                () => new Engine(cfg => cfg.TimeoutInterval(new TimeSpan(0, 0, 0, 0, 500))).Execute("while(true);")
             );
             );
         }
         }
 
 
@@ -658,7 +658,7 @@ namespace Jint.Tests.Runtime
                 assert(regex.test('a/b') === true);
                 assert(regex.test('a/b') === true);
                 assert(regex.test('a\\/b') === false);
                 assert(regex.test('a\\/b') === false);
             ");
             ");
-      }
+        }
 
 
         [Fact]
         [Fact]
         public void ShouldComputeFractionInBase()
         public void ShouldComputeFractionInBase()
@@ -708,45 +708,37 @@ namespace Jint.Tests.Runtime
         [Fact]
         [Fact]
         public void JsonParserShouldParseNegativeNumber()
         public void JsonParserShouldParseNegativeNumber()
         {
         {
-            var engine = new Engine();
-            var result = engine.Execute(@"JSON.parse('{ ""x"":-1 }').x === -1").GetCompletionValue().AsBoolean();
-            Assert.Equal(true, result);
+            RunTest(@"
+                var a = JSON.parse('{ ""x"":-1 }');
+                assert(a.x === -1);
 
 
-            result = engine.Execute(@"JSON.parse('{ ""x"": -1 }').x === -1").GetCompletionValue().AsBoolean();
-            Assert.Equal(true, result);
+                var b = JSON.parse('{ ""x"": -1 }');
+                assert(b.x === -1);
+            ");
         }
         }
 
 
         [Fact]
         [Fact]
         public void JsonParserShouldDetectInvalidNegativeNumberSyntax()
         public void JsonParserShouldDetectInvalidNegativeNumberSyntax()
         {
         {
-            var engine = new Engine();            
-            var code = @"
-                function f() {
-                    try {
-                        JSON.parse('{ ""x"": -.1 }'); // Not allowed
-                        return false;
-                    }
-                    catch(ex) {
-                        return ex.toString().indexOf('Unexpected token') !== -1;
-                    }
+            RunTest(@"
+                try {
+                    JSON.parse('{ ""x"": -.1 }'); // Not allowed
+                    assert(false);
+                }
+                catch(ex) {
+                    assert(ex instanceof SyntaxError);
                 }
                 }
-                f();
-            ";
-            Assert.True(engine.Execute(code).GetCompletionValue().AsBoolean());
+            ");
 
 
-            code = @"
-                function f() {
-                    try {
-                        JSON.parse('{ ""x"": - 1 }'); // Not allowed
-                        return false;
-                    }
-                    catch(ex) {
-                        return ex.toString().indexOf('Unexpected token') !== -1;
-                    }
+            RunTest(@"
+                try {
+                    JSON.parse('{ ""x"": - 1 }'); // Not allowed
+                    assert(false);
+                }
+                catch(ex) {
+                    assert(ex instanceof SyntaxError);
                 }
                 }
-                f();
-            ";
-            Assert.True(engine.Execute(code).GetCompletionValue().AsBoolean());
+            ");
         }
         }
 
 
         [Fact]
         [Fact]
@@ -756,7 +748,7 @@ namespace Jint.Tests.Runtime
             Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
             Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
 
 
             var engine = new Engine();
             var engine = new Engine();
-            
+
             var result = engine.Execute("1.2 + 2.1").GetCompletionValue().AsNumber();
             var result = engine.Execute("1.2 + 2.1").GetCompletionValue().AsNumber();
             Assert.Equal(3.3d, result);
             Assert.Equal(3.3d, result);
 
 
@@ -804,7 +796,7 @@ namespace Jint.Tests.Runtime
         {
         {
             const string customName = "Custom Time";
             const string customName = "Custom Time";
             var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
             var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
-            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone)); 
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
 
 
             var result = engine.Execute("Date.UTC(1970,0,1)").GetCompletionValue().AsNumber();
             var result = engine.Execute("Date.UTC(1970,0,1)").GetCompletionValue().AsNumber();
             Assert.Equal(0, result);
             Assert.Equal(0, result);
@@ -905,7 +897,7 @@ namespace Jint.Tests.Runtime
         {
         {
             var url = "http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js";
             var url = "http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js";
             var content = new WebClient().DownloadString(url);
             var content = new WebClient().DownloadString(url);
-            
+
             RunTest(content);
             RunTest(content);
 
 
             RunTest(@"
             RunTest(@"
@@ -917,5 +909,14 @@ namespace Jint.Tests.Runtime
                 assert('Hello Paul' == html);
                 assert('Hello Paul' == html);
             ");
             ");
         }
         }
+
+        [Fact]
+        public void DateParseReturnsNaN()
+        {
+            RunTest(@"
+                var d = Date.parse('not a date');
+                assert(isNaN(d));
+            ");
+        }
     }
     }
 }
 }

+ 139 - 1
Jint.Tests/Runtime/InteropTests.cs

@@ -560,6 +560,86 @@ namespace Jint.Tests.Runtime
             ");
             ");
         }
         }
 
 
+        [Fact]
+        public void ShouldExecuteFunctionCallBackAsPredicate()
+        {
+            _engine.SetValue("a", new A());
+            
+            // Func<>
+            RunTest(@"
+                assert(a.Call8(function(){ return 'foo'; }) === 'foo');
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteFunctionWithParameterCallBackAsPredicate()
+        {
+            _engine.SetValue("a", new A());
+
+            // Func<,>
+            RunTest(@"
+                assert(a.Call7('foo', function(a){ return a === 'foo'; }) === true);
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteActionCallBackAsPredicate()
+        {
+            _engine.SetValue("a", new A());
+
+            // Action
+            RunTest(@"
+                var value;
+                a.Call9(function(){ value = 'foo'; });
+                assert(value === 'foo');
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteActionWithParameterCallBackAsPredicate()
+        {
+            _engine.SetValue("a", new A());
+
+            // Action<>
+            RunTest(@"
+                var value;
+                a.Call10('foo', function(b){ value = b; });
+                assert(value === 'foo');
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteActionWithMultipleParametersCallBackAsPredicate()
+        {
+            _engine.SetValue("a", new A());
+
+            // Action<,>
+            RunTest(@"
+                var value;
+                a.Call11('foo', 'bar', function(a,b){ value = a + b; });
+                assert(value === 'foobar');
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteActionCallbackOnEventChanged()
+        {
+            var collection = new System.Collections.ObjectModel.ObservableCollection<string>();
+            Assert.True(collection.Count == 0);
+
+            _engine.SetValue("collection", collection);
+
+            RunTest(@"
+                var eventAction;
+                collection.add_CollectionChanged(function(sender, eventArgs) { eventAction = eventArgs.Action; } );
+                collection.Add('test');
+            ");
+
+            var eventAction = _engine.GetValue("eventAction").AsNumber();
+            Assert.True(eventAction == 0);
+            Assert.True(collection.Count == 1);
+        }
+
         [Fact]
         [Fact]
         public void ShouldUseSystemIO()
         public void ShouldUseSystemIO()
         {
         {
@@ -859,7 +939,65 @@ namespace Jint.Tests.Runtime
             ");
             ");
 
 
             Assert.Equal(Colors.Blue | Colors.Green, s.Color);
             Assert.Equal(Colors.Blue | Colors.Green, s.Color);
-        }
+        }
+
+        [Fact]
+        public void ShouldUseExplicitPropertyGetter()
+        {
+            _engine.SetValue("c", new Company("ACME"));
+
+            RunTest(@"
+                assert(c.Name === 'ACME');
+            ");
+        }
+
+        [Fact]
+        public void ShouldUseExplicitIndexerPropertyGetter()
+        {
+            var company = new Company("ACME");
+            ((ICompany)company)["Foo"] = "Bar";
+            _engine.SetValue("c", company);
+
+            RunTest(@"
+                assert(c.Foo === 'Bar');
+            ");
+        }
+
+
+        [Fact]
+        public void ShouldUseExplicitPropertySetter()
+        {
+            _engine.SetValue("c", new Company("ACME"));
+
+            RunTest(@"
+                c.Name = 'Foo';
+                assert(c.Name === 'Foo');
+            ");
+        }
+
+        [Fact]
+        public void ShouldUseExplicitIndexerPropertySetter()
+        {
+            var company = new Company("ACME");
+            ((ICompany)company)["Foo"] = "Bar";
+            _engine.SetValue("c", company);
+
+            RunTest(@"
+                c.Foo = 'Baz';
+                assert(c.Foo === 'Baz');
+            ");
+        }
+
+
+        [Fact]
+        public void ShouldUseExplicitMethod()
+        {
+            _engine.SetValue("c", new Company("ACME"));
+
+            RunTest(@"
+                assert(0 === c.CompareTo(c));
+            ");
+        }
 
 
     }
     }
 }
 }

+ 4 - 0
Jint/Engine.cs

@@ -34,6 +34,8 @@ namespace Jint
         private int _statementsCount;
         private int _statementsCount;
         private long _timeoutTicks;
         private long _timeoutTicks;
         private SyntaxNode _lastSyntaxNode = null;
         private SyntaxNode _lastSyntaxNode = null;
+        
+        public ITypeConverter ClrTypeConverter;
 
 
         // cache of types used when resolving CLR type names
         // cache of types used when resolving CLR type names
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(); 
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(); 
@@ -130,6 +132,8 @@ namespace Jint
                     return new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)));
                     return new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)));
                 }), false, false, false);
                 }), false, false, false);
             }
             }
+
+            ClrTypeConverter = new DefaultTypeConverter(this);
         }
         }
 
 
         public LexicalEnvironment GlobalEnvironment;
         public LexicalEnvironment GlobalEnvironment;

+ 2 - 1
Jint/Native/Date/DateConstructor.cs

@@ -81,7 +81,8 @@ namespace Jint.Native.Date
                 {
                 {
                     if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal,out result))
                     if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal,out result))
                     {
                     {
-                        throw new JavaScriptException(Engine.SyntaxError, "Invalid date");
+                        // unrecognized dates should return NaN (15.9.4.2)
+                        return double.NaN;
                     }
                     }
                 }
                 }
             }
             }

+ 0 - 15
Jint/Options.cs

@@ -14,7 +14,6 @@ namespace Jint
         private bool _strict;
         private bool _strict;
         private bool _allowDebuggerStatement;
         private bool _allowDebuggerStatement;
         private bool _allowClr;
         private bool _allowClr;
-        private ITypeConverter _typeConverter = new DefaultTypeConverter();
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private int _maxStatements;
         private int _maxStatements;
         private TimeSpan _timeoutInterval;
         private TimeSpan _timeoutInterval;
@@ -54,15 +53,6 @@ namespace Jint
             return this;
             return this;
         }
         }
 
 
-        /// <summary>
-        /// Sets a <see cref="ITypeConverter"/> instance to use when converting CLR types
-        /// </summary>
-        public Options SetTypeConverter(ITypeConverter typeConverter)
-        {
-            _typeConverter = typeConverter;
-            return this;
-        }
-
         /// <summary>
         /// <summary>
          /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
          /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
         /// </summary>
         /// </summary>
@@ -132,11 +122,6 @@ namespace Jint
             return _lookupAssemblies;
             return _lookupAssemblies;
         }
         }
 
 
-        internal ITypeConverter GetTypeConverter()
-        {
-            return _typeConverter;
-        }
-
         internal IEnumerable<IObjectConverter> GetObjectConverters()
         internal IEnumerable<IObjectConverter> GetObjectConverters()
         {
         {
             return _objectConverters;
             return _objectConverters;

+ 1 - 1
Jint/Runtime/Descriptors/Specialized/FieldInfoDescriptor.cs

@@ -40,7 +40,7 @@ namespace Jint.Runtime.Descriptors.Specialized
                     obj = currentValue.ToObject();
                     obj = currentValue.ToObject();
                     if (obj.GetType() != _fieldInfo.FieldType)
                     if (obj.GetType() != _fieldInfo.FieldType)
                     {
                     {
-                        obj = _engine.Options.GetTypeConverter().Convert(obj, _fieldInfo.FieldType, CultureInfo.InvariantCulture);
+                        obj = _engine.ClrTypeConverter.Convert(obj, _fieldInfo.FieldType, CultureInfo.InvariantCulture);
                     }
                     }
                 }
                 }
                 
                 

+ 13 - 5
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -1,4 +1,5 @@
-using System.Globalization;
+using System;
+using System.Globalization;
 using System.Reflection;
 using System.Reflection;
 using Jint.Native;
 using Jint.Native;
 
 
@@ -12,19 +13,26 @@ namespace Jint.Runtime.Descriptors.Specialized
         private readonly MethodInfo _getter;
         private readonly MethodInfo _getter;
         private readonly MethodInfo _setter;
         private readonly MethodInfo _setter;
 
 
-        public IndexDescriptor(Engine engine, string key, object item)
+        public IndexDescriptor(Engine engine, Type targetType, string key, object item)
         {
         {
             _engine = engine;
             _engine = engine;
             _item = item;
             _item = item;
 
 
-            _getter = item.GetType().GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public);
-            _setter = item.GetType().GetMethod("set_Item", BindingFlags.Instance | BindingFlags.Public);
+            _getter = targetType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public);
+            _setter = targetType.GetMethod("set_Item", BindingFlags.Instance | BindingFlags.Public);
 
 
-            _key = _engine.Options.GetTypeConverter().Convert(key, _getter.GetParameters()[0].ParameterType, CultureInfo.InvariantCulture);
+            _key = _engine.ClrTypeConverter.Convert(key, _getter.GetParameters()[0].ParameterType, CultureInfo.InvariantCulture);
 
 
             Writable = true;
             Writable = true;
         }
         }
 
 
+
+        public IndexDescriptor(Engine engine, string key, object item)
+            : this(engine, item.GetType(), key, item)
+        {
+            
+        }
+
         public override JsValue? Value
         public override JsValue? Value
         {
         {
             get
             get

+ 1 - 1
Jint/Runtime/Descriptors/Specialized/PropertyInfoDescriptor.cs

@@ -40,7 +40,7 @@ namespace Jint.Runtime.Descriptors.Specialized
                     obj = currentValue.ToObject();
                     obj = currentValue.ToObject();
                     if (obj.GetType() != _propertyInfo.PropertyType)
                     if (obj.GetType() != _propertyInfo.PropertyType)
                     {
                     {
-                        obj = _engine.Options.GetTypeConverter().Convert(obj, _propertyInfo.PropertyType, CultureInfo.InvariantCulture);
+                        obj = _engine.ClrTypeConverter.Convert(obj, _propertyInfo.PropertyType, CultureInfo.InvariantCulture);
                     }
                     }
                 }
                 }
                 
                 

+ 101 - 0
Jint/Runtime/Interop/DefaultTypeConverter.cs

@@ -1,9 +1,20 @@
 using System;
 using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Linq.Expressions;
+using Jint.Native;
 
 
 namespace Jint.Runtime.Interop
 namespace Jint.Runtime.Interop
 {
 {
     public class DefaultTypeConverter : ITypeConverter
     public class DefaultTypeConverter : ITypeConverter
     {
     {
+        private readonly Engine _engine;
+
+        public DefaultTypeConverter(Engine engine)
+        {
+            _engine = engine;
+        }
+
         public object Convert(object value, Type type, IFormatProvider formatProvider)
         public object Convert(object value, Type type, IFormatProvider formatProvider)
         {
         {
             // don't try to convert if value is derived from type
             // don't try to convert if value is derived from type
@@ -23,6 +34,96 @@ namespace Jint.Runtime.Interop
                 return Enum.ToObject(type, integer);
                 return Enum.ToObject(type, integer);
             }
             }
 
 
+            var valueType = value.GetType();
+            // is the javascript value an ICallable instance ?
+            if (valueType == typeof (Func<JsValue, JsValue[], JsValue>))
+            {
+                var function = (Func<JsValue, JsValue[], JsValue>) value;
+
+                if (type.IsGenericType)
+                {
+                    var genericType = type.GetGenericTypeDefinition();
+
+                    // create the requested Delegate
+                    if (genericType.Name.StartsWith("Action"))
+                    {
+                        var genericArguments = type.GetGenericArguments();
+
+                        var @params = new ParameterExpression[genericArguments.Count()];
+                        for (var i = 0; i < @params.Count(); i++)
+                        {
+                            @params[i] = Expression.Parameter(genericArguments[i], genericArguments[i].Name + i);
+                        }
+                        var @vars = Expression.NewArrayInit(typeof(JsValue), @params.Select(p => Expression.Call(null, typeof(JsValue).GetMethod("FromObject"), Expression.Constant(_engine, typeof(Engine)), p)));
+
+                        var callExpresion = Expression.Block(Expression.Call(
+                                                Expression.Call(Expression.Constant(function.Target),
+                                                    function.Method,
+                                                    Expression.Constant(JsValue.Undefined, typeof(JsValue)),
+                                                    @vars),
+                                                typeof(JsValue).GetMethod("ToObject")), Expression.Empty());
+
+                        return Expression.Lambda(callExpresion, new ReadOnlyCollection<ParameterExpression>(@params));
+                    }
+                    else if (genericType.Name.StartsWith("Func"))
+                    {
+                        var genericArguments = type.GetGenericArguments();
+                        var returnType = genericArguments.Last();
+                        
+                        var @params = new ParameterExpression[genericArguments.Count() - 1];
+                        for (var i = 0; i < @params.Count(); i++)
+                        {
+                            @params[i] = Expression.Parameter(genericArguments[i], genericArguments[i].Name + i);
+                        }
+                        var @vars = Expression.NewArrayInit(typeof(JsValue), @params.Select(p => Expression.Call(null, typeof(JsValue).GetMethod("FromObject"), Expression.Constant(_engine, typeof(Engine)), p)));
+
+                        var callExpresion = Expression.Convert(
+                                                Expression.Call(
+                                                    Expression.Call(Expression.Constant(function.Target),
+                                                            function.Method,
+                                                            Expression.Constant(JsValue.Undefined, typeof(JsValue)),
+                                                            @vars),
+                                                    typeof(JsValue).GetMethod("ToObject")),
+                                                returnType);
+
+                        return Expression.Lambda(callExpresion, new ReadOnlyCollection<ParameterExpression>(@params));
+                    }
+                }
+                else
+                {
+                    if (type == typeof (Action))
+                    {
+                        return (Action)(() => function(JsValue.Undefined, new JsValue[0]));
+                    }
+                    else if (type.IsSubclassOf(typeof(System.MulticastDelegate)))
+                    {
+                        var method = type.GetMethod("Invoke");
+                        var arguments = method.GetParameters();
+
+                        var @params = new ParameterExpression[arguments.Count()];
+                        for (var i = 0; i < @params.Count(); i++)
+                        {
+                            @params[i] = Expression.Parameter(typeof(object), arguments[i].Name);
+                        }
+                        var @vars = Expression.NewArrayInit(typeof(JsValue), @params.Select(p => Expression.Call(null, typeof(JsValue).GetMethod("FromObject"), Expression.Constant(_engine, typeof(Engine)), p)));
+
+                        var callExpression = Expression.Block(
+                                                Expression.Call(
+                                                    Expression.Call(Expression.Constant(function.Target),
+                                                        function.Method,
+                                                        Expression.Constant(JsValue.Undefined, typeof(JsValue)),
+                                                        @vars),
+                                                    typeof(JsValue).GetMethod("ToObject")),
+                                                Expression.Empty());
+
+                        var dynamicExpression = Expression.Invoke(Expression.Lambda(callExpression, new ReadOnlyCollection<ParameterExpression>(@params)), new ReadOnlyCollection<ParameterExpression>(@params));
+
+                        return Expression.Lambda(type, dynamicExpression, new ReadOnlyCollection<ParameterExpression>(@params));
+                    }
+                }
+
+            }
+
             return System.Convert.ChangeType(value, type, formatProvider);
             return System.Convert.ChangeType(value, type, formatProvider);
         }
         }
     }
     }

+ 1 - 1
Jint/Runtime/Interop/DelegateWrapper.cs

@@ -35,7 +35,7 @@ namespace Jint.Runtime.Interop
                 }
                 }
                 else
                 else
                 {
                 {
-                    parameters[i] = Engine.Options.GetTypeConverter().Convert(
+                    parameters[i] = Engine.ClrTypeConverter.Convert(
                         arguments[i].ToObject(),
                         arguments[i].ToObject(),
                         parameterType,
                         parameterType,
                         CultureInfo.InvariantCulture);
                         CultureInfo.InvariantCulture);

+ 6 - 1
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -41,10 +41,15 @@ namespace Jint.Runtime.Interop
                         }
                         }
                         else
                         else
                         {
                         {
-                            parameters[i] = Engine.Options.GetTypeConverter().Convert(
+                            parameters[i] = Engine.ClrTypeConverter.Convert(
                                 arguments[i].ToObject(),
                                 arguments[i].ToObject(),
                                 parameterType,
                                 parameterType,
                                 CultureInfo.InvariantCulture);
                                 CultureInfo.InvariantCulture);
+
+                            if (typeof(System.Linq.Expressions.LambdaExpression).IsAssignableFrom(parameters[i].GetType()))
+                            {
+                                parameters[i] = (parameters[i] as System.Linq.Expressions.LambdaExpression).Compile();
+                            }
                         }
                         }
                     }
                     }
 
 

+ 38 - 0
Jint/Runtime/Interop/ObjectWrapper .cs

@@ -95,6 +95,44 @@ namespace Jint.Runtime.Interop
             {
             {
                 return new IndexDescriptor(Engine, propertyName, Target);
                 return new IndexDescriptor(Engine, propertyName, Target);
             }
             }
+
+            var interfaces = type.GetInterfaces();
+
+            // try to find a single explicit property implementation
+            var explicitProperties = (from iface in interfaces
+                                      from iprop in iface.GetProperties()
+                                      where propertyName.Equals(iprop.Name)
+                                      select iprop).ToList();
+
+            if (explicitProperties.Count == 1)
+            {
+                var descriptor = new PropertyInfoDescriptor(Engine, explicitProperties[0], Target);
+                Properties.Add(propertyName, descriptor);
+                return descriptor;
+            }
+
+            // try to find explicit method implementations
+            var explicitMethods = (from iface in interfaces
+                                   from imethod in iface.GetMethods()
+                                   where propertyName.Equals(imethod.Name)
+                                   select imethod).ToList();
+
+            if (explicitMethods.Count > 0)
+            {
+                return new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods.ToArray()), false, true, false);
+            }
+
+            // try to find explicit indexer implementations
+            var explicitIndexers =
+                (from iface in interfaces
+                 from iprop in iface.GetProperties()
+                 where iprop.GetIndexParameters().Length != 0
+                 select iprop).ToList();
+
+            if (explicitIndexers.Count == 1)
+            {
+                return new IndexDescriptor(Engine, explicitIndexers[0].DeclaringType, propertyName, Target);
+            }
 
 
             return PropertyDescriptor.Undefined;
             return PropertyDescriptor.Undefined;
         }
         }

+ 1 - 1
Jint/Runtime/Interop/TypeReference.cs

@@ -63,7 +63,7 @@ namespace Jint.Runtime.Interop
                         }
                         }
                         else
                         else
                         {
                         {
-                            parameters[i] = Engine.Options.GetTypeConverter().Convert(
+                            parameters[i] = Engine.ClrTypeConverter.Convert(
                                 arguments[i].ToObject(),
                                 arguments[i].ToObject(),
                                 parameterType,
                                 parameterType,
                                 CultureInfo.InvariantCulture);
                                 CultureInfo.InvariantCulture);

+ 2 - 2
Jint/Runtime/TypeConverter.cs

@@ -388,8 +388,8 @@ namespace Jint.Runtime
                 {
                 {
                     for (var i = 0; i < arguments.Length; i++)
                     for (var i = 0; i < arguments.Length; i++)
                     {
                     {
-                        parameters[i] = engine.Options.GetTypeConverter().Convert(
-                            arguments[i].ToObject(),
+                        parameters[i] = engine.ClrTypeConverter.Convert(
+                            objectArguments[i],
                             method.GetParameters()[i].ParameterType,
                             method.GetParameters()[i].ParameterType,
                             CultureInfo.InvariantCulture);
                             CultureInfo.InvariantCulture);
                     }
                     }