From 304e178946ae985599bc17003960fbe49ed01f14 Mon Sep 17 00:00:00 2001 From: "satish.srinivasan" Date: Thu, 29 Aug 2024 22:59:12 +0530 Subject: [PATCH] FIX: test with all opt levels --- .../org/mozilla/javascript/IRFactory.java | 6 +- .../java/org/mozilla/javascript/Parser.java | 12 ++- .../org/mozilla/javascript/ast/AstNode.java | 1 + .../javascript/resources/Messages.properties | 3 + .../resources/Messages_fr.properties | 3 + .../tests/NullishCoalescingOpTest.java | 74 +++++++++++-------- tests/testsrc/test262.properties | 4 +- 7 files changed, 68 insertions(+), 35 deletions(-) diff --git a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java index eebfe47a2f..25faea2892 100644 --- a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java +++ b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java @@ -2053,7 +2053,11 @@ private static Node createBinary(int nodeType, Node left, Node right) { new Node(Token.SHEQ, nullNode, left), new Node(Token.SHEQ, undefinedNode, left)); - return new Node(Token.HOOK, conditional, right, left); + return new Node( + Token.HOOK, + /* left= */ conditional, + /* mid= */ right, + /* right= */ left); } } diff --git a/rhino/src/main/java/org/mozilla/javascript/Parser.java b/rhino/src/main/java/org/mozilla/javascript/Parser.java index 3014c977dc..09aab64f8c 100644 --- a/rhino/src/main/java/org/mozilla/javascript/Parser.java +++ b/rhino/src/main/java/org/mozilla/javascript/Parser.java @@ -2406,7 +2406,17 @@ private AstNode nullishCoalescingExpr() throws IOException { AstNode pn = orExpr(); if (matchToken(Token.NULLISH_COALESCING, true)) { int opPos = ts.tokenBeg; - pn = new InfixExpression(Token.NULLISH_COALESCING, pn, nullishCoalescingExpr(), opPos); + AstNode rn = nullishCoalescingExpr(); + + // Cannot immediately contain, or be contained within, an && or || operation. + if (pn.getType() == Token.OR + || pn.getType() == Token.AND + || rn.getType() == Token.OR + || rn.getType() == Token.AND) { + reportError("msg.nullish.bad.token"); + } + + pn = new InfixExpression(Token.NULLISH_COALESCING, pn, rn, opPos); } return pn; } diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/AstNode.java b/rhino/src/main/java/org/mozilla/javascript/ast/AstNode.java index c40dcf720c..45225ebb53 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/AstNode.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/AstNode.java @@ -82,6 +82,7 @@ public abstract class AstNode extends Node implements Comparable { operatorNames.put(Token.COMMA, ","); operatorNames.put(Token.COLON, ":"); operatorNames.put(Token.OR, "||"); + operatorNames.put(Token.NULLISH_COALESCING, "??"); operatorNames.put(Token.AND, "&&"); operatorNames.put(Token.INC, "++"); operatorNames.put(Token.DEC, "--"); diff --git a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties index 642491e89c..a91dcd0aec 100644 --- a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties +++ b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties @@ -122,6 +122,9 @@ msg.bad.yield =\ msg.yield.parenthesized =\ yield expression must be parenthesized. +msg.nullish.bad.token =\ + Syntax Error: Unexpected token. + # NativeGlobal msg.cant.call.indirect =\ Function "{0}" must be called directly, and not by way of a \ diff --git a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages_fr.properties b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages_fr.properties index 2082b17c72..436ebccdb0 100644 --- a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages_fr.properties +++ b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages_fr.properties @@ -87,6 +87,9 @@ msg.bad.yield =\ msg.yield.parenthesized =\ L''expression suivant ''yield'' doit \u00eatre entre parenth\u00e8ses. +msg.nullish.bad.token =\ + Erreur de syntaxe: Jeton inattendu. + # NativeGlobal msg.cant.call.indirect =\ La fonction "{0}" doit \u00EAtre appel\u00E9e directement et non par l''interm\u00E9diaire \ diff --git a/tests/src/test/java/org/mozilla/javascript/tests/NullishCoalescingOpTest.java b/tests/src/test/java/org/mozilla/javascript/tests/NullishCoalescingOpTest.java index 6e3c4aee59..861a5d9364 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/NullishCoalescingOpTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/NullishCoalescingOpTest.java @@ -9,41 +9,51 @@ public class NullishCoalescingOpTest { @Test public void testNullishColascingBasic() { - try (Context cx = Context.enter()) { - Scriptable scope = cx.initStandardObjects(); - cx.setLanguageVersion(Context.VERSION_ES6); - - String script = "null ?? 'default string'"; - Assert.assertEquals( - "default string", - cx.evaluateString(scope, script, "nullish coalescing basic", 0, null)); - - String script2 = "undefined ?? 'default string'"; - Assert.assertEquals( - "default string", - cx.evaluateString(scope, script2, "nullish coalescing basic", 0, null)); - } + Utils.runWithAllOptimizationLevels( + cx -> { + Scriptable scope = cx.initStandardObjects(); + cx.setLanguageVersion(Context.VERSION_ES6); + + String script = "null ?? 'default string'"; + Assert.assertEquals( + "default string", + cx.evaluateString(scope, script, "nullish coalescing basic", 0, null)); + + String script2 = "undefined ?? 'default string'"; + Assert.assertEquals( + "default string", + cx.evaluateString(scope, script2, "nullish coalescing basic", 0, null)); + return null; + }); + } + + @Test + public void testNullishColascingShortCircuit() { + String script = "0 || 0 ?? true"; + Utils.assertEvaluatorExceptionES6("Syntax Error: Unexpected token. (test#1)", script); + + String script2 = "0 && 0 ?? true"; + Utils.assertEvaluatorExceptionES6("Syntax Error: Unexpected token. (test#1)", script2); + + String script3 = "0 ?? 0 && true;"; + Utils.assertEvaluatorExceptionES6("Syntax Error: Unexpected token. (test#1)", script3); + + String script4 = "0 ?? 0 || true;"; + Utils.assertEvaluatorExceptionES6("Syntax Error: Unexpected token. (test#1)", script4); } @Test public void testNullishColascingPrecedence() { - try (Context cx = Context.enter()) { - Scriptable scope = cx.initStandardObjects(); - cx.setLanguageVersion(Context.VERSION_ES6); - cx.setOptimizationLevel(-1); - - String script1 = "3 == 3 ? 'yes' ?? 'default string' : 'no'"; - Assert.assertEquals( - "yes", cx.evaluateString(scope, script1, "nullish coalescing basic", 0, null)); - - String script3 = "3 || null ?? 'default string'"; - Assert.assertEquals( - 3.0, cx.evaluateString(scope, script3, "nullish coalescing basic", 0, null)); - - String script2 = "3 && null ?? 'default string'"; - Assert.assertEquals( - "default string", - cx.evaluateString(scope, script2, "nullish coalescing basic", 0, null)); - } + Utils.runWithAllOptimizationLevels( + cx -> { + Scriptable scope = cx.initStandardObjects(); + cx.setLanguageVersion(Context.VERSION_ES6); + + String script1 = "3 == 3 ? 'yes' ?? 'default string' : 'no'"; + Assert.assertEquals( + "yes", + cx.evaluateString(scope, script1, "nullish coalescing basic", 0, null)); + return null; + }); } } diff --git a/tests/testsrc/test262.properties b/tests/testsrc/test262.properties index 838524d971..c758217d8f 100644 --- a/tests/testsrc/test262.properties +++ b/tests/testsrc/test262.properties @@ -4470,7 +4470,9 @@ language/expressions/call 60/92 (65.22%) ~language/expressions/class -~language/expressions/coalesce +language/expressions/coalesce 2/24 (8.33%) + tco-pos-null.js {unsupported: [tail-call-optimization]} + tco-pos-undefined.js {unsupported: [tail-call-optimization]} language/expressions/comma 1/6 (16.67%) tco-final.js {unsupported: [tail-call-optimization]}