Browse Source

Fetch from upstream, resolve conflicts

Fetch from upstream, resolve conflicts
h15ter 11 years ago
parent
commit
f27fc879ce

+ 1 - 0
.gitignore

@@ -151,3 +151,4 @@ $RECYCLE.BIN/
 
 # Mac crap
 .DS_Store
+Jint.sln.ide/*

+ 4 - 0
.nuget/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="xunit.runners" version="1.9.2" />
+</packages>

+ 1 - 1
Jint.Benchmark/Program.cs

@@ -30,7 +30,7 @@ namespace Jint.Benchmark
             const bool runJint = true;
             const bool runJurassic = true;
 
-            const int iterations = 100;
+            const int iterations = 1000;
             const bool reuseEngine = false;
 
             var watch = new Stopwatch();

+ 3 - 0
Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj

@@ -59,6 +59,9 @@
       <Name>Jint</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 26 - 26
Jint.Tests.CommonScripts/SunSpiderTests.cs

@@ -30,7 +30,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("3d-cube", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/3d-cube.js")]
+        [InlineData("3d-cube", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/3d-cube.js")]
         public void ThreeDCube(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -38,7 +38,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("3d-morph", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/3d-morph.js")]
+        [InlineData("3d-morph", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/3d-morph.js")]
         public void ThreeDMorph(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -46,7 +46,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("3d-raytrace", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/3d-raytrace.js")]
+        [InlineData("3d-raytrace", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/3d-raytrace.js")]
         public void ThreeDRaytrace(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -54,7 +54,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("access-binary-trees", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/access-binary-trees.js")]
+        [InlineData("access-binary-trees", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/access-binary-trees.js")]
         public void AccessBinaryTrees(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -62,7 +62,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("access-fannkuch", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/access-fannkuch.js")]
+        [InlineData("access-fannkuch", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/access-fannkuch.js")]
         public void AccessFannkych(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -70,7 +70,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("access-nbody", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/access-nbody.js")]
+        [InlineData("access-nbody", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/access-nbody.js")]
         public void AccessNBody(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -78,14 +78,14 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("access-nsieve", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/access-nsieve.js")]
+        [InlineData("access-nsieve", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/access-nsieve.js")]
         public void AccessNSieve(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
             RunTest(content);
         }
 
-        [InlineData("bitops-3bit-bits-in-byte", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/bitops-3bit-bits-in-byte.js")]
+        [InlineData("bitops-3bit-bits-in-byte", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/bitops-3bit-bits-in-byte.js")]
         public void Bitops3BitBitsInByte(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -93,7 +93,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("bitops-bits-in-byte", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/bitops-bits-in-byte.js")]
+        [InlineData("bitops-bits-in-byte", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/bitops-bits-in-byte.js")]
         public void BitopsBitsInByte(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -101,7 +101,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("bitops-bitwise-and", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/bitops-bitwise-and.js")]
+        [InlineData("bitops-bitwise-and", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/bitops-bitwise-and.js")]
         public void BitopsBitwiseAnd(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -109,7 +109,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("bitops-nsieve-bits", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/bitops-nsieve-bits.js")]
+        [InlineData("bitops-nsieve-bits", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/bitops-nsieve-bits.js")]
         public void BitopsNSieveBits(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -117,7 +117,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("controlflow-recursive", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/controlflow-recursive.js")]
+        [InlineData("controlflow-recursive", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/controlflow-recursive.js")]
         public void ControlFlowRecursive(string name, string url)
         {
             var t = new Thread(() =>
@@ -131,7 +131,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("crypto-aes", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/crypto-aes.js")]
+        [InlineData("crypto-aes", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/crypto-aes.js")]
         public void CryptoAES(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -139,14 +139,14 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("crypto-md5", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/crypto-md5.js")]
+        [InlineData("crypto-md5", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/crypto-md5.js")]
         public void CryptoMD5(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
             RunTest(content);
         }
 
-        [InlineData("crypto-sha1", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/crypto-sha1.js")]
+        [InlineData("crypto-sha1", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/crypto-sha1.js")]
         public void CryptoSha1(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -154,7 +154,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("date-format-tofte", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/date-format-tofte.js")]
+        [InlineData("date-format-tofte", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/date-format-tofte.js")]
         public void DateFormatTofte(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -162,14 +162,14 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("date-format-xparb", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/date-format-xparb.js")]
+        [InlineData("date-format-xparb", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/date-format-xparb.js")]
         public void DateFormatXParb(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
             RunTest(content);
         }
 
-        [InlineData("math-cordic", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/math-cordic.js")]
+        [InlineData("math-cordic", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/math-cordic.js")]
         public void MathCordic(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -177,7 +177,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("math-partial-sums", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/math-partial-sums.js")]
+        [InlineData("math-partial-sums", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/math-partial-sums.js")]
         public void MathPartialSums(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -185,7 +185,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("math-spectral-norm", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/math-spectral-norm.js")]
+        [InlineData("math-spectral-norm", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/math-spectral-norm.js")]
         public void MathSpectralNorm(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -193,7 +193,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("regexp-dna", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/regexp-dna.js")]
+        [InlineData("regexp-dna", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/regexp-dna.js")]
         public void RegexpDna(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -201,14 +201,14 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("string-base64", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/string-base64.js")]
+        [InlineData("string-base64", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/string-base64.js")]
         public void StringBase64(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
             RunTest(content);
         }
 
-        [InlineData("string-fasta", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/string-fasta.js")]
+        [InlineData("string-fasta", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/string-fasta.js")]
         public void StringFasta(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -216,7 +216,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("string-tagcloud", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/string-tagcloud.js")]
+        [InlineData("string-tagcloud", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/string-tagcloud.js")]
         public void StringTagCloud(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -224,7 +224,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("string-unpack-code", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/string-unpack-code.js")]
+        [InlineData("string-unpack-code", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/string-unpack-code.js")]
         public void StringUnpackCode(string name, string url)
         {
             var content = new WebClient().DownloadString(url);
@@ -232,7 +232,7 @@ namespace Jint.Tests.CommonScripts
         }
 
         [Theory]
-        [InlineData("string-validate-input", "https://raw.github.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.1/string-validate-input.js")]
+        [InlineData("string-validate-input", "https://raw.githubusercontent.com/WebKit/webkit/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/string-validate-input.js")]
         public void StringValidateInput(string name, string url)
         {
             var content = new WebClient().DownloadString(url);

+ 3 - 2
Jint.Tests.Ecma/EcmaTest.cs

@@ -25,8 +25,9 @@ namespace Jint.Tests.Ecma
         {
             _lastError = null;
 
-            var engine = new Engine();
-
+            //NOTE: The Date tests in test262 assume the local timezone is Pacific Standard Time
+            var pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
+            var engine = new Engine(cfg => cfg.LocalTimeZone(pacificTimeZone));
 
             // loading driver
 

+ 3 - 0
Jint.Tests.Ecma/Jint.Tests.Ecma.csproj

@@ -12038,6 +12038,9 @@
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

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

@@ -59,6 +59,8 @@
     <Compile Include="Runtime\Domain\ClassWithField.cs" />
     <Compile Include="Runtime\Domain\ClassWithStaticFields.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\Person.cs" />
     <Compile Include="Runtime\Domain\Shape.cs" />
@@ -96,6 +98,12 @@
   <ItemGroup>
     <EmbeddedResource Include="Parser\Scripts\JSXTransformer.js" />
   </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Parser\Scripts\handlebars.js" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 1 - 0
Jint.Tests/Parser/JavascriptParserTests.cs

@@ -21,6 +21,7 @@ namespace Jint.Tests.Parser
         [InlineData("mootools.js", "1.4.5")]
         [InlineData("angular.js", "1.2.5")]
         [InlineData("JSXTransformer.js", "0.10.0")]
+        [InlineData("handlebars.js", "2.0.0")]
         public void ShouldParseScriptFile(string file, string version)
         {
             const string prefix = "Jint.Tests.Parser.Scripts.";

File diff suppressed because it is too large
+ 983 - 0
Jint.Tests/Parser/Scripts/handlebars.js


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

@@ -45,5 +45,29 @@ namespace Jint.Tests.Runtime.Domain
 
             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; }
+    }
+}

+ 185 - 5
Jint.Tests/Runtime/EngineTests.cs

@@ -9,6 +9,7 @@ using Jint.Parser.Ast;
 using Jint.Runtime;
 using Xunit;
 using Xunit.Extensions;
+using System.Net;
 
 namespace Jint.Tests.Runtime
 {
@@ -31,7 +32,6 @@ namespace Jint.Tests.Runtime
 
         private void RunTest(string source)
         {
-
             _engine.Execute(source);
         }
 
@@ -594,9 +594,9 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldNotExecuteDebuggerStatement()
         {
-            new Engine().Execute("debugger"); 
+            new Engine().Execute("debugger");
         }
-       
+
         [Fact]
         public void ShouldThrowStatementCountOverflow()
         {
@@ -605,6 +605,14 @@ namespace Jint.Tests.Runtime
             );
         }
 
+        [Fact]
+        public void ShouldThrowTimeout()
+        {
+            Assert.Throws<TimeoutException>(
+                () => new Engine(cfg => cfg.TimeoutInterval(new TimeSpan(0, 0, 0, 0, 500))).Execute("while(true);")
+            );
+        }
+
         [Fact]
         public void ShouldConvertDoubleToStringWithoutLosingPrecision()
         {
@@ -650,7 +658,7 @@ namespace Jint.Tests.Runtime
                 assert(regex.test('a/b') === true);
                 assert(regex.test('a\\/b') === false);
             ");
-      }
+        }
 
         [Fact]
         public void ShouldComputeFractionInBase()
@@ -697,6 +705,42 @@ namespace Jint.Tests.Runtime
             Assert.Equal(expected, result);
         }
 
+        [Fact]
+        public void JsonParserShouldParseNegativeNumber()
+        {
+            RunTest(@"
+                var a = JSON.parse('{ ""x"":-1 }');
+                assert(a.x === -1);
+
+                var b = JSON.parse('{ ""x"": -1 }');
+                assert(b.x === -1);
+            ");
+        }
+
+        [Fact]
+        public void JsonParserShouldDetectInvalidNegativeNumberSyntax()
+        {
+            RunTest(@"
+                try {
+                    JSON.parse('{ ""x"": -.1 }'); // Not allowed
+                    assert(false);
+                }
+                catch(ex) {
+                    assert(ex instanceof SyntaxError);
+                }
+            ");
+
+            RunTest(@"
+                try {
+                    JSON.parse('{ ""x"": - 1 }'); // Not allowed
+                    assert(false);
+                }
+                catch(ex) {
+                    assert(ex instanceof SyntaxError);
+                }
+            ");
+        }
+
         [Fact]
         public void ShouldBeCultureInvariant()
         {
@@ -704,7 +748,7 @@ namespace Jint.Tests.Runtime
             Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
 
             var engine = new Engine();
-            
+
             var result = engine.Execute("1.2 + 2.1").GetCompletionValue().AsNumber();
             Assert.Equal(3.3d, result);
 
@@ -738,5 +782,141 @@ namespace Jint.Tests.Runtime
             }
         }
 
+        [Fact]
+        public void ParseShouldReturnNumber()
+        {
+            var engine = new Engine();
+
+            var result = engine.Execute("Date.parse('1970-01-01');").GetCompletionValue().AsNumber();
+            Assert.Equal(0, result);
+        }
+
+        [Fact]
+        public void UtcShouldUseUtc()
+        {
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
+
+            var result = engine.Execute("Date.UTC(1970,0,1)").GetCompletionValue().AsNumber();
+            Assert.Equal(0, result);
+        }
+
+        [Fact]
+        public void ShouldUseLocalTimeZoneOverride()
+        {
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
+
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
+
+            var epochGetLocalMinutes = engine.Execute("var d = new Date(0); d.getMinutes();").GetCompletionValue().AsNumber();
+            Assert.Equal(11, epochGetLocalMinutes);
+
+            var localEpochGetUtcMinutes = engine.Execute("var d = new Date(1970,0,1); d.getUTCMinutes();").GetCompletionValue().AsNumber();
+            Assert.Equal(-11, localEpochGetUtcMinutes);
+
+            var parseLocalEpoch = engine.Execute("Date.parse('January 1, 1970');").GetCompletionValue().AsNumber();
+            Assert.Equal(-11 * 60 * 1000, parseLocalEpoch);
+
+            var epochToLocalString = engine.Execute("var d = new Date(0); d.toString();").GetCompletionValue().AsString();
+            Assert.Equal("Thu Jan 01 1970 00:11:00 GMT", epochToLocalString);
+        }
+
+        [Theory]
+        [InlineData("1970")]
+        [InlineData("1970-01")]
+        [InlineData("1970-01-01")]
+        [InlineData("1970-01-01T00:00")]
+        [InlineData("1970-01-01T00:00:00")]
+        [InlineData("1970-01-01T00:00:00.000")]
+        [InlineData("1970Z")]
+        [InlineData("1970-1Z")]
+        [InlineData("1970-1-1Z")]
+        [InlineData("1970-1-1T0:0Z")]
+        [InlineData("1970-1-1T0:0:0Z")]
+        [InlineData("1970-1-1T0:0:0.0Z")]
+        [InlineData("1970/1Z")]
+        [InlineData("1970/1/1Z")]
+        [InlineData("1970/1/1 0:0Z")]
+        [InlineData("1970/1/1 0:0:0Z")]
+        [InlineData("1970/1/1 0:0:0.0Z")]
+        [InlineData("January 1, 1970 GMT")]
+        [InlineData("1970-01-01T00:00:00.000-00:00")]
+        public void ShouldParseAsUtc(string date)
+        {
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
+
+            engine.SetValue("d", date);
+            var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
+
+            Assert.Equal(0, result);
+        }
+
+        [Theory]
+        [InlineData("1970/01")]
+        [InlineData("1970/01/01")]
+        [InlineData("1970/01/01T00:00")]
+        [InlineData("1970/01/01 00:00")]
+        [InlineData("1970-1")]
+        [InlineData("1970-1-1")]
+        [InlineData("1970-1-1T0:0")]
+        [InlineData("1970-1-1 0:0")]
+        [InlineData("1970/1")]
+        [InlineData("1970/1/1")]
+        [InlineData("1970/1/1T0:0")]
+        [InlineData("1970/1/1 0:0")]
+        [InlineData("01-1970")]
+        [InlineData("01-01-1970")]
+        [InlineData("January 1, 1970")]
+        [InlineData("1970-01-01T00:00:00.000+00:11")]
+        public void ShouldParseAsLocalTime(string date)
+        {
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone)).SetValue("d", date);
+
+            var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
+
+            Assert.Equal(-11 * 60 * 1000, result);
+        }
+
+        [Fact]
+        public void EmptyStringShouldMatchRegex()
+        {
+            RunTest(@"
+                var regex = /^(?:$)/g;
+                assert(''.match(regex) instanceof Array);
+            ");
+        }
+
+        [Fact]
+        public void ShouldExecuteHandlebars()
+        {
+            var url = "http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js";
+            var content = new WebClient().DownloadString(url);
+
+            RunTest(content);
+
+            RunTest(@"
+                var source = 'Hello {{name}}';
+                var template = Handlebars.compile(source);
+                var context = {name: 'Paul'};
+                var html = template(context);
+
+                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]
         public void ShouldUseSystemIO()
         {
@@ -859,7 +939,65 @@ namespace Jint.Tests.Runtime
             ");
 
             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));
+            ");
+        }
 
     }
 }

+ 1 - 1
Jint.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2013
-VisualStudioVersion = 12.0.30110.0
+VisualStudioVersion = 12.0.30723.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jint.Tests", "Jint.Tests\Jint.Tests.csproj", "{37C7D4E0-8770-4E2A-8B6D-E53087868354}"
 EndProject

+ 17 - 0
Jint/Engine.cs

@@ -32,7 +32,10 @@ namespace Jint
         private readonly Stack<ExecutionContext> _executionContexts;
         private JsValue _completionValue = JsValue.Undefined;
         private int _statementsCount;
+        private long _timeoutTicks;
         private SyntaxNode _lastSyntaxNode = null;
+        
+        public ITypeConverter ClrTypeConverter;
 
         // cache of types used when resolving CLR type names
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(); 
@@ -129,6 +132,8 @@ namespace Jint
                     return new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)));
                 }), false, false, false);
             }
+
+            ClrTypeConverter = new DefaultTypeConverter(this);
         }
 
         public LexicalEnvironment GlobalEnvironment;
@@ -216,6 +221,12 @@ namespace Jint
             _statementsCount = 0;
         }
 
+        public void ResetTimeoutTicks()
+        {
+            var timeoutIntervalTicks = Options.GetTimeoutInterval().Ticks;
+            _timeoutTicks = timeoutIntervalTicks > 0 ? DateTime.UtcNow.Ticks + timeoutIntervalTicks : 0;
+        }
+
         public Engine Execute(string source)
         {
             var parser = new JavaScriptParser();
@@ -231,6 +242,7 @@ namespace Jint
         public Engine Execute(Program program)
         {
             ResetStatementsCount();
+            ResetTimeoutTicks();
             ResetLastStatement();
 
             using (new StrictModeScope(Options.IsStrict() || program.Strict))
@@ -270,6 +282,11 @@ namespace Jint
                 throw new StatementsCountOverflowException();
             }
 
+            if (_timeoutTicks > 0 && _timeoutTicks < DateTime.UtcNow.Ticks)
+            {
+                throw new TimeoutException();
+            }
+
             _lastSyntaxNode = statement;
 
             switch (statement.Type)

+ 75 - 47
Jint/Native/Date/DateConstructor.cs

@@ -46,48 +46,53 @@ namespace Jint.Native.Date
 
             if (!DateTime.TryParseExact(date, new[]
             {
-                "yyyy/MM/ddTH:m:s.fff",
-                "yyyy/MM/dd",
-                "yyyy/MM",
-                "yyyy-MM-ddTH:m:s.fff",
+                "yyyy-MM-ddTHH:mm:ss.FFF",
+                "yyyy-MM-ddTHH:mm:ss",
+                "yyyy-MM-ddTHH:mm",
                 "yyyy-MM-dd",
                 "yyyy-MM",
-                "yyyy",
-                "THH:m:s.fff",
-                "TH:mm:sm",
-                "THH:mm",
-                "THH"
+                "yyyy"
             }, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out result))
             {
                 if (!DateTime.TryParseExact(date, new[]
                 {
-                    "yyyy/MM/ddTH:m:s.fffK",
-                    "yyyy/MM/ddK",
-                    "yyyy/MMK",
-                    "yyyy-MM-ddTH:m:s.fffK",
-                    "yyyy-MM-ddK",
-                    "yyyy-MMK",
+                    "yyyy-M-dTH:m:s.FFFK",
+                    "yyyy/M/dTH:m:s.FFFK",
+                    "yyyy-M-dTH:m:sK",
+                    "yyyy/M/dTH:m:sK",
+                    "yyyy-M-dTH:mK",
+                    "yyyy/M/dTH:mK",
+                    "yyyy-M-d H:m:s.FFFK",
+                    "yyyy/M/d H:m:s.FFFK",
+                    "yyyy-M-d H:m:sK",
+                    "yyyy/M/d H:m:sK",
+                    "yyyy-M-d H:mK",
+                    "yyyy/M/d H:mK",
+                    "yyyy-M-dK",
+                    "yyyy/M/dK",
+                    "yyyy-MK",
+                    "yyyy/MK",
                     "yyyyK",
-                    "THH:m:s.fffK",
-                    "TH:mm:smK",
+                    "THH:mm:ss.FFFK",
+                    "THH:mm:ssK",
                     "THH:mmK",
                     "THHK"
                 }, 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;
                     }
                 }
             }
 
-            return Construct(result);
+            return FromDateTime(result);
         }
 
         private JsValue Utc(JsValue thisObj, JsValue[] arguments)
         {
-            var local = (DateInstance) Construct(arguments);
-            return local.PrimitiveValue;
+            return TimeClip(ConstructTimeValue(arguments, useUtc: true));
         }
 
         private JsValue Now(JsValue thisObj, JsValue[] arguments)
@@ -109,46 +114,56 @@ namespace Jint.Native.Date
         {
             if (arguments.Length == 0)
             {
-                return Construct(DateTime.Now);
+                return Construct(DateTime.UtcNow);
             }
             else if (arguments.Length == 1)
             {
                 var v = TypeConverter.ToPrimitive(arguments[0]);
                 if (v.IsString())
                 {
-                    return Parse(Undefined.Instance, Arguments.From(v)).AsObject();
+                    return Construct(Parse(Undefined.Instance, Arguments.From(v)).AsNumber());
                 }
 
-                return Construct(DatePrototype.TimeClip(TypeConverter.ToNumber(v)));
+                return Construct(TypeConverter.ToNumber(v));
             }
             else
             {
-                var y = TypeConverter.ToNumber(arguments[0]);
-                var m = (int)TypeConverter.ToInteger(arguments[1]);
-                var dt = arguments.Length > 2 ? (int)TypeConverter.ToInteger(arguments[2]) : 1;
-                var h = arguments.Length > 3 ? (int)TypeConverter.ToInteger(arguments[3]) : 0;
-                var min = arguments.Length > 4 ? (int)TypeConverter.ToInteger(arguments[4]) : 0;
-                var s = arguments.Length > 5 ? (int)TypeConverter.ToInteger(arguments[5]) : 0;
-                var milli = arguments.Length > 6 ? (int)TypeConverter.ToInteger(arguments[6]) : 0;
-
-                for (int i = 2; i < arguments.Length; i++)
-                {
-                    if (double.IsNaN(TypeConverter.ToNumber(arguments[i])))
-                    {
-                        return Construct(double.NaN);
-                    }
-                }
+                return Construct(ConstructTimeValue(arguments, useUtc: false));
+            }
+        }
 
-                if ((!double.IsNaN(y)) && (0 <= TypeConverter.ToInteger(y)) && (TypeConverter.ToInteger(y) <= 99))
+        private double ConstructTimeValue(JsValue[] arguments, bool useUtc)
+        {
+            if (arguments.Length < 2)
+            {
+                throw new ArgumentOutOfRangeException("arguments", "There must be at least two arguments.");
+            }
+
+            var y = TypeConverter.ToNumber(arguments[0]);
+            var m = (int)TypeConverter.ToInteger(arguments[1]);
+            var dt = arguments.Length > 2 ? (int)TypeConverter.ToInteger(arguments[2]) : 1;
+            var h = arguments.Length > 3 ? (int)TypeConverter.ToInteger(arguments[3]) : 0;
+            var min = arguments.Length > 4 ? (int)TypeConverter.ToInteger(arguments[4]) : 0;
+            var s = arguments.Length > 5 ? (int)TypeConverter.ToInteger(arguments[5]) : 0;
+            var milli = arguments.Length > 6 ? (int)TypeConverter.ToInteger(arguments[6]) : 0;
+
+            for (int i = 2; i < arguments.Length; i++)
+            {
+                if (double.IsNaN(TypeConverter.ToNumber(arguments[i])))
                 {
-                    y += 1900;
+                    return double.NaN;
                 }
+            }
 
-                var finalDate = DatePrototype.MakeDate(DatePrototype.MakeDay(y, m, dt),
-                    DatePrototype.MakeTime(h, min, s, milli));
-
-                return Construct(DatePrototype.TimeClip(DatePrototype.Utc(finalDate)));
+            if ((!double.IsNaN(y)) && (0 <= TypeConverter.ToInteger(y)) && (TypeConverter.ToInteger(y) <= 99))
+            {
+                y += 1900;
             }
+
+            var finalDate = DatePrototype.MakeDate(DatePrototype.MakeDay(y, m, dt),
+                DatePrototype.MakeTime(h, min, s, milli));
+
+            return useUtc ? finalDate : PrototypeObject.Utc(finalDate);
         }
 
         public DatePrototype PrototypeObject { get; private set; }
@@ -197,9 +212,22 @@ namespace Jint.Native.Date
             return TypeConverter.ToInteger(time);
         }
 
-        public static double FromDateTime(DateTime dt)
+        public double FromDateTime(DateTime dt)
         {
-            return System.Math.Floor((dt.ToUniversalTime() - Epoch).TotalMilliseconds);
+            var convertToUtcAfter = (dt.Kind == DateTimeKind.Unspecified);
+
+            var dateAsUtc = dt.Kind == DateTimeKind.Local
+                ? dt.ToUniversalTime()
+                : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
+
+            var result = (dateAsUtc - Epoch).TotalMilliseconds;
+
+            if (convertToUtcAfter)
+            {
+                result = PrototypeObject.Utc(result);
+            }
+
+            return System.Math.Floor(result);
         }
     }
 }

+ 35 - 25
Jint/Native/Date/DatePrototype.cs

@@ -85,7 +85,7 @@ namespace Jint.Native.Date
 
         public JsValue ToString(JsValue thisObj, JsValue[] arg2)
         {
-            return thisObj.TryCast<DateInstance>().ToDateTime().ToLocalTime().ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
+            return ToLocalTime(thisObj.TryCast<DateInstance>().ToDateTime()).ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
         }
 
         private static JsValue ToDateString(JsValue thisObj, JsValue[] arguments)
@@ -123,7 +123,7 @@ namespace Jint.Native.Date
             return thisObj.TryCast<DateInstance>().PrimitiveValue;
         }
 
-        private static JsValue GetFullYear(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetFullYear(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -134,7 +134,7 @@ namespace Jint.Native.Date
             return YearFromTime(LocalTime(t));
         }
 
-        private static JsValue GetYear(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetYear(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -156,7 +156,7 @@ namespace Jint.Native.Date
             return YearFromTime(t);
         }
 
-        private static JsValue GetMonth(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetMonth(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -178,7 +178,7 @@ namespace Jint.Native.Date
             return MonthFromTime(t);
         }
 
-        private static JsValue GetDate(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetDate(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -200,7 +200,7 @@ namespace Jint.Native.Date
             return DateFromTime(t);
         }
 
-        private static JsValue GetDay(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetDay(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -222,7 +222,7 @@ namespace Jint.Native.Date
             return WeekDay(t);
         }
 
-        private static JsValue GetHours(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetHours(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -244,7 +244,7 @@ namespace Jint.Native.Date
             return HourFromTime(t);
         }
 
-        private static JsValue GetMinutes(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetMinutes(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -266,7 +266,7 @@ namespace Jint.Native.Date
             return MinFromTime(t);
         }
 
-        private static JsValue GetSeconds(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetSeconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -288,7 +288,7 @@ namespace Jint.Native.Date
             return SecFromTime(t);
         }
 
-        private static JsValue GetMilliseconds(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetMilliseconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -310,7 +310,7 @@ namespace Jint.Native.Date
             return MsFromTime(t);
         }
 
-        private static JsValue GetTimezoneOffset(JsValue thisObj, JsValue[] arguments)
+        private JsValue GetTimezoneOffset(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
@@ -326,7 +326,7 @@ namespace Jint.Native.Date
             return thisObj.As<DateInstance>().PrimitiveValue = TimeClip(TypeConverter.ToNumber(arguments.At(0)));
         }
 
-        private static JsValue SetMilliseconds(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetMilliseconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
@@ -344,7 +344,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetSeconds(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetSeconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var s = TypeConverter.ToNumber(arguments.At(0));
@@ -366,7 +366,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetMinutes(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetMinutes(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var m = TypeConverter.ToNumber(arguments.At(0));
@@ -390,7 +390,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetHours(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetHours(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var h = TypeConverter.ToNumber(arguments.At(0));
@@ -416,7 +416,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetDate(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetDate(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var dt = TypeConverter.ToNumber(arguments.At(0));
@@ -436,7 +436,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetMonth(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetMonth(JsValue thisObj, JsValue[] arguments)
         {
             var t = LocalTime(thisObj.As<DateInstance>().PrimitiveValue);
             var m = TypeConverter.ToNumber(arguments.At(0));
@@ -458,7 +458,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetFullYear(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetFullYear(JsValue thisObj, JsValue[] arguments)
         {
             var thisTime = thisObj.As<DateInstance>().PrimitiveValue;
             var t = double.IsNaN(thisTime) ? +0 : LocalTime(thisTime);
@@ -471,7 +471,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private static JsValue SetYear(JsValue thisObj, JsValue[] arguments)
+        private JsValue SetYear(JsValue thisObj, JsValue[] arguments)
         {
             var thisTime = thisObj.As<DateInstance>().PrimitiveValue;
             var t = double.IsNaN(thisTime) ? +0 : LocalTime(thisTime);
@@ -830,15 +830,15 @@ namespace Jint.Native.Date
             return (Day(t) + 4)%7;
         }
 
-        public static double LocalTza
+        public double LocalTza
         {
             get
             {
-                return TimeZoneInfo.Local.BaseUtcOffset.TotalMilliseconds;
+                return Engine.Options.GetLocalTimeZone().BaseUtcOffset.TotalMilliseconds;
             }
         }
 
-        public static double DaylightSavingTa(double t)
+        public double DaylightSavingTa(double t)
         {
             var timeInYear = t - TimeFromYear(YearFromTime(t));
 
@@ -861,15 +861,25 @@ namespace Jint.Native.Date
 
             var dateTime = new DateTime((int)year, 1, 1).AddMilliseconds(timeInYear);
 
-            return TimeZoneInfo.Local.IsDaylightSavingTime(dateTime) ? MsPerHour : 0;
+            return Engine.Options.GetLocalTimeZone().IsDaylightSavingTime(dateTime) ? MsPerHour : 0;
         }
 
-        public static double LocalTime(double t)
+        public DateTime ToLocalTime(DateTime t)
+        {
+            if (t.Kind == DateTimeKind.Unspecified)
+            {
+                return t;
+            }
+
+            return TimeZoneInfo.ConvertTime(t, Engine.Options.GetLocalTimeZone());
+        }
+
+        public double LocalTime(double t)
         {
             return t + LocalTza + DaylightSavingTa(t);
         }
 
-        public static double Utc(double t)
+        public double Utc(double t)
         {
             return t - LocalTza - DaylightSavingTa(t - LocalTza);
         }

+ 19 - 2
Jint/Native/Json/JsonParser.cs

@@ -161,9 +161,17 @@ namespace Jint.Native.Json
 
             int start = _index;
             string number = "";
+            
+            // Number start with a -
+            if (ch == '-')
+            {
+                number += _source.CharCodeAt(_index++).ToString();
+                ch = _source.CharCodeAt(_index);
+            }
+
             if (ch != '.')
             {
-                number = _source.CharCodeAt(_index++).ToString();
+                number += _source.CharCodeAt(_index++).ToString();
                 ch = _source.CharCodeAt(_index);
 
                 // Hex number starts with '0x'.
@@ -219,7 +227,7 @@ namespace Jint.Native.Json
             return new Token
                 {
                     Type = Tokens.Number,
-                    Value = Double.Parse(number, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture),
+                    Value = Double.Parse(number, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture),
                     LineNumber = _lineNumber,
                     LineStart = _lineStart,
                     Range = new[] {start, _index}
@@ -447,6 +455,15 @@ namespace Jint.Native.Json
                 return ScanPunctuator();
             }
 
+            if (ch == '-') // Negative Number
+            {
+                if (IsDecimalDigit(_source.CharCodeAt(_index + 1)))
+                {
+                    return ScanNumericLiteral();
+                }
+                return ScanPunctuator();
+            }
+
             if (IsDecimalDigit(ch))
             {
                 return ScanNumericLiteral();

+ 1 - 1
Jint/Native/RegExp/RegExpPrototype.cs

@@ -86,7 +86,7 @@ namespace Jint.Native.RegExp
             }
 
             Match r = null;
-            if (i < 0 || i >= length)
+            if (i < 0 || i > length)
             {
                 R.Put("lastIndex", (double) 0, true);
                 return Null.Instance;

+ 26 - 16
Jint/Options.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Reflection;
@@ -13,10 +14,11 @@ namespace Jint
         private bool _strict;
         private bool _allowDebuggerStatement;
         private bool _allowClr;
-        private ITypeConverter _typeConverter = new DefaultTypeConverter();
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private int _maxStatements;
+        private TimeSpan _timeoutInterval;
         private CultureInfo _culture = CultureInfo.CurrentCulture;
+        private TimeZoneInfo _localTimeZone = TimeZoneInfo.Local;
         private List<Assembly> _lookupAssemblies = new List<Assembly>(); 
 
         /// <summary>
@@ -51,15 +53,6 @@ namespace Jint
             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>
          /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
         /// </summary>
@@ -86,12 +79,24 @@ namespace Jint
             return this;
         }
 
+        public Options TimeoutInterval(TimeSpan timeoutInterval)
+        {
+            _timeoutInterval = timeoutInterval;
+            return this;
+        }
+
         public Options Culture(CultureInfo cultureInfo)
         {
             _culture = cultureInfo;
             return this;
         }
 
+        public Options LocalTimeZone(TimeZoneInfo timeZoneInfo)
+        {
+            _localTimeZone = timeZoneInfo;
+            return this;
+        }
+
         internal bool GetDiscardGlobal()
         {
             return _discardGlobal;
@@ -117,11 +122,6 @@ namespace Jint
             return _lookupAssemblies;
         }
 
-        internal ITypeConverter GetTypeConverter()
-        {
-            return _typeConverter;
-        }
-
         internal IEnumerable<IObjectConverter> GetObjectConverters()
         {
             return _objectConverters;
@@ -132,9 +132,19 @@ namespace Jint
             return _maxStatements;
         }
 
+        internal TimeSpan GetTimeoutInterval()
+        {
+            return _timeoutInterval;
+        }
+
         internal CultureInfo GetCulture()
         {
             return _culture;
         }
+
+        internal TimeZoneInfo GetLocalTimeZone()
+        {
+            return _localTimeZone;
+        }
     }
 }

+ 8 - 8
Jint/Parser/JavascriptParser.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
@@ -10,7 +10,7 @@ namespace Jint.Parser
 {
     public class JavaScriptParser
     {
-        private static readonly object[] Keywords =
+        private static readonly HashSet<string> Keywords = new HashSet<string>
         {
             "if", "in", "do", "var", "for", "new", "try", "let",
             "this", "else", "case", "void", "with", "enum",
@@ -20,7 +20,7 @@ namespace Jint.Parser
             "function", "continue", "debugger", "instanceof"
         };
 
-        private static readonly object[] StrictModeReservedWords =
+        private static readonly HashSet<string> StrictModeReservedWords = new HashSet<string>
         {
             "implements",
             "interface",
@@ -33,7 +33,7 @@ namespace Jint.Parser
             "let"
         };
 
-        private static readonly object[] FutureReservedWords =
+        private static readonly HashSet<string> FutureReservedWords = new HashSet<string>
         {
             "class",
             "enum",
@@ -145,12 +145,12 @@ namespace Jint.Parser
 
         private static bool IsFutureReservedWord(string id)
         {
-            return Array.IndexOf(FutureReservedWords, id) >= 0;
+            return FutureReservedWords.Contains(id);
         }
 
         private static bool IsStrictModeReservedWord(string id)
         {
-            return Array.IndexOf(StrictModeReservedWords, id) >= 0;
+            return StrictModeReservedWords.Contains(id);
         }
 
         private static bool IsRestrictedWord(string id)
@@ -170,8 +170,8 @@ namespace Jint.Parser
             // 'const' is specialized as Keyword in V8.
             // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
             // Some others are from future reserved words.
-            
-            return Array.IndexOf(Keywords, id) >= 0;
+
+            return Keywords.Contains(id);
         }
 
         // 7.4 Comments

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

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

+ 17 - 8
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -13,19 +13,16 @@ namespace Jint.Runtime.Descriptors.Specialized
         private readonly object _item;
         private readonly PropertyInfo _indexer;
 
-        public IndexDescriptor(Engine engine, string key, object item)
+        public IndexDescriptor(Engine engine, Type targetType, string key, object item)
         {
             _engine = engine;
             _item = item;
 
             // get all instance indexers with exactly 1 argument
-            var indexers = item
-                .GetType()
+            var indexers = targetType
                 .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                 .Where(x => x.GetIndexParameters().Length == 1);
 
-            var converter = _engine.Options.GetTypeConverter();
-
             // try to find first indexer having either public getter or setter with matching argument type
             foreach (var indexer in indexers)
             {
@@ -33,7 +30,7 @@ namespace Jint.Runtime.Descriptors.Specialized
                 {
                     var paramType = indexer.GetIndexParameters()[0].ParameterType;
 
-                    if (converter.TryConvert(key, paramType, CultureInfo.InvariantCulture, out _key))
+                    if (_engine.ClrTypeConverter.TryConvert(key, paramType, CultureInfo.InvariantCulture, out _key))
                     {
                         _indexer = indexer;
                         break;
@@ -43,19 +40,29 @@ namespace Jint.Runtime.Descriptors.Specialized
             }
 
             // throw if no indexer found
-            if(_indexer == null)
+            if (_indexer == null)
+            {
                 throw new InvalidOperationException("No matching indexer found.");
+            }
 
             Writable = true;
         }
 
+
+        public IndexDescriptor(Engine engine, string key, object item)
+            : this(engine, item.GetType(), key, item)
+        {
+        }
+
         public override JsValue? Value
         {
             get
             {
                 var getter = _indexer.GetGetMethod();
-                if(getter == null)
+                if (getter == null)
+                {
                     throw new InvalidOperationException("Indexer has no public getter.");
+                }
 
                 object[] parameters = { _key };
                 return JsValue.FromObject(_engine, getter.Invoke(_item, parameters));
@@ -65,7 +72,9 @@ namespace Jint.Runtime.Descriptors.Specialized
             {
                 var setter = _indexer.GetSetMethod();
                 if (setter == null)
+                {
                     throw new InvalidOperationException("Indexer has no public setter.");
+                }
 
                 object[] parameters = { _key, value.HasValue ? value.Value.ToObject() : null };
                 setter.Invoke(_item, parameters);

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

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

+ 109 - 10
Jint/Runtime/Interop/DefaultTypeConverter.cs

@@ -1,15 +1,24 @@
 using System;
-using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Linq.Expressions;
 using Jint.Native;
+using System.Collections.Generic;
 
 namespace Jint.Runtime.Interop
 {
     public class DefaultTypeConverter : ITypeConverter
     {
-        private static readonly Dictionary<string, bool> KnownConversions = new Dictionary<string, bool>();
-        private static readonly object LockObject = new object();
+        private readonly Engine _engine;
+        private static readonly Dictionary<string, bool> _knownConversions = new Dictionary<string, bool>();
+        private static readonly object _lockObject = new object();
+
+        public DefaultTypeConverter(Engine engine)
+        {
+            _engine = engine;
+        }
 
-        public object Convert(object value, Type type, IFormatProvider formatProvider)
+        public virtual object Convert(object value, Type type, IFormatProvider formatProvider)
         {
             // don't try to convert if value is derived from type
             if (type.IsInstanceOfType(value))
@@ -28,30 +37,120 @@ namespace Jint.Runtime.Interop
                 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);
         }
 
-        public bool TryConvert(object value, Type type, IFormatProvider formatProvider, out object converted)
+        public virtual bool TryConvert(object value, Type type, IFormatProvider formatProvider, out object converted)
         {
             bool canConvert;
             var key = value == null ? String.Format("Null->{0}", type) : String.Format("{0}->{1}", value.GetType(), type);
 
-            if (!KnownConversions.TryGetValue(key, out canConvert))
+            if (!_knownConversions.TryGetValue(key, out canConvert))
             {
-                lock (LockObject)
+                lock (_lockObject)
                 {
-                    if (!KnownConversions.TryGetValue(key, out canConvert))
+                    if (!_knownConversions.TryGetValue(key, out canConvert))
                     {
                         try
                         {
                             converted = Convert(value, type, formatProvider);
-                            KnownConversions.Add(key, true);
+                            _knownConversions.Add(key, true);
                             return true;
                         }
                         catch
                         {
                             converted = null;
-                            KnownConversions.Add(key, false);
+                            _knownConversions.Add(key, false);
                             return false;
                         }
                     }

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

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

+ 10 - 5
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -25,12 +25,13 @@ namespace Jint.Runtime.Interop
         public JsValue Invoke(MethodInfo[] methodInfos, JsValue thisObject, JsValue[] arguments)
         {
             var methods = TypeConverter.FindBestMatch(Engine, methodInfos, arguments).ToList();
-            var converter = Engine.Options.GetTypeConverter();
+            var converter = Engine.ClrTypeConverter;
 
             foreach (var method in methods)
             {
                 var parameters = new object[arguments.Length];
                 var argumentsMatch = true;
+
                 for (var i = 0; i < arguments.Length; i++)
                 {
                     var parameterType = method.GetParameters()[i].ParameterType;
@@ -46,17 +47,21 @@ namespace Jint.Runtime.Interop
                             argumentsMatch = false;
                             break;
                         }
+
+                        if (typeof(System.Linq.Expressions.LambdaExpression).IsAssignableFrom(parameters[i].GetType()))
+                        {
+                            parameters[i] = (parameters[i] as System.Linq.Expressions.LambdaExpression).Compile();
+                        }
                     }
                 }
 
                 if (!argumentsMatch)
+                { 
                     continue;
-
-                var result = JsValue.FromObject(Engine, method.Invoke(thisObject.ToObject(), parameters.ToArray()));
+                }
 
                 // todo: cache method info
-
-                return result;
+                return JsValue.FromObject(Engine, method.Invoke(thisObject.ToObject(), parameters.ToArray()));
             }
 
             throw new JavaScriptException(Engine.TypeError, "No public methods with the specified arguments were found.");

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

@@ -95,6 +95,44 @@ namespace Jint.Runtime.Interop
             {
                 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;
         }

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

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

+ 3 - 3
Jint/Runtime/TypeConverter.cs

@@ -350,8 +350,7 @@ namespace Jint.Runtime
         {
             methods = methods
                 .Where(m => m.GetParameters().Count() == arguments.Length)
-                .ToArray()
-                ;
+                .ToArray();
 
             if (methods.Length == 1 && !methods[0].GetParameters().Any())
             {
@@ -392,8 +391,9 @@ namespace Jint.Runtime
             }
 
             foreach (var method in methods)
+            {
                 yield return method;
+            }
         }
-
     }
 }

+ 5 - 1
README.md

@@ -1,4 +1,4 @@
-[![Build status](https://ci.appveyor.com/api/projects/status/c84b8rdswh2w4744/branch/master)](https://ci.appveyor.com/project/SebastienRos/jint)
+[![Build status](http://teamcity.codebetter.com/app/rest/builds/buildType:(id:Jint_Master)/statusIcon)](http://teamcity.codebetter.com/project.html?projectId=Jint&tab=projectOverview)
 
 # Jint
 
@@ -124,3 +124,7 @@ Generic types are also supported. Here is how to declare, instantiate and use a
   - boolean -> bool
   - Regex -> RegExp
   - Function -> Delegate
+
+Continuous Integration kindly provided by  
+[![](http://www.jetbrains.com/img/banners/Codebetter300x250.png)](http://www.jetbrains.com/teamcity)
+

Some files were not shown because too many files changed in this diff