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

Fix #3933: Missing then doesn’t trigger nearby error (#4862)

* fix #3933

* tests
This commit is contained in:
zdenko 2018-01-31 00:04:29 +01:00 committed by Geoffrey Booth
parent 84d596d534
commit 70b510bcb7
3 changed files with 89 additions and 3 deletions

View file

@ -281,7 +281,7 @@
stack = [];
start = null;
return this.scanTokens(function(token, i, tokens) {
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
var endImplicitCall, endImplicitObject, forward, implicitObjectContinues, inControlFlow, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, nextToken, offset, prevTag, prevToken, ref, ref1, ref2, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
[tag] = token;
[prevTag] = prevToken = i > 0 ? tokens[i - 1] : [];
[nextTag] = nextToken = i < tokens.length - 1 ? tokens[i + 1] : [];
@ -420,10 +420,31 @@
}
start = stack.pop();
}
inControlFlow = () => {
var controlFlow, isFunc, seenFor, tagCurrentLine;
seenFor = this.findTagsBackwards(i, ['FOR']) && this.findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM']);
controlFlow = seenFor || this.findTagsBackwards(i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']);
if (!controlFlow) {
return false;
}
isFunc = false;
tagCurrentLine = token[2].first_line;
this.detectEnd(i, function(token, i) {
var ref;
return ref = token[0], indexOf.call(LINEBREAKS, ref) >= 0;
}, function(token, i) {
var first_line;
[prevTag, , {first_line}] = tokens[i - 1] || [];
return isFunc = tagCurrentLine === first_line && (prevTag === '->' || prevTag === '=>');
}, {
returnOnNegativeLevel: true
});
return isFunc;
};
// Recognize standard implicit calls like
// f a, f() b, f? c, h[0] d etc.
// Added support for spread dots on the left side: f ...a
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || (nextTag === '...' && (ref = this.tag(i + 2), indexOf.call(IMPLICIT_CALL, ref) >= 0) && !this.findTagsBackwards(i, ['INDEX_START', '['])) || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine)) {
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || (nextTag === '...' && (ref = this.tag(i + 2), indexOf.call(IMPLICIT_CALL, ref) >= 0) && !this.findTagsBackwards(i, ['INDEX_START', '['])) || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !nextToken.spaced && !nextToken.newLine) && !inControlFlow()) {
if (tag === '?') {
tag = token[0] = 'FUNC_EXIST';
}

View file

@ -263,6 +263,20 @@ exports.Rewriter = class Rewriter
stack.pop()
start = stack.pop()
inControlFlow = =>
seenFor = @findTagsBackwards(i, ['FOR']) and @findTagsBackwards(i, ['FORIN', 'FOROF', 'FORFROM'])
controlFlow = seenFor or @findTagsBackwards i, ['WHILE', 'UNTIL', 'LOOP', 'LEADING_WHEN']
return no unless controlFlow
isFunc = no
tagCurrentLine = token[2].first_line
@detectEnd i,
(token, i) -> token[0] in LINEBREAKS
(token, i) ->
[prevTag, ,{first_line}] = tokens[i - 1] || []
isFunc = tagCurrentLine is first_line and prevTag in ['->', '=>']
returnOnNegativeLevel: yes
isFunc
# Recognize standard implicit calls like
# f a, f() b, f? c, h[0] d etc.
# Added support for spread dots on the left side: f ...a
@ -271,7 +285,8 @@ exports.Rewriter = class Rewriter
(nextTag in IMPLICIT_CALL or
(nextTag is '...' and @tag(i + 2) in IMPLICIT_CALL and not @findTagsBackwards(i, ['INDEX_START', '['])) or
nextTag in IMPLICIT_UNSPACED_CALL and
not nextToken.spaced and not nextToken.newLine)
not nextToken.spaced and not nextToken.newLine) and
not inControlFlow()
tag = token[0] = 'FUNC_EXIST' if tag is '?'
startImplicitCall i + 1
return forward(2)

View file

@ -1777,3 +1777,53 @@ test "#4811: '///' inside a heregex comment does not close the heregex", ->
/// .* # comment ///
^^^
'''
test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
assertErrorFormat '''
for a in b do ->
''','''
[stdin]:1:12: error: unexpected do
for a in b do ->
^^
'''
assertErrorFormat '''
for a in b ->
''','''
[stdin]:1:12: error: unexpected ->
for a in b ->
^^
'''
assertErrorFormat '''
for a in b do =>
''','''
[stdin]:1:12: error: unexpected do
for a in b do =>
^^
'''
assertErrorFormat '''
while a do ->
''','''
[stdin]:1:9: error: unexpected do
while a do ->
^^
'''
assertErrorFormat '''
until a do =>
''','''
[stdin]:1:9: error: unexpected do
until a do =>
^^
'''
assertErrorFormat '''
switch
when a ->
''','''
[stdin]:2:10: error: unexpected ->
when a ->
^^
'''