Merge branch 'master' into 2

# Conflicts:
#	test/error_messages.coffee
This commit is contained in:
Geoffrey Booth
2016-10-26 08:59:43 -07:00
4 changed files with 84 additions and 14 deletions

View File

@@ -25,6 +25,7 @@
this.seenFor = false;
this.seenImport = false;
this.seenExport = false;
this.exportSpecifierList = false;
this.chunkLine = opts.line || 0;
this.chunkColumn = opts.column || 0;
code = this.clean(code);
@@ -66,7 +67,7 @@
};
Lexer.prototype.identifierToken = function() {
var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, tag, tagToken;
var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, ref6, ref7, tag, tagToken;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0;
}
@@ -81,12 +82,16 @@
this.token('FROM', id);
return id.length;
}
if (id === 'as' && this.seenImport && (this.tag() === 'IDENTIFIER' || this.value() === '*')) {
if (id === 'as' && this.seenImport) {
if (this.value() === '*') {
this.tokens[this.tokens.length - 1][0] = 'IMPORT_ALL';
} else if (ref2 = this.value(), indexOf.call(COFFEE_KEYWORDS, ref2) >= 0) {
this.tokens[this.tokens.length - 1][0] = 'IDENTIFIER';
}
if ((ref3 = this.tag()) === 'IMPORT_ALL' || ref3 === 'IDENTIFIER') {
this.token('AS', id);
return id.length;
}
this.token('AS', id);
return id.length;
}
if (id === 'as' && this.seenExport && this.tag() === 'IDENTIFIER') {
this.token('AS', id);
@@ -96,11 +101,11 @@
this.token('DEFAULT', id);
return id.length;
}
ref2 = this.tokens, prev = ref2[ref2.length - 1];
tag = colon || (prev != null) && (((ref3 = prev[0]) === '.' || ref3 === '?.' || ref3 === '::' || ref3 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
if (tag === 'IDENTIFIER' && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
ref4 = this.tokens, prev = ref4[ref4.length - 1];
tag = colon || (prev != null) && (((ref5 = prev[0]) === '.' || ref5 === '?.' || ref5 === '::' || ref5 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER';
if (tag === 'IDENTIFIER' && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0) && !(this.exportSpecifierList && indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (ref4 = this.tag(), indexOf.call(LINE_BREAK, ref4) >= 0)) {
if (tag === 'WHEN' && (ref6 = this.tag(), indexOf.call(LINE_BREAK, ref6) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
@@ -162,7 +167,7 @@
tagToken.origin = [tag, alias, tagToken[2]];
}
if (poppedToken) {
ref5 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref5[0], tagToken[2].first_column = ref5[1];
ref7 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref7[0], tagToken[2].first_column = ref7[1];
}
if (colon) {
colonOffset = input.lastIndexOf(':');
@@ -563,6 +568,11 @@
return value.length;
}
}
if (value === '{' && (prev != null ? prev[0] : void 0) === 'EXPORT') {
this.exportSpecifierList = true;
} else if (this.exportSpecifierList && value === '}') {
this.exportSpecifierList = false;
}
if (value === ';') {
this.seenFor = this.seenImport = this.seenExport = false;
tag = 'TERMINATOR';

View File

@@ -46,6 +46,7 @@ exports.Lexer = class Lexer
@seenFor = no # Used to recognize FORIN and FOROF tokens.
@seenImport = no # Used to recognize IMPORT FROM? AS? tokens.
@seenExport = no # Used to recognize EXPORT FROM? AS? tokens.
@exportSpecifierList = no # Used to identify when in an EXPORT {...} FROM? ...
@chunkLine =
opts.line or 0 # The start line for the current @chunk.
@@ -116,10 +117,14 @@ exports.Lexer = class Lexer
if id is 'from' and @tag() is 'YIELD'
@token 'FROM', id
return id.length
if id is 'as' and @seenImport and (@tag() is 'IDENTIFIER' or @value() is '*')
@tokens[@tokens.length - 1][0] = 'IMPORT_ALL' if @value() is '*'
@token 'AS', id
return id.length
if id is 'as' and @seenImport
if @value() is '*'
@tokens[@tokens.length - 1][0] = 'IMPORT_ALL'
else if @value() in COFFEE_KEYWORDS
@tokens[@tokens.length - 1][0] = 'IDENTIFIER'
if @tag() in ['IMPORT_ALL', 'IDENTIFIER']
@token 'AS', id
return id.length
if id is 'as' and @seenExport and @tag() is 'IDENTIFIER'
@token 'AS', id
return id.length
@@ -137,7 +142,8 @@ exports.Lexer = class Lexer
else
'IDENTIFIER'
if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS)
if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS) and
not (@exportSpecifierList and id in COFFEE_KEYWORDS)
tag = id.toUpperCase()
if tag is 'WHEN' and @tag() in LINE_BREAK
tag = 'LEADING_WHEN'
@@ -469,6 +475,11 @@ exports.Lexer = class Lexer
@error message, origin[2] if message
return value.length if skipToken
if value is '{' and prev?[0] is 'EXPORT'
@exportSpecifierList = yes
else if @exportSpecifierList and value is '}'
@exportSpecifierList = no
if value is ';'
@seenFor = @seenImport = @seenExport = no
tag = 'TERMINATOR'

View File

@@ -1149,3 +1149,23 @@ test "bound functions cannot be generators", ->
f = => yield this
^^^^^^^^^^
'''
test "CoffeeScript keywords cannot be used as unaliased names in import lists", ->
assertErrorFormat """
import { unless, baz as bar } from 'lib'
bar.barMethod()
""", '''
[stdin]:1:10: error: unexpected unless
import { unless, baz as bar } from 'lib'
^^^^^^
'''
test "CoffeeScript keywords cannot be used as local names in import list aliases", ->
assertErrorFormat """
import { bar as unless, baz as bar } from 'lib'
bar.barMethod()
""", '''
[stdin]:1:17: error: unexpected unless
import { bar as unless, baz as bar } from 'lib'
^^^^^^
'''

View File

@@ -510,6 +510,23 @@ test "export as aliases members imported from another module", ->
} from 'lib';"""
eq toJS(input), output
test "export list can contain CoffeeScript keywords", ->
input = "export { unless } from 'lib'"
output = """
export {
unless
} from 'lib';"""
eq toJS(input), output
test "export list can contain CoffeeScript keywords when aliasing", ->
input = "export { when as bar, baz as unless } from 'lib'"
output = """
export {
when as bar,
baz as unless
} from 'lib';"""
eq toJS(input), output
# Edge cases
@@ -608,6 +625,18 @@ test "`as` can be used as an alias name", ->
} from 'lib';"""
eq toJS(input), output
test "CoffeeScript keywords can be used as imported names in import lists", ->
input = """
import { unless as bar } from 'lib'
bar.barMethod()"""
output = """
import {
unless as bar
} from 'lib';
bar.barMethod();"""
eq toJS(input), output
test "`*` can be used in an expression on the same line as an export keyword", ->
input = "export foo = (x) -> x * x"
output = """