mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Detect when from
in a for
loop declaration is an identifier (#4393)
* Try to detect when `from` in a `for` loop declaration is an identifier, not a keyword * Handle destructured arrays * from as a destructured, aliased object variable name in a for loop declaration
This commit is contained in:
parent
3ea0481bbe
commit
88f2bf9fa5
3 changed files with 98 additions and 4 deletions
|
@ -1,6 +1,6 @@
|
|||
// Generated by CoffeeScript 1.12.0
|
||||
(function() {
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError,
|
||||
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError,
|
||||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
slice = [].slice;
|
||||
|
||||
|
@ -131,7 +131,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (tag === 'IDENTIFIER' && this.seenFor && id === 'from') {
|
||||
} else if (tag === 'IDENTIFIER' && this.seenFor && id === 'from' && isForFrom(prev)) {
|
||||
tag = 'FORFROM';
|
||||
this.seenFor = false;
|
||||
}
|
||||
|
@ -963,6 +963,23 @@
|
|||
|
||||
exports.isUnassignable = isUnassignable;
|
||||
|
||||
isForFrom = function(prev) {
|
||||
var ref2;
|
||||
if (prev[0] === 'IDENTIFIER') {
|
||||
if (prev[1] === 'from') {
|
||||
prev[1][0] = 'IDENTIFIER';
|
||||
true;
|
||||
}
|
||||
return true;
|
||||
} else if (prev[0] === 'FOR') {
|
||||
return false;
|
||||
} else if ((ref2 = prev[1]) === '{' || ref2 === '[' || ref2 === ',' || ref2 === ':') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'yield', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super', 'import', 'export', 'default'];
|
||||
|
||||
COFFEE_KEYWORDS = ['undefined', 'Infinity', 'NaN', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||
|
|
|
@ -165,7 +165,8 @@ exports.Lexer = class Lexer
|
|||
if @value() is '!'
|
||||
poppedToken = @tokens.pop()
|
||||
id = '!' + id
|
||||
else if tag is 'IDENTIFIER' and @seenFor and id is 'from'
|
||||
else if tag is 'IDENTIFIER' and @seenFor and id is 'from' and
|
||||
isForFrom(prev)
|
||||
tag = 'FORFROM'
|
||||
@seenFor = no
|
||||
|
||||
|
@ -824,6 +825,27 @@ isUnassignable = (name, displayName = name) -> switch
|
|||
|
||||
exports.isUnassignable = isUnassignable
|
||||
|
||||
# `from` isn’t a CoffeeScript keyword, but it behaves like one in `import` and
|
||||
# `export` statements (handled above) and in the declaration line of a `for`
|
||||
# loop. Try to detect when `from` is a variable identifier and when it is this
|
||||
# “sometimes” keyword.
|
||||
isForFrom = (prev) ->
|
||||
if prev[0] is 'IDENTIFIER'
|
||||
# `for i from from`, `for from from iterable`
|
||||
if prev[1] is 'from'
|
||||
prev[1][0] = 'IDENTIFIER'
|
||||
yes
|
||||
# `for i from iterable`
|
||||
yes
|
||||
# `for from…`
|
||||
else if prev[0] is 'FOR'
|
||||
no
|
||||
# `for {from}…`, `for [from]…`, `for {a, from}…`, `for {a: from}…`
|
||||
else if prev[1] in ['{', '[', ',', ':']
|
||||
no
|
||||
else
|
||||
yes
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
|
||||
|
|
|
@ -277,7 +277,6 @@ test "for-from loops over generators", ->
|
|||
ok array3.length is 0 or array3.join(',') is '70,20'
|
||||
arrayEq array4, []
|
||||
|
||||
|
||||
test "for-from comprehensions over generators", ->
|
||||
gen = ->
|
||||
yield from [30, 41, 51, 60]
|
||||
|
@ -288,3 +287,59 @@ test "for-from comprehensions over generators", ->
|
|||
|
||||
ok array1.join(' ') is '41 51'
|
||||
ok array2.length is 0
|
||||
|
||||
test "from as an iterable variable name in a for loop declaration", ->
|
||||
from = [1, 2, 3]
|
||||
out = []
|
||||
for i from from
|
||||
out.push i
|
||||
arrayEq from, out
|
||||
|
||||
test "from as an iterator variable name in a for loop declaration", ->
|
||||
a = [1, 2, 3]
|
||||
b = []
|
||||
for from from a
|
||||
b.push from
|
||||
arrayEq a, b
|
||||
|
||||
test "from as a destructured object variable name in a for loop declaration", ->
|
||||
a = [
|
||||
from: 1
|
||||
to: 2
|
||||
,
|
||||
from: 3
|
||||
to: 4
|
||||
]
|
||||
b = []
|
||||
for {from, to} in a
|
||||
b.push from
|
||||
arrayEq b, [1, 3]
|
||||
|
||||
c = []
|
||||
for {to, from} in a
|
||||
c.push from
|
||||
arrayEq c, [1, 3]
|
||||
|
||||
test "from as a destructured, aliased object variable name in a for loop declaration", ->
|
||||
a = [
|
||||
b: 1
|
||||
c: 2
|
||||
,
|
||||
b: 3
|
||||
c: 4
|
||||
]
|
||||
out = []
|
||||
|
||||
for {b: from} in a
|
||||
out.push from
|
||||
arrayEq out, [1, 3]
|
||||
|
||||
test "from as a destructured array variable name in a for loop declaration", ->
|
||||
a = [
|
||||
[1, 2]
|
||||
[3, 4]
|
||||
]
|
||||
b = []
|
||||
for [from, to] from a
|
||||
b.push from
|
||||
arrayEq b, [1, 3]
|
||||
|
|
Loading…
Reference in a new issue