1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Fix #3098: Suppressed newline should be unsuppressed by semicolon (#4669)

This commit is contained in:
Geoffrey Booth 2017-09-01 07:09:36 -07:00 committed by GitHub
parent b20e52da99
commit 4a4f752204
3 changed files with 39 additions and 11 deletions

View file

@ -672,9 +672,7 @@
if (dent) {
this.outdebt -= moveOut;
}
while (this.value() === ';') {
this.tokens.pop();
}
this.suppressSemicolons();
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
this.token('TERMINATOR', '\n', outdentLength, 0);
}
@ -703,9 +701,7 @@
// Generate a newline token. Consecutive newlines get merged together.
newlineToken(offset) {
while (this.value() === ';') {
this.tokens.pop();
}
this.suppressSemicolons();
if (this.tag() !== 'TERMINATOR') {
this.token('TERMINATOR', '\n', offset, 0);
}
@ -844,7 +840,7 @@
// here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
// parentheses that indicate a method call from regular parentheses, and so on.
literalToken() {
var match, message, origin, prev, ref, ref1, ref2, ref3, skipToken, tag, token, value;
var match, message, origin, prev, ref, ref1, ref2, ref3, ref4, skipToken, tag, token, value;
if (match = OPERATOR.exec(this.chunk)) {
[value] = match;
if (CODE.test(value)) {
@ -884,6 +880,9 @@
this.exportSpecifierList = false;
}
if (value === ';') {
if (ref2 = prev != null ? prev[0] : void 0, indexOf.call(['=', ...UNFINISHED], ref2) >= 0) {
this.error('unexpected ;');
}
this.seenFor = this.seenImport = this.seenExport = false;
tag = 'TERMINATOR';
} else if (value === '*' && (prev != null ? prev[0] : void 0) === 'EXPORT') {
@ -903,12 +902,12 @@
} else if (value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'BIN?';
} else if (prev) {
if (value === '(' && !prev.spaced && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0)) {
if (value === '(' && !prev.spaced && (ref3 = prev[0], indexOf.call(CALLABLE, ref3) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && (((ref3 = prev[0], indexOf.call(INDEXABLE, ref3) >= 0) && !prev.spaced) || (prev[0] === '::'))) { // `.prototype` cant be a method you can call.
} else if (value === '[' && (((ref4 = prev[0], indexOf.call(INDEXABLE, ref4) >= 0) && !prev.spaced) || (prev[0] === '::'))) { // `.prototype` cant be a method you can call.
tag = 'INDEX_START';
switch (prev[0]) {
case '?':
@ -1407,6 +1406,20 @@
return `${options.delimiter}${body}${options.delimiter}`;
}
suppressSemicolons() {
var ref, ref1, results;
results = [];
while (this.value() === ';') {
this.tokens.pop();
if (ref = (ref1 = this.prev()) != null ? ref1[0] : void 0, indexOf.call(['=', ...UNFINISHED], ref) >= 0) {
results.push(this.error('unexpected ;'));
} else {
results.push(void 0);
}
}
return results;
}
// Throws an error at either a given offset from the current chunk or at the
// location of a token (`token[2]`).
error(message, options = {}) {

View file

@ -509,7 +509,7 @@ exports.Lexer = class Lexer
@token 'OUTDENT', moveOut, 0, outdentLength
moveOut -= dent
@outdebt -= moveOut if dent
@tokens.pop() while @value() is ';'
@suppressSemicolons()
@token 'TERMINATOR', '\n', outdentLength, 0 unless @tag() is 'TERMINATOR' or noNewlines
@indent = decreasedIndent
@ -527,7 +527,7 @@ exports.Lexer = class Lexer
# Generate a newline token. Consecutive newlines get merged together.
newlineToken: (offset) ->
@tokens.pop() while @value() is ';'
@suppressSemicolons()
@token 'TERMINATOR', '\n', offset, 0 unless @tag() is 'TERMINATOR'
this
@ -662,6 +662,7 @@ exports.Lexer = class Lexer
@exportSpecifierList = no
if value is ';'
@error 'unexpected ;' if prev?[0] in ['=', UNFINISHED...]
@seenFor = @seenImport = @seenExport = no
tag = 'TERMINATOR'
else if value is '*' and prev?[0] is 'EXPORT'
@ -1053,6 +1054,11 @@ exports.Lexer = class Lexer
when other then (if options.double then "\\#{other}" else other)
"#{options.delimiter}#{body}#{options.delimiter}"
suppressSemicolons: ->
while @value() is ';'
@tokens.pop()
@error 'unexpected ;' if @prev()?[0] in ['=', UNFINISHED...]
# Throws an error at either a given offset from the current chunk or at the
# location of a token (`token[2]`).
error: (message, options = {}) ->

View file

@ -1759,3 +1759,12 @@ test "#3199: error message for throw indented comprehension", ->
x for x in [1, 2, 3]
^
'''
test "#3098: suppressed newline should be unsuppressed by semicolon", ->
assertErrorFormat '''
a = ; 5
''', '''
[stdin]:1:5: error: unexpected ;
a = ; 5
^
'''