Skip to content

Commit

Permalink
Add nullish coalescing
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea authored Apr 13, 2020
1 parent b4a6e52 commit ec7cbd1
Show file tree
Hide file tree
Showing 7 changed files with 570 additions and 4 deletions.
2 changes: 1 addition & 1 deletion acorn-loose/src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ lp.parseExprOp = function(left, start, minPrec, noIn, indent, line) {
let rightStart = this.storeCurrentPos()
node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line)
}
this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression")
this.finishNode(node, /&&|\|\||\?\?/.test(node.operator) ? "LogicalExpression" : "BinaryExpression")
return this.parseExprOp(node, start, minPrec, noIn, indent, line)
}
}
Expand Down
11 changes: 10 additions & 1 deletion acorn/src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,20 @@ pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
if (prec != null && (!noIn || this.type !== tt._in)) {
if (prec > minPrec) {
let logical = this.type === tt.logicalOR || this.type === tt.logicalAND
let coalesce = this.type === tt.coalesce
if (coalesce) {
// Handle the precedence of `tt.coalesce` as equal to the range of logical expressions.
// In other words, `node.right` shouldn't contain logical expressions in order to check the mixed error.
prec = tt.logicalAND.binop
}
let op = this.value
this.next()
let startPos = this.start, startLoc = this.startLoc
let right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn)
let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical)
let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce)
if ((logical && this.type === tt.coalesce) || (coalesce && (this.type === tt.logicalOR || this.type === tt.logicalAND))) {
this.raiseRecoverable(this.start, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses")
}
return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn)
}
}
Expand Down
12 changes: 11 additions & 1 deletion acorn/src/tokenize.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ pp.readToken_eq_excl = function(code) { // '=!'
return this.finishOp(code === 61 ? tt.eq : tt.prefix, 1)
}

pp.readToken_question = function() { // '?'
if (this.options.ecmaVersion >= 11) {
let next = this.input.charCodeAt(this.pos + 1)
if (next === 63) return this.finishOp(tt.coalesce, 2)
}
return this.finishOp(tt.question, 1)
}

pp.getTokenFromCode = function(code) {
switch (code) {
// The interpretation of a dot depends on whether it is followed
Expand All @@ -306,7 +314,6 @@ pp.getTokenFromCode = function(code) {
case 123: ++this.pos; return this.finishToken(tt.braceL)
case 125: ++this.pos; return this.finishToken(tt.braceR)
case 58: ++this.pos; return this.finishToken(tt.colon)
case 63: ++this.pos; return this.finishToken(tt.question)

case 96: // '`'
if (this.options.ecmaVersion < 6) break
Expand Down Expand Up @@ -356,6 +363,9 @@ pp.getTokenFromCode = function(code) {
case 61: case 33: // '=!'
return this.readToken_eq_excl(code)

case 63: // '?'
return this.readToken_question()

case 126: // '~'
return this.finishOp(tt.prefix, 1)
}
Expand Down
1 change: 1 addition & 0 deletions acorn/src/tokentype.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export const types = {
star: binop("*", 10),
slash: binop("/", 10),
starstar: new TokenType("**", {beforeExpr: true}),
coalesce: binop("??", 1),

// Keyword token types.
_break: kw("break"),
Expand Down
1 change: 0 additions & 1 deletion bin/run_test262.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const unsupportedFeatures = [
"class-static-fields-private",
"class-static-fields-public",
"class-static-methods-private",
"coalesce-expression",
"numeric-separator-literal",
"optional-chaining",
"top-level-await"
Expand Down
1 change: 1 addition & 0 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
require("./tests-dynamic-import.js");
require("./tests-export-all-as-ns-from-source.js");
require("./tests-import-meta.js");
require("./tests-nullish-coalescing.js");
var acorn = require("../acorn")
var acorn_loose = require("../acorn-loose")

Expand Down
Loading

0 comments on commit ec7cbd1

Please sign in to comment.