diff --git a/lib/coffeescript/lexer.js b/lib/coffeescript/lexer.js index 50a214faec..d9882df30e 100644 --- a/lib/coffeescript/lexer.js +++ b/lib/coffeescript/lexer.js @@ -587,12 +587,16 @@ // Keeps track of the level of indentation, because a single outdent token // can close multiple indents, so we need to know how far in we happen to be. lineToken(chunk = this.chunk) { - var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size; + var backslash, diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, prev, size; if (!(match = MULTI_DENT.exec(chunk))) { return 0; } indent = match[0]; - this.seenFor = false; + prev = this.prev(); + backslash = (prev != null) && prev[0] === '\\'; + if (!(backslash && this.seenFor)) { + this.seenFor = false; + } if (!this.importSpecifierList) { this.seenImport = false; } diff --git a/src/lexer.coffee b/src/lexer.coffee index 6e70762d61..b0f4cff7ca 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -449,7 +449,9 @@ exports.Lexer = class Lexer return 0 unless match = MULTI_DENT.exec chunk indent = match[0] - @seenFor = no + prev = @prev() + backslash = prev? and prev[0] is '\\' + @seenFor = no unless backslash and @seenFor @seenImport = no unless @importSpecifierList @seenExport = no unless @exportSpecifierList diff --git a/test/control_flow.coffee b/test/control_flow.coffee index 22837e8ceb..2825ffa1f7 100644 --- a/test/control_flow.coffee +++ b/test/control_flow.coffee @@ -515,3 +515,118 @@ test "#3441: `StatementLiteral` in parentheses", -> r9 = for a in arr then (a; continue) arrayEq r9, [] + +# Issue #3909: backslash to break line in `for` loops throw syntax error +test "#3909: backslash `for own ... of`", -> + + obj = {a: 1, b: 2, c: 3} + arr = ['a', 'b', 'c'] + + x1 \ + = ( key for own key of obj ) + arrayEq x1, arr + + x2 = \ + ( key for own key of obj ) + arrayEq x2, arr + + x3 = ( \ + key for own key of obj ) + arrayEq x3, arr + + x4 = ( key \ + for own key of obj ) + arrayEq x4, arr + + x5 = ( key for own key of \ + obj ) + arrayEq x5, arr + + x6 = ( key for own key of obj \ + ) + arrayEq x6, arr + + x7 = ( key for \ + own key of obj ) + arrayEq x7, arr + + x8 = ( key for own \ + key of obj ) + arrayEq x8, arr + + x9 = ( key for own key \ + of obj ) + arrayEq x9, arr + + +test "#3909: backslash `for ... of`", -> + obj = {a: 1, b: 2, c: 3} + arr = ['a', 'b', 'c'] + + x1 \ + = ( key for key of obj ) + arrayEq x1, arr + + x2 = \ + ( key for key of obj ) + arrayEq x2, arr + + x3 = ( \ + key for key of obj ) + arrayEq x3, arr + + x4 = ( key \ + for key of obj ) + arrayEq x4, arr + + x5 = ( key for key of \ + obj ) + arrayEq x5, arr + + x6 = ( key for key of obj \ + ) + arrayEq x6, arr + + x7 = ( key for \ + key of obj ) + arrayEq x7, arr + + x8 = ( key for key \ + of obj ) + arrayEq x8, arr + + +test "#3909: backslash `for ... in`", -> + arr = ['a', 'b', 'c'] + + x1 \ + = ( key for key in arr ) + arrayEq x1, arr + + x2 = \ + ( key for key in arr ) + arrayEq x2, arr + + x3 = ( \ + key for key in arr ) + arrayEq x3, arr + + x4 = ( key \ + for key in arr ) + arrayEq x4, arr + + x5 = ( key for key in \ + arr ) + arrayEq x5, arr + + x6 = ( key for key in arr \ + ) + arrayEq x6, arr + + x7 = ( key for \ + key in arr ) + arrayEq x7, arr + + x8 = ( key for key \ + in arr ) + arrayEq x8, arr