浏览代码

Upgrade to Esprima 1.0.1270 (#712)

Marko Lahma 5 年之前
父节点
当前提交
9e7027abcd

+ 3 - 2
Jint.Benchmark/EngineConstructionBenchmark.cs

@@ -1,17 +1,18 @@
 using BenchmarkDotNet.Attributes;
 using Esprima;
+using Esprima.Ast;
 
 namespace Jint.Benchmark
 {
     [MemoryDiagnoser]
     public class EngineConstructionBenchmark
     {
-        private readonly Esprima.Ast.Program _program;
+        private readonly Script _program;
 
         public EngineConstructionBenchmark()
         {
             var parser = new JavaScriptParser("return [].length + ''.length");
-            _program = parser.ParseProgram();
+            _program = parser.ParseScript();
         }
 
         [Benchmark]

+ 1 - 1
Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFrameworks>net461;netcoreapp3.1</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
     <EmbeddedResource Include="Scripts\*.*" />

+ 1 - 1
Jint.Tests.Ecma/Jint.Tests.Ecma.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Jint\Jint.csproj" />

+ 1 - 1
Jint.Tests.Test262/Jint.Tests.Test262.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFrameworks>net452;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net461;netcoreapp3.1</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Jint\Jint.csproj" />

+ 13 - 197
Jint.Tests.Test262/test/skipped.json

@@ -61,6 +61,10 @@
     "source": "built-ins/Symbol/species/builtin-getter-name.js",
     "reason": "Promise not implemented"
   },
+  {
+    "source": "language/expressions/object/method-definition/object-method-returns-promise.js",
+    "reason": "Promise not implemented"
+  },
   {
     "source": "built-ins/Symbol/species/subclassing.js",
     "reason": "subclassing not implemented"
@@ -613,199 +617,11 @@
   },
 
   // Esprima problems
-  
-  {
-    "source": "language/statements/for/dstr-var-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-var-obj-ptrn-rest-skip-non-enumerable",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-var-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-const-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-const-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-const-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-const-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-let-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-let-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-let-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/statements/for/dstr-var-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/call/trailing-comma.js",
-    "reason": "Esprima problem"
-  },
+
   {
     "source": "language/statements/for/head-lhs-let.js",
     "reason": "Esprima problem"
   },
-  {
-    "source": "language/white-space/mongolian-vowel-separator-eval.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dflt-params-trailing-comma.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-dflt-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-dflt-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-dflt-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/params-trailing-comma-multiple.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/arrow-function/params-trailing-comma-single.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dflt-params-trailing-comma.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-dflt-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-dflt-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-dflt-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/dstr-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/params-trailing-comma-multiple.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-getter.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-val-obj.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/let-non-strict-access.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/async-meth-dflt-params-abrupt.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/async-meth-dflt-params-arg-val-not-undefined.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-later.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-prior.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-self.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-skip-non-enumerable.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/let-non-strict-syntax.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/meth-dflt-params-trailing-comma.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/meth-params-trailing-comma-multiple.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/meth-params-trailing-comma-single.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/object/method-definition/name-param-id-yield.js",
-    "reason": "Esprima problem"
-  },
   {
     "source": "language/expressions/object/yield-non-strict-access.js",
     "reason": "Esprima problem"
@@ -814,14 +630,6 @@
     "source": "language/expressions/object/yield-non-strict-syntax.js",
     "reason": "Esprima problem"
   },
-  {
-    "source": "language/expressions/object/method-definition/object-method-returns-promise.js",
-    "reason": "Esprima problem"
-  },
-  {
-    "source": "language/expressions/function/params-trailing-comma-single.js",
-    "reason": "Esprima problem"
-  },
   {
     "source": "built-ins/RegExp/prototype/source/value-u.js",
     "reason": "Esprima problem"
@@ -854,4 +662,12 @@
     "source": "built-ins/RegExp/S15.10.2.13_A2_T8.js",
     "reason": "Esprima problem"
   },
+  {
+    "source": "language/expressions/object/let-non-strict-access.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/let-non-strict-syntax.js",
+    "reason": "Esprima problem"
+  },
 ]

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

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp3.0;net452</TargetFrameworks>
+    <TargetFrameworks>net461;netcoreapp3.1</TargetFrameworks>
   </PropertyGroup>
   <ItemGroup>
     <EmbeddedResource Include="Runtime\Scripts\*.*;Parser\Scripts\*.*" />
@@ -9,7 +9,7 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.CSharp" Condition=" '$(TargetFramework)' == 'net452' " />
+    <Reference Include="Microsoft.CSharp" Condition=" '$(TargetFramework)' == 'net461' " />
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />

+ 9 - 9
Jint.Tests/Parser/JavascriptParserTests.cs

@@ -12,7 +12,7 @@ namespace Jint.Tests.Parser
         [Fact]
         public void ShouldParseThis()
         {
-            var program = new JavaScriptParser("this").ParseProgram();
+            var program = new JavaScriptParser("this").ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -22,7 +22,7 @@ namespace Jint.Tests.Parser
         [Fact]
         public void ShouldParseNull()
         {
-            var program = new JavaScriptParser("null").ParseProgram();
+            var program = new JavaScriptParser("null").ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -37,7 +37,7 @@ namespace Jint.Tests.Parser
             var program = new JavaScriptParser(
                 @"
                 42
-            ").ParseProgram();
+            ").ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -51,7 +51,7 @@ namespace Jint.Tests.Parser
         {
             BinaryExpression binary;
 
-            var program = new JavaScriptParser("(1 + 2 ) * 3").ParseProgram();
+            var program = new JavaScriptParser("(1 + 2 ) * 3").ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -87,7 +87,7 @@ namespace Jint.Tests.Parser
         {
             Literal literal;
 
-            var program = new JavaScriptParser(source).ParseProgram();
+            var program = new JavaScriptParser(source).ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -106,7 +106,7 @@ namespace Jint.Tests.Parser
         {
             Literal literal;
 
-            var program = new JavaScriptParser(source).ParseProgram();
+            var program = new JavaScriptParser(source).ParseScript();
             var body = program.Body;
 
             Assert.Single(body);
@@ -149,7 +149,7 @@ namespace Jint.Tests.Parser
 
         public void ShouldInsertSemicolons(string source)
         {
-            new JavaScriptParser(source).ParseProgram();
+            new JavaScriptParser(source).ParseScript();
         }
 
         [Fact]
@@ -159,7 +159,7 @@ namespace Jint.Tests.Parser
 \
 '
 ";
-            var program = new JavaScriptParser(source, new ParserOptions { Loc = true }).ParseProgram();
+            var program = new JavaScriptParser(source, new ParserOptions { Loc = true }).ParseScript();
             var expr = program.Body.First().As<ExpressionStatement>().Expression;
             Assert.Equal(1, expr.Location.Start.Line);
             Assert.Equal(0, expr.Location.Start.Column);
@@ -181,7 +181,7 @@ namespace Jint.Tests.Parser
         [InlineData("-.-")]
         public void ShouldThrowParserExceptionForInvalidCode(string code)
         {
-            Assert.Throws<ParserException>(() => new JavaScriptParser(code).ParseProgram());
+            Assert.Throws<ParserException>(() => new JavaScriptParser(code).ParseScript());
         }
     }
 }

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

@@ -1458,7 +1458,12 @@ var prep = function (fn) { fn(); };
             Assert.Equal(new DateTime(1, 1, 1, 0, 0, 0, DateTimeKind.Utc), minValue);
 
             var maxValue = engine.Execute("new Date('9999-12-31T23:59:59.999')").GetCompletionValue().ToObject();
+
+#if NETCOREAPP
+            Assert.Equal(new DateTime(9999, 12, 31, 23, 59, 59, 998, DateTimeKind.Utc), maxValue);
+#else
             Assert.Equal(new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc), maxValue);
+#endif
         }
 
         [Fact]

+ 3 - 3
Jint/Engine.cs

@@ -399,10 +399,10 @@ namespace Jint
         public Engine Execute(string source, ParserOptions parserOptions)
         {
             var parser = new JavaScriptParser(source, parserOptions);
-            return Execute(parser.ParseProgram());
+            return Execute(parser.ParseScript());
         }
 
-        public Engine Execute(Program program)
+        public Engine Execute(Script program)
         {
             ResetStatementsCount();
 
@@ -863,7 +863,7 @@ namespace Jint
         }
 
         private void AddFunctionDeclarations(
-            ref NodeList<FunctionDeclaration> functionDeclarations,
+            ref NodeList<IFunctionDeclaration> functionDeclarations,
             EnvironmentRecord env,
             bool configurableBindings,
             bool strict)

+ 2 - 2
Jint/Jint.csproj

@@ -1,12 +1,12 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <NeutralLanguage>en-US</NeutralLanguage>
-    <TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
+    <TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks>
     <AssemblyOriginatorKeyFile>Jint.snk</AssemblyOriginatorKeyFile>
     <SignAssembly>true</SignAssembly>
     <LangVersion>latest</LangVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="1.0.1258" />
+    <PackageReference Include="Esprima" Version="1.0.1270" />
   </ItemGroup>
 </Project>

+ 1 - 1
Jint/Native/Function/EvalFunctionInstance.cs

@@ -36,7 +36,7 @@ namespace Jint.Native.Function
             try
             {
                 var parser = new JavaScriptParser(code, ParserOptions);
-                var program = parser.ParseProgram(StrictModeScope.IsStrictModeCode);
+                var program = parser.ParseScript(StrictModeScope.IsStrictModeCode);
                 using (new StrictModeScope(program.Strict))
                 {
                     using (new EvalCodeScope())

+ 2 - 2
Jint/Native/Function/FunctionConstructor.cs

@@ -73,7 +73,7 @@ namespace Jint.Native.Function
             {
                 var functionExpression = "function f(" + p + ") { " + body + "}";
                 var parser = new JavaScriptParser(functionExpression, ParserOptions);
-                function = (IFunction) parser.ParseProgram().Body[0];
+                function = (IFunction) parser.ParseScript().Body[0];
             }
             catch (ParserException)
             {
@@ -95,7 +95,7 @@ namespace Jint.Native.Function
         /// </summary>
         /// <param name="functionDeclaration"></param>
         /// <returns></returns>
-        public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration)
+        public FunctionInstance CreateFunctionObject(IFunctionDeclaration functionDeclaration)
         {
             var functionObject = new ScriptFunctionInstance(
                 Engine,

+ 1 - 1
Jint/Native/Json/JsonParser.cs

@@ -552,7 +552,7 @@ namespace Jint.Native.Json
         {
             if (_extra.Range != null)
             {
-                node.Range = new Range(_state.MarkerStack.Pop(), _index);
+                node.Range = new Esprima.Ast.Range(_state.MarkerStack.Pop(), _index);
             }
             if (_extra.Loc.HasValue)
             {

+ 19 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -1197,6 +1197,25 @@ namespace Jint.Native.Object
             return jsValue as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(engine, "Value returned for property '" + p + "' of object is not a function");
         }
 
+        internal ObjectInstance CreateRestObject(
+            HashSet<string> processedProperties)
+        {
+            var rest = _engine.Object.Construct(_properties.Count - processedProperties.Count);
+            foreach (var pair in _properties)
+            {
+                if (!processedProperties.Contains(pair.Key))
+                {
+                    var descriptor = pair.Value;
+                    if (descriptor.Enumerable)
+                    {
+                        rest.SetDataProperty(pair.Key, UnwrapJsValue(descriptor, this));
+                    }
+                }
+            }
+
+            return rest;
+        }
+
         internal ObjectInstance AssertThisIsObjectInstance(JsValue value, string methodName)
         {
             return value as ObjectInstance ?? ThrowIncompatibleReceiver<ObjectInstance>(value, methodName);

+ 119 - 66
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using Esprima.Ast;
 using Jint.Collections;
@@ -179,7 +180,7 @@ namespace Jint.Runtime.Environments
 
         private void SetFunctionParameterUnlikely(
             INode parameter,
-            JsValue[]arguments,
+            JsValue[] arguments,
             int index,
             bool initiallyEmpty)
         {
@@ -187,32 +188,7 @@ namespace Jint.Runtime.Environments
 
             if (parameter is RestElement restElement)
             {
-                // index + 1 == parameters.count because rest is last
-                int restCount = arguments.Length - (index + 1) + 1;
-                uint count = restCount > 0 ? (uint) restCount : 0;
-
-                var rest = _engine.Array.ConstructFast(count);
-
-                uint targetIndex = 0;
-                for (var argIndex = index; argIndex < arguments.Length; ++argIndex)
-                {
-                    rest.SetIndexValue(targetIndex++, arguments[argIndex], updateLength: false);
-                }
-
-                argument = rest;
-
-                if (restElement.Argument is Identifier restIdentifier)
-                {
-                    SetItemSafely(restIdentifier.Name, argument, initiallyEmpty);
-                }
-                else if (restElement.Argument is BindingPattern bindingPattern)
-                {
-                    SetFunctionParameter(bindingPattern, new [] { argument }, index, initiallyEmpty);
-                }
-                else
-                {
-                    ExceptionHelper.ThrowSyntaxError(_engine, "Rest parameters can only be identifiers or arrays");
-                }
+                HandleRestElementArray(restElement, arguments, index, initiallyEmpty);
             }
             else if (parameter is ArrayPattern arrayPattern)
             {
@@ -263,67 +239,144 @@ namespace Jint.Runtime.Environments
 
                 var argumentObject = argument.AsObject();
 
+                var processedProperties = objectPattern.Properties.Count > 0 && objectPattern.Properties[objectPattern.Properties.Count - 1] is RestElement
+                    ? new HashSet<string>()
+                    : null;
+
                 var jsValues = _engine._jsValueArrayPool.RentArray(1);
                 foreach (var property in objectPattern.Properties)
                 {
-                    if (property.Key is Identifier propertyIdentifier)
-                    {
-                        argument = argumentObject.Get(propertyIdentifier.Name);
-                    }
-                    else if (property.Key is Literal propertyLiteral)
+                    if (property is Property p)
                     {
-                        argument = argumentObject.Get(propertyLiteral.Raw);
+                        JsString propertyName;
+                        if (p.Key is Identifier propertyIdentifier)
+                        {
+                            propertyName = JsString.Create(propertyIdentifier.Name);
+                        }
+                        else if (p.Key is Literal propertyLiteral)
+                        {
+                            propertyName = JsString.Create(propertyLiteral.Raw);
+                        }
+                        else if (p.Key is CallExpression callExpression)
+                        {
+                            var jintCallExpression = JintExpression.Build(_engine, callExpression);
+                            propertyName = (JsString) jintCallExpression.GetValue();
+                        }
+                        else
+                        {
+                            propertyName = ExceptionHelper.ThrowArgumentOutOfRangeException<JsString>("property", "unknown object pattern property type");
+                        }
+
+                        processedProperties?.Add(propertyName.AsStringWithoutTypeCheck());
+                        jsValues[0] = argumentObject.Get(propertyName);
+                        SetFunctionParameter(p.Value, jsValues, 0, initiallyEmpty);
                     }
-                    else if (property.Key is CallExpression callExpression)
+                    else
                     {
-                        var jintCallExpression = JintExpression.Build(_engine, callExpression);
-                        argument = argumentObject.Get(jintCallExpression.GetValue().AsString());
+                        if (((RestElement) property).Argument is Identifier restIdentifier)
+                        {
+                            var rest = argumentObject.CreateRestObject(processedProperties);
+                            SetItemSafely(restIdentifier.Name, rest, initiallyEmpty);
+                        }
+                        else
+                        {
+                            ExceptionHelper.ThrowSyntaxError(_engine, "Object rest parameter can only be objects");
+                        }
                     }
-
-                    jsValues[0] = argument;
-                    SetFunctionParameter(property.Value, jsValues, 0, initiallyEmpty);
                 }
                 _engine._jsValueArrayPool.ReturnArray(jsValues);
             }
             else if (parameter is AssignmentPattern assignmentPattern)
             {
-                var idLeft = assignmentPattern.Left as Identifier;
-                if (idLeft != null
-                    && assignmentPattern.Right is Identifier idRight
-                    && idLeft.Name == idRight.Name)
+                HandleAssignmentPatternOrExpression(assignmentPattern.Left, assignmentPattern.Right, argument, initiallyEmpty);
+            }
+            else if (parameter is AssignmentExpression assignmentExpression)
+            {
+                HandleAssignmentPatternOrExpression(assignmentExpression.Left, assignmentExpression.Right, argument, initiallyEmpty);
+            }
+        }
+
+        private void HandleRestElementArray(
+            RestElement restElement,
+            JsValue[] arguments,
+            int index,
+            bool initiallyEmpty)
+        {
+            // index + 1 == parameters.count because rest is last
+            int restCount = arguments.Length - (index + 1) + 1;
+            uint count = restCount > 0 ? (uint) restCount : 0;
+
+            var rest = _engine.Array.ConstructFast(count);
+
+            uint targetIndex = 0;
+            for (var argIndex = index; argIndex < arguments.Length; ++argIndex)
+            {
+                rest.SetIndexValue(targetIndex++, arguments[argIndex], updateLength: false);
+            }
+
+            if (restElement.Argument is Identifier restIdentifier)
+            {
+                SetItemSafely(restIdentifier.Name, rest, initiallyEmpty);
+            }
+            else if (restElement.Argument is BindingPattern bindingPattern)
+            {
+                SetFunctionParameter(bindingPattern, new JsValue[]
                 {
-                    ExceptionHelper.ThrowReferenceError(_engine, idRight.Name);
-                }
+                    rest
+                }, index, initiallyEmpty);
+            }
+            else
+            {
+                ExceptionHelper.ThrowSyntaxError(_engine, "Rest parameters can only be identifiers or arrays");
+            }
+        }
 
-                if (argument.IsUndefined())
+        private void HandleAssignmentPatternOrExpression(
+            INode left,
+            INode right,
+            JsValue argument,
+            bool initiallyEmpty)
+        {
+            var idLeft = left as Identifier;
+            if (idLeft != null
+                && right is Identifier idRight
+                && idLeft.Name == idRight.Name)
+            {
+                ExceptionHelper.ThrowReferenceError(_engine, idRight.Name);
+            }
+
+            if (argument.IsUndefined())
+            {
+                JsValue RunInNewParameterEnvironment(JintExpression exp)
                 {
-                    JsValue RunInNewParameterEnvironment(JintExpression exp)
-                    {
-                        var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
-                        var paramVarEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, oldEnv);
+                    var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
+                    var paramVarEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, oldEnv);
 
-                        _engine.EnterExecutionContext(paramVarEnv, paramVarEnv, _engine.ExecutionContext.ThisBinding);
-                        var result = exp.GetValue();
-                        _engine.LeaveExecutionContext();
+                    _engine.EnterExecutionContext(paramVarEnv, paramVarEnv, _engine.ExecutionContext.ThisBinding);
+                    var result = exp.GetValue();
+                    _engine.LeaveExecutionContext();
 
-                        return result;
-                    }
+                    return result;
+                }
 
-                    var expression = assignmentPattern.Right.As<Expression>();
-                    var jintExpression = JintExpression.Build(_engine, expression);
+                var expression = right.As<Expression>();
+                var jintExpression = JintExpression.Build(_engine, expression);
 
-                    argument = jintExpression is JintSequenceExpression
-                        ? RunInNewParameterEnvironment(jintExpression)
-                        : jintExpression.GetValue();
+                argument = jintExpression is JintSequenceExpression
+                    ? RunInNewParameterEnvironment(jintExpression)
+                    : jintExpression.GetValue();
 
-                    if (idLeft != null && assignmentPattern.Right.IsFunctionWithName())
-                    {
-                        ((FunctionInstance) argument).SetFunctionName(idLeft.Name);
-                    }
+                if (idLeft != null && right.IsFunctionWithName())
+                {
+                    ((FunctionInstance) argument).SetFunctionName(idLeft.Name);
                 }
+            }
 
-                SetFunctionParameter(assignmentPattern.Left, new []{ argument }, 0, initiallyEmpty);
-            }        }
+            SetFunctionParameter(left, new[]
+            {
+                argument
+            }, 0, initiallyEmpty);
+        }
 
         private void SetItemSafely(in Key name, JsValue argument, bool initiallyEmpty)
         {

+ 59 - 37
Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs

@@ -1,3 +1,4 @@
+using System.Collections.Generic;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Array;
@@ -41,7 +42,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
         private static void HandleArrayPattern(Engine engine, ArrayPattern pattern, JsValue argument)
         {
-            bool ConsumeFromIterator(IIterator it, out JsValue value, out bool done)
+            static bool ConsumeFromIterator(IIterator it, out JsValue value, out bool done)
             {
                 var item = it.Next();
                 value = JsValue.Undefined;
@@ -133,7 +134,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                             protocol.Execute();
                         }
 
-                        if (restElement.Argument is Esprima.Ast.Identifier leftIdentifier)
+                        if (restElement.Argument is Identifier leftIdentifier)
                         {
                             AssignToIdentifier(engine, leftIdentifier.Name, array);
                         }
@@ -191,56 +192,77 @@ namespace Jint.Runtime.Interpreter.Expressions
 
         private static void HandleObjectPattern(Engine engine, ObjectPattern pattern, JsValue argument)
         {
+            var processedProperties = pattern.Properties.Count > 0 && pattern.Properties[pattern.Properties.Count - 1] is RestElement
+                ? new HashSet<string>()
+                : null;
+
             var source = TypeConverter.ToObject(engine, argument);
-            for (uint i = 0; i < pattern.Properties.Count; i++)
+            for (var i = 0; i < pattern.Properties.Count; i++)
             {
-                var left = pattern.Properties[(int) i];
-                JsValue sourceKey;
-                var identifier = left.Key as Identifier;
-                if (identifier == null)
+                if (pattern.Properties[i] is Property p)
                 {
-                    var keyExpression = Build(engine, left.Key);
-                    sourceKey = TypeConverter.ToPropertyKey(keyExpression.GetValue());
-                }
-                else
-                {
-                    sourceKey = identifier.Name;
-                }
+                    JsValue sourceKey;
+                    var identifier = p.Key as Identifier;
+                    if (identifier == null)
+                    {
+                        var keyExpression = Build(engine, p.Key);
+                        sourceKey = TypeConverter.ToPropertyKey(keyExpression.GetValue());
+                    }
+                    else
+                    {
+                        sourceKey = identifier.Name;
+                    }
 
-                source.TryGetValue(sourceKey, out var value);
-                if (left.Value is AssignmentPattern assignmentPattern)
-                {
-                    if (value.IsUndefined() && assignmentPattern.Right is Expression expression)
+                    processedProperties?.Add(sourceKey.AsStringWithoutTypeCheck());
+                    source.TryGetValue(sourceKey, out var value);
+                    if (p.Value is AssignmentPattern assignmentPattern)
                     {
-                        var jintExpression = Build(engine, expression);
+                        if (value.IsUndefined() && assignmentPattern.Right is Expression expression)
+                        {
+                            var jintExpression = Build(engine, expression);
 
-                        value = jintExpression.GetValue();
+                            value = jintExpression.GetValue();
+                        }
+
+                        if (assignmentPattern.Left is BindingPattern bp)
+                        {
+                            ProcessPatterns(engine, bp, value);
+                            continue;
+                        }
+
+                        var target = assignmentPattern.Left as Identifier ?? identifier;
+
+                        if (assignmentPattern.Right.IsFunctionWithName())
+                        {
+                            ((FunctionInstance) value).SetFunctionName(target.Name);
+                        }
+
+                        AssignToIdentifier(engine, target.Name, value);
                     }
-                    
-                    if (assignmentPattern.Left is BindingPattern bp)
+                    else if (p.Value is BindingPattern bindingPattern)
                     {
-                        ProcessPatterns(engine, bp, value);
-                        continue;
+                        ProcessPatterns(engine, bindingPattern, value);
                     }
-                    
-                    var target = assignmentPattern.Left as Identifier ?? identifier;
-
-                    if (assignmentPattern.Right.IsFunctionWithName())
+                    else
                     {
-                        ((FunctionInstance) value).SetFunctionName(target.Name);
+                        var target = p.Value as Identifier ?? identifier;
+                        AssignToIdentifier(engine, target.Name, value);
                     }
-
-                    AssignToIdentifier(engine, target.Name, value);
-                }
-                else if (left.Value is BindingPattern bindingPattern)
-                {
-                    ProcessPatterns(engine, bindingPattern, value);
                 }
                 else
                 {
-                    var target = left.Value as Identifier ?? identifier;
-                    AssignToIdentifier(engine, target.Name, value);
+                    var restElement = (RestElement) pattern.Properties[i];
+                    if (restElement.Argument is Identifier leftIdentifier)
+                    {
+                        var rest = source.CreateRestObject(processedProperties);
+                        AssignToIdentifier(engine, leftIdentifier.Name, rest);
+                    }
+                    else if (restElement.Argument is BindingPattern bp)
+                    {
+                        ProcessPatterns(engine, bp, argument);
+                    }
                 }
+
             }
         }
 

+ 0 - 1
Jint/Runtime/Interpreter/Expressions/JintLiteralExpression.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using Esprima;
 using Esprima.Ast;
 using Jint.Native;

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs

@@ -55,7 +55,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             for (var i = 0; i < _properties.Length; i++)
             {
-                var property = expression.Properties[i];
+                var property = (Property) expression.Properties[i];
                 string propName = null;
 
                 if (property.Key is Literal literal)

+ 5 - 1
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -66,7 +66,11 @@ namespace Jint.Runtime.Interpreter
             }
             if (parameter is ObjectPattern objectPattern)
             {
-                return objectPattern.Properties.SelectMany(property => GetParameterIdentifiers(property.Value));
+                return objectPattern.Properties.SelectMany(property =>
+                    property is Property p
+                        ? GetParameterIdentifiers(p.Value)
+                        : GetParameterIdentifiers((RestElement) property)
+                );
             }
             if (parameter is AssignmentPattern assignmentPattern)
             {

+ 2 - 2
Jint/Runtime/Interpreter/Statements/JintProgram.cs → Jint/Runtime/Interpreter/Statements/JintScript.cs

@@ -2,11 +2,11 @@ using Esprima.Ast;
 
 namespace Jint.Runtime.Interpreter.Statements
 {
-    internal sealed class JintProgram : JintStatement<Program>
+    internal sealed class JintScript : JintStatement<Script>
     {
         private readonly JintStatementList _list;
 
-        public JintProgram(Engine engine, Program statement) : base(engine, statement)
+        public JintScript(Engine engine, Script script) : base(engine, script)
         {
             _list = new JintStatementList(_engine, null, _statement.Body);
         }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintStatement.cs

@@ -122,7 +122,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     return new JintDebuggerStatement(engine, (DebuggerStatement) statement);
 
                 case Nodes.Program:
-                    return new JintProgram(engine, (Program) statement);
+                    return new JintScript(engine, statement as Script ?? ExceptionHelper.ThrowArgumentException<Script>("modules not supported"));
 
                 default:
                     return ExceptionHelper.ThrowArgumentOutOfRangeException<JintStatement>();

+ 4 - 6
appveyor.yml

@@ -22,12 +22,10 @@ build_script:
   - dotnet --version
   - dotnet pack -c Release
 test_script:
-  - dotnet test .\Jint.Tests\Jint.Tests.csproj -c Release -f netcoreapp3.0
-  - dotnet test .\Jint.Tests\Jint.Tests.csproj -c Release -f net452
-  - dotnet test .\Jint.Tests.CommonScripts\Jint.Tests.CommonScripts.csproj -c Release -f netcoreapp3.0
-  - dotnet test .\Jint.Tests.Ecma\Jint.Tests.Ecma.csproj -c Release -f netcoreapp3.0
-  - dotnet test .\Jint.Tests.Test262\Jint.Tests.Test262.csproj -c Release -f netcoreapp3.0
-  - dotnet test .\Jint.Tests.Test262\Jint.Tests.Test262.csproj -c Release -f net452
+  - dotnet test .\Jint.Tests\Jint.Tests.csproj -c Release
+  - dotnet test .\Jint.Tests.CommonScripts\Jint.Tests.CommonScripts.csproj -c Release
+  - dotnet test .\Jint.Tests.Ecma\Jint.Tests.Ecma.csproj -c Release
+  - dotnet test .\Jint.Tests.Test262\Jint.Tests.Test262.csproj -c Release
 artifacts:
   - path: 'Jint\**\*.nupkg'
 deploy: