mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Fixes chaining after inline implicit objects
This commit is contained in:
@@ -152,7 +152,7 @@
|
||||
var stack;
|
||||
stack = [];
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var endAllImplicitCalls, endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, nextTag, offset, prevTag, prevToken, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
tag = token[0];
|
||||
prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0];
|
||||
nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0];
|
||||
@@ -197,11 +197,6 @@
|
||||
tokens.splice(i, 0, generate('CALL_END', ')'));
|
||||
return i += 1;
|
||||
};
|
||||
endAllImplicitCalls = function() {
|
||||
while (inImplicitCall()) {
|
||||
endImplicitCall();
|
||||
}
|
||||
};
|
||||
startImplicitObject = function(j, startsLine) {
|
||||
var idx;
|
||||
if (startsLine == null) {
|
||||
@@ -283,7 +278,7 @@
|
||||
while (this.tag(s - 2) === 'HERECOMMENT') {
|
||||
s -= 2;
|
||||
}
|
||||
this.objectValueIsFor = nextTag === 'FOR';
|
||||
this.insideForDeclaration = nextTag === 'FOR';
|
||||
startsLine = s === 0 || (_ref2 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref2) >= 0) || tokens[s - 1].newLine;
|
||||
if (stackTop()) {
|
||||
_ref3 = stackTop(), stackTag = _ref3[0], stackIdx = _ref3[1];
|
||||
@@ -294,19 +289,16 @@
|
||||
startImplicitObject(s, !!startsLine);
|
||||
return forward(2);
|
||||
}
|
||||
if (inImplicitCall() && __indexOf.call(CALL_CLOSERS, tag) >= 0 && (prevTag === 'OUTDENT' || prevToken.newLine)) {
|
||||
endAllImplicitCalls();
|
||||
return forward(1);
|
||||
}
|
||||
if (inImplicitObject() && __indexOf.call(LINEBREAKS, tag) >= 0) {
|
||||
stackTop()[2].sameLine = false;
|
||||
}
|
||||
if (__indexOf.call(IMPLICIT_END, tag) >= 0) {
|
||||
newLine = prevTag === 'OUTDENT' || prevToken.newLine;
|
||||
if (__indexOf.call(IMPLICIT_END, tag) >= 0 || __indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
|
||||
while (inImplicit()) {
|
||||
_ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1], (_ref5 = _ref4[2], sameLine = _ref5.sameLine, startsLine = _ref5.startsLine);
|
||||
if (inImplicitCall() && prevTag !== ',') {
|
||||
endImplicitCall();
|
||||
} else if (inImplicitObject() && !this.objectValueIsFor && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && endImplicitObject()) {
|
||||
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && endImplicitObject()) {
|
||||
|
||||
} else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) {
|
||||
endImplicitObject();
|
||||
@@ -315,7 +307,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.objectValueIsFor && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
||||
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
||||
offset = nextTag === 'OUTDENT' ? 1 : 0;
|
||||
while (inImplicitObject()) {
|
||||
endImplicitObject(i + offset);
|
||||
|
||||
@@ -160,11 +160,6 @@ class exports.Rewriter
|
||||
tokens.splice i, 0, generate 'CALL_END', ')'
|
||||
i += 1
|
||||
|
||||
endAllImplicitCalls = ->
|
||||
while inImplicitCall()
|
||||
endImplicitCall()
|
||||
return
|
||||
|
||||
startImplicitObject = (j, startsLine = yes) ->
|
||||
idx = j ? i
|
||||
stack.push ['{', idx, sameLine: yes, startsLine: startsLine, ours: yes]
|
||||
@@ -289,15 +284,11 @@ class exports.Rewriter
|
||||
# f a
|
||||
# .g b
|
||||
# .h a
|
||||
#
|
||||
if inImplicitCall() and tag in CALL_CLOSERS and
|
||||
(prevTag is 'OUTDENT' or prevToken.newLine)
|
||||
endAllImplicitCalls()
|
||||
return forward(1)
|
||||
|
||||
stackTop()[2].sameLine = no if inImplicitObject() and tag in LINEBREAKS
|
||||
|
||||
if tag in IMPLICIT_END
|
||||
newLine = prevTag is 'OUTDENT' or prevToken.newLine
|
||||
if tag in IMPLICIT_END or tag in CALL_CLOSERS and newLine
|
||||
while inImplicit()
|
||||
[stackTag, stackIdx, {sameLine, startsLine}] = stackTop()
|
||||
# Close implicit calls when reached end of argument list
|
||||
@@ -495,4 +486,4 @@ SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADIN
|
||||
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']
|
||||
|
||||
# Tokens that close open calls when they follow a newline.
|
||||
CALL_CLOSERS = ['.', '?.', '::', '?::']
|
||||
CALL_CLOSERS = ['.', '?.', '::', '?::']
|
||||
|
||||
@@ -7,13 +7,6 @@
|
||||
# string literals -> string literals
|
||||
# function invocations -> function invocations
|
||||
|
||||
# * Line Continuation
|
||||
# * Property Accesss
|
||||
# * Operators
|
||||
# * Array Literals
|
||||
# * Function Invocations
|
||||
# * String Literals
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile "a = then b"
|
||||
|
||||
test "multiple semicolon-separated statements in parentheticals", ->
|
||||
@@ -21,7 +14,12 @@ test "multiple semicolon-separated statements in parentheticals", ->
|
||||
eq nonce, (1; 2; nonce)
|
||||
eq nonce, (-> return (1; 2; nonce))()
|
||||
|
||||
# Line Continuation
|
||||
# * Line Continuation
|
||||
# * Property Accesss
|
||||
# * Operators
|
||||
# * Array Literals
|
||||
# * Function Invocations
|
||||
# * String Literals
|
||||
|
||||
# Property Access
|
||||
|
||||
@@ -57,54 +55,6 @@ test "chained accesses split on period/newline, backwards and forwards", ->
|
||||
reverse()
|
||||
.reverse()
|
||||
|
||||
test "#1495, method call chaining", ->
|
||||
str = 'abc'
|
||||
|
||||
result = str.split ''
|
||||
.join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
result = str
|
||||
.split ''
|
||||
.join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
eq 'a, b, c', (str
|
||||
.split ''
|
||||
.join ', '
|
||||
)
|
||||
|
||||
eq 'abc',
|
||||
'aaabbbccc'.replace /(\w)\1\1/g, '$1$1'
|
||||
.replace /([abc])\1/g, '$1'
|
||||
|
||||
# Nested calls
|
||||
result = [1..3]
|
||||
.slice Math.max 0, 1
|
||||
.concat [3]
|
||||
arrayEq result, [2, 3, 3]
|
||||
|
||||
# Single line function arguments.
|
||||
result = [1..6]
|
||||
.map (x) -> x * x
|
||||
.filter (x) -> x % 2 is 0
|
||||
.reverse()
|
||||
arrayEq result, [36, 16, 4]
|
||||
|
||||
# The parens are forced
|
||||
result = str.split(''.
|
||||
split ''
|
||||
.join ''
|
||||
).join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
test "chaining after outdent", ->
|
||||
str = 'abc'
|
||||
zero = parseInt str.replace /\w/, (letter) ->
|
||||
0
|
||||
.toString()
|
||||
eq '0', zero
|
||||
|
||||
# Operators
|
||||
|
||||
test "newline suppression for operators", ->
|
||||
@@ -169,6 +119,85 @@ test "indented heredoc", ->
|
||||
""")
|
||||
eq "abc", result
|
||||
|
||||
# Chaining - all open calls are closed by property access starting a new line
|
||||
# * chaining after
|
||||
# * indented argument
|
||||
# * function block
|
||||
# * indented object
|
||||
#
|
||||
# * single line arguments
|
||||
# * inline function literal
|
||||
# * inline object literal
|
||||
|
||||
test "chaining after outdent", ->
|
||||
id = (x) -> x
|
||||
|
||||
# indented argument
|
||||
ff = id parseInt "ff",
|
||||
16
|
||||
.toString()
|
||||
eq '255', ff
|
||||
|
||||
# function block
|
||||
str = 'abc'
|
||||
zero = parseInt str.replace /\w/, (letter) ->
|
||||
0
|
||||
.toString()
|
||||
eq '0', zero
|
||||
|
||||
# indented object
|
||||
a = id id
|
||||
a: 1
|
||||
.a
|
||||
eq 1, a
|
||||
|
||||
test "#1495, method call chaining", ->
|
||||
str = 'abc'
|
||||
|
||||
result = str.split ''
|
||||
.join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
result = str
|
||||
.split ''
|
||||
.join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
eq 'a, b, c', (str
|
||||
.split ''
|
||||
.join ', '
|
||||
)
|
||||
|
||||
eq 'abc',
|
||||
'aaabbbccc'.replace /(\w)\1\1/g, '$1$1'
|
||||
.replace /([abc])\1/g, '$1'
|
||||
|
||||
# Nested calls
|
||||
result = [1..3]
|
||||
.slice Math.max 0, 1
|
||||
.concat [3]
|
||||
arrayEq [2, 3, 3], result
|
||||
|
||||
# Single line function arguments
|
||||
result = [1..6]
|
||||
.map (x) -> x * x
|
||||
.filter (x) -> x % 2 is 0
|
||||
.reverse()
|
||||
arrayEq [36, 16, 4], result
|
||||
|
||||
# Single line implicit objects
|
||||
id = (x) -> x
|
||||
result = id a: 1
|
||||
.a
|
||||
eq 1, result
|
||||
|
||||
# The parens are forced
|
||||
result = str.split(''.
|
||||
split ''
|
||||
.join ''
|
||||
).join ', '
|
||||
eq 'a, b, c', result
|
||||
|
||||
# Nested blocks caused by paren unwrapping
|
||||
test "#1492: Nested blocks don't cause double semicolons", ->
|
||||
js = CoffeeScript.compile '(0;0)'
|
||||
|
||||
Reference in New Issue
Block a user