Skip to content

Commit fe7b3f1

Browse files
mysticateamarijnh
authored andcommitted
add logical assignment operators
1 parent 459fa1e commit fe7b3f1

File tree

4 files changed

+200
-5
lines changed

4 files changed

+200
-5
lines changed

acorn/src/tokenize.js

+16-3
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,13 @@ pp.readToken_mult_modulo_exp = function(code) { // '%*'
233233

234234
pp.readToken_pipe_amp = function(code) { // '|&'
235235
let next = this.input.charCodeAt(this.pos + 1)
236-
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)
236+
if (next === code) {
237+
if (this.options.ecmaVersion >= 12) {
238+
let next2 = this.input.charCodeAt(this.pos + 2)
239+
if (next2 === 61) return this.finishOp(tt.assign, 3)
240+
}
241+
return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)
242+
}
237243
if (next === 61) return this.finishOp(tt.assign, 2)
238244
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1)
239245
}
@@ -290,13 +296,20 @@ pp.readToken_eq_excl = function(code) { // '=!'
290296
}
291297

292298
pp.readToken_question = function() { // '?'
293-
if (this.options.ecmaVersion >= 11) {
299+
const ecmaVersion = this.options.ecmaVersion
300+
if (ecmaVersion >= 11) {
294301
let next = this.input.charCodeAt(this.pos + 1)
295302
if (next === 46) {
296303
let next2 = this.input.charCodeAt(this.pos + 2)
297304
if (next2 < 48 || next2 > 57) return this.finishOp(tt.questionDot, 2)
298305
}
299-
if (next === 63) return this.finishOp(tt.coalesce, 2)
306+
if (next === 63) {
307+
if (ecmaVersion >= 12) {
308+
let next2 = this.input.charCodeAt(this.pos + 2)
309+
if (next2 === 61) return this.finishOp(tt.assign, 3)
310+
}
311+
return this.finishOp(tt.coalesce, 2)
312+
}
300313
}
301314
return this.finishOp(tt.question, 1)
302315
}

bin/run_test262.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ const unsupportedFeatures = [
1111
"class-static-fields-public",
1212
"class-static-methods-private",
1313
"numeric-separator-literal",
14-
"logical-assignment-operators",
1514
];
1615

1716
run(
18-
(content, {sourceType}) => parse(content, {sourceType, ecmaVersion: 11, allowHashBang: true, allowAwaitOutsideFunction: true}),
17+
(content, {sourceType}) => parse(content, {sourceType, ecmaVersion: 12, allowHashBang: true, allowAwaitOutsideFunction: true}),
1918
{
2019
testsDirectory: path.dirname(require.resolve("test262/package.json")),
2120
skip: test => (test.attrs.features && unsupportedFeatures.some(f => test.attrs.features.includes(f))),

test/run.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
require("./tests-import-meta.js");
2222
require("./tests-nullish-coalescing.js");
2323
require("./tests-optional-chaining.js");
24+
require("./tests-logical-assignment-operators.js");
2425
var acorn = require("../acorn")
2526
var acorn_loose = require("../acorn-loose")
2627

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Tests for ECMAScript 2021 `&&=`, `||=`, `??=`
2+
3+
if (typeof exports != 'undefined') {
4+
var test = require('./driver.js').test;
5+
var testFail = require('./driver.js').testFail;
6+
}
7+
8+
test(
9+
"a &&= b",
10+
{
11+
"type": "Program",
12+
"start": 0,
13+
"end": 7,
14+
"body": [
15+
{
16+
"type": "ExpressionStatement",
17+
"start": 0,
18+
"end": 7,
19+
"expression": {
20+
"type": "AssignmentExpression",
21+
"start": 0,
22+
"end": 7,
23+
"operator": "&&=",
24+
"left": {
25+
"type": "Identifier",
26+
"start": 0,
27+
"end": 1,
28+
"name": "a"
29+
},
30+
"right": {
31+
"type": "Identifier",
32+
"start": 6,
33+
"end": 7,
34+
"name": "b"
35+
}
36+
}
37+
}
38+
],
39+
"sourceType": "script"
40+
},
41+
{ ecmaVersion: 12 }
42+
);
43+
44+
test(
45+
"a ||= b",
46+
{
47+
"type": "Program",
48+
"start": 0,
49+
"end": 7,
50+
"body": [
51+
{
52+
"type": "ExpressionStatement",
53+
"start": 0,
54+
"end": 7,
55+
"expression": {
56+
"type": "AssignmentExpression",
57+
"start": 0,
58+
"end": 7,
59+
"operator": "||=",
60+
"left": {
61+
"type": "Identifier",
62+
"start": 0,
63+
"end": 1,
64+
"name": "a"
65+
},
66+
"right": {
67+
"type": "Identifier",
68+
"start": 6,
69+
"end": 7,
70+
"name": "b"
71+
}
72+
}
73+
}
74+
],
75+
"sourceType": "script"
76+
},
77+
{ ecmaVersion: 12 }
78+
);
79+
80+
test(
81+
"a ??= b",
82+
{
83+
"type": "Program",
84+
"start": 0,
85+
"end": 7,
86+
"body": [
87+
{
88+
"type": "ExpressionStatement",
89+
"start": 0,
90+
"end": 7,
91+
"expression": {
92+
"type": "AssignmentExpression",
93+
"start": 0,
94+
"end": 7,
95+
"operator": "??=",
96+
"left": {
97+
"type": "Identifier",
98+
"start": 0,
99+
"end": 1,
100+
"name": "a"
101+
},
102+
"right": {
103+
"type": "Identifier",
104+
"start": 6,
105+
"end": 7,
106+
"name": "b"
107+
}
108+
}
109+
}
110+
],
111+
"sourceType": "script"
112+
},
113+
{ ecmaVersion: 12 }
114+
);
115+
116+
test(
117+
"a &&= b ||= c ??= d",
118+
{
119+
"type": "Program",
120+
"start": 0,
121+
"end": 19,
122+
"body": [
123+
{
124+
"type": "ExpressionStatement",
125+
"start": 0,
126+
"end": 19,
127+
"expression": {
128+
"type": "AssignmentExpression",
129+
"start": 0,
130+
"end": 19,
131+
"operator": "&&=",
132+
"left": {
133+
"type": "Identifier",
134+
"start": 0,
135+
"end": 1,
136+
"name": "a"
137+
},
138+
"right": {
139+
"type": "AssignmentExpression",
140+
"start": 6,
141+
"end": 19,
142+
"operator": "||=",
143+
"left": {
144+
"type": "Identifier",
145+
"start": 6,
146+
"end": 7,
147+
"name": "b"
148+
},
149+
"right": {
150+
"type": "AssignmentExpression",
151+
"start": 12,
152+
"end": 19,
153+
"operator": "??=",
154+
"left": {
155+
"type": "Identifier",
156+
"start": 12,
157+
"end": 13,
158+
"name": "c"
159+
},
160+
"right": {
161+
"type": "Identifier",
162+
"start": 18,
163+
"end": 19,
164+
"name": "d"
165+
}
166+
}
167+
}
168+
}
169+
}
170+
],
171+
"sourceType": "script"
172+
},
173+
{ ecmaVersion: 12 }
174+
);
175+
176+
testFail("a &&= b", "Unexpected token (1:4)", { ecmaVersion: 11 });
177+
testFail("a ||= b", "Unexpected token (1:4)", { ecmaVersion: 11 });
178+
testFail("a ??= b", "Unexpected token (1:4)", { ecmaVersion: 11 });
179+
180+
testFail("({a} &&= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });
181+
testFail("({a} ||= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });
182+
testFail("({a} ??= b)", "Assigning to rvalue (1:1)", { ecmaVersion: 12 });

0 commit comments

Comments
 (0)