Forráskód Böngészése

Merge pull request #5 from sebastienros/master

sync
fvaneijk 10 éve
szülő
commit
447bcac2a4
53 módosított fájl, 1897 hozzáadás és 246 törlés
  1. 2 0
      .gitignore
  2. 1 0
      .nuget/packages.config
  3. 23 7
      Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj
  4. 6 2
      Jint.Tests.CommonScripts/packages.config
  5. 22 8
      Jint.Tests.Ecma/Jint.Tests.Ecma.csproj
  6. 6 2
      Jint.Tests.Ecma/packages.config
  7. 21 6
      Jint.Tests/Jint.Tests.csproj
  8. 4 0
      Jint.Tests/Runtime/Domain/A.cs
  9. 35 1
      Jint.Tests/Runtime/Domain/ClassWithStaticFields.cs
  10. 36 1
      Jint.Tests/Runtime/Domain/Shape.cs
  11. 332 5
      Jint.Tests/Runtime/EngineTests.cs
  12. 184 0
      Jint.Tests/Runtime/InteropTests.cs
  13. 171 0
      Jint.Tests/Runtime/JsValueConversionTests.cs
  14. 6 2
      Jint.Tests/packages.config
  15. 37 2
      Jint/Engine.cs
  16. 7 1
      Jint/Jint.csproj
  17. 7 2
      Jint/Jint.nuspec
  18. 39 0
      Jint/Native/Argument/ArgumentsObject.cs
  19. 43 4
      Jint/Native/Array/ArrayInstance.cs
  20. 10 2
      Jint/Native/Array/ArrayPrototype.cs
  21. 4 2
      Jint/Native/Function/ScriptFunctionInstance.cs
  22. 2 2
      Jint/Native/Global/GlobalObject.cs
  23. 46 20
      Jint/Native/JsValue.cs
  24. 2 2
      Jint/Native/Null.cs
  25. 1 9
      Jint/Native/Number/NumberPrototype.cs
  26. 10 10
      Jint/Native/Object/ObjectConstructor.cs
  27. 43 83
      Jint/Native/Object/ObjectInstance.cs
  28. 1 1
      Jint/Native/Object/ObjectPrototype.cs
  29. 2 2
      Jint/Native/Undefined.cs
  30. 15 0
      Jint/Options.cs
  31. 1 3
      Jint/Parser/Ast/WithStatement.cs
  32. 2 2
      Jint/Properties/AssemblyInfo.cs
  33. 2 0
      Jint/Runtime/Completion.cs
  34. 21 0
      Jint/Runtime/Debugger/BreakPoint.cs
  35. 202 0
      Jint/Runtime/Debugger/DebugHandler.cs
  36. 16 0
      Jint/Runtime/Debugger/DebugInformation.cs
  37. 10 0
      Jint/Runtime/Debugger/StepMode.cs
  38. 12 22
      Jint/Runtime/Descriptors/PropertyDescriptor.cs
  39. 10 0
      Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs
  40. 5 1
      Jint/Runtime/Environments/EnvironmentRecord.cs
  41. 11 1
      Jint/Runtime/Environments/ObjectEnvironmentRecord.cs
  42. 10 0
      Jint/Runtime/ExpressionIntepreter.cs
  43. 15 12
      Jint/Runtime/Interop/DefaultTypeConverter.cs
  44. 16 9
      Jint/Runtime/Interop/DelegateWrapper.cs
  45. 20 0
      Jint/Runtime/Interop/MethodInfoFunctionInstance.cs
  46. 57 6
      Jint/Runtime/Interop/NamespaceReference.cs
  47. 28 9
      Jint/Runtime/Interop/ObjectWrapper.cs
  48. 6 0
      Jint/Runtime/JavaScriptException.cs
  49. 165 0
      Jint/Runtime/MruPropertyCache.cs
  50. 157 0
      Jint/Runtime/MruPropertyCache2.cs
  51. 10 3
      Jint/Runtime/StatementInterpreter.cs
  52. 2 2
      README.md
  53. 1 0
      buildnuget.cmd

+ 2 - 0
.gitignore

@@ -28,6 +28,7 @@ build/
 *_p.c
 *.ilk
 *.meta
+*.nupkg
 *.obj
 *.pch
 *.pdb
@@ -152,3 +153,4 @@ $RECYCLE.BIN/
 # Mac crap
 .DS_Store
 Jint.sln.ide/*
+/Jint.sln.GhostDoc.xml

+ 1 - 0
.nuget/packages.config

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

+ 23 - 7
Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj

@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
+  <Import Project="..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" />
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -13,6 +15,7 @@
     <FileAlignment>512</FileAlignment>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
     <RestorePackages>true</RestorePackages>
+    <NuGetPackageImportStamp>2412b238</NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -39,20 +42,23 @@
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
-    <Reference Include="xunit">
-      <HintPath>..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
+    <Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
+      <Private>True</Private>
     </Reference>
-    <Reference Include="xunit.extensions">
-      <HintPath>..\packages\xunit.extensions.1.9.2\lib\net20\xunit.extensions.dll</HintPath>
+    <Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
+      <Private>True</Private>
     </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SunSpiderTests.cs" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Jint\Jint.csproj">
       <Project>{678738da-f723-4920-b9e5-cad667104bda}</Project>
@@ -62,8 +68,18 @@
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props'))" />
+    <Error Condition="!Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
+  </Target>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 6 - 2
Jint.Tests.CommonScripts/packages.config

@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="xunit" version="1.9.2" targetFramework="net45" />
-  <package id="xunit.extensions" version="1.9.2" targetFramework="net45" />
+  <package id="xunit" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.assert" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" />
 </packages>

+ 22 - 8
Jint.Tests.Ecma/Jint.Tests.Ecma.csproj

@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" />
+  <Import Project="..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -13,6 +15,7 @@
     <FileAlignment>512</FileAlignment>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
     <RestorePackages>true</RestorePackages>
+    <NuGetPackageImportStamp>f0c14de6</NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -39,13 +42,17 @@
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
-    <Reference Include="xunit, Version=1.9.2.1705, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
+    <Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
+      <Private>True</Private>
     </Reference>
-    <Reference Include="xunit.extensions, Version=1.9.2.1705, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\xunit.extensions.1.9.2\lib\net20\xunit.extensions.dll</HintPath>
+    <Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
+      <Private>True</Private>
     </Reference>
   </ItemGroup>
   <ItemGroup>
@@ -12036,13 +12043,20 @@
     <Content Include="TestCases\sta.js" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="packages.config" />
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <None Include="packages.config" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
+    <Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props'))" />
+  </Target>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 6 - 2
Jint.Tests.Ecma/packages.config

@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="xunit" version="1.9.2" targetFramework="net45" />
-  <package id="xunit.extensions" version="1.9.2" targetFramework="net45" />
+  <package id="xunit" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.assert" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" />
 </packages>

+ 21 - 6
Jint.Tests/Jint.Tests.csproj

@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" />
+  <Import Project="..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -13,6 +15,7 @@
     <FileAlignment>512</FileAlignment>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
     <RestorePackages>true</RestorePackages>
+    <NuGetPackageImportStamp>c4676ded</NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -42,13 +45,17 @@
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
-    <Reference Include="xunit, Version=1.9.2.1705, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
+    <Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
+      <Private>True</Private>
     </Reference>
-    <Reference Include="xunit.extensions, Version=1.9.2.1705, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\xunit.extensions.1.9.2\lib\net20\xunit.extensions.dll</HintPath>
+    <Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
+      <HintPath>..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
+      <Private>True</Private>
     </Reference>
   </ItemGroup>
   <ItemGroup>
@@ -65,6 +72,7 @@
     <Compile Include="Runtime\Domain\IPerson.cs" />
     <Compile Include="Runtime\Domain\Person.cs" />
     <Compile Include="Runtime\Domain\Shape.cs" />
+    <Compile Include="Runtime\JsValueConversionTests.cs" />
     <Compile Include="Runtime\SamplesTests.cs" />
     <Compile Include="Runtime\InteropTests.cs" />
     <Compile Include="Runtime\EngineTests.cs" />
@@ -107,6 +115,13 @@
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
+    <Error Condition="!Exists('..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props'))" />
+  </Target>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

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

@@ -90,5 +90,9 @@ namespace Jint.Tests.Runtime.Domain
         {
 
         }
+        public string Call16(params JsValue[] values)
+        {
+            return String.Join(",", values);
+        }
     }
 }

+ 35 - 1
Jint.Tests/Runtime/Domain/ClassWithStaticFields.cs

@@ -14,5 +14,39 @@
         {
             Setter = "Setter";
         }
-    }
+    }
+
+    public class Nested
+    {
+        public class ClassWithStaticFields
+        {
+            public static string Get = "Get";
+            public static string Set = "Set";
+
+            public static string Getter
+            {
+                get { return "Getter"; }
+            }
+
+            public static string Setter
+            {
+                get
+                {
+                    return _setter;
+                }
+                set
+                {
+                    _setter = value;
+                }
+            }
+
+            public static readonly string Readonly = "Readonly";
+            private static string _setter;
+
+            static ClassWithStaticFields()
+            {
+                Setter = "Setter";
+            }
+        }
+    }
 }

+ 36 - 1
Jint.Tests/Runtime/Domain/Shape.cs

@@ -15,7 +15,42 @@ namespace Shapes
     }
 
     public class Circle : Shape
-    {
+    {
+        public class Meta
+        {
+            public Meta()
+            {
+                _description = "descp";
+            }
+          private string _description;
+
+          public string Description
+          {
+            get
+            {
+              return _description;
+            }
+            set
+            {
+              _description = value;
+            }
+          }
+
+          public enum Usage
+          {
+            Public,
+            Private,
+            Internal = 11
+          }
+        }
+
+        public enum Kind
+        {
+          Unit,
+          Ellipse,
+          Round = 5
+        }
+
         public Circle()
         {
         }

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

@@ -1,12 +1,13 @@
-using System;
+using System;
 using System.Globalization;
 using System.IO;
 using System.Reflection;
-using System.Threading;
+using System.Threading;
 using Jint.Native.Number;
 using Jint.Parser;
 using Jint.Parser.Ast;
-using Jint.Runtime;
+using Jint.Runtime;
+using Jint.Runtime.Debugger;
 using Xunit;
 using Xunit.Extensions;
 using System.Net;
@@ -15,7 +16,9 @@ namespace Jint.Tests.Runtime
 {
     public class EngineTests : IDisposable
     {
-        private readonly Engine _engine;
+        private readonly Engine _engine;
+        private int countBreak = 0;
+        private StepMode stepMode;
 
         public EngineTests()
         {
@@ -93,6 +96,17 @@ namespace Jint.Tests.Runtime
             var result = engine.Execute(source).GetCompletionValue().ToObject();
 
             Assert.Equal(expected, result);
+        }
+
+        [Theory]
+        [InlineData(-59d, "~58")]
+        [InlineData(58d, "~~58")]
+        public void ShouldInterpretUnaryExpression(object expected, string source)
+        {
+            var engine = new Engine();
+            var result = engine.Execute(source).GetCompletionValue().ToObject();
+
+            Assert.Equal(expected, result);
         }
 
         [Fact]
@@ -556,7 +570,7 @@ namespace Jint.Tests.Runtime
         }
 
         [Theory]
-        [InlineData(true, "'ab' == 'a' + 'b'")]
+        [InlineData(true, "'ab' == 'a' + 'b'")]
         public void OperatorsPrecedence(object expected, string source)
         {
             var engine = new Engine();
@@ -1153,5 +1167,318 @@ namespace Jint.Tests.Runtime
                 assert(a[0] === 3);
             ");
         }
+
+        [Fact]
+        public void ShouldReturnTrueForEmptyIsNaNStatement()
+        {
+            RunTest(@"
+                assert(true === isNaN());
+            ");
+        }
+
+        [Theory]
+        [InlineData(4d, 0, "4")]
+        [InlineData(4d, 1, "4.0")]
+        [InlineData(4d, 2, "4.00")]
+        [InlineData(28.995, 2, "29.00")]
+        [InlineData(-28.995, 2, "-29.00")]
+        [InlineData(-28.495, 2, "-28.50")]
+        [InlineData(-28.445, 2, "-28.45")]
+        [InlineData(28.445, 2, "28.45")]
+        [InlineData(10.995, 0, "11")]
+        public void ShouldRoundToFixedDecimal(double number, int fractionDigits, string result)
+        {
+            var engine = new Engine();
+            var value = engine.Execute(
+                String.Format("new Number({0}).toFixed({1})",
+                    number.ToString(CultureInfo.InvariantCulture),
+                    fractionDigits.ToString(CultureInfo.InvariantCulture)))
+                .GetCompletionValue().ToObject();
+
+            Assert.Equal(value, result);
+        }
+
+
+
+        [Fact]
+        public void ShouldSortArrayWhenCompareFunctionReturnsFloatingPointNumber()
+        {
+            RunTest(@"
+                var nums = [1, 1.1, 1.2, 2, 2, 2.1, 2.2];
+                nums.sort(function(a,b){return b-a;});
+                assert(nums[0] === 2.2);
+                assert(nums[1] === 2.1);
+                assert(nums[2] === 2);
+                assert(nums[3] === 2);
+                assert(nums[4] === 1.2);
+                assert(nums[5] === 1.1);
+                assert(nums[6] === 1);
+            ");
+        }
+
+        [Fact]
+        public void ShouldBreakWhenBreakpointIsReached()
+        {
+            countBreak = 0;
+            stepMode = StepMode.None;
+
+            var engine = new Engine(options => options.DebugMode());
+
+            engine.Break += EngineStep;
+
+            engine.BreakPoints.Add(new BreakPoint(1, 1));
+
+            engine.Execute(@"var local = true;
+                if (local === true)
+                {}");
+
+            engine.Break -= EngineStep;
+
+            Assert.Equal(1, countBreak);
+        }
+
+        [Fact]
+        public void ShouldExecuteStepByStep()
+        {
+            countBreak = 0;
+            stepMode = StepMode.Into;
+
+            var engine = new Engine(options => options.DebugMode());
+
+            engine.Step += EngineStep;
+            
+            engine.Execute(@"var local = true;
+                var creatingSomeOtherLine = 0;
+                var lastOneIPromise = true");
+
+            engine.Step -= EngineStep;
+
+            Assert.Equal(3, countBreak);
+        }
+
+        [Fact]
+        public void ShouldNotBreakTwiceIfSteppingOverBreakpoint()
+        {
+            countBreak = 0;
+            stepMode = StepMode.Into;
+
+            var engine = new Engine(options => options.DebugMode());
+            engine.BreakPoints.Add(new BreakPoint(1, 1));
+            engine.Step += EngineStep;
+            engine.Break += EngineStep;
+
+            engine.Execute(@"var local = true;");
+
+            engine.Step -= EngineStep;
+            engine.Break -= EngineStep;
+
+            Assert.Equal(1, countBreak);
+        }
+        
+        private StepMode EngineStep(object sender, DebugInformation debugInfo)
+        {
+            Assert.NotNull(sender);
+            Assert.IsType(typeof(Engine), sender);
+            Assert.NotNull(debugInfo);
+
+            countBreak++;
+            return stepMode;
+        }
+
+        [Fact]
+        public void ShouldShowProperDebugInformation()
+        {
+            countBreak = 0;
+            stepMode = StepMode.None;
+
+            var engine = new Engine(options => options.DebugMode());
+            engine.BreakPoints.Add(new BreakPoint(5, 0));
+            engine.Break += EngineStepVerifyDebugInfo;
+
+            engine.Execute(@"var global = true;
+                            function func1()
+                            {
+                                var local = false;
+;
+                            }
+                            func1();");
+
+            engine.Break -= EngineStepVerifyDebugInfo;
+
+            Assert.Equal(1, countBreak);
+        }
+
+        private StepMode EngineStepVerifyDebugInfo(object sender, DebugInformation debugInfo)
+        {
+            Assert.NotNull(sender);
+            Assert.IsType(typeof(Engine), sender);
+            Assert.NotNull(debugInfo);
+
+            Assert.NotNull(debugInfo.CallStack);
+            Assert.NotNull(debugInfo.CurrentStatement);
+            Assert.NotNull(debugInfo.Locals);
+
+            Assert.Equal(1, debugInfo.CallStack.Count);
+            Assert.Equal("func1()", debugInfo.CallStack.Peek());
+            Assert.Contains(debugInfo.Globals, kvp => kvp.Key.Equals("global", StringComparison.Ordinal) && kvp.Value.AsBoolean() == true);
+            Assert.Contains(debugInfo.Globals, kvp => kvp.Key.Equals("local", StringComparison.Ordinal) && kvp.Value.AsBoolean() == false);
+            Assert.Contains(debugInfo.Locals, kvp => kvp.Key.Equals("local", StringComparison.Ordinal) && kvp.Value.AsBoolean() == false);
+            Assert.DoesNotContain(debugInfo.Locals, kvp => kvp.Key.Equals("global", StringComparison.Ordinal));
+            
+            countBreak++;
+            return stepMode;
+        }
+
+        [Fact]
+        public void ShouldBreakWhenConditionIsMatched()
+        {
+            countBreak = 0;
+            stepMode = StepMode.None;
+
+            var engine = new Engine(options => options.DebugMode());
+
+            engine.Break += EngineStep;
+
+            engine.BreakPoints.Add(new BreakPoint(5, 16, "condition === true"));
+            engine.BreakPoints.Add(new BreakPoint(6, 16, "condition === false"));
+
+            engine.Execute(@"var local = true;
+                var condition = true;
+                if (local === true)
+                {
+                ;
+                ;
+                }");
+
+            engine.Break -= EngineStep;
+
+            Assert.Equal(1, countBreak);
+        }
+
+        [Fact]
+        public void ShouldNotStepInSameLevelStatementsWhenStepOut()
+        {
+            countBreak = 0;
+            stepMode = StepMode.Out;
+
+            var engine = new Engine(options => options.DebugMode());
+
+            engine.Step += EngineStep;
+
+            engine.Execute(@"function func() // first step - then stepping out
+                {
+                    ; // shall not step
+                    ; // not even here
+                }
+                func(); // shall not step                 
+                ; // shall not step ");
+
+            engine.Step -= EngineStep;
+
+            Assert.Equal(1, countBreak);
+        }
+
+        [Fact]
+        public void ShouldNotStepInIfRequiredToStepOut()
+        {
+            countBreak = 0;
+            
+            var engine = new Engine(options => options.DebugMode());
+
+            engine.Step += EngineStepOutWhenInsideFunction;
+
+            engine.Execute(@"function func() // first step
+                {
+                    ; // third step - now stepping out
+                    ; // it should not step here
+                }
+                func(); // second step                 
+                ; // fourth step ");
+
+            engine.Step -= EngineStepOutWhenInsideFunction;
+
+            Assert.Equal(4, countBreak);
+        }
+
+        private StepMode EngineStepOutWhenInsideFunction(object sender, DebugInformation debugInfo)
+        {
+            Assert.NotNull(sender);
+            Assert.IsType(typeof(Engine), sender);
+            Assert.NotNull(debugInfo);
+
+            countBreak++;
+            if (debugInfo.CallStack.Count > 0)
+                return StepMode.Out;
+            
+            return StepMode.Into;
+        }
+
+        [Fact]
+        public void ShouldBreakWhenStatementIsMultiLine()
+        {
+            countBreak = 0;
+            stepMode = StepMode.None;
+
+            var engine = new Engine(options => options.DebugMode());
+            engine.BreakPoints.Add(new BreakPoint(4, 33));
+            engine.Break += EngineStep;
+
+            engine.Execute(@"var global = true;
+                            function func1()
+                            {
+                                var local = 
+                                    false;
+                            }
+                            func1();");
+
+            engine.Break -= EngineStep;
+
+            Assert.Equal(1, countBreak);
+        }
+
+        [Fact]
+        public void ShouldNotStepInsideIfRequiredToStepOver()
+        {
+            countBreak = 0;
+            
+            var engine = new Engine(options => options.DebugMode());
+
+            stepMode = StepMode.Over;
+            engine.Step += EngineStep;
+
+            engine.Execute(@"function func() // first step
+                {
+                    ; // third step - it shall not step here
+                    ; // it shall not step here
+                }
+                func(); // second step                 
+                ; // third step ");
+
+            engine.Step -= EngineStep;
+
+            Assert.Equal(3, countBreak);
+        }
+
+        [Fact]
+        public void ShouldStepAllStatementsWithoutInvocationsIfStepOver()
+        {
+            countBreak = 0;
+
+            var engine = new Engine(options => options.DebugMode());
+
+            stepMode = StepMode.Over;
+            engine.Step += EngineStep;
+
+            engine.Execute(@"var step1 = 1; // first step
+                var step2 = 2; // second step                 
+                if (step1 !== step2) // third step
+                { // fourth step
+                    ; // fifth step
+                }");
+
+            engine.Step -= EngineStep;
+
+            Assert.Equal(5, countBreak);
+        }
     }
 }

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

@@ -74,6 +74,56 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void DelegateWithNullableParameterCanBePassedAnUndefined()
+        {
+            _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull(undefined) === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithObjectParameterCanBePassedAnUndefined()
+        {
+            _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull(undefined) === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithNullableParameterCanBeExcluded()
+        {
+            _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull() === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithObjectParameterCanBeExcluded()
+        {
+            _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull() === true);
+            ");
+        }
+
+        [Fact]
+        public void ExtraParametersAreIgnored()
+        {
+            _engine.SetValue("passNumber", new Func<int, int>(x => x));
+
+            RunTest(@"
+                assert(passNumber(123,'test',{},[],null) === 123);
+            ");
+        }
+
         private delegate string callParams(params object[] values);
         private delegate string callArgumentAndParams(string firstParam, params object[] values);
 
@@ -92,6 +142,7 @@ namespace Jint.Tests.Runtime
                 assert(callArgumentAndParams('a','1','2','3') === 'a:1,2,3');
                 assert(callArgumentAndParams('a','1') === 'a:1');
                 assert(callArgumentAndParams('a') === 'a:');
+                assert(callArgumentAndParams() === ':');
             ");
         }
 
@@ -125,6 +176,21 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void CanInvokeObjectMethodsWithPascalCase()
+        {
+            var p = new Person
+            {
+                Name = "Mickey Mouse"
+            };
+
+            _engine.SetValue("p", p);
+
+            RunTest(@"
+                assert(p.toString() === 'Mickey Mouse');
+            ");
+        }
+
         [Fact]
         public void CanSetObjectProperties()
         {
@@ -1074,6 +1140,20 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void ShouldCallInstanceMethodWithJsValueParams()
+        {
+            _engine.SetValue("a", new A());
+
+            RunTest(@"
+                assert(a.Call16('1','2','3') === '1,2,3');
+                assert(a.Call16('1') === '1');
+                assert(a.Call16(1) === '1');
+                assert(a.Call16() === '');
+                assert(a.Call16('1','2','3') === a.Call16(['1','2','3']));
+            ");
+        }
+
         [Fact]
         public void NullValueAsArgumentShouldWork()
         {
@@ -1143,5 +1223,109 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void ShouldImportNamespaceNestedType()
+        {
+          RunTest(@"
+                var shapes = importNamespace('Shapes.Circle');
+                var kinds = shapes.Kind;
+                assert(kinds.Unit === 0);
+                assert(kinds.Ellipse === 1);
+                assert(kinds.Round === 5);
+            ");
+        }
+
+        [Fact]
+        public void ShouldImportNamespaceNestedNestedType()
+        {
+          RunTest(@"
+                var meta = importNamespace('Shapes.Circle.Meta');
+                var usages = meta.Usage;
+                assert(usages.Public === 0);
+                assert(usages.Private === 1);
+                assert(usages.Internal === 11);
+            ");
+        }
+
+        [Fact]
+        public void ShouldGetNestedNestedProp()
+        {
+            RunTest(@"
+                var meta = importNamespace('Shapes.Circle');
+                var m = new meta.Meta();
+                assert(m.Description === 'descp');
+            ");
+        }
+
+        [Fact]
+        public void ShouldSetNestedNestedProp()
+        {
+            RunTest(@"
+                var meta = importNamespace('Shapes.Circle');
+                var m = new meta.Meta();
+                m.Description = 'hello';
+                assert(m.Description === 'hello');
+            ");
+        }
+
+        [Fact]
+        public void CanGetStaticNestedField()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
+                var statics = domain.ClassWithStaticFields;
+                assert(statics.Get == 'Get');
+            ");
+        }
+
+        [Fact]
+        public void CanSetStaticNestedField()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
+                var statics = domain.ClassWithStaticFields;
+                statics.Set = 'hello';
+                assert(statics.Set == 'hello');
+            ");
+
+            Assert.Equal(Nested.ClassWithStaticFields.Set, "hello");
+        }
+
+        [Fact]
+        public void CanGetStaticNestedAccessor()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
+                var statics = domain.ClassWithStaticFields;
+                assert(statics.Getter == 'Getter');
+            ");
+        }
+
+        [Fact]
+        public void CanSetStaticNestedAccessor()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
+                var statics = domain.ClassWithStaticFields;
+                statics.Setter = 'hello';
+                assert(statics.Setter == 'hello');
+            ");
+
+            Assert.Equal(Nested.ClassWithStaticFields.Setter, "hello");
+        }
+
+        [Fact]
+        public void CantSetStaticNestedReadonly()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
+                var statics = domain.ClassWithStaticFields;
+                statics.Readonly = 'hello';
+                assert(statics.Readonly == 'Readonly');
+            ");
+
+            Assert.Equal(Nested.ClassWithStaticFields.Readonly, "Readonly");
+        }
+
     }
 }

+ 171 - 0
Jint.Tests/Runtime/JsValueConversionTests.cs

@@ -0,0 +1,171 @@
+using Jint.Native;
+using Jint.Native.Array;
+using Jint.Native.Date;
+using Jint.Native.Object;
+using Jint.Native.RegExp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Jint.Tests.Runtime
+{
+    public class JsValueConversionTests
+    {
+        [Fact]
+        public void ShouldBeAnArray()
+        {
+            var value = new JsValue(new ArrayInstance(null));
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(true, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(true, value.IsObject());
+            Assert.Equal(false, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+
+            Assert.Equal(true, value.AsArray() != null);
+        }
+
+        [Fact]
+        public void ShouldBeABoolean()
+        {
+            var value = new JsValue(true);
+            Assert.Equal(true, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(false, value.IsObject());
+            Assert.Equal(true, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+
+            Assert.Equal(true, value.AsBoolean());
+        }
+
+        [Fact]
+        public void ShouldBeADate()
+        {
+            var value = new JsValue(new DateInstance(null));
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(true, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(true, value.IsObject());
+            Assert.Equal(false, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+
+            Assert.Equal(true, value.AsDate() != null);
+        }
+
+        [Fact]
+        public void ShouldBeNull()
+        {
+            var value = Null.Instance;
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(true, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(false, value.IsObject());
+            Assert.Equal(true, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+        }
+
+        [Fact]
+        public void ShouldBeANumber()
+        {
+            var value = new JsValue(2);
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(true, value.IsNumber());
+            Assert.Equal(2, value.AsNumber());
+            Assert.Equal(false, value.IsObject());
+            Assert.Equal(true, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+        }
+
+        [Fact]
+        public void ShouldBeAnObject()
+        {
+            var value = new JsValue(new ObjectInstance(null));
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(true, value.IsObject());
+            Assert.Equal(true, value.AsObject() != null);
+            Assert.Equal(false, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+        }
+
+        [Fact]
+        public void ShouldBeARegExp()
+        {
+            var value = new JsValue(new RegExpInstance(null));
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(true, value.IsObject());
+            Assert.Equal(false, value.IsPrimitive());
+            Assert.Equal(true, value.IsRegExp());
+            Assert.Equal(true, value.AsRegExp() != null);
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(false, value.IsUndefined());
+        }
+
+        [Fact]
+        public void ShouldBeAString()
+        {
+            var value = new JsValue("a");
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(false, value.IsObject());
+            Assert.Equal(true, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(true, value.IsString());
+            Assert.Equal("a", value.AsString());
+            Assert.Equal(false, value.IsUndefined());
+        }
+
+        [Fact]
+        public void ShouldBeUndefined()
+        {
+            var value = Undefined.Instance;
+            Assert.Equal(false, value.IsBoolean());
+            Assert.Equal(false, value.IsArray());
+            Assert.Equal(false, value.IsDate());
+            Assert.Equal(false, value.IsNull());
+            Assert.Equal(false, value.IsNumber());
+            Assert.Equal(false, value.IsObject());
+            Assert.Equal(true, value.IsPrimitive());
+            Assert.Equal(false, value.IsRegExp());
+            Assert.Equal(false, value.IsString());
+            Assert.Equal(true, value.IsUndefined());
+        }
+    }
+}

+ 6 - 2
Jint.Tests/packages.config

@@ -1,6 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="Newtonsoft.Json" version="5.0.6" targetFramework="net45" />
-  <package id="xunit" version="1.9.2" targetFramework="net45" />
-  <package id="xunit.extensions" version="1.9.2" targetFramework="net45" />
+  <package id="xunit" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.assert" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
+  <package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" />
 </packages>

+ 37 - 2
Jint/Engine.cs

@@ -18,6 +18,7 @@ using Jint.Native.String;
 using Jint.Parser;
 using Jint.Parser.Ast;
 using Jint.Runtime;
+using Jint.Runtime.Debugger;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Interop;
@@ -138,6 +139,8 @@ namespace Jint
             }
 
             ClrTypeConverter = new DefaultTypeConverter(this);
+            BreakPoints = new List<BreakPoint>();
+            DebugHandler = new DebugHandler(this);
         }
 
         public LexicalEnvironment GlobalEnvironment;
@@ -166,6 +169,33 @@ namespace Jint
         public ExecutionContext ExecutionContext { get { return _executionContexts.Peek(); } }
 
         internal Options Options { get; private set; }
+        
+        #region Debugger
+        public delegate StepMode DebugStepDelegate(object sender, DebugInformation e);
+        public delegate StepMode BreakDelegate(object sender, DebugInformation e);
+        public event DebugStepDelegate Step;
+        public event BreakDelegate Break;
+        internal DebugHandler DebugHandler { get; private set; }
+        public List<BreakPoint> BreakPoints { get; private set; }
+
+        internal StepMode? InvokeStepEvent(DebugInformation info)
+        {
+            if (Step != null)
+            {
+                return Step(this, info);
+            }
+            return null;
+        }
+
+        internal StepMode? InvokeBreakEvent(DebugInformation info)
+        {
+            if (Break != null)
+            {
+                return Break(this, info);
+            }
+            return null;
+        }
+        #endregion
 
         public ExecutionContext EnterExecutionContext(LexicalEnvironment lexicalEnvironment, LexicalEnvironment variableEnvironment, JsValue thisBinding)
         {
@@ -301,6 +331,11 @@ namespace Jint
             }
 
             _lastSyntaxNode = statement;
+            
+            if (Options.IsDebugMode())
+            {
+                DebugHandler.OnStep(statement);
+            }
 
             switch (statement.Type)
             {
@@ -697,7 +732,7 @@ namespace Jint
                     {
                         var go = Global;
                         var existingProp = go.GetProperty(fn);
-                        if (existingProp.Configurable.Value.AsBoolean())
+                        if (existingProp.Configurable.Value)
                         {
                             go.DefineOwnProperty(fn,
                                                  new PropertyDescriptor(
@@ -709,7 +744,7 @@ namespace Jint
                         }
                         else
                         {
-                            if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable.Value.AsBoolean()))
+                            if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable.Value))
                             {
                                 throw new JavaScriptException(TypeError);
                             }

+ 7 - 1
Jint/Jint.csproj

@@ -148,7 +148,7 @@
     <Compile Include="Parser\Ast\WhileStatement.cs" />
     <Compile Include="Parser\Ast\WithStatement.cs" />
     <Compile Include="Parser\Comment.cs" />
-    <Compile Include="Parser\JavaScriptParser.cs" />
+    <Compile Include="Parser\JavascriptParser.cs" />
     <Compile Include="Parser\Loc.cs" />
     <Compile Include="Parser\Messages.cs" />
     <Compile Include="Parser\ParserException.cs" />
@@ -163,6 +163,10 @@
     <Compile Include="Runtime\CallStack\CallStackElementComparer.cs" />
     <Compile Include="Runtime\CallStack\CallStackElement.cs" />
     <Compile Include="Runtime\Completion.cs" />
+    <Compile Include="Runtime\Debugger\BreakPoint.cs" />
+    <Compile Include="Runtime\Debugger\DebugHandler.cs" />
+    <Compile Include="Runtime\Debugger\DebugInformation.cs" />
+    <Compile Include="Runtime\Debugger\StepMode.cs" />
     <Compile Include="Runtime\Descriptors\PropertyDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\Specialized\FieldInfoDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\Specialized\IndexDescriptor.cs" />
@@ -189,6 +193,8 @@
     <Compile Include="Runtime\Interop\TypeReference.cs" />
     <Compile Include="Runtime\Interop\TypeReferencePrototype.cs" />
     <Compile Include="Runtime\JavaScriptException.cs" />
+    <Compile Include="Runtime\MruPropertyCache2.cs" />
+    <Compile Include="Runtime\MruPropertyCache.cs" />
     <Compile Include="Runtime\RecursionDepthOverflowException.cs" />
     <Compile Include="Runtime\References\Reference.cs" />
     <Compile Include="Runtime\StatementInterpreter.cs" />

+ 7 - 2
Jint/Jint.nuspec

@@ -2,14 +2,19 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
   <metadata>
     <id>Jint</id>
-    <version>2.4.0</version>
+    <version>2.5.0</version>
     <owners>Sebastien Ros</owners>
     <authors>Sebastien Ros</authors>
     <description>Javascript Interpreter for .NET</description>
     <language>en-US</language>
     <projectUrl>http://github.com/sebastienros/jint</projectUrl>
     <licenseUrl>https://raw.githubusercontent.com/sebastienros/jint/master/LICENSE.txt</licenseUrl>
-    <releaseNotes>Fixing important bug related to Json parsing. Added params arguments support for .NET methods.</releaseNotes>
+    <releaseNotes>
+      Automatic support of camelCase mapping for .NET members.
+      Support for nested types.
+      Support for params JsValue[].
+      Bug fixes.
+    </releaseNotes>
     <tags>javascript interpreter jint</tags>
   </metadata>
 </package>

+ 39 - 0
Jint/Native/Argument/ArgumentsObject.cs

@@ -107,6 +107,45 @@ namespace Jint.Native.Argument
             return base.GetOwnProperty(propertyName);
         }
 
+        /// Implementation from ObjectInstance official specs as the one 
+        /// in ObjectInstance is optimized for the general case and wouldn't work 
+        /// for arrays
+        public override void Put(string propertyName, JsValue value, bool throwOnError)
+        {
+            if (!CanPut(propertyName))
+            {
+                if (throwOnError)
+                {
+                    throw new JavaScriptException(Engine.TypeError);
+                }
+
+                return;
+            }
+
+            var ownDesc = GetOwnProperty(propertyName);
+
+            if (ownDesc.IsDataDescriptor())
+            {
+                var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable: null, configurable: null);
+                DefineOwnProperty(propertyName, valueDesc, throwOnError);
+                return;
+            }
+
+            // property is an accessor or inherited
+            var desc = GetProperty(propertyName);
+
+            if (desc.IsAccessorDescriptor())
+            {
+                var setter = desc.Set.Value.TryCast<ICallable>();
+                setter.Call(new JsValue(this), new[] { value });
+            }
+            else
+            {
+                var newDesc = new PropertyDescriptor(value, true, true, true);
+                DefineOwnProperty(propertyName, newDesc, throwOnError);
+            }
+        }
+
         public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             if (!Strict && ParameterMap != null)

+ 43 - 4
Jint/Native/Array/ArrayInstance.cs

@@ -22,6 +22,45 @@ namespace Jint.Native.Array
             }
         }
 
+        /// Implementation from ObjectInstance official specs as the one 
+        /// in ObjectInstance is optimized for the general case and wouldn't work 
+        /// for arrays
+        public override void Put(string propertyName, JsValue value, bool throwOnError)
+        {
+            if (!CanPut(propertyName))
+            {
+                if (throwOnError)
+                {
+                    throw new JavaScriptException(Engine.TypeError);
+                }
+
+                return;
+            }
+
+            var ownDesc = GetOwnProperty(propertyName);
+
+            if (ownDesc.IsDataDescriptor())
+            {
+                var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable: null, configurable: null);
+                DefineOwnProperty(propertyName, valueDesc, throwOnError);
+                return;
+            }
+
+            // property is an accessor or inherited
+            var desc = GetProperty(propertyName);
+
+            if (desc.IsAccessorDescriptor())
+            {
+                var setter = desc.Set.Value.TryCast<ICallable>();
+                setter.Call(new JsValue(this), new[] { value });
+            }
+            else
+            {
+                var newDesc = new PropertyDescriptor(value, true, true, true);
+                DefineOwnProperty(propertyName, newDesc, throwOnError);
+            }
+        }
+
         public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             var oldLenDesc = GetOwnProperty("length");
@@ -45,7 +84,7 @@ namespace Jint.Native.Array
                 {
                     return base.DefineOwnProperty("length", newLenDesc, throwOnError);
                 }
-                if (!oldLenDesc.Writable.Value.AsBoolean())
+                if (!oldLenDesc.Writable.Value)
                 {
                     if (throwOnError)
                     {
@@ -55,7 +94,7 @@ namespace Jint.Native.Array
                     return false;
                 }
                 bool newWritable;
-                if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value.AsBoolean())
+                if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value)
                 {
                     newWritable = true;
                 }
@@ -88,7 +127,7 @@ namespace Jint.Native.Array
                                 newLenDesc.Value = new JsValue(index + 1);
                                 if (!newWritable)
                                 {
-                                    newLenDesc.Writable = JsValue.False;
+                                    newLenDesc.Writable = false;
                                 }
                                 base.DefineOwnProperty("length", newLenDesc, false);
                                 if (throwOnError)
@@ -134,7 +173,7 @@ namespace Jint.Native.Array
             else if (IsArrayIndex(propertyName))
             {
                 var index = TypeConverter.ToUint32(propertyName);
-                if (index >= oldLen && !oldLenDesc.Writable.Value.AsBoolean())
+                if (index >= oldLen && !oldLenDesc.Writable.Value)
                 {
                     if (throwOnError)
                     {

+ 10 - 2
Jint/Native/Array/ArrayPrototype.cs

@@ -518,8 +518,16 @@ namespace Jint.Native.Array
 
                     if (compareFn != null)
                     {
-                        var s = (int) TypeConverter.ToUint32(compareFn.Call(Undefined.Instance, new[] {x, y}));
-                        return s;
+                        var s = TypeConverter.ToNumber(compareFn.Call(Undefined.Instance, new[] {x, y}));
+                        if (s < 0)
+                        {
+                            return -1;
+                        }
+                        if (s > 0)
+                        {
+                            return 1;
+                        }
+                        return 0;
                     }
 
                     var xString = TypeConverter.ToString(x);

+ 4 - 2
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -94,7 +94,9 @@ namespace Jint.Native.Function
 
                     if (result.Type == Completion.Throw)
                     {
-                        throw new JavaScriptException(result.GetValueOrDefault());
+                        JavaScriptException ex = new JavaScriptException(result.GetValueOrDefault());
+                        ex.Location = result.Location;
+                        throw ex;
                     }
 
                     if (result.Type == Completion.Return)
@@ -134,4 +136,4 @@ namespace Jint.Native.Function
 
         public ObjectInstance PrototypeObject { get; private set; }
     }
-}
+}

+ 2 - 2
Jint/Native/Global/GlobalObject.cs

@@ -317,7 +317,7 @@ namespace Jint.Native.Global
         /// </summary>
         public static JsValue IsNaN(JsValue thisObject, JsValue[] arguments)
         {
-            var x = TypeConverter.ToNumber(arguments[0]);
+            var x = TypeConverter.ToNumber(arguments.At(0));
             return double.IsNaN(x);
         }
 
@@ -331,7 +331,7 @@ namespace Jint.Native.Global
                 return false;
             }
 
-            var n = TypeConverter.ToNumber(arguments[0]);
+            var n = TypeConverter.ToNumber(arguments.At(0));
             if (double.IsNaN(n) || double.IsInfinity(n))
             {
                 return false;

+ 46 - 20
Jint/Native/JsValue.cs

@@ -21,10 +21,10 @@ namespace Jint.Native
     [DebuggerTypeProxy(typeof(JsValueDebugView))]
     public struct JsValue : IEquatable<JsValue>
     {
-        public static JsValue Undefined = new JsValue(Types.Undefined);
-        public static JsValue Null = new JsValue(Types.Null);
-        public static JsValue False = new JsValue(false);
-        public static JsValue True = new JsValue(true);
+        public readonly static JsValue Undefined = new JsValue(Types.Undefined);
+        public readonly static JsValue Null = new JsValue(Types.Null);
+        public readonly static JsValue False = new JsValue(false);
+        public readonly static JsValue True = new JsValue(true);
 
         public JsValue(bool value)
         {
@@ -103,18 +103,24 @@ namespace Jint.Native
             return IsObject() && AsObject() is ArrayInstance;
         }
 
+        [Pure]
+        public bool IsDate()
+        {
+            return IsObject() && AsObject() is DateInstance;
+        }
+
         [Pure]
         public bool IsRegExp()
         {
             return IsObject() && AsObject() is RegExpInstance;
         }
-        
+
         [Pure]
         public bool IsObject()
         {
             return _type == Types.Object;
         }
-        
+
         [Pure]
         public bool IsString()
         {
@@ -157,11 +163,31 @@ namespace Jint.Native
             {
                 throw new ArgumentException("The value is not an array");
             }
-            return AsObject() as ArrayInstance;            
+            return AsObject() as ArrayInstance;
+        }
+
+        [Pure]
+        public DateInstance AsDate()
+        {
+            if (!IsDate())
+            {
+                throw new ArgumentException("The value is not a date");
+            }
+            return AsObject() as DateInstance;
         }
 
         [Pure]
-        public T TryCast<T>(Action<JsValue> fail = null) where T: class
+        public RegExpInstance AsRegExp()
+        {
+            if (!IsRegExp())
+            {
+                throw new ArgumentException("The value is not a date");
+            }
+            return AsObject() as RegExpInstance;
+        }
+
+        [Pure]
+        public T TryCast<T>(Action<JsValue> fail = null) where T : class
         {
             if (IsObject())
             {
@@ -190,7 +216,7 @@ namespace Jint.Native
         {
             return _object as T;
         }
-        
+
         [Pure]
         public bool AsBoolean()
         {
@@ -275,7 +301,7 @@ namespace Jint.Native
                 return Null;
             }
 
-            foreach(var converter in engine.Options.GetObjectConverters())
+            foreach (var converter in engine.Options.GetObjectConverters())
             {
                 JsValue result;
                 if (converter.TryConvert(value, out result))
@@ -327,7 +353,7 @@ namespace Jint.Native
 
             if (value is DateTimeOffset)
             {
-                    return engine.Date.Construct((DateTimeOffset)value);
+                return engine.Date.Construct((DateTimeOffset)value);
             }
 
             // if an ObjectInstance is passed directly, use it as is
@@ -340,7 +366,7 @@ namespace Jint.Native
             // if a JsValue is passed directly, use it as is
             if (value is JsValue)
             {
-                return (JsValue) value;
+                return (JsValue)value;
             }
 
             var array = value as System.Array;
@@ -428,7 +454,7 @@ namespace Jint.Native
                                 return result;
                             }
                             break;
-                        
+
                         case "String":
                             var stringInstance = _object as StringInstance;
                             if (stringInstance != null)
@@ -460,10 +486,10 @@ namespace Jint.Native
                             var function = _object as FunctionInstance;
                             if (function != null)
                             {
-                                return (Func<JsValue, JsValue[], JsValue>) function.Call;
+                                return (Func<JsValue, JsValue[], JsValue>)function.Call;
                             }
 
-                            break; 
+                            break;
 
                         case "Number":
                             var numberInstance = _object as NumberInstance;
@@ -484,12 +510,12 @@ namespace Jint.Native
                             break;
 
                         case "Object":
-                            #if __IOS__
+#if __IOS__
                                 IDictionary<string, object> o = new Dictionary<string, object>(); 
-                            #else
-                                IDictionary<string, object> o = new ExpandoObject();
-                            #endif
-                            
+#else
+                            IDictionary<string, object> o = new ExpandoObject();
+#endif
+
                             foreach (var p in _object.Properties)
                             {
                                 if (!p.Value.Enumerable.HasValue || p.Value.Enumerable.Value == false)

+ 2 - 2
Jint/Native/Null.cs

@@ -2,7 +2,7 @@
 {
     public static class Null
     {
-        public static JsValue Instance = JsValue.Null;
-        public static string Text = "null";
+        public readonly static JsValue Instance = JsValue.Null;
+        public readonly static string Text = "null";
     }
 }

+ 1 - 9
Jint/Native/Number/NumberPrototype.cs

@@ -108,16 +108,8 @@ namespace Jint.Native.Number
             {
                 return ToNumberString(x);
             }
-    
-            var l = (long) x; // extract integer part
 
-            if (f == 0)
-            {
-                return l.ToString(CultureInfo.InvariantCulture);
-            }
-
-            var d = x - l;
-            return l.ToString(CultureInfo.InvariantCulture) + d.ToString("." + new string('0', f), CultureInfo.InvariantCulture);
+            return x.ToString("f" + f, CultureInfo.InvariantCulture);
         }
 
         private JsValue ToExponential(JsValue thisObj, JsValue[] arguments)

+ 10 - 10
Jint/Native/Object/ObjectConstructor.cs

@@ -217,7 +217,7 @@ namespace Jint.Native.Object
             var descriptors = new List<KeyValuePair<string, PropertyDescriptor>>();
             foreach (var p in props.Properties)
             {
-                if (!p.Value.Enumerable.HasValue || !p.Value.Enumerable.Value.AsBoolean())
+                if (!p.Value.Enumerable.HasValue || !p.Value.Enumerable.Value)
                 {
                     continue;
                 }
@@ -245,9 +245,9 @@ namespace Jint.Native.Object
 
             foreach (var prop in o.Properties)
             {
-                if (prop.Value.Configurable.HasValue && prop.Value.Configurable.Value.AsBoolean())
+                if (prop.Value.Configurable.HasValue && prop.Value.Configurable.Value)
                 {
-                    prop.Value.Configurable = JsValue.False;
+                    prop.Value.Configurable = false;
                 }
 
                 o.DefineOwnProperty(prop.Key, prop.Value, true);
@@ -273,14 +273,14 @@ namespace Jint.Native.Object
                 var desc = o.GetOwnProperty(p);
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value.AsBoolean())
+                    if (desc.Writable.HasValue && desc.Writable.Value)
                     {
-                        desc.Writable = JsValue.False;
+                        desc.Writable = false;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean())
+                if (desc.Configurable.HasValue && desc.Configurable.Value)
                 {
-                    desc.Configurable = JsValue.False;
+                    desc.Configurable = false;
                 }
                 o.DefineOwnProperty(p, desc, true);
             }
@@ -343,12 +343,12 @@ namespace Jint.Native.Object
                 var desc = o.GetOwnProperty(p);
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value.AsBoolean())
+                    if (desc.Writable.HasValue && desc.Writable.Value)
                     {
                         return false;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean())
+                if (desc.Configurable.HasValue && desc.Configurable.Value)
                 {
                     return false;
                 }
@@ -384,7 +384,7 @@ namespace Jint.Native.Object
             }
 
             var enumerableProperties = o.Properties
-                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value.AsBoolean())
+                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value)
                 .ToArray();
             var n = enumerableProperties.Length;
             var array = Engine.Array.Construct(new JsValue[] {n});

+ 43 - 83
Jint/Native/Object/ObjectInstance.cs

@@ -1,6 +1,4 @@
 using System.Collections.Generic;
-using Jint.Native.Date;
-using Jint.Native.String;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 
@@ -11,7 +9,7 @@ namespace Jint.Native.Object
         public ObjectInstance(Engine engine)
         {
             Engine = engine;
-            Properties = new Dictionary<string, PropertyDescriptor>();
+            Properties = new MruPropertyCache2<string, PropertyDescriptor>();
         }
 
         public Engine Engine { get; set; }
@@ -69,7 +67,7 @@ namespace Jint.Native.Object
             var callable = getter.TryCast<ICallable>();
             return callable.Call(this, Arguments.Empty);
         }
-        
+
         /// <summary>
         /// Returns the Property Descriptor of the named 
         /// own property of this object, or undefined if 
@@ -150,9 +148,13 @@ namespace Jint.Native.Object
 
             if (ownDesc.IsDataDescriptor())
             {
-                var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable:null, configurable:null);
-                DefineOwnProperty(propertyName, valueDesc, throwOnError);
+                ownDesc.Value = value;
                 return;
+                
+                // as per specification
+                // var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable: null, configurable: null);
+                // DefineOwnProperty(propertyName, valueDesc, throwOnError);
+                // return;
             }
 
             // property is an accessor or inherited
@@ -194,7 +196,7 @@ namespace Jint.Native.Object
                     return true;
                 }
 
-                return desc.Writable.HasValue && desc.Writable.Value.AsBoolean();
+                return desc.Writable.HasValue && desc.Writable.Value;
             }
 
             if (Prototype == null)
@@ -225,7 +227,7 @@ namespace Jint.Native.Object
             }
             else
             {
-                return inherited.Writable.HasValue && inherited.Writable.Value.AsBoolean();
+                return inherited.Writable.HasValue && inherited.Writable.Value;
             }
         }
 
@@ -258,7 +260,7 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean())
+            if (desc.Configurable.HasValue && desc.Configurable.Value)
             {
                 Properties.Remove(propertyName);
                 return true;
@@ -347,7 +349,11 @@ namespace Jint.Native.Object
         public virtual bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             var current = GetOwnProperty(propertyName);
-            
+
+            if (current == desc) {
+                return true;
+            }
+
             if (current == PropertyDescriptor.Undefined)
             {
                 if (!Extensible)
@@ -366,13 +372,17 @@ namespace Jint.Native.Object
                         Properties[propertyName] = new PropertyDescriptor(desc)
                         {
                             Value = desc.Value.HasValue ? desc.Value : JsValue.Undefined,
-                            Writable = desc.Writable.HasValue ? desc.Writable : false
+                            Writable = desc.Writable.HasValue ? desc.Writable.Value : false,
+                            Enumerable = desc.Enumerable.HasValue ? desc.Enumerable.Value : false,
+                            Configurable = desc.Configurable.HasValue ? desc.Configurable.Value : false
                         };
                     }
                     else
                     {
                         Properties[propertyName] = new PropertyDescriptor(desc)
                         {
+                            Get = desc.Get,
+                            Set = desc.Set,
                             Enumerable = desc.Enumerable.HasValue ? desc.Enumerable : false,
                             Configurable = desc.Configurable.HasValue ? desc.Configurable : false,
                         };
@@ -390,76 +400,26 @@ namespace Jint.Native.Object
                 !current.Set.HasValue &&
                 !current.Value.HasValue)
             {
+
                 return true;
             }
 
             // Step 6
-            var configurableIsSame = current.Configurable.HasValue
-                ? desc.Configurable.HasValue && (current.Configurable.Value == desc.Configurable.Value)
-                : !desc.Configurable.HasValue;
-
-            var enumerableIsSame = current.Enumerable.HasValue
-                ? desc.Enumerable.HasValue && (current.Enumerable.Value == desc.Enumerable.Value)
-                : !desc.Enumerable.HasValue;
-
-            var writableIsSame = true;
-            var valueIsSame = true;
-
-            if (current.IsDataDescriptor() && desc.IsDataDescriptor())
-            {
-                var currentDataDescriptor = current;
-                var descDataDescriptor = desc;
-                writableIsSame = currentDataDescriptor.Writable.HasValue
-                ? descDataDescriptor.Writable.HasValue && (currentDataDescriptor.Writable.Value == descDataDescriptor.Writable.Value)
-                : !descDataDescriptor.Writable.HasValue;
-
-                var valueA = currentDataDescriptor.Value.HasValue
-                    ? currentDataDescriptor.Value.Value
-                    : Undefined.Instance;
-
-                var valueB = descDataDescriptor.Value.HasValue
-                                    ? descDataDescriptor.Value.Value
-                                    : Undefined.Instance;
-
-                valueIsSame = ExpressionInterpreter.SameValue(valueA, valueB);
-            }
-            else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
-            {
-                var currentAccessorDescriptor = current;
-                var descAccessorDescriptor = desc;
-
-                var getValueA = currentAccessorDescriptor.Get.HasValue
-                    ? currentAccessorDescriptor.Get.Value
-                    : Undefined.Instance;
-
-                var getValueB = descAccessorDescriptor.Get.HasValue
-                                    ? descAccessorDescriptor.Get.Value
-                                    : Undefined.Instance;
-
-                var setValueA = currentAccessorDescriptor.Set.HasValue
-                   ? currentAccessorDescriptor.Set.Value
-                   : Undefined.Instance;
-
-                var setValueB = descAccessorDescriptor.Set.HasValue
-                                    ? descAccessorDescriptor.Set.Value
-                                    : Undefined.Instance;
-
-                valueIsSame = ExpressionInterpreter.SameValue(getValueA, getValueB)
-                              && ExpressionInterpreter.SameValue(setValueA, setValueB);
-            }
-            else
-            {
-                valueIsSame = false;
-            }
-
-            if (configurableIsSame && enumerableIsSame && writableIsSame && valueIsSame)
-            {
+            if (
+                current.Configurable == desc.Configurable &&
+                current.Writable == desc.Writable &&
+                current.Enumerable == desc.Enumerable &&
+
+                ((!current.Get.HasValue && !desc.Get.HasValue) || (current.Get.HasValue && desc.Get.HasValue && ExpressionInterpreter.SameValue(current.Get.Value, desc.Get.Value))) &&
+                ((!current.Set.HasValue && !desc.Set.HasValue) || (current.Set.HasValue && desc.Set.HasValue && ExpressionInterpreter.SameValue(current.Set.Value, desc.Set.Value))) &&
+                ((!current.Value.HasValue && !desc.Value.HasValue) || (current.Value.HasValue && desc.Value.HasValue && ExpressionInterpreter.StrictlyEqual(current.Value.Value, desc.Value.Value)))
+            ) {
                 return true;
             }
 
-            if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
+            if (!current.Configurable.HasValue || !current.Configurable.Value)
             {
-                if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean())
+                if (desc.Configurable.HasValue && desc.Configurable.Value)
                 {
                     if (throwOnError)
                     {
@@ -485,7 +445,7 @@ namespace Jint.Native.Object
 
                 if (current.IsDataDescriptor() != desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
+                    if (!current.Configurable.HasValue || !current.Configurable.Value)
                     {
                         if (throwOnError)
                         {
@@ -500,8 +460,8 @@ namespace Jint.Native.Object
                         Properties[propertyName] = current = new PropertyDescriptor(
                             get: Undefined.Instance,
                             set: Undefined.Instance,
-                            enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(),
-                            configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean()
+                            enumerable: current.Enumerable,
+                            configurable: current.Configurable
                             );
                     }
                     else
@@ -509,16 +469,16 @@ namespace Jint.Native.Object
                         Properties[propertyName] = current = new PropertyDescriptor(
                             value: Undefined.Instance, 
                             writable: null,
-                            enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(),
-                            configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean()
+                            enumerable: current.Enumerable,
+                            configurable: current.Configurable
                             );
                     }
                 }
                 else if (current.IsDataDescriptor() && desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || current.Configurable.Value.AsBoolean() == false)
+                    if (!current.Configurable.HasValue || current.Configurable.Value == false)
                     {
-                        if (!current.Writable.HasValue || !current.Writable.Value.AsBoolean() && desc.Writable.HasValue && desc.Writable.Value.AsBoolean())
+                        if (!current.Writable.HasValue || !current.Writable.Value && desc.Writable.HasValue && desc.Writable.Value)
                         {
                             if (throwOnError)
                             {
@@ -528,9 +488,9 @@ namespace Jint.Native.Object
                             return false;
                         }
 
-                        if (!current.Writable.Value.AsBoolean())
+                        if (!current.Writable.Value)
                         {
-                            if (desc.Value.HasValue && !valueIsSame)
+                            if (desc.Value.HasValue && !ExpressionInterpreter.SameValue(desc.Value.Value, current.Value.Value))
                             {
                                 if (throwOnError)
                                 {
@@ -544,7 +504,7 @@ namespace Jint.Native.Object
                 }
                 else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
+                    if (!current.Configurable.HasValue || !current.Configurable.Value)
                     {
                         if ((desc.Set.HasValue && !ExpressionInterpreter.SameValue(desc.Set.Value, current.Set.HasValue ? current.Set.Value : Undefined.Instance))
                             ||

+ 1 - 1
Jint/Native/Object/ObjectPrototype.cs

@@ -38,7 +38,7 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            return desc.Enumerable.HasValue && desc.Enumerable.Value.AsBoolean();
+            return desc.Enumerable.HasValue && desc.Enumerable.Value;
         }
 
         private JsValue ValueOf(JsValue thisObject, JsValue[] arguments)

+ 2 - 2
Jint/Native/Undefined.cs

@@ -2,7 +2,7 @@
 {
     public static class Undefined
     {
-        public static JsValue Instance = JsValue.Undefined;
-        public static string Text = "undefined";
+        public readonly static JsValue Instance = JsValue.Undefined;
+        public readonly static string Text = "undefined";
     }
 }

+ 15 - 0
Jint/Options.cs

@@ -13,6 +13,7 @@ namespace Jint
         private bool _discardGlobal;
         private bool _strict;
         private bool _allowDebuggerStatement;
+        private bool _debugMode;
         private bool _allowClr;
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private int _maxStatements;
@@ -54,6 +55,15 @@ namespace Jint
             return this;
         }
 
+        /// <summary>
+        /// Allow to run the script in debug mode.
+        /// </summary>
+        public Options DebugMode(bool debugMode = true)
+        {
+            _debugMode = debugMode;
+            return this;
+        }
+
         /// <summary>
          /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
         /// </summary>
@@ -128,6 +138,11 @@ namespace Jint
             return _allowDebuggerStatement;
         }
 
+        internal bool IsDebugMode()
+        {
+            return _debugMode;
+        }
+
         internal bool IsClrAllowed()
         {
             return _allowClr;

+ 1 - 3
Jint/Parser/Ast/WithStatement.cs

@@ -1,6 +1,4 @@
-using Jint.Parser.Ast;
-
-namespace Jint
+namespace Jint.Parser.Ast
 {
     public class WithStatement : Statement
     {

+ 2 - 2
Jint/Properties/AssemblyInfo.cs

@@ -14,5 +14,5 @@ using System.Reflection;
 [assembly: AssemblyCulture("")]
 [assembly: NeutralResourcesLanguage("en")]
 
-[assembly: AssemblyVersion("2.4.0")]
-[assembly: AssemblyFileVersion("2.4.0")]
+[assembly: AssemblyVersion("2.5.0")]
+[assembly: AssemblyFileVersion("2.5.0")]

+ 2 - 0
Jint/Runtime/Completion.cs

@@ -28,5 +28,7 @@ namespace Jint.Runtime
         {
             return Value.HasValue ? Value.Value : Undefined.Instance;
         }
+
+        public Jint.Parser.Location Location { get; set; }
     }
 }

+ 21 - 0
Jint/Runtime/Debugger/BreakPoint.cs

@@ -0,0 +1,21 @@
+namespace Jint.Runtime.Debugger
+{
+    public class BreakPoint
+    {
+        public int Line { get; set; }
+        public int Char { get; set; }
+        public string Condition { get; set; }
+
+        public BreakPoint(int line, int character)
+        {
+            Line = line;
+            Char = character;
+        }
+
+        public BreakPoint(int line, int character, string condition)
+            : this(line, character)
+        {
+            Condition = condition;
+        }
+    }
+}

+ 202 - 0
Jint/Runtime/Debugger/DebugHandler.cs

@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Jint.Native;
+using Jint.Parser.Ast;
+using Jint.Runtime.Environments;
+using Jint.Runtime.References;
+
+namespace Jint.Runtime.Debugger
+{
+    internal class DebugHandler
+    {
+        private readonly Stack<string> _debugCallStack;
+        private StepMode _stepMode;
+        private int _callBackStepOverDepth;
+        private readonly Engine _engine;
+
+        public DebugHandler(Engine engine)
+        {
+            _engine = engine;
+            _debugCallStack = new Stack<string>();
+            _stepMode = StepMode.Into;
+        }
+
+        internal void PopDebugCallStack()
+        {
+            if (_debugCallStack.Count > 0)
+            {
+                _debugCallStack.Pop();
+            }
+            if (_stepMode == StepMode.Out && _debugCallStack.Count < _callBackStepOverDepth)
+            {
+                _callBackStepOverDepth = _debugCallStack.Count;
+                _stepMode = StepMode.Into;
+            }
+            else if (_stepMode == StepMode.Over && _debugCallStack.Count == _callBackStepOverDepth)
+            {
+                _callBackStepOverDepth = _debugCallStack.Count;
+                _stepMode = StepMode.Into;
+            }
+        }
+
+        internal void AddToDebugCallStack(CallExpression callExpression)
+        {
+            var identifier = callExpression.Callee as Identifier;
+            if (identifier != null)
+            {
+                var stack = identifier.Name + "(";
+                var paramStrings = new List<string>();
+
+                foreach (var argument in callExpression.Arguments)
+                {
+                    if (argument != null)
+                    {
+                        var argIdentifier = argument as Identifier;
+                        paramStrings.Add(argIdentifier != null ? argIdentifier.Name : "null");
+                    }
+                    else
+                    {
+                        paramStrings.Add("null");
+                    }
+                }
+
+                stack += string.Join(", ", paramStrings);
+                stack += ")";
+                _debugCallStack.Push(stack);
+            }
+        }
+
+        internal void OnStep(Statement statement)
+        {
+            var old = _stepMode;
+            if (statement == null)
+            {
+                return;
+            }
+            
+            BreakPoint breakpoint = _engine.BreakPoints.FirstOrDefault(breakPoint => BpTest(statement, breakPoint));
+            bool breakpointFound = false;
+
+            if (breakpoint != null)
+            {
+                DebugInformation info = CreateDebugInformation(statement);
+                var result = _engine.InvokeBreakEvent(info);
+                if (result.HasValue)
+                {
+                    _stepMode = result.Value;
+                    breakpointFound = true;
+                }
+            }
+
+            if (breakpointFound == false && _stepMode == StepMode.Into)
+            {
+                DebugInformation info = CreateDebugInformation(statement);
+                var result = _engine.InvokeStepEvent(info);
+                if (result.HasValue)
+                {
+                    _stepMode = result.Value;
+                }
+            }
+
+            if (old == StepMode.Into && _stepMode == StepMode.Out)
+            {
+                _callBackStepOverDepth = _debugCallStack.Count;
+            }
+            else if (old == StepMode.Into && _stepMode == StepMode.Over)
+            {
+                var expressionStatement = statement as ExpressionStatement;
+                if (expressionStatement != null && expressionStatement.Expression is CallExpression)
+                {
+                    _callBackStepOverDepth = _debugCallStack.Count;
+                }
+                else
+                {
+                    _stepMode = StepMode.Into;
+                }
+            }
+        }
+
+        private bool BpTest(Statement statement, BreakPoint breakpoint)
+        {
+            bool afterStart, beforeEnd;
+
+            afterStart = (breakpoint.Line == statement.Location.Start.Line &&
+                             breakpoint.Char >= statement.Location.Start.Column);
+
+            if (!afterStart)
+            {
+                return false;
+            }
+
+            beforeEnd = breakpoint.Line < statement.Location.End.Line
+                        || (breakpoint.Line == statement.Location.End.Line &&
+                            breakpoint.Char <= statement.Location.End.Column);
+
+            if (!beforeEnd)
+            {
+                return false;
+            }
+
+            if (!string.IsNullOrEmpty(breakpoint.Condition))
+            {
+                return _engine.Execute(breakpoint.Condition).GetCompletionValue().AsBoolean();
+            }
+
+            return true;
+        }
+
+        private DebugInformation CreateDebugInformation(Statement statement)
+        {
+            var info = new DebugInformation { CurrentStatement = statement, CallStack = _debugCallStack };
+
+            if (_engine.ExecutionContext != null && _engine.ExecutionContext.LexicalEnvironment != null)
+            {
+                var lexicalEnvironment = _engine.ExecutionContext.LexicalEnvironment;
+                info.Locals = GetLocalVariables(lexicalEnvironment);
+                info.Globals = GetGlobalVariables(lexicalEnvironment);
+            }
+
+            return info;
+        }
+
+        private static Dictionary<string, JsValue> GetLocalVariables(LexicalEnvironment lex)
+        {
+            Dictionary<string, JsValue> locals = new Dictionary<string, JsValue>();
+            if (lex != null && lex.Record != null)
+            {
+                AddRecordsFromEnvironment(lex, locals);
+            }
+            return locals;
+        }
+
+        private static Dictionary<string, JsValue> GetGlobalVariables(LexicalEnvironment lex)
+        {
+            Dictionary<string, JsValue> globals = new Dictionary<string, JsValue>();
+            LexicalEnvironment tempLex = lex;
+
+            while (tempLex != null && tempLex.Record != null)
+            {
+                AddRecordsFromEnvironment(tempLex, globals);
+                tempLex = tempLex.Outer;
+            }
+            return globals;
+        }
+
+        private static void AddRecordsFromEnvironment(LexicalEnvironment lex, Dictionary<string, JsValue> locals)
+        {
+            var bindings = lex.Record.GetAllBindingNames();
+            foreach (var binding in bindings)
+            {
+                if (locals.ContainsKey(binding) == false)
+                {
+                    var jsValue = lex.Record.GetBindingValue(binding, false);
+                    if (jsValue.TryCast<ICallable>() == null)
+                    {
+                        locals.Add(binding, jsValue);
+                    }
+                }
+            }
+        }
+    }
+}

+ 16 - 0
Jint/Runtime/Debugger/DebugInformation.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using Jint.Native;
+using Jint.Parser.Ast;
+using Jint.Runtime.Environments;
+
+namespace Jint.Runtime.Debugger
+{
+    public class DebugInformation : EventArgs
+    {
+        public Stack<String> CallStack { get; set; }
+        public Statement CurrentStatement { get; set; }
+        public Dictionary<string, JsValue> Locals { get; set; }
+        public Dictionary<string, JsValue> Globals { get; set; }
+    }
+}

+ 10 - 0
Jint/Runtime/Debugger/StepMode.cs

@@ -0,0 +1,10 @@
+namespace Jint.Runtime.Debugger
+{
+    public enum StepMode
+    {
+        None,
+        Over,
+        Into,
+        Out
+    }
+}

+ 12 - 22
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -3,16 +3,6 @@ using Jint.Native.Object;
 
 namespace Jint.Runtime.Descriptors
 {
-    public enum Fields
-    {
-        Get,
-        Set,
-        Enumerable,
-        Configurable,
-        Writable,
-        Value
-    }
-    
     public class PropertyDescriptor
     {
         public static PropertyDescriptor Undefined = new PropertyDescriptor();
@@ -27,17 +17,17 @@ namespace Jint.Runtime.Descriptors
 
             if (writable.HasValue)
             {
-                Writable = new JsValue(writable.Value);
+                Writable = writable.Value;
             }
 
             if (enumerable.HasValue)
             {
-                Enumerable = new JsValue(enumerable.Value);
+                Enumerable = enumerable.Value;
             }
 
             if (configurable.HasValue)
             {
-                Configurable = new JsValue(configurable.Value);
+                Configurable = configurable.Value;
             }
         }
 
@@ -48,12 +38,12 @@ namespace Jint.Runtime.Descriptors
 
             if (enumerable.HasValue)
             {
-                Enumerable = new JsValue(enumerable.Value);
+                Enumerable = enumerable.Value;
             }
 
             if (configurable.HasValue)
             {
-                Configurable = new JsValue(configurable.Value);
+                Configurable = configurable.Value;
             }
         }
 
@@ -69,9 +59,9 @@ namespace Jint.Runtime.Descriptors
 
         public JsValue? Get { get; set; }
         public JsValue? Set { get; set; }
-        public JsValue? Enumerable { get; set; }
-        public JsValue? Writable { get; set; }
-        public JsValue? Configurable { get; set; }
+        public bool? Enumerable { get; set; }
+        public bool? Writable { get; set; }
+        public bool? Configurable { get; set; }
         public virtual JsValue? Value { get; set; }
         
         public bool IsAccessorDescriptor()
@@ -182,8 +172,8 @@ namespace Jint.Runtime.Descriptors
 
             if (desc.IsDataDescriptor())
             {
-                obj.DefineOwnProperty("value", new PropertyDescriptor(value: desc.Value.HasValue ? desc.Value.Value : Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false);
-                obj.DefineOwnProperty("writable", new PropertyDescriptor(value: desc.Writable.HasValue && desc.Writable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);
+                obj.DefineOwnProperty("value", new PropertyDescriptor(value: desc.Value.HasValue ? desc.Value : Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false);
+                obj.DefineOwnProperty("writable", new PropertyDescriptor(value: desc.Writable.HasValue && desc.Writable.Value, writable: true, enumerable: true, configurable: true), false);
             }
             else
             {
@@ -191,8 +181,8 @@ namespace Jint.Runtime.Descriptors
                 obj.DefineOwnProperty("set", new PropertyDescriptor(desc.Set ?? Native.Undefined.Instance, writable: true, enumerable: true, configurable: true), false);
             }
 
-            obj.DefineOwnProperty("enumerable", new PropertyDescriptor(value: desc.Enumerable.HasValue && desc.Enumerable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);
-            obj.DefineOwnProperty("configurable", new PropertyDescriptor(value: desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);
+            obj.DefineOwnProperty("enumerable", new PropertyDescriptor(value: desc.Enumerable.HasValue && desc.Enumerable.Value, writable: true, enumerable: true, configurable: true), false);
+            obj.DefineOwnProperty("configurable", new PropertyDescriptor(value: desc.Configurable.HasValue && desc.Configurable.Value, writable: true, enumerable: true, configurable: true), false);
 
             return obj;
         }

+ 10 - 0
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.Linq;
 using Jint.Native;
 
 namespace Jint.Runtime.Environments
@@ -112,5 +113,14 @@ namespace Jint.Runtime.Environments
             var binding = _bindings[name];
             binding.Value = value;
         }
+
+        /// <summary>
+        /// Returns an array of all the defined binding names
+        /// </summary>
+        /// <returns>The array of all defined bindings</returns>
+        public override string[] GetAllBindingNames()
+        {
+            return _bindings.Keys.ToArray();
+        }
     }
 }

+ 5 - 1
Jint/Runtime/Environments/EnvironmentRecord.cs

@@ -56,6 +56,10 @@ namespace Jint.Runtime.Environments
         /// <returns>The value to use as <c>this</c>.</returns>
         public abstract JsValue ImplicitThisValue();
 
-
+        /// <summary>
+        /// Returns an array of all the defined binding names
+        /// </summary>
+        /// <returns>The array of all defined bindings</returns>
+        public abstract string[] GetAllBindingNames();
     }
 }

+ 11 - 1
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -1,4 +1,5 @@
-using Jint.Native;
+using System.Linq;
+using Jint.Native;
 using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 
@@ -72,5 +73,14 @@ namespace Jint.Runtime.Environments
 
             return Undefined.Instance;
         }
+
+        public override string[] GetAllBindingNames()
+        {
+            if (_bindingObject != null && _bindingObject.Properties != null)
+            {
+                return _bindingObject.Properties.Keys.ToArray();
+            }
+            return new string[0];
+        }
     }
 }

+ 10 - 0
Jint/Runtime/ExpressionIntepreter.cs

@@ -789,6 +789,11 @@ namespace Jint.Runtime
         {
             var callee = EvaluateExpression(callExpression.Callee);
 
+            if (_engine.Options.IsDebugMode())
+            {
+                _engine.DebugHandler.AddToDebugCallStack(callExpression);
+            }
+
             JsValue thisObject;
 
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
@@ -853,6 +858,11 @@ namespace Jint.Runtime
             
             var result = callable.Call(thisObject, arguments);
 
+            if (_engine.Options.IsDebugMode())
+            {
+                _engine.DebugHandler.PopDebugCallStack();
+            }
+
             if (isRecursionHandled)
             {
                 _engine.CallStack.Pop();

+ 15 - 12
Jint/Runtime/Interop/DefaultTypeConverter.cs

@@ -178,21 +178,24 @@ namespace Jint.Runtime.Interop
             bool canConvert;
             var key = value == null ? String.Format("Null->{0}", type) : String.Format("{0}->{1}", value.GetType(), type);
 
-            lock (_lockObject)
+            if (!_knownConversions.TryGetValue(key, out canConvert))
             {
-                if (!_knownConversions.TryGetValue(key, out canConvert))
+                lock (_lockObject)
                 {
-                    try
+                    if (!_knownConversions.TryGetValue(key, out canConvert))
                     {
-                        converted = Convert(value, type, formatProvider);
-                        _knownConversions.Add(key, true);
-                        return true;
-                    }
-                    catch
-                    {
-                        converted = null;
-                        _knownConversions.Add(key, false);
-                        return false;
+                        try
+                        {
+                            converted = Convert(value, type, formatProvider);
+                            _knownConversions.Add(key, true);
+                            return true;
+                        }
+                        catch
+                        {
+                            converted = null;
+                            _knownConversions.Add(key, false);
+                            return false;
+                        }
                     }
                 }
             }

+ 16 - 9
Jint/Runtime/Interop/DelegateWrapper.cs

@@ -27,11 +27,13 @@ namespace Jint.Runtime.Interop
             int delegateArgumentsCount = parameterInfos.Length;
             int delegateNonParamsArgumentsCount = delegateContainsParamsArgument ? delegateArgumentsCount - 1 : delegateArgumentsCount;
 
-            var parameters = new object[delegateArgumentsCount];
+            int jsArgumentsCount = jsArguments.Length;
+            int jsArgumentsWithoutParamsCount = Math.Min(jsArgumentsCount, delegateNonParamsArgumentsCount);
 
+            var parameters = new object[delegateArgumentsCount];
 
             // convert non params parameter to expected types
-            for (var i = 0; i < delegateNonParamsArgumentsCount; i++)
+            for (var i = 0; i < jsArgumentsWithoutParamsCount; i++)
             {
                 var parameterType = parameterInfos[i].ParameterType;
 
@@ -49,7 +51,7 @@ namespace Jint.Runtime.Interop
             }
 
             // assign null to parameters not provided
-            for (var i = jsArguments.Length; i < delegateNonParamsArgumentsCount; i++)
+            for (var i = jsArgumentsWithoutParamsCount; i < delegateNonParamsArgumentsCount; i++)
             {
                 if (parameterInfos[i].ParameterType.IsValueType)
                 {
@@ -64,24 +66,29 @@ namespace Jint.Runtime.Interop
             // assign params to array and converts each objet to expected type
             if(delegateContainsParamsArgument)
             {
-                object[] paramsParameter = new object[jsArguments.Length - delegateNonParamsArgumentsCount];
-                var paramsParameterType = parameterInfos[delegateArgumentsCount -1].ParameterType.GetElementType();
+                int paramsArgumentIndex = delegateArgumentsCount - 1;
+                int paramsCount = Math.Max(0, jsArgumentsCount - delegateNonParamsArgumentsCount);
 
-                for (var i = delegateNonParamsArgumentsCount; i < jsArguments.Length; i++)
+                object[] paramsParameter = new object[paramsCount];
+                var paramsParameterType = parameterInfos[paramsArgumentIndex].ParameterType.GetElementType();
+
+                for (var i = paramsArgumentIndex; i < jsArgumentsCount; i++)
                 {
+                    var paramsIndex = i - paramsArgumentIndex;
+
                     if (paramsParameterType == typeof(JsValue))
                     {
-                        paramsParameter[i - delegateNonParamsArgumentsCount] = jsArguments[i];
+                        paramsParameter[paramsIndex] = jsArguments[i];
                     }
                     else
                     {
-                        paramsParameter[i - delegateNonParamsArgumentsCount] = Engine.ClrTypeConverter.Convert(
+                        paramsParameter[paramsIndex] = Engine.ClrTypeConverter.Convert(
                             jsArguments[i].ToObject(),
                             paramsParameterType,
                             CultureInfo.InvariantCulture);
                     }                    
                 }
-                parameters[delegateNonParamsArgumentsCount] = paramsParameter;
+                parameters[paramsArgumentIndex] = paramsParameter;
             }
 
             return JsValue.FromObject(Engine, _d.DynamicInvoke(parameters));

+ 20 - 0
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -45,6 +45,23 @@ namespace Jint.Runtime.Interop
                     {
                         parameters[i] = arguments[i];
                     }
+                    else if (parameterType == typeof(JsValue[]) && arguments[i].IsArray())
+                    {
+                        // Handle specific case of F(params JsValue[])
+
+                        var arrayInstance = arguments[i].AsArray();
+                        var len = TypeConverter.ToInt32(arrayInstance.Get("length"));
+                        var result = new JsValue[len];
+                        for (var k = 0; k < len; k++)
+                        {
+                            var pk = k.ToString();
+                            result[k] = arrayInstance.HasProperty(pk)
+                                ? arrayInstance.Get(pk)
+                                : JsValue.Undefined;
+                        }
+
+                        parameters[i] = result;
+                    }
                     else
                     {
                         if (!converter.TryConvert(arguments[i].ToObject(), parameterType, CultureInfo.InvariantCulture, out parameters[i]))
@@ -73,6 +90,9 @@ namespace Jint.Runtime.Interop
             throw new JavaScriptException(Engine.TypeError, "No public methods with the specified arguments were found.");
         }
 
+        /// <summary>
+        /// Reduces a flat list of parameters to a params array
+        /// </summary>
         private JsValue[] ProcessParamsArrays(JsValue[] jsArguments, IEnumerable<MethodInfo> methodInfos)
         {
             foreach (var methodInfo in methodInfos)

+ 57 - 6
Jint/Runtime/Interop/NamespaceReference.cs

@@ -1,4 +1,5 @@
-using System;
+using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Reflection;
@@ -110,7 +111,7 @@ namespace Jint.Runtime.Interop
                 }
             }
 
-            // search in lookup asemblies
+            // search in lookup assemblies
             foreach (var assembly in Engine.Options.GetLookupAssemblies())
             {
                 type = assembly.GetType(path);
@@ -118,16 +119,66 @@ namespace Jint.Runtime.Interop
                 {
                     Engine.TypeCache.Add(path, type);
                     return TypeReference.CreateTypeReference(Engine, type);
-                }
+                }
+
+                var lastPeriodPos = path.LastIndexOf(".", StringComparison.Ordinal);
+                var trimPath = path.Substring(0, lastPeriodPos);
+                type = GetType(assembly, trimPath);
+                if (type != null)
+                  foreach (Type nType in GetAllNestedTypes(type))
+                  {
+                    if (nType.FullName.Replace("+", ".").Equals(path.Replace("+", ".")))
+                    {
+                      Engine.TypeCache.Add(path.Replace("+", "."), nType);
+                      return TypeReference.CreateTypeReference(Engine, nType);
+                    }
+                  }            
             }
 
             // the new path doesn't represent a known class, thus return a new namespace instance
 
             Engine.TypeCache.Add(path, null);
             return new NamespaceReference(Engine, path);
-        }
-
-        public override PropertyDescriptor GetOwnProperty(string propertyName)
+        }
+
+        /// <summary>   Gets a type. </summary>
+        ///<remarks>Nested type separators are converted to '.' instead of '+' </remarks>
+        /// <param name="assembly"> The assembly. </param>
+        /// <param name="typeName"> Name of the type. </param>
+        ///
+        /// <returns>   The type. </returns>
+
+        private static Type GetType(Assembly assembly, string typeName)
+        {
+            Type[] types = assembly.GetTypes();
+            foreach (Type t in types)
+            {
+                if (t.FullName.Replace("+", ".") == typeName.Replace("+", "."))
+                {
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        private static IEnumerable<Type> GetAllNestedTypes(Type type)
+        {
+          var types = new List<Type>();
+          AddNestedTypesRecursively(types, type);
+          return types.ToArray();
+        }
+
+        private static void AddNestedTypesRecursively(List<Type> types, Type type)
+        {
+          Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public);
+          foreach (Type nestedType in nestedTypes)
+          {
+            types.Add(nestedType);
+            AddNestedTypesRecursively(types, nestedType);
+          }
+        }
+
+      public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             return PropertyDescriptor.Undefined;
         }

+ 28 - 9
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Linq;
 using System.Reflection;
 using Jint.Native;
@@ -60,8 +60,9 @@ namespace Jint.Runtime.Interop
             var type = Target.GetType();
 
             // look for a property
-            var property = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
-
+            var property = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public)
+                .Where(p => EqualsIgnoreCasing(p.Name, propertyName))
+                .FirstOrDefault();
             if (property != null)
             {
                 var descriptor = new PropertyInfoDescriptor(Engine, property, Target);
@@ -70,8 +71,9 @@ namespace Jint.Runtime.Interop
             }
 
             // look for a field
-            var field = type.GetField(propertyName, BindingFlags.Instance | BindingFlags.Public);
-
+            var field = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public)
+                .Where(f => EqualsIgnoreCasing(f.Name, propertyName))
+                .FirstOrDefault();
             if (field != null)
             {
                 var descriptor = new FieldInfoDescriptor(Engine, field, Target);
@@ -80,8 +82,8 @@ namespace Jint.Runtime.Interop
             }
 
             // if no properties were found then look for a method 
-            var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
-                .Where(m => m.Name == propertyName)
+            var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public)
+                .Where(m => EqualsIgnoreCasing(m.Name, propertyName))
                 .ToArray();
 
             if (methods.Any())
@@ -102,7 +104,7 @@ namespace Jint.Runtime.Interop
             // try to find a single explicit property implementation
             var explicitProperties = (from iface in interfaces
                                       from iprop in iface.GetProperties()
-                                      where propertyName.Equals(iprop.Name)
+                                      where EqualsIgnoreCasing(iprop.Name, propertyName)
                                       select iprop).ToArray();
 
             if (explicitProperties.Length == 1)
@@ -115,7 +117,7 @@ namespace Jint.Runtime.Interop
             // try to find explicit method implementations
             var explicitMethods = (from iface in interfaces
                                    from imethod in iface.GetMethods()
-                                   where propertyName.Equals(imethod.Name)
+                                   where EqualsIgnoreCasing(imethod.Name, propertyName)
                                    select imethod).ToArray();
 
             if (explicitMethods.Length > 0)
@@ -139,5 +141,22 @@ namespace Jint.Runtime.Interop
 
             return PropertyDescriptor.Undefined;
         }
+
+        private bool EqualsIgnoreCasing(string s1, string s2)
+        {
+            bool equals = false;
+            if (s1.Length == s2.Length)
+            {
+                if (s1.Length > 0 && s2.Length > 0) 
+                {
+                    equals = (s1.ToLower()[0] == s2.ToLower()[0]);
+                }
+                if (s1.Length > 1 && s2.Length > 1) 
+                {
+                    equals = equals && (s1.Substring(1) == s2.Substring(1));
+                }
+            }
+            return equals;
+        }
     }
 }

+ 6 - 0
Jint/Runtime/JavaScriptException.cs

@@ -43,5 +43,11 @@ namespace Jint.Runtime
         {
             return _errorObject.ToString();
         }
+
+        public Jint.Parser.Location Location { get; set; }
+
+        public int LineNumber { get { return null == Location ? 0 : Location.Start.Line; } }
+
+        public int Column { get { return null == Location ? 0 : Location.Start.Column; } }
     }
 }

+ 165 - 0
Jint/Runtime/MruPropertyCache.cs

@@ -0,0 +1,165 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Jint.Runtime
+{
+    public class MruPropertyCache<TKey, TValue> : IDictionary<TKey, TValue>
+    {
+        private IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
+        private LinkedList<KeyValuePair<TKey, TValue>> _list;
+        private uint _length;
+
+        public MruPropertyCache(uint length) {
+            _length = length;
+            _list = new LinkedList<KeyValuePair<TKey, TValue>>();
+            for(int i=0; i<length; i++) {
+                _list.AddLast(new KeyValuePair<TKey, TValue>(default(TKey), default(TValue)));
+            }
+        }
+
+        private bool Find(TKey key, out LinkedListNode<KeyValuePair<TKey, TValue>> result) {
+            result = _list.First;
+            while(result != null) {
+                if(key.Equals(result.Value.Key)) {
+                    return true;
+                }
+
+                result = result.Next;
+            }
+
+            return false;
+        }
+        public TValue this[TKey key] {
+            get {
+                LinkedListNode<KeyValuePair<TKey, TValue>> node;
+                if(Find(key, out node)) {
+                    return node.Value.Value;
+                }
+                
+                return _dictionary[key];
+            }
+
+            set {
+                LinkedListNode<KeyValuePair<TKey, TValue>> node;
+                if (!Find(key, out node)) {
+                    _list.AddFirst(new KeyValuePair<TKey, TValue>(key, value));
+                    _list.RemoveLast();
+                }
+                else
+                {
+                    node.Value = new KeyValuePair<TKey, TValue>(key, value);
+                }
+
+                _dictionary[key] = value;
+            }
+        }
+
+        public int Count {
+            get {
+                return _dictionary.Count;
+            }
+        }
+
+        public bool IsReadOnly {
+            get {
+                return _dictionary.IsReadOnly;
+            }
+        }
+
+        public ICollection<TKey> Keys {
+            get {
+                return _dictionary.Keys;
+            }
+        }
+
+        public ICollection<TValue> Values {
+            get {
+                return _dictionary.Values;
+            }
+        }
+
+        public void Add(KeyValuePair<TKey, TValue> item) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (!Find(item.Key, out node)) {
+                _list.AddFirst(item);
+                _list.RemoveLast();
+            }
+
+            _dictionary.Add(item);
+        }
+
+        public void Add(TKey key, TValue value) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (!Find(key, out node)) {
+                _list.AddFirst(new KeyValuePair<TKey, TValue>(key, value));
+                _list.RemoveLast();
+            }
+            _dictionary.Add(key, value);
+        }
+
+        public void Clear() {
+            _list.Clear();
+            _dictionary.Clear();
+        }
+
+        public bool Contains(KeyValuePair<TKey, TValue> item) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (Find(item.Key, out node)) {
+                return true;
+            }
+
+            return _dictionary.Contains(item);
+        }
+
+        public bool ContainsKey(TKey key) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (Find(key, out node)) {
+                return true;
+            }
+
+            return _dictionary.ContainsKey(key);
+        }
+
+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
+            _dictionary.CopyTo(array, arrayIndex);
+        }
+
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
+            return _dictionary.GetEnumerator();
+        }
+
+        public bool Remove(KeyValuePair<TKey, TValue> item) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (Find(item.Key, out node))
+            {
+                _list.Remove(node);
+            }
+
+            return _dictionary.Remove(item);
+        }
+
+        public bool Remove(TKey key) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (Find(key, out node))
+            {
+                _list.Remove(node);
+            }
+
+            return _dictionary.Remove(key);
+        }
+
+        public bool TryGetValue(TKey key, out TValue value) {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (Find(key, out node)) {
+                value = node.Value.Value;
+                return true;
+            }
+
+            return _dictionary.TryGetValue(key, out value);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator() {
+            return _dictionary.GetEnumerator();
+        }
+    }
+}

+ 157 - 0
Jint/Runtime/MruPropertyCache2.cs

@@ -0,0 +1,157 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Jint.Runtime {
+    public class MruPropertyCache2<TKey, TValue> : IDictionary<TKey, TValue> 
+        where TKey:class 
+        where TValue:class
+    {
+        private IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
+        private TKey _key;
+        private TValue _value;
+
+        public MruPropertyCache2() {
+        }
+
+        public TValue this[TKey key] {
+            get {
+                if (_value != null)
+                {
+                    if (key.Equals(_key))
+                    {
+                        return _value;
+                    }
+                }
+
+                return _dictionary[key];
+            }
+
+            set {
+                if(value != null)
+                {
+                    _key = key;
+                    _value = value;
+                }
+
+                _dictionary[key] = value;
+            }
+        }
+
+        public int Count {
+            get {
+                return _dictionary.Count;
+            }
+        }
+
+        public bool IsReadOnly {
+            get {
+                return _dictionary.IsReadOnly;
+            }
+        }
+
+        public ICollection<TKey> Keys {
+            get {
+                return _dictionary.Keys;
+            }
+        }
+
+        public ICollection<TValue> Values {
+            get {
+                return _dictionary.Values;
+            }
+        }
+
+        public void Add(KeyValuePair<TKey, TValue> item) {
+            if(item.Value != null)
+            {
+                _key = item.Key;
+                _value = item.Value;
+            }
+
+            _dictionary.Add(item);
+        }
+
+        public void Add(TKey key, TValue value) {
+            if (value != null)
+            {
+                _key = key;
+                _value = value;
+            }
+
+            _dictionary.Add(key, value);
+        }
+
+        public void Clear() {
+            _key = null;
+            _value = null;
+
+            _dictionary.Clear();
+        }
+
+        public bool Contains(KeyValuePair<TKey, TValue> item) {
+            if(item.Key.Equals(_key) && _value != null)
+            {
+                return true;
+            }
+
+            return _dictionary.Contains(item);
+        }
+
+        public bool ContainsKey(TKey key) {
+            if (key.Equals(_key) && _value != null)
+            {
+                return true;
+            }
+
+            return _dictionary.ContainsKey(key);
+        }
+
+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
+            _dictionary.CopyTo(array, arrayIndex);
+        }
+
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
+            return _dictionary.GetEnumerator();
+        }
+
+        public bool Remove(KeyValuePair<TKey, TValue> item) {
+            if(item.Key.Equals(_key))
+            {
+                _key = null;
+                _value = null;
+            }
+
+            return _dictionary.Remove(item);
+        }
+
+        public bool Remove(TKey key) {
+            if (key.Equals(_key))
+            {
+                _key = null;
+                _value = null;
+            }
+
+            return _dictionary.Remove(key);
+        }
+
+        public bool TryGetValue(TKey key, out TValue value) {
+            if (_value != null)
+            {
+                if (key.Equals(_key))
+                {
+                    value = _value;
+                    return true;
+                }
+            }
+
+            return _dictionary.TryGetValue(key, out value);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator() {
+            return _dictionary.GetEnumerator();
+        }
+    }
+}

+ 10 - 3
Jint/Runtime/StatementInterpreter.cs

@@ -244,7 +244,7 @@ namespace Jint.Runtime
                     }
 
                     var value = cursor.Properties[p];
-                    if (!value.Enumerable.HasValue || !value.Enumerable.Value.AsBoolean())
+                    if (!value.Enumerable.HasValue || !value.Enumerable.Value)
                     {
                         continue;
                     }
@@ -332,6 +332,7 @@ namespace Jint.Runtime
             catch (JavaScriptException e)
             {
                 c = new Completion(Completion.Throw, e.Error, null);
+                c.Location = withStatement.Location;
             }
             finally
             {
@@ -409,11 +410,13 @@ namespace Jint.Runtime
         {
             var c = new Completion(Completion.Normal, null, null);
             Completion sl = c;
+            Statement s = null;
 
             try
             {
                 foreach (var statement in statementList)
                 {
+                    s = statement;
                     c = ExecuteStatement(statement);
                     if (c.Type != Completion.Normal)
                     {
@@ -425,7 +428,9 @@ namespace Jint.Runtime
             }
             catch(JavaScriptException v)
             {
-                return new Completion(Completion.Throw, v.Error, null);
+                c = new Completion(Completion.Throw, v.Error, null);
+                c.Location = s.Location;
+                return c;
             }
 
             return new Completion(c.Type, c.GetValueOrDefault(), c.Identifier);
@@ -439,7 +444,9 @@ namespace Jint.Runtime
         public Completion ExecuteThrowStatement(ThrowStatement throwStatement)
         {
             var exprRef = _engine.EvaluateExpression(throwStatement.Argument);
-            return new Completion(Completion.Throw, _engine.GetValue(exprRef), null);
+            Completion c = new Completion(Completion.Throw, _engine.GetValue(exprRef), null);
+            c.Location = throwStatement.Location;
+            return c;
         }
 
         /// <summary>

+ 2 - 2
README.md

@@ -50,7 +50,7 @@ You can also directly pass POCOs or anonymous objects and use them from JavaScri
 You can invoke JavaScript function reference
 ```c#
     var add = new Engine()
-        .Execute("function add(a, b) { return a + b; }");
+        .Execute("function add(a, b) { return a + b; }")
         .GetValue("add")
         ;
 
@@ -72,7 +72,7 @@ You can allow an engine to access any .NET class by configuring the engine insta
 ```
 Then you have access to the `System` namespace as a global value. Here is how it's used in the context on the command line utility:
 ```javascript
-    jint> var file = new System.IO.File('log.txt');
+    jint> var file = new System.IO.StreamWriter('log.txt');
     jint> file.WriteLine('Hello World !');
     jint> file.Dispose();
 ```

+ 1 - 0
buildnuget.cmd

@@ -0,0 +1 @@
+nuget pack jint\Jint.csproj -Properties Configuration=Release