Fix #3194: Make strings always uncallable

No matter if they have interpolations or not.
This commit is contained in:
Simon Lydell 2015-01-14 21:27:24 +01:00
parent 9fa77af576
commit fce502ac98
7 changed files with 41 additions and 6 deletions

View File

@ -301,7 +301,7 @@
index = regex.length;
prev = last(this.tokens);
if (prev) {
if (prev.spaced && (_ref3 = prev[0], __indexOf.call(CALLABLE, _ref3) >= 0)) {
if (prev.spaced && (_ref3 = prev[0], __indexOf.call(CALLABLE, _ref3) >= 0) && !prev.stringEnd) {
if (!closed || POSSIBLY_DIVISION.test(regex)) {
return 0;
}
@ -505,7 +505,7 @@
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'LOGIC';
} else if (prev && !prev.spaced) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0) && !prev.stringEnd) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}

View File

@ -264,7 +264,7 @@
startImplicitCall(i + 1);
return forward(2);
}
if (__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.matchTags(i + 1, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
if (__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && !token.stringEnd && this.matchTags(i + 1, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
startImplicitCall(i + 1);
stack.push(['INDENT', i + 2]);
return forward(3);

View File

@ -263,7 +263,7 @@ exports.Lexer = class Lexer
index = regex.length
prev = last @tokens
if prev
if prev.spaced and prev[0] in CALLABLE
if prev.spaced and prev[0] in CALLABLE and not prev.stringEnd
return 0 if not closed or POSSIBLY_DIVISION.test regex
else if prev[0] in NOT_REGEX
return 0
@ -417,7 +417,7 @@ exports.Lexer = class Lexer
else if value in SHIFT then tag = 'SHIFT'
else if value in LOGIC or value is '?' and prev?.spaced then tag = 'LOGIC'
else if prev and not prev.spaced
if value is '(' and prev[0] in CALLABLE
if value is '(' and prev[0] in CALLABLE and not prev.stringEnd
prev[0] = 'FUNC_EXIST' if prev[0] is '?'
tag = 'CALL_START'
else if value is '[' and prev[0] in INDEXABLE

View File

@ -243,7 +243,8 @@ class exports.Rewriter
# which is probably always unintended.
# Furthermore don't allow this in literal arrays, as
# that creates grammatical ambiguities.
if tag in IMPLICIT_FUNC and @matchTags(i + 1, 'INDENT', null, ':') and
if tag in IMPLICIT_FUNC and not token.stringEnd and
@matchTags(i + 1, 'INDENT', null, ':') and
not @findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH',
'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
startImplicitCall i + 1

View File

@ -75,3 +75,19 @@ test "#1274: `[] = a()` compiles to `false` instead of `a()`", ->
fn = -> a = true
[] = fn()
ok a
test "#3194: string interpolation in array", ->
arr = [ "a"
key: 'value'
]
eq 2, arr.length
eq 'a', arr[0]
eq 'value', arr[1].key
b = 'b'
arr = [ "a#{b}"
key: 'value'
]
eq 2, arr.length
eq 'ab', arr[0]
eq 'value', arr[1].key

View File

@ -128,6 +128,10 @@ test "always division and never regex after some tokens", ->
eq 2, "4"/b/g
eq 2, "4"/ b/g
eq 2, "4" /b/g
eq 20, "4#{0}" / b/g
eq 20, "4#{0}"/b/g
eq 20, "4#{0}"/ b/g
eq 20, "4#{0}" /b/g
ok isNaN /a/ / b/g
ok isNaN /a/i / b/g
ok isNaN /a//b/g

View File

@ -345,3 +345,17 @@ eq ''' <- keep these spaces -> ''', ' <- keep these spaces -> '
test "#1046, empty string interpolations", ->
eq "#{ }", ''
test "strings are not callable", ->
throws -> CoffeeScript.compile '"a"()'
throws -> CoffeeScript.compile '"a#{b}"()'
throws -> CoffeeScript.compile '"a" 1'
throws -> CoffeeScript.compile '"a#{b}" 1'
throws -> CoffeeScript.compile '''
"a"
k: v
'''
throws -> CoffeeScript.compile '''
"a#{b}"
k: v
'''