Skip to content

Commit

Permalink
for..of no longer requires a variable qualifier
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Oct 8, 2017
1 parent 95c3353 commit 19b141c
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 26 deletions.
35 changes: 24 additions & 11 deletions src/parser/statement.js
Expand Up @@ -336,6 +336,30 @@ pp.parseForStatement = function (node) {
return this.parseFor(node, null);
}

if (this.hasPlugin("lightscript") && (!forAwait)) {
// idx, elem, key, or val begins a LS-enhanced loop.
if (
this.isContextual("idx") ||
this.isContextual("elem") ||
this.isContextual("key") ||
this.isContextual("val")
) {
// Disambiguate between:
// for idx of e: body
// for idx of in e: body
// for idx of, elem x in e: body
//
// If next isn't "of", or next+1 is "in" or ",", then it's a for-in
const nextTwo = this.tokenLookahead(2);
if (
(!(nextTwo[0] === tt.name && nextTwo[1] === "of")) || // next isnt of
(nextTwo[2] === tt._in || nextTwo[2] === tt.comma) // next+1 is "in" or ","
) {
return this.parseEnhancedForIn(node);
}
}
}

if (this.match(tt._var) || this.match(tt._let) || this.match(tt._const)) {
const init = this.startNode();
const varKind = this.state.type;
Expand All @@ -354,23 +378,12 @@ pp.parseForStatement = function (node) {
return this.parseFor(node, init);
}

if (this.hasPlugin("lightscript") && (!forAwait)) {
// idx, elem, key, or val begins a LS-enhanced loop.
if (
(this.isContextual("idx") || this.isContextual("elem") || this.isContextual("key") || this.isContextual("val"))
) {
return this.parseEnhancedForIn(node);
}
}

const refShorthandDefaultPos = { start: 0 };
const init = this.parseExpression(true, refShorthandDefaultPos);
if (this.match(tt._in) || this.isContextual("of")) {
if (this.hasPlugin("lightscript") && (!init.isNowAssign)) {
if (this.match(tt._in)) {
this.raise(this.state.lastTokStart, "for-in requires a variable qualifier: `now` to reassign an existing variable, or `const`, `let`, `var` to declare a new one. Use `idx` or `elem` to iterate an array. Use `key` or `val` to iterate an object.");
} else {
this.raise(this.state.lastTokStart, "for-of requires a variable qualifier: `now` to reassign an existing variable, or `const`, `let`, `var` to declare a new one.");
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/tokenizer/index.js
Expand Up @@ -97,6 +97,24 @@ export default class Tokenizer {
return curr;
}

tokenLookahead(n) {
const result = [];

const old = this.state;
this.state = old.clone(true);

this.isLookahead = true;
while (n > 0) {
this.next();
result.push(this.state.type, this.state.value);
n--;
}
this.isLookahead = false;

this.state = old;
return result;
}

// Toggle strict mode. Re-reads the next number or string to please
// pedantic tests (`"use strict"; 010;` should fail).

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions test/fixtures/lightscript/for-in/like-for-of/actual.js
@@ -0,0 +1 @@
for elem of in arr: of
115 changes: 115 additions & 0 deletions test/fixtures/lightscript/for-in/like-for-of/expected.json
@@ -0,0 +1,115 @@
{
"type": "File",
"start": 0,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 22
}
},
"program": {
"type": "Program",
"start": 0,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 22
}
},
"sourceType": "script",
"body": [
{
"type": "ForInArrayStatement",
"start": 0,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 22
}
},
"elem": {
"type": "Identifier",
"start": 9,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "of"
},
"name": "of"
},
"body": {
"type": "ExpressionStatement",
"start": 20,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 20
},
"end": {
"line": 1,
"column": 22
}
},
"expression": {
"type": "Identifier",
"start": 20,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 20
},
"end": {
"line": 1,
"column": 22
},
"identifierName": "of"
},
"name": "of"
}
},
"array": {
"type": "Identifier",
"start": 15,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 15
},
"end": {
"line": 1,
"column": 18
},
"identifierName": "arr"
},
"name": "arr"
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
for elem of elems: elem
115 changes: 115 additions & 0 deletions test/fixtures/lightscript/for-of/like-enhanced-for-in/expected.json
@@ -0,0 +1,115 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"sourceType": "script",
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"left": {
"type": "Identifier",
"start": 4,
"end": 8,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 8
},
"identifierName": "elem"
},
"name": "elem"
},
"right": {
"type": "Identifier",
"start": 12,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 17
},
"identifierName": "elems"
},
"name": "elems"
},
"body": {
"type": "ExpressionStatement",
"start": 19,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 23
}
},
"expression": {
"type": "Identifier",
"start": 19,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 23
},
"identifierName": "elem"
},
"name": "elem"
}
}
}
],
"directives": []
}
}

0 comments on commit 19b141c

Please sign in to comment.