Skip to content

Commit

Permalink
add logical assignment operators
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea authored and marijnh committed Aug 3, 2020
1 parent 459fa1e commit fe7b3f1
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 5 deletions.
19 changes: 16 additions & 3 deletions acorn/src/tokenize.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,13 @@ pp.readToken_mult_modulo_exp = function(code) { // '%*'

pp.readToken_pipe_amp = function(code) { // '|&'
let next = this.input.charCodeAt(this.pos + 1)
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)
if (next === code) {
if (this.options.ecmaVersion >= 12) {
let next2 = this.input.charCodeAt(this.pos + 2)
if (next2 === 61) return this.finishOp(tt.assign, 3)
}
return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)
}
if (next === 61) return this.finishOp(tt.assign, 2)
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1)
}
Expand Down Expand Up @@ -290,13 +296,20 @@ pp.readToken_eq_excl = function(code) { // '=!'
}

pp.readToken_question = function() { // '?'
if (this.options.ecmaVersion >= 11) {
const ecmaVersion = this.options.ecmaVersion
if (ecmaVersion >= 11) {
let next = this.input.charCodeAt(this.pos + 1)
if (next === 46) {
let next2 = this.input.charCodeAt(this.pos + 2)
if (next2 < 48 || next2 > 57) return this.finishOp(tt.questionDot, 2)
}
if (next === 63) return this.finishOp(tt.coalesce, 2)
if (next === 63) {
if (ecmaVersion >= 12) {
let next2 = this.input.charCodeAt(this.pos + 2)
if (next2 === 61) return this.finishOp(tt.assign, 3)
}
return this.finishOp(tt.coalesce, 2)
}
}
return this.finishOp(tt.question, 1)
}
Expand Down
3 changes: 1 addition & 2 deletions bin/run_test262.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ const unsupportedFeatures = [
"class-static-fields-public",
"class-static-methods-private",
"numeric-separator-literal",
"logical-assignment-operators",
];

run(
(content, {sourceType}) => parse(content, {sourceType, ecmaVersion: 11, allowHashBang: true, allowAwaitOutsideFunction: true}),
(content, {sourceType}) => parse(content, {sourceType, ecmaVersion: 12, allowHashBang: true, allowAwaitOutsideFunction: true}),
{
testsDirectory: path.dirname(require.resolve("test262/package.json")),
skip: test => (test.attrs.features && unsupportedFeatures.some(f => test.attrs.features.includes(f))),
Expand Down
1 change: 1 addition & 0 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
require("./tests-import-meta.js");
require("./tests-nullish-coalescing.js");
require("./tests-optional-chaining.js");
require("./tests-logical-assignment-operators.js");
var acorn = require("../acorn")
var acorn_loose = require("../acorn-loose")

Expand Down
182 changes: 182 additions & 0 deletions test/tests-logical-assignment-operators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Tests for ECMAScript 2021 `&&=`, `||=`, `??=`

if (typeof exports != 'undefined') {
var test = require('./driver.js').test;
var testFail = require('./driver.js').testFail;
}

test(
"a &&= b",
{
"type": "Program",
"start": 0,
"end": 7,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 7,
"expression": {
"type": "AssignmentExpression",
"start": 0,
"end": 7,
"operator": "&&=",
"left": {
"type": "Identifier",
"start": 0,
"end": 1,
"name": "a"
},
"right": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "b"
}
}
}
],
"sourceType": "script"
},
{ ecmaVersion: 12 }
);

test(
"a ||= b",
{
"type": "Program",
"start": 0,
"end": 7,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 7,
"expression": {
"type": "AssignmentExpression",
"start": 0,
"end": 7,
"operator": "||=",
"left": {
"type": "Identifier",
"start": 0,
"end": 1,
"name": "a"
},
"right": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "b"
}
}
}
],
"sourceType": "script"
},
{ ecmaVersion: 12 }
);

test(
"a ??= b",
{
"type": "Program",
"start": 0,
"end": 7,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 7,
"expression": {
"type": "AssignmentExpression",
"start": 0,
"end": 7,
"operator": "??=",
"left": {
"type": "Identifier",
"start": 0,
"end": 1,
"name": "a"
},
"right": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "b"
}
}
}
],
"sourceType": "script"
},
{ ecmaVersion: 12 }
);

test(
"a &&= b ||= c ??= d",
{
"type": "Program",
"start": 0,
"end": 19,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 19,
"expression": {
"type": "AssignmentExpression",
"start": 0,
"end": 19,
"operator": "&&=",
"left": {
"type": "Identifier",
"start": 0,
"end": 1,
"name": "a"
},
"right": {
"type": "AssignmentExpression",
"start": 6,
"end": 19,
"operator": "||=",
"left": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "b"
},
"right": {
"type": "AssignmentExpression",
"start": 12,
"end": 19,
"operator": "??=",
"left": {
"type": "Identifier",
"start": 12,
"end": 13,
"name": "c"
},
"right": {
"type": "Identifier",
"start": 18,
"end": 19,
"name": "d"
}
}
}
}
}
],
"sourceType": "script"
},
{ ecmaVersion: 12 }
);

testFail("a &&= b", "Unexpected token (1:4)", { ecmaVersion: 11 });
testFail("a ||= b", "Unexpected token (1:4)", { ecmaVersion: 11 });
testFail("a ??= b", "Unexpected token (1:4)", { ecmaVersion: 11 });

testFail("({a} &&= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });
testFail("({a} ||= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });
testFail("({a} ??= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });

0 comments on commit fe7b3f1

Please sign in to comment.