Browse Source

Support nullish coalescing (#817)

Marko Lahma 4 years ago
parent
commit
869222d83e
34 changed files with 1435 additions and 10 deletions
  1. 1 1
      Jint.Benchmark/Jint.Benchmark.csproj
  2. 1 1
      Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj
  3. 1 1
      Jint.Tests.Ecma/Jint.Tests.Ecma.csproj
  4. 1 1
      Jint.Tests.Test262/Jint.Tests.Test262.csproj
  5. 15 0
      Jint.Tests.Test262/Language/Expressions/CoalesceTests.cs
  6. 58 0
      Jint.Tests.Test262/test/language/expressions/coalesce/abrupt-is-a-short-circuit.js
  7. 31 0
      Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-head-with-logical-and.js
  8. 31 0
      Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-head-with-logical-or.js
  9. 32 0
      Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-tail-with-logical-and.js
  10. 32 0
      Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-tail-with-logical-or.js
  11. 53 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable-if-parenthesis-covered-logical-and.js
  12. 61 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable-if-parenthesis-covered-logical-or.js
  13. 49 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-and.js
  14. 49 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-or.js
  15. 49 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-xor.js
  16. 50 0
      Jint.Tests.Test262/test/language/expressions/coalesce/chainable.js
  17. 49 0
      Jint.Tests.Test262/test/language/expressions/coalesce/follows-null.js
  18. 49 0
      Jint.Tests.Test262/test/language/expressions/coalesce/follows-undefined.js
  19. 81 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-0.js
  20. 81 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-42.js
  21. 82 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-empty-string.js
  22. 81 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-false.js
  23. 89 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-object.js
  24. 82 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-string.js
  25. 82 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-symbol.js
  26. 81 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-true.js
  27. 56 0
      Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-prevents-evaluation.js
  28. 26 0
      Jint.Tests.Test262/test/language/expressions/coalesce/tco-pos-null.js
  29. 26 0
      Jint.Tests.Test262/test/language/expressions/coalesce/tco-pos-undefined.js
  30. 1 1
      Jint.Tests/Jint.Tests.csproj
  31. 1 1
      Jint/Jint.csproj
  32. 3 4
      Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs
  33. 1 0
      Jint/Runtime/Interpreter/Expressions/JintExpression.cs
  34. 50 0
      Jint/Runtime/Interpreter/Expressions/NullishCoalescingExpression.cs

+ 1 - 1
Jint.Benchmark/Jint.Benchmark.csproj

@@ -25,7 +25,7 @@
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
-    <PackageReference Include="Jurassic" Version="3.0.0" />
+    <PackageReference Include="Jurassic" Version="3.1.0" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
     <PackageReference Include="NiL.JS.NetCore" Version="2.5.1419" />
   </ItemGroup>

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

@@ -9,7 +9,7 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />

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

@@ -6,7 +6,7 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />

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

@@ -6,7 +6,7 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />

+ 15 - 0
Jint.Tests.Test262/Language/Expressions/CoalesceTests.cs

@@ -0,0 +1,15 @@
+using Xunit;
+
+namespace Jint.Tests.Test262.Language.Expressions
+{
+    public class CoalesceTests : Test262Test
+    {
+        [Theory(DisplayName = "language\\expressions\\\\coalesce")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\\\coalesce", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\\\coalesce", true, Skip = "Skipped")]
+        protected void Addition(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+    }
+}

+ 58 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/abrupt-is-a-short-circuit.js

@@ -0,0 +1,58 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Abrupt completions are also a Short circuit and prevent evaluation of the right-side expressions
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+function poison() {
+    throw new Test262Error('poison handled');
+}
+
+function morePoison() {
+    throw 'poison!!!!';
+}
+
+x = undefined;
+assert.throws(Test262Error, function() {
+    undefined ?? poison() ?? morePoison();
+}, 'undefined ?? poison() ?? morePoison();');
+
+x = undefined;
+assert.throws(Test262Error, function() {
+    null ?? poison() ?? morePoison();
+}, 'null ?? poison() ?? morePoison();');
+
+assert.throws(Test262Error, function() {
+    poison() ?? morePoison();
+}, 'poison() ?? morePoison();');

+ 31 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-head-with-logical-and.js

@@ -0,0 +1,31 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Cannot immediately contain, or be contained within, an && or || operation.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+features: [coalesce-expression]
+negative:
+    phase: parse
+    type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+0 && 0 ?? true;

+ 31 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-head-with-logical-or.js

@@ -0,0 +1,31 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Cannot immediately contain, or be contained within, an && or || operation.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+features: [coalesce-expression]
+negative:
+    phase: parse
+    type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+0 || 0 ?? true;

+ 32 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-tail-with-logical-and.js

@@ -0,0 +1,32 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
+    Otherwise, return the left-side value.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+features: [coalesce-expression]
+negative:
+    phase: parse
+    type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+0 ?? 0 && true;

+ 32 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/cannot-chain-tail-with-logical-or.js

@@ -0,0 +1,32 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
+    Otherwise, return the left-side value.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+features: [coalesce-expression]
+negative:
+    phase: parse
+    type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+0 ?? 0 || true;

+ 53 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable-if-parenthesis-covered-logical-and.js

@@ -0,0 +1,53 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    CoalesceExpression is chainable with the LogicalANDExpression is any is covered.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = (null ?? 41) && 42;
+assert.sameValue(x, 42, '(null ?? 41) && 42');
+
+x = undefined;
+x = null ?? (41 && 42);
+assert.sameValue(x, 42, 'null ?? (41 && 42)`');
+
+x = undefined;
+x = (41 && 42) ?? null;
+assert.sameValue(x, 42, '(41 && 42) ?? null');
+
+x = undefined;
+x = 41 && (null ?? 42);
+assert.sameValue(x, 42, '41 && (null ?? 42)`');

+ 61 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable-if-parenthesis-covered-logical-or.js

@@ -0,0 +1,61 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    CoalesceExpression is chainable with the LogicalORExpression is any is covered.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = (null ?? 42) || 43;
+assert.sameValue(x, 42, '(null ?? 42) || 43');
+
+x = undefined;
+x = null ?? (42 || 43);
+assert.sameValue(x, 42, 'null ?? (42 || 43)`');
+
+x = undefined;
+x = (null || 42) ?? 43;
+assert.sameValue(x, 42, '(null || 42) ?? 43');
+
+x = undefined;
+x = null || (42 ?? 43);
+assert.sameValue(x, 42, 'null || (42 ?? 43)`');
+
+x = undefined;
+x = (42 || 43) ?? null;
+assert.sameValue(x, 42, '(42 || 43) ?? null');
+
+x = undefined;
+x = 42 || (null ?? 43);
+assert.sameValue(x, 42, '42 || (null ?? 43)');

+ 49 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-and.js

@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    CoalesceExpression is chainable with the BitwiseANDExpression
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = null ?? 42 & 43;
+assert.sameValue(x, 42, 'null ?? 42 & 43');
+
+x = undefined ?? 42 & 43;
+assert.sameValue(x, 42, 'null ?? 42 & 43');
+
+x = false ?? 42 & 43;
+assert.sameValue(x, false, 'false ?? 42 & 43');
+
+x = true ?? 42 & 43;
+assert.sameValue(x, true, 'true ?? 42 & 43');

+ 49 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-or.js

@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    CoalesceExpression is chainable with the BitwiseORExpression
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = null ?? 1 | 42;
+assert.sameValue(x, 43, 'null ?? 1 | 42');
+
+x = undefined ?? 1 | 42;
+assert.sameValue(x, 43, 'null ?? 1 | 42');
+
+x = false ?? 1 | 42;
+assert.sameValue(x, false, 'false ?? 1 | 42');
+
+x = true ?? 1 | 42;
+assert.sameValue(x, true, 'true ?? 1 | 42');

+ 49 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable-with-bitwise-xor.js

@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    CoalesceExpression is chainable with the BitwiseXORExpression
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = null ?? 1 ^ 42;
+assert.sameValue(x, 43, 'null ?? 1 ^ 42');
+
+x = undefined ?? 1 ^ 42;
+assert.sameValue(x, 43, 'null ?? 1 ^ 42');
+
+x = false ?? 1 ^ 42;
+assert.sameValue(x, false, 'false ?? 1 ^ 42');
+
+x = true ?? 1 ^ 42;
+assert.sameValue(x, true, 'true ?? 1 ^ 42');

+ 50 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/chainable.js

@@ -0,0 +1,50 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
+    Otherwise, return the left-side value.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = null ?? undefined ?? 42;
+assert.sameValue(x, 42, 'null ?? undefined ?? 42');
+
+x = undefined ?? null ?? 42;
+assert.sameValue(x, 42, 'undefined ?? null ?? 42');
+
+x = null ?? null ?? 42;
+assert.sameValue(x, 42, 'null ?? null ?? 42');
+
+x = undefined ?? undefined ?? 42;
+assert.sameValue(x, 42, 'null ?? null ?? 42');

+ 49 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/follows-null.js

@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    If the CoalesceExpressionHead is null, follow return the right-side eval.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = null ?? 42;
+assert.sameValue(x, 42, 'null ?? 42');
+
+x = null ?? undefined;
+assert.sameValue(x, undefined, 'null ?? undefined');
+
+x = null ?? null;
+assert.sameValue(x, null, 'null ?? null');
+
+x = null ?? false;
+assert.sameValue(x, false, 'null ?? false');

+ 49 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/follows-undefined.js

@@ -0,0 +1,49 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    If the CoalesceExpressionHead is undefined, follow return the right-side eval.
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined ?? 42;
+assert.sameValue(x, 42, 'undefined ?? 42');
+
+x = undefined ?? undefined;
+assert.sameValue(x, undefined, 'undefined ?? undefined');
+
+x = undefined ?? null;
+assert.sameValue(x, null, 'undefined ?? null');
+
+x = undefined ?? false;
+assert.sameValue(x, false, 'undefined ?? false');

+ 81 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-0.js

@@ -0,0 +1,81 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (0)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = 0 ?? 1;
+assert.sameValue(x, 0, '0 ?? 1');
+
+x = undefined;
+x = 0 ?? null;
+assert.sameValue(x, 0, '0 ?? null');
+
+x = undefined;
+x = 0 ?? undefined;
+assert.sameValue(x, 0, '0 ?? undefined');
+
+x = undefined;
+x = 0 ?? null ?? undefined;
+assert.sameValue(x, 0, '0 ?? null ?? undefined');
+
+x = undefined;
+x = 0 ?? undefined ?? null;
+assert.sameValue(x, 0, '0 ?? undefined ?? null');
+
+x = undefined;
+x = 0 ?? null ?? null;
+assert.sameValue(x, 0, '0 ?? null ?? null');
+
+x = undefined;
+x = 0 ?? undefined ?? undefined;
+assert.sameValue(x, 0, '0 ?? null ?? null');
+
+x = undefined;
+x = null ?? 0 ?? null;
+assert.sameValue(x, 0, 'null ?? 0 ?? null');
+
+x = undefined;
+x = null ?? 0 ?? undefined;
+assert.sameValue(x, 0, 'null ?? 0 ?? undefined');
+
+x = undefined;
+x = undefined ?? 0 ?? null;
+assert.sameValue(x, 0, 'undefined ?? 0 ?? null');
+
+x = undefined;
+x = undefined ?? 0 ?? undefined;
+assert.sameValue(x, 0, 'undefined ?? 0 ?? undefined');

+ 81 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-42.js

@@ -0,0 +1,81 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (42)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = 42 ?? 1;
+assert.sameValue(x, 42, '42 ?? 1');
+
+x = undefined;
+x = 42 ?? null;
+assert.sameValue(x, 42, '42 ?? null');
+
+x = undefined;
+x = 42 ?? undefined;
+assert.sameValue(x, 42, '42 ?? undefined');
+
+x = undefined;
+x = 42 ?? null ?? undefined;
+assert.sameValue(x, 42, '42 ?? null ?? undefined');
+
+x = undefined;
+x = 42 ?? undefined ?? null;
+assert.sameValue(x, 42, '42 ?? undefined ?? null');
+
+x = undefined;
+x = 42 ?? null ?? null;
+assert.sameValue(x, 42, '42 ?? null ?? null');
+
+x = undefined;
+x = 42 ?? undefined ?? undefined;
+assert.sameValue(x, 42, '42 ?? null ?? null');
+
+x = undefined;
+x = null ?? 42 ?? null;
+assert.sameValue(x, 42, 'null ?? 42 ?? null');
+
+x = undefined;
+x = null ?? 42 ?? undefined;
+assert.sameValue(x, 42, 'null ?? 42 ?? undefined');
+
+x = undefined;
+x = undefined ?? 42 ?? null;
+assert.sameValue(x, 42, 'undefined ?? 42 ?? null');
+
+x = undefined;
+x = undefined ?? 42 ?? undefined;
+assert.sameValue(x, 42, 'undefined ?? 42 ?? undefined');

+ 82 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-empty-string.js

@@ -0,0 +1,82 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (the empty string)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+var str = '';
+
+x = undefined;
+x = str ?? 1;
+assert.sameValue(x, str, 'str ?? 1');
+
+x = undefined;
+x = str ?? null;
+assert.sameValue(x, str, 'str ?? null');
+
+x = undefined;
+x = str ?? undefined;
+assert.sameValue(x, str, 'str ?? undefined');
+
+x = undefined;
+x = str ?? null ?? undefined;
+assert.sameValue(x, str, 'str ?? null ?? undefined');
+
+x = undefined;
+x = str ?? undefined ?? null;
+assert.sameValue(x, str, 'str ?? undefined ?? null');
+
+x = undefined;
+x = str ?? null ?? null;
+assert.sameValue(x, str, 'str ?? null ?? null');
+
+x = undefined;
+x = str ?? undefined ?? undefined;
+assert.sameValue(x, str, 'str ?? null ?? null');
+
+x = undefined;
+x = null ?? str ?? null;
+assert.sameValue(x, str, 'null ?? str ?? null');
+
+x = undefined;
+x = null ?? str ?? undefined;
+assert.sameValue(x, str, 'null ?? str ?? undefined');
+
+x = undefined;
+x = undefined ?? str ?? null;
+assert.sameValue(x, str, 'undefined ?? str ?? null');
+
+x = undefined;
+x = undefined ?? str ?? undefined;
+assert.sameValue(x, str, 'undefined ?? str ?? undefined');

+ 81 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-false.js

@@ -0,0 +1,81 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (false)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = false ?? 1;
+assert.sameValue(x, false, 'false ?? 1');
+
+x = undefined;
+x = false ?? null;
+assert.sameValue(x, false, 'false ?? null');
+
+x = undefined;
+x = false ?? undefined;
+assert.sameValue(x, false, 'false ?? undefined');
+
+x = undefined;
+x = false ?? null ?? undefined;
+assert.sameValue(x, false, 'false ?? null ?? undefined');
+
+x = undefined;
+x = false ?? undefined ?? null;
+assert.sameValue(x, false, 'false ?? undefined ?? null');
+
+x = undefined;
+x = false ?? null ?? null;
+assert.sameValue(x, false, 'false ?? null ?? null');
+
+x = undefined;
+x = false ?? undefined ?? undefined;
+assert.sameValue(x, false, 'false ?? null ?? null');
+
+x = undefined;
+x = null ?? false ?? null;
+assert.sameValue(x, false, 'null ?? false ?? null');
+
+x = undefined;
+x = null ?? false ?? undefined;
+assert.sameValue(x, false, 'null ?? false ?? undefined');
+
+x = undefined;
+x = undefined ?? false ?? null;
+assert.sameValue(x, false, 'undefined ?? false ?? null');
+
+x = undefined;
+x = undefined ?? false ?? undefined;
+assert.sameValue(x, false, 'undefined ?? false ?? undefined');

+ 89 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-object.js

@@ -0,0 +1,89 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (object)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+var obj = {
+    toString() {
+        return null;
+    },
+    valueOf() {
+        return null;
+    }
+};
+
+x = undefined;
+x = obj ?? 1;
+assert.sameValue(x, obj, 'obj ?? 1');
+
+x = undefined;
+x = obj ?? null;
+assert.sameValue(x, obj, 'obj ?? null');
+
+x = undefined;
+x = obj ?? undefined;
+assert.sameValue(x, obj, 'obj ?? undefined');
+
+x = undefined;
+x = obj ?? null ?? undefined;
+assert.sameValue(x, obj, 'obj ?? null ?? undefined');
+
+x = undefined;
+x = obj ?? undefined ?? null;
+assert.sameValue(x, obj, 'obj ?? undefined ?? null');
+
+x = undefined;
+x = obj ?? null ?? null;
+assert.sameValue(x, obj, 'obj ?? null ?? null');
+
+x = undefined;
+x = obj ?? undefined ?? undefined;
+assert.sameValue(x, obj, 'obj ?? null ?? null');
+
+x = undefined;
+x = null ?? obj ?? null;
+assert.sameValue(x, obj, 'null ?? obj ?? null');
+
+x = undefined;
+x = null ?? obj ?? undefined;
+assert.sameValue(x, obj, 'null ?? obj ?? undefined');
+
+x = undefined;
+x = undefined ?? obj ?? null;
+assert.sameValue(x, obj, 'undefined ?? obj ?? null');
+
+x = undefined;
+x = undefined ?? obj ?? undefined;
+assert.sameValue(x, obj, 'undefined ?? obj ?? undefined');

+ 82 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-string.js

@@ -0,0 +1,82 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (string)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+var str = 'undefined';
+
+x = undefined;
+x = str ?? 1;
+assert.sameValue(x, str, 'str ?? 1');
+
+x = undefined;
+x = str ?? null;
+assert.sameValue(x, str, 'str ?? null');
+
+x = undefined;
+x = str ?? undefined;
+assert.sameValue(x, str, 'str ?? undefined');
+
+x = undefined;
+x = str ?? null ?? undefined;
+assert.sameValue(x, str, 'str ?? null ?? undefined');
+
+x = undefined;
+x = str ?? undefined ?? null;
+assert.sameValue(x, str, 'str ?? undefined ?? null');
+
+x = undefined;
+x = str ?? null ?? null;
+assert.sameValue(x, str, 'str ?? null ?? null');
+
+x = undefined;
+x = str ?? undefined ?? undefined;
+assert.sameValue(x, str, 'str ?? null ?? null');
+
+x = undefined;
+x = null ?? str ?? null;
+assert.sameValue(x, str, 'null ?? str ?? null');
+
+x = undefined;
+x = null ?? str ?? undefined;
+assert.sameValue(x, str, 'null ?? str ?? undefined');
+
+x = undefined;
+x = undefined ?? str ?? null;
+assert.sameValue(x, str, 'undefined ?? str ?? null');
+
+x = undefined;
+x = undefined ?? str ?? undefined;
+assert.sameValue(x, str, 'undefined ?? str ?? undefined');

+ 82 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-symbol.js

@@ -0,0 +1,82 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (Symbol)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+var s = Symbol();
+
+x = undefined;
+x = s ?? 1;
+assert.sameValue(x, s, 's ?? null');
+
+x = undefined;
+x = s ?? null;
+assert.sameValue(x, s, 's ?? null');
+
+x = undefined;
+x = s ?? undefined;
+assert.sameValue(x, s, 's ?? undefined');
+
+x = undefined;
+x = s ?? null ?? undefined;
+assert.sameValue(x, s, 's ?? null ?? undefined');
+
+x = undefined;
+x = s ?? undefined ?? null;
+assert.sameValue(x, s, 's ?? undefined ?? null');
+
+x = undefined;
+x = s ?? null ?? null;
+assert.sameValue(x, s, 's ?? null ?? null');
+
+x = undefined;
+x = s ?? undefined ?? undefined;
+assert.sameValue(x, s, 's ?? null ?? null');
+
+x = undefined;
+x = null ?? s ?? null;
+assert.sameValue(x, s, 'null ?? s ?? null');
+
+x = undefined;
+x = null ?? s ?? undefined;
+assert.sameValue(x, s, 'null ?? s ?? undefined');
+
+x = undefined;
+x = undefined ?? s ?? null;
+assert.sameValue(x, s, 'undefined ?? s ?? null');
+
+x = undefined;
+x = undefined ?? s ?? undefined;
+assert.sameValue(x, s, 'undefined ?? s ?? undefined');

+ 81 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-number-true.js

@@ -0,0 +1,81 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit if the CoalesceExpressionHead is not undefined or null (true)
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+
+x = undefined;
+x = true ?? 1;
+assert.sameValue(x, true, 'true ?? null');
+
+x = undefined;
+x = true ?? null;
+assert.sameValue(x, true, 'true ?? null');
+
+x = undefined;
+x = true ?? undefined;
+assert.sameValue(x, true, 'true ?? undefined');
+
+x = undefined;
+x = true ?? null ?? undefined;
+assert.sameValue(x, true, 'true ?? null ?? undefined');
+
+x = undefined;
+x = true ?? undefined ?? null;
+assert.sameValue(x, true, 'true ?? undefined ?? null');
+
+x = undefined;
+x = true ?? null ?? null;
+assert.sameValue(x, true, 'true ?? null ?? null');
+
+x = undefined;
+x = true ?? undefined ?? undefined;
+assert.sameValue(x, true, 'true ?? null ?? null');
+
+x = undefined;
+x = null ?? true ?? null;
+assert.sameValue(x, true, 'null ?? true ?? null');
+
+x = undefined;
+x = null ?? true ?? undefined;
+assert.sameValue(x, true, 'null ?? true ?? undefined');
+
+x = undefined;
+x = undefined ?? true ?? null;
+assert.sameValue(x, true, 'undefined ?? true ?? null');
+
+x = undefined;
+x = undefined ?? true ?? undefined;
+assert.sameValue(x, true, 'undefined ?? true ?? undefined');

+ 56 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/short-circuit-prevents-evaluation.js

@@ -0,0 +1,56 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+    Short circuit can prevent evaluation of the right-side expressions
+esid: sec-conditional-operator
+info: |
+    ConditionalExpression :
+        ShortCircuitExpression
+        ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
+
+    ShortCircuitExpression :
+        LogicalORExpression
+        CoalesceExpression
+
+    CoalesceExpression :
+        CoalesceExpressionHead ?? BitwiseORExpression
+
+    CoalesceExpressionHead :
+        CoalesceExpression
+        BitwiseORExpression
+
+    Runtime Semantics: Evaluation
+
+    CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
+
+    1. Let lref be the result of evaluating CoalesceExpressionHead.
+    2. Let lval be ? GetValue(lref).
+    3. If lval is undefined or null,
+        a. Let rref be the result of evaluating BitwiseORExpression.
+        b. Return ? GetValue(rref).
+    4. Otherwise, return lval.
+features: [coalesce-expression]
+---*/
+
+var x;
+function poison() {
+    throw new Test262Error('should not evaluate poison');
+}
+
+x = undefined;
+x = undefined ?? 42 ?? undefined ?? poison();
+assert.sameValue(x, 42);
+
+x = undefined;
+x = 42 ?? undefined ?? poison();
+assert.sameValue(x, 42);
+
+x = undefined;
+x = undefined ?? 42 ?? poison();
+assert.sameValue(x, 42);
+
+x = undefined;
+x = 42 ?? poison();
+assert.sameValue(x, 42);

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/tco-pos-null.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Expression is a candidate for tail-call optimization.
+esid: sec-static-semantics-hascallintailposition
+info: |
+  Expression Rules
+
+  CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
+
+  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
+flags: [onlyStrict]
+features: [tail-call-optimization, coalesce-expression]
+includes: [tcoHelper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return null ?? f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);

+ 26 - 0
Jint.Tests.Test262/test/language/expressions/coalesce/tco-pos-undefined.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Expression is a candidate for tail-call optimization.
+esid: sec-static-semantics-hascallintailposition
+info: |
+  Expression Rules
+
+  CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
+
+  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
+flags: [onlyStrict]
+features: [tail-call-optimization, coalesce-expression]
+includes: [tcoHelper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return undefined ?? f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);

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

@@ -15,7 +15,7 @@
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="Flurl.Http.Signed" Version="3.0.0" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
     <PackageReference Include="MongoDB.Bson.signed" Version="2.11.2" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
     <PackageReference Include="xunit" Version="2.4.1" />

+ 1 - 1
Jint/Jint.csproj

@@ -7,6 +7,6 @@
     <LangVersion>latest</LangVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="2.0.0-beta-1328" />
+    <PackageReference Include="Esprima" Version="2.0.0-beta-1331" />
   </ItemGroup>
 </Project>

+ 3 - 4
Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs

@@ -11,13 +11,11 @@ namespace Jint.Runtime.Interpreter.Expressions
     {
         private readonly JintExpression _left;
         private readonly JintExpression _right;
-        private readonly BinaryOperator _operatorType;
 
         private JintBinaryExpression(Engine engine, BinaryExpression expression) : base(engine, expression)
         {
             _left = Build(engine, expression.Left);
             _right = Build(engine, expression.Right);
-            _operatorType = expression.Operator;
         }
 
         internal static JintExpression Build(Engine engine, BinaryExpression expression)
@@ -82,7 +80,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                     result = new InBinaryExpression(engine, expression);
                     break;                
                 default:
-                    result = ExceptionHelper.ThrowArgumentOutOfRangeException<JintBinaryExpression>(nameof(_operatorType), "cannot handle operator");
+                    result = ExceptionHelper.ThrowArgumentOutOfRangeException<JintBinaryExpression>(nameof(expression.Operator), "cannot handle operator");
                     break;
             }
 
@@ -94,7 +92,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 var lval = JintLiteralExpression.ConvertToJsValue(leftLiteral);
                 var rval = JintLiteralExpression.ConvertToJsValue(rightLiteral);
 
-                if (!(lval is null) && !(rval is null))
+                if (lval is not null && rval is not null)
                 {
                     // we have fixed result
                     return new JintConstantExpression(engine, expression, result.GetValue());
@@ -530,5 +528,6 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
             }
         }
+
     }
 }

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

@@ -69,6 +69,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 {
                     BinaryOperator.LogicalAnd => new JintLogicalAndExpression(engine, (BinaryExpression) expression),
                     BinaryOperator.LogicalOr => new JintLogicalOrExpression(engine, (BinaryExpression) expression),
+                    BinaryOperator.NullishCoalescing => new NullishCoalescingExpression(engine, (BinaryExpression) expression),
                     _ => ExceptionHelper.ThrowArgumentOutOfRangeException<JintExpression>()
                 },
                 Nodes.MemberExpression => new JintMemberExpression(engine, (MemberExpression) expression),

+ 50 - 0
Jint/Runtime/Interpreter/Expressions/NullishCoalescingExpression.cs

@@ -0,0 +1,50 @@
+using System.Runtime.CompilerServices;
+using Esprima.Ast;
+using Jint.Native;
+
+namespace Jint.Runtime.Interpreter.Expressions
+{
+    internal sealed class NullishCoalescingExpression : JintExpression
+    {
+        private readonly JintExpression _left;
+        private readonly JintExpression _right;
+        private readonly JsValue _constant;
+
+        public NullishCoalescingExpression(Engine engine, BinaryExpression expression) : base(engine, expression)
+        {
+            _left = Build(engine, expression.Left);
+
+            // we can create a fast path for common literal case like variable ?? 0
+            if (expression.Right is Literal l)
+            {
+                _constant = JintLiteralExpression.ConvertToJsValue(l);
+            }
+            else
+            {
+                _right = Build(engine, expression.Right);
+            }
+        }
+
+        public override JsValue GetValue()
+        {
+            // need to notify correct node when taking shortcut
+            _engine._lastSyntaxNode = _expression;
+            return EvaluateConstantOrExpression();
+        }
+
+        protected override object EvaluateInternal()
+        {
+            return EvaluateConstantOrExpression();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private JsValue EvaluateConstantOrExpression()
+        {
+            var left = _left.GetValue();
+
+            return !left.IsNullOrUndefined()
+                ? left
+                : _constant ?? _right.GetValue();
+        }
+    }
+}