Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions src/parser/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,14 @@ pp.parseDoStatement = function (node) {
// b/c it expects a trailing colon or brace, which you don't have here.

if (this.hasPlugin("lightscript")) {
// allow parens; if not used, enforce semicolon or newline.
if (this.eat(tt.parenL)) {
node.test = this.parseExpression();
this.expect(tt.parenR);
this.eat(tt.semi);
} else {
node.test = this.parseExpression();
this.semicolon();
// allow parens; enforce semicolon or newline whether they're used or not.
node.test = this.parseExpression();
if (node.test.extra && node.test.extra.parenthesized) {
delete node.test.extra.parenthesized;
delete node.test.extra.parenStart;
this.addExtra(node, "hasParens", true);
}
this.semicolon();
} else {
node.test = this.parseParenExpression();
this.eat(tt.semi);
Expand Down Expand Up @@ -272,8 +271,9 @@ pp.parseForStatement = function (node) {
}

if (this.hasPlugin("lightscript")) {
// TODO: check that closing paren is/isnt there to match
this.eat(tt.parenL);
if (this.eat(tt.parenL)) {
this.addExtra(node, "hasParens", true);
}
} else {
this.expect(tt.parenL);
}
Expand Down Expand Up @@ -450,14 +450,16 @@ pp.parseTryStatement = function (node) {
this.next();

if (this.hasPlugin("lightscript")) {
this.eat(tt.parenL);
if (this.eat(tt.parenL)) {
this.addExtra(clause, "hasParens", true);
}
} else {
this.expect(tt.parenL);
}
clause.param = this.parseBindingAtom();
this.checkLVal(clause.param, true, Object.create(null), "catch clause");
if (this.hasPlugin("lightscript")) {
this.eat(tt.parenR);
this.expectParenFreeBlockStart(clause);
} else {
this.expect(tt.parenR);
}
Expand Down Expand Up @@ -617,7 +619,7 @@ pp.parseFor = function (node, init) {
node.update = this.match(tt.parenR) ? null : this.parseExpression();

if (this.hasPlugin("lightscript")) {
this.expectParenFreeBlockStart();
this.expectParenFreeBlockStart(node);
} else {
this.expect(tt.parenR);
}
Expand All @@ -643,7 +645,7 @@ pp.parseForIn = function (node, init, forAwait) {
node.right = this.parseExpression();

if (this.hasPlugin("lightscript")) {
this.expectParenFreeBlockStart();
this.expectParenFreeBlockStart(node);
} else {
this.expect(tt.parenR);
}
Expand Down
33 changes: 28 additions & 5 deletions src/plugins/lightscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pp.parseEnhancedForIn = function (node) {

const iterable = this.parseMaybeAssign(true);

this.expectParenFreeBlockStart();
this.expectParenFreeBlockStart(node);
node.body = this.parseStatement(false);

if ((matchingIterationType === "idx") || (matchingIterationType === "elem")) {
Expand All @@ -105,12 +105,13 @@ pp.parseEnhancedForIn = function (node) {
}
};

pp.expectParenFreeBlockStart = function () {
pp.expectParenFreeBlockStart = function (node) {
// if true: blah
// if true { blah }
// if (true) blah
// TODO: ensure matching parens, not just allowing one on either side
if (!(this.match(tt.colon) || this.match(tt.braceL) || this.eat(tt.parenR))) {
if (node && node.extra && node.extra.hasParens) {
this.expect(tt.parenR);
} else if (!(this.match(tt.colon) || this.match(tt.braceL))) {
this.unexpected(null, "Paren-free test expressions must be followed by braces or a colon.");
}
};
Expand Down Expand Up @@ -483,7 +484,29 @@ export default function (instance) {

instance.extend("parseParenExpression", function (inner) {
return function () {
if (this.match(tt.parenL)) return inner.apply(this, arguments);
// parens are special here; they might be `if (x) -1` or `if (x < 1) and y: -1`
if (this.match(tt.parenL)) {
const state = this.state.clone();

// first, try paren-free style
try {
const val = this.parseExpression();
if (this.match(tt.braceL) || this.match(tt.colon)) {
if (val.extra && val.extra.parenthesized) {
delete val.extra.parenthesized;
delete val.extra.parenStart;
}
return val;
}
} catch (_err) {
// fall-through, will re-raise if it's an error below
}

// otherwise, try traditional parseParenExpression
this.state = state;
return inner.apply(this, arguments);
}

const val = this.parseExpression();
this.expectParenFreeBlockStart();
return val;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ecmaVersion": 6,
"throws": "Unexpected token, expected ; (1:20)"
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
do {} while (a) (b)
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"type": "File",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"program": {
"type": "Program",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"sourceType": "script",
"body": [
{
"type": "DoWhileStatement",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"body": {
"type": "BlockStatement",
"start": 3,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 3
},
"end": {
"line": 1,
"column": 5
}
},
"body": [],
"directives": [],
"extra": {
"curly": true
}
},
"test": {
"type": "CallExpression",
"start": 12,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 19
}
},
"callee": {
"type": "Identifier",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 13
},
"end": {
"line": 1,
"column": 14
},
"identifierName": "a"
},
"name": "a",
"extra": {
"parenthesized": true,
"parenStart": 12
}
},
"arguments": [
{
"type": "Identifier",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 18
},
"identifierName": "b"
},
"name": "b"
}
]
}
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
for (;; {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected ) (1:10)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
for ;;) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Paren-free test expressions must be followed by braces or a colon. (1:6)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
for (let x of {a: 1} {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected ) (1:21)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
for let x of {a: 1}) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Paren-free test expressions must be followed by braces or a colon. (1:19)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
if (a){}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"type": "File",
"start": 0,
"end": 8,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 8
}
},
"program": {
"type": "Program",
"start": 0,
"end": 8,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 8
}
},
"sourceType": "script",
"body": [
{
"type": "IfStatement",
"start": 0,
"end": 8,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 8
}
},
"test": {
"type": "Identifier",
"start": 4,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 5
},
"identifierName": "a"
},
"name": "a"
},
"consequent": {
"type": "BlockStatement",
"start": 6,
"end": 8,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 8
}
},
"body": [],
"directives": [],
"extra": {
"curly": true
}
},
"alternate": null
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
if (1)a;
Loading