Skip to content

Commit

Permalink
FEAT: Implement ??
Browse files Browse the repository at this point in the history
Co-authored-by: Greg Caban <[email protected]>
  • Loading branch information
0xe and nabacg committed Sep 10, 2024
1 parent 19eabd3 commit 6996917
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 6 deletions.
17 changes: 17 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -2038,6 +2038,23 @@ private static Node createBinary(int nodeType, Node left, Node right) {
}
break;
}

case Token.NULLISH_COALESCING:
{
// foo ?? default =>
// (foo == undefined || foo == null) ? foo (left) : default (right)

Node undefinedNode = new Name(0, "undefined");
Node nullNode = new Node(Token.NULL);

Node conditional =
new Node(
Token.OR,
new Node(Token.SHEQ, nullNode, left),
new Node(Token.SHEQ, undefinedNode, left));

return new Node(Token.HOOK, conditional, right, left);
}
}

return new Node(nodeType, left, right);
Expand Down
11 changes: 10 additions & 1 deletion rhino/src/main/java/org/mozilla/javascript/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2370,7 +2370,7 @@ private AstNode assignExpr() throws IOException {
}

private AstNode condExpr() throws IOException {
AstNode pn = orExpr();
AstNode pn = nullishCoalescingExpr();
if (matchToken(Token.HOOK, true)) {
int line = ts.lineno;
int qmarkPos = ts.tokenBeg, colonPos = -1;
Expand Down Expand Up @@ -2402,6 +2402,15 @@ private AstNode condExpr() throws IOException {
return pn;
}

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);
}
return pn;
}

private AstNode orExpr() throws IOException {
AstNode pn = andExpr();
if (matchToken(Token.OR, true)) {
Expand Down
5 changes: 4 additions & 1 deletion rhino/src/main/java/org/mozilla/javascript/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ public static enum CommentType {
TEMPLATE_LITERAL_SUBST = 175, // template literal - substitution
TAGGED_TEMPLATE_LITERAL = 176, // template literal - tagged/handler
DOTDOTDOT = 177, // spread/rest ...
LAST_TOKEN = 177;
NULLISH_COALESCING = 178, // nullish coalescing (??)
LAST_TOKEN = 178;

/**
* Returns a name for the token. If Rhino is compiled with certain hardcoded debugging flags in
Expand Down Expand Up @@ -468,6 +469,8 @@ public static String typeToName(int token) {
return "COLON";
case OR:
return "OR";
case NULLISH_COALESCING:
return "NULLISH_COALESCING";
case AND:
return "AND";
case INC:
Expand Down
3 changes: 3 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/TokenStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,9 @@ && peekChar() == '!'
case ',':
return Token.COMMA;
case '?':
if (matchChar('?')) {
return Token.NULLISH_COALESCING;
}
return Token.HOOK;
case ':':
if (matchChar(':')) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.mozilla.javascript.tests;

import org.junit.Assert;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

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));
}
}

@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));
}
}
}
6 changes: 2 additions & 4 deletions tests/testsrc/test262.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4616,8 +4616,7 @@ language/expressions/compound-assignment 137/454 (30.18%)

language/expressions/concatenation 0/5 (0.0%)

language/expressions/conditional 3/22 (13.64%)
coalesce-expr-ternary.js
language/expressions/conditional 2/22 (9.09%)
tco-cond.js {unsupported: [tail-call-optimization]}
tco-pos.js {unsupported: [tail-call-optimization]}

Expand Down Expand Up @@ -5271,7 +5270,7 @@ language/expressions/new 41/59 (69.49%)

~language/expressions/new.target

language/expressions/object 864/1169 (73.91%)
language/expressions/object 865/1169 (73.99%)
dstr/async-gen-meth-ary-init-iter-close.js {unsupported: [async-iteration, async]}
dstr/async-gen-meth-ary-init-iter-get-err.js {unsupported: [async-iteration]}
dstr/async-gen-meth-ary-init-iter-get-err-array-prototype.js {unsupported: [async-iteration]}
Expand Down Expand Up @@ -6077,7 +6076,6 @@ language/expressions/object 864/1169 (73.91%)
cpn-obj-lit-computed-property-name-from-assignment-expression-coalesce.js
cpn-obj-lit-computed-property-name-from-async-arrow-function-expression.js
cpn-obj-lit-computed-property-name-from-await-expression.js {unsupported: [module, async]}
cpn-obj-lit-computed-property-name-from-expression-coalesce.js
cpn-obj-lit-computed-property-name-from-yield-expression.js
fn-name-accessor-get.js
fn-name-accessor-set.js
Expand Down

0 comments on commit 6996917

Please sign in to comment.