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

Fix #4564: indent closes implicit object (#4570)

* indent closes implicit object [Fixes #4564]

* add test for just implicit object

* remove stray lib file
This commit is contained in:
Julian Rosse 2017-06-15 11:07:36 -05:00 committed by Geoffrey Booth
parent 9a48566b24
commit 5e90b224c2
3 changed files with 43 additions and 16 deletions

View file

@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.0.0-beta2
(function() {
var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, rite, throwSyntaxError,
var BALANCED_PAIRS, CALL_CLOSERS, CONTROL_IN_IMPLICIT, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, rite, throwSyntaxError,
indexOf = [].indexOf;
({throwSyntaxError} = require('./helpers'));
@ -255,7 +255,7 @@
}
return this.looksObjectish(nextTerminatorIdx + 1);
};
if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) {
if ((inImplicitCall() || inImplicitObject()) && indexOf.call(CONTROL_IN_IMPLICIT, tag) >= 0 || inImplicitObject() && prevTag === ':' && tag === 'FOR') {
stack.push([
'CONTROL', i, {
ours: true
@ -265,8 +265,12 @@
}
if (tag === 'INDENT' && inImplicit()) {
if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'ELSE' && prevTag !== '=') {
while (inImplicitCall()) {
endImplicitCall();
while (inImplicitCall() || inImplicitObject() && prevTag !== ':') {
if (inImplicitCall()) {
endImplicitCall();
} else {
endImplicitObject();
}
}
}
if (inImplicitControl()) {
@ -318,7 +322,6 @@
while (this.tag(s - 2) === 'HERECOMMENT') {
s -= 2;
}
this.insideForDeclaration = nextTag === 'FOR';
startsLine = s === 0 || (ref = this.tag(s - 1), indexOf.call(LINEBREAKS, ref) >= 0) || tokens[s - 1].newLine;
if (stackTop()) {
[stackTag, stackIdx] = stackTop();
@ -343,7 +346,7 @@
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop();
if (inImplicitCall() && prevTag !== ',') {
endImplicitCall();
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && !(tag === 'POST_IF' && startsLine && implicitObjectContinues(i + 1))) {
} else if (inImplicitObject() && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && !(tag === 'POST_IF' && startsLine && implicitObjectContinues(i + 1))) {
endImplicitObject();
} else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) {
if (nextTag === 'HERECOMMENT') {
@ -355,7 +358,7 @@
}
}
}
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
offset = nextTag === 'OUTDENT' ? 1 : 0;
while (inImplicitObject()) {
endImplicitObject(i + offset);
@ -558,4 +561,6 @@
CALL_CLOSERS = ['.', '?.', '::', '?::'];
CONTROL_IN_IMPLICIT = ['IF', 'TRY', 'FINALLY', 'CATCH', 'CLASS', 'SWITCH'];
}).call(this);

View file

@ -192,9 +192,11 @@ exports.Rewriter = class Rewriter
return no unless nextTerminatorIdx?
@looksObjectish nextTerminatorIdx + 1
# Don't end an implicit call on next indent if any of these are in an argument
if inImplicitCall() and tag in ['IF', 'TRY', 'FINALLY', 'CATCH',
'CLASS', 'SWITCH']
# Don't end an implicit call/object on next indent if any of these are in an argument/value
if (
(inImplicitCall() or inImplicitObject()) and tag in CONTROL_IN_IMPLICIT or
inImplicitObject() and prevTag is ':' and tag is 'FOR'
)
stack.push ['CONTROL', i, ours: yes]
return forward(1)
@ -206,7 +208,11 @@ exports.Rewriter = class Rewriter
# 2. The last token before the indent is part of the list below
#
if prevTag not in ['=>', '->', '[', '(', ',', '{', 'ELSE', '=']
endImplicitCall() while inImplicitCall()
while inImplicitCall() or inImplicitObject() and prevTag isnt ':'
if inImplicitCall()
endImplicitCall()
else
endImplicitObject()
stack.pop() if inImplicitControl()
stack.push [tag, i]
return forward(1)
@ -273,9 +279,6 @@ exports.Rewriter = class Rewriter
else i - 1
s -= 2 while @tag(s - 2) is 'HERECOMMENT'
# Mark if the value is a for loop
@insideForDeclaration = nextTag is 'FOR'
startsLine = s is 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
# Are we just continuing an already declared object?
if stackTop()
@ -316,7 +319,7 @@ exports.Rewriter = class Rewriter
endImplicitCall()
# Close implicit objects such as:
# return a: 1, b: 2 unless true
else if inImplicitObject() and not @insideForDeclaration and sameLine and
else if inImplicitObject() and sameLine and
tag isnt 'TERMINATOR' and prevTag isnt ':' and
not (tag is 'POST_IF' and startsLine and implicitObjectContinues(i + 1))
endImplicitObject()
@ -344,7 +347,6 @@ exports.Rewriter = class Rewriter
# f a, b: c, d: e, f, g: h: i, j
#
if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
not @insideForDeclaration and
(nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
# When nextTag is OUTDENT the comma is insignificant and
# should just be ignored so embed it in the implicit object.
@ -540,3 +542,6 @@ LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']
# Tokens that close open calls when they follow a newline.
CALL_CLOSERS = ['.', '?.', '::', '?::']
# Tokens that prevent a subsequent indent from ending implicit calls/objects
CONTROL_IN_IMPLICIT = ['IF', 'TRY', 'FINALLY', 'CATCH', 'CLASS', 'SWITCH']

View file

@ -594,6 +594,23 @@ test "#1263: Braceless object return", ->
eq 2, obj.b
eq 3, obj.c()
test "#4564: indent should close implicit object", ->
f = (x) -> x
arrayEq ['a'],
for key of f a: 1
key
g = null
if f a: 1
g = 3
eq g, 3
h = null
if a: (i for i in [1, 2, 3])
h = 4
eq h, 4
test "#4544: Postfix conditionals in first line of implicit object literals", ->
two =
foo: