diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index fe5bd6f9..2f0ed8a3 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -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'; } diff --git a/lib/coffee-script/rewriter.js b/lib/coffee-script/rewriter.js index 312ac866..e26fcbe6 100644 --- a/lib/coffee-script/rewriter.js +++ b/lib/coffee-script/rewriter.js @@ -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); diff --git a/src/lexer.coffee b/src/lexer.coffee index 058fbcf7..bd40b7d9 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -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 diff --git a/src/rewriter.coffee b/src/rewriter.coffee index a15414e9..6431adee 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -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 diff --git a/test/arrays.coffee b/test/arrays.coffee index bc4f9fa6..b150593e 100644 --- a/test/arrays.coffee +++ b/test/arrays.coffee @@ -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 diff --git a/test/regexps.coffee b/test/regexps.coffee index c8f7f020..05d7c348 100644 --- a/test/regexps.coffee +++ b/test/regexps.coffee @@ -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 diff --git a/test/strings.coffee b/test/strings.coffee index e374ba2e..2e75bd3d 100644 --- a/test/strings.coffee +++ b/test/strings.coffee @@ -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 + '''