Bladeren bron

Support ES2021 Logical Assignment (#953)

Marko Lahma 3 jaren geleden
bovenliggende
commit
8186a1d574
66 gewijzigde bestanden met toevoegingen van 1691 en 33 verwijderingen
  1. 39 0
      Jint.Tests.Test262/Language/Expressions/LogicalTests.cs
  2. 18 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-arguments-strict.js
  3. 27 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-bigint.js
  4. 53 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs.js
  5. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-arrow-function.js
  6. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-class-expression.js
  7. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-function.js
  8. 28 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set-put.js
  9. 25 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set.js
  10. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-extensible.js
  11. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js
  12. 26 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable-put.js
  13. 23 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable.js
  14. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-lhs.js
  15. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs-put.js
  16. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs.js
  17. 61 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator.js
  18. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-eval-strict.js
  19. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-non-simple.js
  20. 58 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-whitespace.js
  21. 18 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-arguments-strict.js
  22. 26 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-bigint.js
  23. 53 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs.js
  24. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-arrow-function.js
  25. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-class-expression.js
  26. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-function.js
  27. 28 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set-put.js
  28. 25 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set.js
  29. 21 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-extensible.js
  30. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js
  31. 26 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable-put.js
  32. 23 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable.js
  33. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-lhs.js
  34. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs-put.js
  35. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs.js
  36. 60 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator.js
  37. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-eval-strict.js
  38. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-non-simple.js
  39. 58 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-whitespace.js
  40. 18 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-arguments-strict.js
  41. 27 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-bigint.js
  42. 53 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs.js
  43. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-arrow-function.js
  44. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-class-expression.js
  45. 20 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-function.js
  46. 28 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set-put.js
  47. 25 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set.js
  48. 21 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-extensible.js
  49. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js
  50. 26 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable-put.js
  51. 23 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable.js
  52. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-lhs.js
  53. 19 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs-put.js
  54. 16 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs.js
  55. 61 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator.js
  56. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-eval-strict.js
  57. 17 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-non-simple.js
  58. 58 0
      Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-whitespace.js
  59. 2 11
      Jint.Tests/Runtime/EngineTests.cs
  60. 43 5
      Jint/EsprimaExtensions.cs
  61. 1 1
      Jint/Jint.csproj
  62. 1 1
      Jint/Runtime/Environments/FunctionEnvironmentRecord.cs
  63. 2 2
      Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs
  64. 88 6
      Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs
  65. 2 2
      Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs
  66. 5 5
      Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs

+ 39 - 0
Jint.Tests.Test262/Language/Expressions/LogicalTests.cs

@@ -0,0 +1,39 @@
+using Xunit;
+
+namespace Jint.Tests.Test262.Language.Expressions
+{
+    public class LogicalTests : Test262Test
+    {
+        [Theory(DisplayName = "language\\expressions\\logical-and")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-and", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-and", true, Skip = "Skipped")]
+        protected void LogicalAnd(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+
+        [Theory(DisplayName = "language\\expressions\\logical-assignment")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-assignment", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-assignment", true, Skip = "Skipped")]
+        protected void LogicalAssignment(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+
+        [Theory(DisplayName = "language\\expressions\\logical-not")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-not", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-not", true, Skip = "Skipped")]
+        protected void LogicalNot(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+
+        [Theory(DisplayName = "language\\expressions\\logical-or")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-or", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\logical-or", true, Skip = "Skipped")]
+        protected void LogicalOr(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+    }
+}

+ 18 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-arguments-strict.js

@@ -0,0 +1,18 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier arguments
+    appear as the LeftHandSideExpression of a Logical Assignment
+    operator(&&=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+arguments &&= 20;

+ 27 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-bigint.js

@@ -0,0 +1,27 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical And Assignment Operator
+features: [BigInt, logical-assignment-operators]
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression &&= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. Let lbool be ! ToBoolean(lval).
+    4. If lbool is false, return lval.
+    5. Let rref be the result of evaluating AssignmentExpression.
+    6. Let rval be ? GetValue(rref).
+    7. Perform ? PutValue(lref, rval).
+    8. Return rval.
+
+---*/
+
+var value = 0n;
+assert.sameValue(value &&= 1n, 0n, "(value &&= 1n) === 0n; where value = 0n");
+
+value = 2n;
+assert.sameValue(value &&= 1n, 1n, "(value &&= 1n) === 1n; where value = 2n");

+ 53 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs.js

@@ -0,0 +1,53 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    The LeftHandSideExpression is evaluated before the AssignmentExpression.
+features: [logical-assignment-operators]
+
+---*/
+
+function DummyError() { }
+
+assert.throws(DummyError, function() {
+  var base = null;
+  var prop = function() {
+    throw new DummyError();
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop()] &&= expr();
+});
+
+assert.throws(TypeError, function() {
+  var base = null;
+  var prop = {
+    toString: function() {
+      throw new Test262Error("property key evaluated");
+    }
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop] &&= expr();
+});
+
+var count = 0;
+var obj = {};
+function incr() {
+  return ++count;
+}
+
+assert.sameValue(obj[incr()] &&= incr(), undefined, "obj[incr()] &&= incr()");
+assert.sameValue(obj[1], undefined, "obj[1]");
+assert.sameValue(count, 1, "count");
+
+obj[2] = 1;
+assert.sameValue(obj[incr()] &&= incr(), 3, "obj[incr()] &&= incr()");
+assert.sameValue(obj[2], 3, "obj[2]");
+assert.sameValue(count, 3, "count");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-arrow-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical And Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression &&= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 1;
+value &&= () => {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-class-expression.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical And Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression &&= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 1;
+value &&= class {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-namedevaluation-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical And Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression &&= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 1;
+value &&= function() {};
+
+assert.sameValue(value.name, "value", "value");

+ 28 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set-put.js

@@ -0,0 +1,28 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(&&=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return 2;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop &&= 1;
+});
+assert.sameValue(obj.prop, 2, "obj.prop");

+ 25 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set.js

@@ -0,0 +1,25 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(&&=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return 0;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop &&= 1, 0, "obj.prop");

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-extensible.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if The LeftHandSide of a Logical
+    Assignment operator(&&=) is a reference to a non-existent property of an
+    object whose [[Extensible]] internal property is false.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.preventExtensions(obj);
+
+obj.prop &&= 1;
+assert.sameValue(obj.prop, undefined, "obj.prop");

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+description: >
+    It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is
+    not simple.
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+
+---*/
+
+$DONOTEVALUATE();
+
+function test() {}
+test() &&= 1;

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable-put.js

@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(&&=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: 2,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop &&= 1;
+});
+assert.sameValue(obj.prop, 2, "obj.prop");

+ 23 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable.js

@@ -0,0 +1,23 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(&&=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: 0,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop &&= 1, 0, "obj.prop");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-lhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the LeftHandSideExpression of a Logical
+    Assignment operator(&&=) evaluates to an unresolvable reference
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+assert.throws(ReferenceError, function() {
+  unresolved &&= 1;
+});

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs-put.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the AssignmentExpression of a Logical
+    Assignment operator(&&=) evaluates to an unresolvable reference and the
+    AssignmentExpression is evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 2;
+
+assert.throws(ReferenceError, function() {
+  value &&= unresolved;
+});
+assert.sameValue(value, 2, "value");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is not thrown if the AssignmentExpression of a Logical
+    Assignment operator(&&=) evaluates to an unresolvable reference and the
+    AssignmentExpression is not evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+
+assert.sameValue(value &&= unresolved, 0, "value");

+ 61 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-assignment-operator.js

@@ -0,0 +1,61 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical And Assignment Operator
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression &&= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. Let lbool be ! ToBoolean(lval).
+    4. If lbool is false, return lval.
+    5. Let rref be the result of evaluating AssignmentExpression.
+    6. Let rval be ? GetValue(rref).
+    7. Perform ? PutValue(lref, rval).
+    8. Return rval.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+assert.sameValue(value &&= 1, undefined, "(value &&= 1) === undefined; where value = undefined");
+
+value = null;
+assert.sameValue(value &&= 1, null, "(value &&= 1) === null where value = null");
+
+value = false;
+assert.sameValue(value &&= 1, false, "(value &&= 1) === false; where value = false");
+
+value = 0;
+assert.sameValue(value &&= 1, 0, "(value &&= 1) === 0; where value = 0");
+
+value = -0;
+assert.sameValue(value &&= 1, -0, "(value &&= 1) === -0; where value = -0");
+
+value = NaN;
+assert.sameValue(value &&= 1, NaN, "(value &&= 1) === NaN; where value = NaN");
+
+value = "";
+assert.sameValue(value &&= 1, "", '(value &&= 1) === "" where value = ""');
+
+
+
+value = true;
+assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = true");
+
+value = 2;
+assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = 2");
+
+value = "test";
+assert.sameValue(value &&= 1, 1, '(value &&= 1) === 1; where value = "test"');
+
+var sym = Symbol("");
+value = sym;
+assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = Symbol()");
+
+var obj = {};
+value = obj;
+assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = {}");

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-eval-strict.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier eval appear
+    as the LeftHandSideExpression of a Logical Assignment operator(&&=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+eval &&= 20;

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-non-simple.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+info: |
+    It is an early Syntax Error if AssignmentTargetType of
+    LeftHandSideExpression is invalid or strict.
+description: Logical "&&=" assignment with non-simple target
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+1 &&= 1;

+ 58 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-and-whitespace.js

@@ -0,0 +1,58 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: |
+    White Space and Line Terminator between LeftHandSideExpression and "@="
+    or between "@=" and AssignmentExpression are allowed
+esid: sec-assignment-operators
+description: Checking by evaluating expression "x[...]&&=[...]y"
+features: [logical-assignment-operators]
+---*/
+var x;
+
+x = 1;
+assert.sameValue(x	&&=	2, 2, 'U+0009 (expression)');
+assert.sameValue(x, 2, 'U+0009 (side effect)');
+
+x = 1;
+assert.sameValue(x&&=2, 2, 'U+000B (expression)');
+assert.sameValue(x, 2, 'U+000B (side effect)');
+
+x = 1;
+assert.sameValue(x&&=2, 2, 'U+000C (expression)');
+assert.sameValue(x, 2, 'U+000C (side effect)');
+
+x = 1;
+assert.sameValue(x &&= 2, 2, 'U+0020 (expression)');
+assert.sameValue(x, 2, 'U+0020 (side effect)');
+
+x = 1;
+assert.sameValue(x &&= 2, 2, 'U+00A0 (expression)');
+assert.sameValue(x, 2, 'U+00A0 (side effect)');
+
+x = 1;
+assert.sameValue(x
+&&=
+2, 2, 'U+000A (expression)');
+assert.sameValue(x, 2, 'U+000A (side effect)');
+
+x = 1;
+assert.sameValue(x
+&&=
+2, 2, 'U+000D (expression)');
+assert.sameValue(x, 2, 'U+000D (side effect)');
+
+x = 1;
+assert.sameValue(x
&&=
2, 2, 'U+2028 (expression)');
+assert.sameValue(x, 2, 'U+2028 (side effect)');
+
+x = 1;
+assert.sameValue(x
&&=
2, 2, 'U+2029 (expression)');
+assert.sameValue(x, 2, 'U+2029 (side effect)');
+
+x = 1;
+assert.sameValue(x	  
+

&&=	  
+

2, 2, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (expression)');
+assert.sameValue(x, 2, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (side effect)');

+ 18 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-arguments-strict.js

@@ -0,0 +1,18 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier arguments
+    appear as the LeftHandSideExpression of a Logical Assignment
+    operator(??=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+arguments ??= 20;

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-bigint.js

@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical Nullish Assignment Operator
+features: [BigInt, logical-assignment-operators]
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ??= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is neither undefined nor null, return lval.
+    4. Let rref be the result of evaluating AssignmentExpression.
+    5. Let rval be ? GetValue(rref).
+    6. Perform ? PutValue(lref, rval).
+    7. Return rval.
+
+---*/
+
+var value = 0n;
+assert.sameValue(value ??= 1n, 0n, "(value ??= 1n) === 0n; where value = 0n");
+
+value = 2n;
+assert.sameValue(value ??= 1n, 2n, "(value ??= 1n) === 2n; where value = 2n");

+ 53 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs.js

@@ -0,0 +1,53 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    The LeftHandSideExpression is evaluated before the AssignmentExpression.
+features: [logical-assignment-operators]
+
+---*/
+
+function DummyError() { }
+
+assert.throws(DummyError, function() {
+  var base = null;
+  var prop = function() {
+    throw new DummyError();
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop()] ??= expr();
+});
+
+assert.throws(TypeError, function() {
+  var base = null;
+  var prop = {
+    toString: function() {
+      throw new Test262Error("property key evaluated");
+    }
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop] ??= expr();
+});
+
+var count = 0;
+var obj = {};
+function incr() {
+  return ++count;
+}
+
+assert.sameValue(obj[incr()] ??= incr(), 2, "obj[incr()] ??= incr()");
+assert.sameValue(obj[1], 2, "obj[1]");
+assert.sameValue(count, 2, "count");
+
+obj[3] = 1;
+assert.sameValue(obj[incr()] ??= incr(), 1, "obj[incr()] ??= incr()");
+assert.sameValue(obj[3], 1, "obj[3]");
+assert.sameValue(count, 3, "count");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-arrow-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Nullish Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ??= AssignmentExpression
+
+    4. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+value ??= () => {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-class-expression.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Nullish Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ??= AssignmentExpression
+
+    4. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+value ??= class {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-namedevaluation-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Nullish Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ??= AssignmentExpression
+
+    4. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+value ??= function() {};
+
+assert.sameValue(value.name, "value", "value");

+ 28 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set-put.js

@@ -0,0 +1,28 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(??=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return undefined;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop ??= 1;
+});
+assert.sameValue(obj.prop, undefined, "obj.prop");

+ 25 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set.js

@@ -0,0 +1,25 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(??=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return 0;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop ??= 1, 0, "obj.prop");

+ 21 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-extensible.js

@@ -0,0 +1,21 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if The LeftHandSide of a Logical
+    Assignment operator(??=) is a reference to a non-existent property
+    of an object whose [[Extensible]] internal property is false.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.preventExtensions(obj);
+
+assert.throws(TypeError, function() {
+  obj.prop ??= 1;
+});
+assert.sameValue(obj.prop, undefined, "obj.prop");

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+description: >
+    It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is
+    not simple.
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+
+---*/
+
+$DONOTEVALUATE();
+
+function test() {}
+test() ??= 1;

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable-put.js

@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(??=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: undefined,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop ??= 1;
+});
+assert.sameValue(obj.prop, undefined, "obj.prop");

+ 23 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable.js

@@ -0,0 +1,23 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(??=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: 0,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop ??= 1, 0, "obj.prop");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-lhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the LeftHandSideExpression of a Logical
+    Assignment operator(??=) evaluates to an unresolvable reference
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+assert.throws(ReferenceError, function() {
+  unresolved ??= 1;
+});

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs-put.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the AssignmentExpression of a Logical
+    Assignment operator(??=) evaluates to an unresolvable reference and the
+    AssignmentExpression is evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+
+assert.throws(ReferenceError, function() {
+  value ??= unresolved;
+});
+assert.sameValue(value, undefined, "value");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is not thrown if the AssignmentExpression of a Logical
+    Assignment operator(??=) evaluates to an unresolvable reference and the
+    AssignmentExpression is not evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+
+assert.sameValue(value ??= unresolved, 0, "value");

+ 60 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator.js

@@ -0,0 +1,60 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical Nullish Assignment Operator
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ??= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is neither undefined nor null, return lval.
+    4. Let rref be the result of evaluating AssignmentExpression.
+    5. Let rval be ? GetValue(rref).
+    6. Perform ? PutValue(lref, rval).
+    7. Return rval.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+assert.sameValue(value ??= 1, 1, "(value ??= 1) === 1; where value = undefined");
+
+value = null;
+assert.sameValue(value ??= 1, 1, "(value ??= 1) === 1; where value = null");
+
+value = false;
+assert.sameValue(value ??= 1, false, "(value ??= 1) === false; where value = false");
+
+value = 0;
+assert.sameValue(value ??= 1, 0, "(value ??= 1) === 0; where value = 0");
+
+value = -0;
+assert.sameValue(value ??= 1, -0, "(value ??= 1) === -0; where value = -0");
+
+value = NaN;
+assert.sameValue(value ??= 1, NaN, "(value ??= 1) === NaN; where value = NaN");
+
+value = "";
+assert.sameValue(value ??= 1, "", '(value ??= 1) === "" where value = ""');
+
+
+
+value = true;
+assert.sameValue(value ??= 1, true, "(value ??= 1) === true; where value = true");
+
+value = 2;
+assert.sameValue(value ??= 1, 2, "(value ??= 1) === 2; where value = 2");
+
+value = "test";
+assert.sameValue(value ??= 1, "test", '(value ??= 1) === "test"; where value = "test"');
+
+var sym = Symbol("");
+value = sym;
+assert.sameValue(value ??= 1, sym, "(value ??= 1) === Symbol(); where value = Symbol()");
+
+var obj = {};
+value = obj;
+assert.sameValue(value ??= 1, obj, "(value ??= 1) === {}; where value = {}");

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-eval-strict.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier eval appear
+    as the LeftHandSideExpression of a Logical Assignment operator(??=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+eval ??= 20;

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-non-simple.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+info: |
+    It is an early Syntax Error if AssignmentTargetType of
+    LeftHandSideExpression is invalid or strict.
+description: Logical "??=" assignment with non-simple target
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+1 ??= 1;

+ 58 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-nullish-whitespace.js

@@ -0,0 +1,58 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: |
+    White Space and Line Terminator between LeftHandSideExpression and "@="
+    or between "@=" and AssignmentExpression are allowed
+esid: sec-assignment-operators
+description: Checking by evaluating expression "x[...]??=[...]y"
+features: [logical-assignment-operators]
+---*/
+var x;
+
+x = null;
+assert.sameValue(x	??=	1, 1, 'U+0009 (expression)');
+assert.sameValue(x, 1, 'U+0009 (side effect)');
+
+x = null;
+assert.sameValue(x??=1, 1, 'U+000B (expression)');
+assert.sameValue(x, 1, 'U+000B (side effect)');
+
+x = null;
+assert.sameValue(x??=1, 1, 'U+000C (expression)');
+assert.sameValue(x, 1, 'U+000C (side effect)');
+
+x = null;
+assert.sameValue(x ??= 1, 1, 'U+0020 (expression)');
+assert.sameValue(x, 1, 'U+0020 (side effect)');
+
+x = null;
+assert.sameValue(x ??= 1, 1, 'U+00A0 (expression)');
+assert.sameValue(x, 1, 'U+00A0 (side effect)');
+
+x = null;
+assert.sameValue(x
+??=
+1, 1, 'U+000A (expression)');
+assert.sameValue(x, 1, 'U+000A (side effect)');
+
+x = null;
+assert.sameValue(x
+??=
+1, 1, 'U+000D (expression)');
+assert.sameValue(x, 1, 'U+000D (side effect)');
+
+x = null;
+assert.sameValue(x
??=
1, 1, 'U+2028 (expression)');
+assert.sameValue(x, 1, 'U+2028 (side effect)');
+
+x = null;
+assert.sameValue(x
??=
1, 1, 'U+2029 (expression)');
+assert.sameValue(x, 1, 'U+2029 (side effect)');
+
+x = null;
+assert.sameValue(x	  
+

??=	  
+

1, 1, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (expression)');
+assert.sameValue(x, 1, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (side effect)');

+ 18 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-arguments-strict.js

@@ -0,0 +1,18 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier arguments
+    appear as the LeftHandSideExpression of a Logical Assignment
+    operator(||=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+arguments ||= 20;

+ 27 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-bigint.js

@@ -0,0 +1,27 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical Or Assignment Operator
+features: [BigInt, logical-assignment-operators]
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ||= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. Let lbool be ! ToBoolean(lval).
+    4. If lbool is true, return lval.
+    5. Let rref be the result of evaluating AssignmentExpression.
+    6. Let rval be ? GetValue(rref).
+    7. Perform ? PutValue(lref, rval).
+    8. Return rval.
+
+---*/
+
+var value = 0n;
+assert.sameValue(value ||= 1n, 1n, "(value ||= 1n) === 1n; where value = 0n");
+
+value = 2n;
+assert.sameValue(value ||= 1n, 2n, "(value ||= 1n) === 2n; where value = 2n");

+ 53 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs.js

@@ -0,0 +1,53 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    The LeftHandSideExpression is evaluated before the AssignmentExpression.
+features: [logical-assignment-operators]
+
+---*/
+
+function DummyError() { }
+
+assert.throws(DummyError, function() {
+  var base = null;
+  var prop = function() {
+    throw new DummyError();
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop()] ||= expr();
+});
+
+assert.throws(TypeError, function() {
+  var base = null;
+  var prop = {
+    toString: function() {
+      throw new Test262Error("property key evaluated");
+    }
+  };
+  var expr = function() {
+    throw new Test262Error("right-hand side expression evaluated");
+  };
+
+  base[prop] ||= expr();
+});
+
+var count = 0;
+var obj = {};
+function incr() {
+  return ++count;
+}
+
+assert.sameValue(obj[incr()] ||= incr(), 2, "obj[incr()] ||= incr()");
+assert.sameValue(obj[1], 2, "obj[1]");
+assert.sameValue(count, 2, "count");
+
+obj[3] = 1;
+assert.sameValue(obj[incr()] ||= incr(), 1, "obj[incr()] ||= incr()");
+assert.sameValue(obj[3], 1, "obj[3]");
+assert.sameValue(count, 3, "count");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-arrow-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Or Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ||= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+value ||= () => {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-class-expression.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Or Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ||= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+value ||= class {};
+
+assert.sameValue(value.name, "value", "value");

+ 20 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-namedevaluation-function.js

@@ -0,0 +1,20 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: NamedEvaluation of Logical Or Assignment
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ||= AssignmentExpression
+
+    5. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
+      a. Let rval be NamedEvaluation of AssignmentExpression with argument GetReferencedName(lref).
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+value ||= function() {};
+
+assert.sameValue(value.name, "value", "value");

+ 28 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set-put.js

@@ -0,0 +1,28 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(||=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return 0;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop ||= 1;
+});
+assert.sameValue(obj.prop, 0, "obj.prop");

+ 25 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set.js

@@ -0,0 +1,25 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(||=) is a reference to a data property with the
+    attribute value {[[Set]]:undefined} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  get: function() {
+    return 2;
+  },
+  set: undefined,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop ||= 1, 2, "obj.prop");

+ 21 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-extensible.js

@@ -0,0 +1,21 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if The LeftHandSide of a Logical
+    Assignment operator(||=) is a reference to a non-existent property
+    of an object whose [[Extensible]] internal property is false.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.preventExtensions(obj);
+
+assert.throws(TypeError, function() {
+  obj.prop ||= 1;
+});
+assert.sameValue(obj.prop, undefined, "obj.prop");

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+description: >
+    It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is
+    not simple.
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+
+---*/
+
+$DONOTEVALUATE();
+
+function test() {}
+test() ||= 1;

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable-put.js

@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is thrown if the LeftHandSide of a Logical
+    Assignment operator(||=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: 0,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.throws(TypeError, function() {
+  obj.prop ||= 1;
+});
+assert.sameValue(obj.prop, 0, "obj.prop");

+ 23 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable.js

@@ -0,0 +1,23 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical
+    Assignment operator(||=) is a reference to a data property with the
+    attribute value {[[Writable]]:false} and PutValue step is not reached.
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+var obj = {};
+Object.defineProperty(obj, "prop", {
+  value: 2,
+  writable: false,
+  enumerable: true,
+  configurable: true
+});
+
+assert.sameValue(obj.prop ||= 1, 2, "obj.prop");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-lhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the LeftHandSideExpression of a Logical
+    Assignment operator(||=) evaluates to an unresolvable reference
+flags: [onlyStrict]
+features: [logical-assignment-operators]
+
+---*/
+
+assert.throws(ReferenceError, function() {
+  unresolved ||= 1;
+});

+ 19 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs-put.js

@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is thrown if the AssignmentExpression of a Logical
+    Assignment operator(||=) evaluates to an unresolvable reference and the
+    AssignmentExpression is evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 0;
+
+assert.throws(ReferenceError, function() {
+  value ||= unresolved;
+});
+assert.sameValue(value, 0, "value");

+ 16 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs.js

@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: >
+    ReferenceError is not thrown if the AssignmentExpression of a Logical
+    Assignment operator(||=) evaluates to an unresolvable reference and the
+    AssignmentExpression is not evaluated.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = 2;
+
+assert.sameValue(value ||= unresolved, 2, "value");

+ 61 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-assignment-operator.js

@@ -0,0 +1,61 @@
+// Copyright (c) 2020 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-runtime-semantics-evaluation
+description: Logical Or Assignment Operator
+info: |
+    AssignmentExpression:
+      LeftHandSideExpression ||= AssignmentExpression
+
+    1. Let lref be the result of evaluating LeftHandSideExpression.
+    2. Let lval be ? GetValue(lref).
+    3. Let lbool be ! ToBoolean(lval).
+    4. If lbool is true, return lval.
+    5. Let rref be the result of evaluating AssignmentExpression.
+    6. Let rval be ? GetValue(rref).
+    7. Perform ? PutValue(lref, rval).
+    8. Return rval.
+features: [logical-assignment-operators]
+
+---*/
+
+var value = undefined;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = undefined");
+
+value = null;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = null");
+
+value = false;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = false");
+
+value = 0;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = 0");
+
+value = -0;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = -0");
+
+value = NaN;
+assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = NaN");
+
+value = "";
+assert.sameValue(value ||= 1, 1, '(value ||= 1) === 1; where value = ""');
+
+
+
+value = true;
+assert.sameValue(value ||= 1, true, "(value ||= 1) === true; where value = true");
+
+value = 2;
+assert.sameValue(value ||= 1, 2, "(value ||= 1) === 2; where value = 2");
+
+value = "test";
+assert.sameValue(value ||= 1, "test", '(value ||= 1) === "test"; where value = "test"');
+
+var sym = Symbol("");
+value = sym;
+assert.sameValue(value ||= 1, sym, "(value ||= 1) === Symbol(); where value = Symbol()");
+
+var obj = {};
+value = obj;
+assert.sameValue(value ||= 1, obj, "(value ||= 1) === {}; where value = {}");

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-eval-strict.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators
+description: >
+    Strict Mode - SyntaxError is thrown if the identifier eval appear
+    as the LeftHandSideExpression of a Logical Assignment operator(||=)
+flags: [onlyStrict]
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+eval ||= 20;

+ 17 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-non-simple.js

@@ -0,0 +1,17 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-assignment-operators-static-semantics-early-errors
+info: |
+    It is an early Syntax Error if AssignmentTargetType of
+    LeftHandSideExpression is invalid or strict.
+description: Logical "||=" assignment with non-simple target
+negative:
+  phase: parse
+  type: SyntaxError
+features: [logical-assignment-operators]
+---*/
+$DONOTEVALUATE();
+
+1 ||= 1;

+ 58 - 0
Jint.Tests.Test262/test/language/expressions/logical-assignment/lgcl-or-whitespace.js

@@ -0,0 +1,58 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: |
+    White Space and Line Terminator between LeftHandSideExpression and "@="
+    or between "@=" and AssignmentExpression are allowed
+esid: sec-assignment-operators
+description: Checking by evaluating expression "x[...]||=[...]y"
+features: [logical-assignment-operators]
+---*/
+var x;
+
+x = 0;
+assert.sameValue(x	||=	1, 1, 'U+0009 (expression)');
+assert.sameValue(x, 1, 'U+0009 (side effect)');
+
+x = 0;
+assert.sameValue(x||=1, 1, 'U+000B (expression)');
+assert.sameValue(x, 1, 'U+000B (side effect)');
+
+x = 0;
+assert.sameValue(x||=1, 1, 'U+000C (expression)');
+assert.sameValue(x, 1, 'U+000C (side effect)');
+
+x = 0;
+assert.sameValue(x ||= 1, 1, 'U+0020 (expression)');
+assert.sameValue(x, 1, 'U+0020 (side effect)');
+
+x = 0;
+assert.sameValue(x ||= 1, 1, 'U+00A0 (expression)');
+assert.sameValue(x, 1, 'U+00A0 (side effect)');
+
+x = 0;
+assert.sameValue(x
+||=
+1, 1, 'U+000A (expression)');
+assert.sameValue(x, 1, 'U+000A (side effect)');
+
+x = 0;
+assert.sameValue(x
+||=
+1, 1, 'U+000D (expression)');
+assert.sameValue(x, 1, 'U+000D (side effect)');
+
+x = 0;
+assert.sameValue(x
||=
1, 1, 'U+2028 (expression)');
+assert.sameValue(x, 1, 'U+2028 (side effect)');
+
+x = 0;
+assert.sameValue(x
||=
1, 1, 'U+2029 (expression)');
+assert.sameValue(x, 1, 'U+2029 (side effect)');
+
+x = 0;
+assert.sameValue(x	  
+

||=	  
+

1, 1, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (expression)');
+assert.sameValue(x, 1, 'U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 (side effect)');

+ 2 - 11
Jint.Tests/Runtime/EngineTests.cs

@@ -1003,7 +1003,7 @@ myarr[0](0);
         {
             const string code = @"var obj = { get test() { return this.test + '2';  } }; obj.test;";
             var engine = new Engine(cfg => cfg.LimitRecursion(10));
-            
+
             Assert.Throws<RecursionDepthOverflowException>(() => engine.Evaluate(code));
         }
 
@@ -1513,15 +1513,6 @@ var prep = function (fn) { fn(); };
             RunTest(content);
         }
 
-        [Fact]
-        public void ShouldExecuteKnockoutWithErrorWhenIntolerant()
-        {
-            var content = GetEmbeddedFile("knockout-3.4.0.js");
-
-            var ex = Assert.Throws<ParserException>(() => _engine.Execute(content, new ParserOptions { Tolerant = false }));
-            Assert.Contains("Duplicate __proto__ fields are not allowed in object literals", ex.Message);
-        }
-
         [Fact]
         public void ShouldExecuteKnockoutWithoutErrorWhenTolerant()
         {
@@ -2101,7 +2092,7 @@ var prep = function (fn) { fn(); };
 
             engine.Evaluate("var d = new Number(-1.23);");
             engine.Evaluate("equal('-1.23', d.toString());");
-            
+
             // NET 5 globalization APIs use ICU libraries on newer Windows 10 giving different result
             // build server is older Windows...
             engine.Evaluate("assert('-1,230' === d.toLocaleString() || '-1,23' === d.toLocaleString());");

+ 43 - 5
Jint/EsprimaExtensions.cs

@@ -59,13 +59,51 @@ namespace Jint
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsFunctionWithName<T>(this T node) where T : Node
+        internal static bool IsFunctionDefinition<T>(this T node) where T : Node
         {
             var type = node.Type;
-            return type == Nodes.FunctionExpression
-                   || type == Nodes.ArrowFunctionExpression
-                   || type == Nodes.ArrowParameterPlaceHolder
-                   || type == Nodes.ClassExpression;
+            return type
+                is Nodes.FunctionExpression
+                or Nodes.ArrowFunctionExpression
+                or Nodes.ArrowParameterPlaceHolder
+                or Nodes.ClassExpression;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static bool HasName<T>(this T node) where T : Node
+        {
+            if (!node.IsFunctionDefinition())
+            {
+                return false;
+            }
+
+            if ((node as IFunction)?.Id is not null)
+            {
+                return true;
+            }
+
+            if ((node as ClassExpression)?.Id is not null)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static bool IsAnonymousFunctionDefinition<T>(this T node) where T : Node
+        {
+            if (!node.IsFunctionDefinition())
+            {
+                return false;
+            }
+
+            if (node.HasName())
+            {
+                return false;
+            }
+
+            return true;
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 1 - 1
Jint/Jint.csproj

@@ -8,7 +8,7 @@
     <IsPackable>true</IsPackable>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="2.0.2" />
+    <PackageReference Include="Esprima" Version="2.0.3" />
     <PackageReference Include="IsExternalInit" Version="1.0.1" PrivateAssets="all" />
     <PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
   </ItemGroup>

+ 1 - 1
Jint/Runtime/Environments/FunctionEnvironmentRecord.cs

@@ -344,7 +344,7 @@ namespace Jint.Runtime.Environments
                     _engine.LeaveExecutionContext();
                 }
 
-                if (idLeft != null && right.IsFunctionWithName())
+                if (idLeft != null && right.IsFunctionDefinition())
                 {
                     ((FunctionInstance) argument).SetFunctionName(idLeft.Name);
                 }

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs

@@ -235,7 +235,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                         if (assignmentPattern.Left is Identifier leftIdentifier)
                         {
-                            if (assignmentPattern.Right.IsFunctionWithName())
+                            if (assignmentPattern.Right.IsFunctionDefinition())
                             {
                                 ((FunctionInstance) value).SetFunctionName(new JsString(leftIdentifier.Name));
                             }
@@ -312,7 +312,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                         var target = assignmentPattern.Left as Identifier ?? identifier;
 
-                        if (assignmentPattern.Right.IsFunctionWithName())
+                        if (assignmentPattern.Right.IsFunctionDefinition())
                         {
                             ((FunctionInstance) value).SetFunctionName(target.Name);
                         }

+ 88 - 6
Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs

@@ -42,7 +42,6 @@ namespace Jint.Runtime.Interpreter.Expressions
                 ExceptionHelper.ThrowReferenceError(_engine.Realm, "not a valid reference");
             }
 
-            var rval = _right.GetValue();
             var lval = _engine.GetValue(lref, false);
             var handledByOverload = false;
 
@@ -90,11 +89,14 @@ namespace Jint.Runtime.Interpreter.Expressions
                         break;
                 }
 
-                if (operatorClrName != null &&
-                    JintBinaryExpression.TryOperatorOverloading(_engine, lval, rval, operatorClrName, out var result))
+                if (operatorClrName != null)
                 {
-                    lval = JsValue.FromObject(_engine, result);
-                    handledByOverload = true;
+                    var rval = _right.GetValue();
+                    if (JintBinaryExpression.TryOperatorOverloading(_engine, lval, rval, operatorClrName, out var result))
+                    {
+                        lval = JsValue.FromObject(_engine, result);
+                        handledByOverload = true;
+                    }
                 }
             }
 
@@ -103,6 +105,8 @@ namespace Jint.Runtime.Interpreter.Expressions
                 switch (_operator)
                 {
                     case AssignmentOperator.PlusAssign:
+                    {
+                        var rval = _right.GetValue();
                         if (AreIntegerOperands(lval, rval))
                         {
                             lval = (long) lval.AsInteger() + rval.AsInteger();
@@ -128,14 +132,20 @@ namespace Jint.Runtime.Interpreter.Expressions
                         }
 
                         break;
+                    }
 
                     case AssignmentOperator.MinusAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = AreIntegerOperands(lval, rval)
                             ? JsNumber.Create(lval.AsInteger() - rval.AsInteger())
                             : JsNumber.Create(TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval));
                         break;
+                    }
 
                     case AssignmentOperator.TimesAssign:
+                    {
+                        var rval = _right.GetValue();
                         if (AreIntegerOperands(lval, rval))
                         {
                             lval = (long) lval.AsInteger() * rval.AsInteger();
@@ -150,12 +160,18 @@ namespace Jint.Runtime.Interpreter.Expressions
                         }
 
                         break;
+                    }
 
                     case AssignmentOperator.DivideAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = Divide(lval, rval);
                         break;
+                    }
 
                     case AssignmentOperator.ModuloAssign:
+                    {
+                        var rval = _right.GetValue();
                         if (lval.IsUndefined() || rval.IsUndefined())
                         {
                             lval = Undefined.Instance;
@@ -166,30 +182,85 @@ namespace Jint.Runtime.Interpreter.Expressions
                         }
 
                         break;
+                    }
 
                     case AssignmentOperator.BitwiseAndAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
                         break;
+                    }
 
                     case AssignmentOperator.BitwiseOrAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
                         break;
+                    }
 
                     case AssignmentOperator.BitwiseXOrAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
                         break;
+                    }
 
                     case AssignmentOperator.LeftShiftAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = TypeConverter.ToInt32(lval) << (int) (TypeConverter.ToUint32(rval) & 0x1F);
                         break;
+                    }
 
                     case AssignmentOperator.RightShiftAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
                         break;
+                    }
 
                     case AssignmentOperator.UnsignedRightShiftAssign:
+                    {
+                        var rval = _right.GetValue();
                         lval = (uint) TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
                         break;
+                    }
+
+                    case AssignmentOperator.NullishAssign:
+                    {
+                        if (!lval.IsNullOrUndefined())
+                        {
+                            return lval;
+                        }
+
+                        var rval = NamedEvaluation(_right);
+                        lval = rval;
+                        break;
+                    }
+
+                    case AssignmentOperator.AndAssign:
+                    {
+                        if (!TypeConverter.ToBoolean(lval))
+                        {
+                            return lval;
+                        }
+
+                        var rval = NamedEvaluation(_right);
+                        lval = rval;
+                        break;
+                    }
+
+                    case AssignmentOperator.OrAssign:
+                    {
+                        if (TypeConverter.ToBoolean(lval))
+                        {
+                            return lval;
+                        }
+
+                        var rval = NamedEvaluation(_right);
+                        lval = rval;
+                        break;
+                    }
 
                     default:
                         ExceptionHelper.ThrowNotImplementedException();
@@ -203,6 +274,17 @@ namespace Jint.Runtime.Interpreter.Expressions
             return lval;
         }
 
+        private JsValue NamedEvaluation(JintExpression expression)
+        {
+            var rval = expression.GetValue();
+            if (expression._expression.IsAnonymousFunctionDefinition() && _left._expression.Type == Nodes.Identifier)
+            {
+                ((FunctionInstance) rval).SetFunctionName(((Identifier) _left._expression).Name);
+            }
+
+            return rval;
+        }
+
         internal sealed class SimpleAssignmentExpression : JintExpression
         {
             private JintExpression _left;
@@ -276,7 +358,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                     var rval = right.GetValue().Clone();
 
-                    if (right._expression.IsFunctionWithName())
+                    if (right._expression.IsFunctionDefinition())
                     {
                         ((FunctionInstance) rval).SetFunctionName(left._expressionName.StringValue);
                     }

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

@@ -76,7 +76,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                     {
                         var propertyValue = p.Value;
                         _valueExpressions[i] = Build(_engine, propertyValue);
-                        _canBuildFast &= !propertyValue.IsFunctionWithName();
+                        _canBuildFast &= !propertyValue.IsFunctionDefinition();
                     }
                     else
                     {
@@ -166,7 +166,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 {
                     var expr = _valueExpressions[i];
                     JsValue propValue = expr.GetValue().Clone();
-                    if (expr._expression.IsFunctionWithName())
+                    if (expr._expression.IsFunctionDefinition())
                     {
                         var closure = (FunctionInstance) propValue;
                         closure.SetFunctionName(propName);

+ 5 - 5
Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs

@@ -45,12 +45,12 @@ namespace Jint.Runtime.Interpreter.Statements
                 {
                     left = JintExpression.Build(_engine, declaration.Id);
                 }
-                
+
                 if (declaration.Init != null)
                 {
                     init = JintExpression.Build(_engine, declaration.Init);
                 }
-                
+
                 var leftIdentifier = left as JintIdentifierExpression;
                 _declarations[i] = new ResolvedDeclaration
                 {
@@ -70,7 +70,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 _initialized = true;
                 Initialize();
             }
-            
+
             foreach (var declaration in _declarations)
             {
                 if (_statement.Kind != VariableDeclarationKind.Var && declaration.Left != null)
@@ -80,7 +80,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     if (declaration.Init != null)
                     {
                         value = declaration.Init.GetValue().Clone();
-                        if (declaration.Init._expression.IsFunctionWithName())
+                        if (declaration.Init._expression.IsFunctionDefinition())
                         {
                             ((FunctionInstance) value).SetFunctionName(lhs.GetReferencedName());
                         }
@@ -117,7 +117,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
                         var value = declaration.Init.GetValue().Clone();
 
-                        if (declaration.Init._expression.IsFunctionWithName())
+                        if (declaration.Init._expression.IsFunctionDefinition())
                         {
                             ((FunctionInstance) value).SetFunctionName(lhs.GetReferencedName());
                         }