From ae55c70ac59da1ba6ac655a9819082406f23a08a Mon Sep 17 00:00:00 2001 From: satyr Date: Sun, 3 Oct 2010 07:45:23 +0900 Subject: [PATCH] 647: fixed quote/newline escaping in here documents --- lib/lexer.js | 21 +++++++++++++++------ src/lexer.coffee | 12 +++++++++--- test/test_literals.coffee | 36 ++++++++++++++++++++---------------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/lib/lexer.js b/lib/lexer.js index 51efdfe2..e5813690 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -124,9 +124,13 @@ quote: quote, indent: null }); - this.interpolateString(quote + doc + quote, { - heredoc: true - }); + if (quote === '"') { + this.interpolateString(quote + doc + quote, { + heredoc: true + }); + } else { + this.token('STRING', quote + doc + quote); + } this.line += count(heredoc, '\n'); this.i += heredoc.length; return true; @@ -362,7 +366,7 @@ return accessor ? 'accessor' : false; }; Lexer.prototype.sanitizeHeredoc = function(doc, options) { - var _ref2, attempt, herecomment, indent, match; + var _ref2, attempt, herecomment, indent, match, quote; _ref2 = options, indent = _ref2.indent, herecomment = _ref2.herecomment; if (herecomment && !include(doc, '\n')) { return doc; @@ -381,8 +385,13 @@ if (herecomment) { return doc; } - doc = doc.replace(/^\n/, '').replace(RegExp("" + (options.quote), "g"), '\\$&'); - if (options.quote === "'") { + quote = options.quote; + doc = doc.replace(/^\n/, ''); + doc = doc.replace(/\\([\s\S])/g, function(m, c) { + return ('\n' === c || quote === c) ? c : m; + }); + doc = doc.replace(RegExp("" + (quote), "g"), '\\$&'); + if (quote === "'") { doc = this.escapeLines(doc, true); } return doc; diff --git a/src/lexer.coffee b/src/lexer.coffee index df83761f..4d9c8bd9 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -139,7 +139,10 @@ exports.Lexer = class Lexer heredoc = match[0] quote = heredoc.charAt 0 doc = @sanitizeHeredoc match[2], {quote, indent: null} - @interpolateString quote + doc + quote, heredoc: yes + if quote is '"' + @interpolateString quote + doc + quote, heredoc: yes + else + @token 'STRING', quote + doc + quote @line += count heredoc, '\n' @i += heredoc.length true @@ -340,8 +343,11 @@ exports.Lexer = class Lexer indent = attempt if indent is null or 0 < attempt.length < indent.length doc = doc.replace /\n#{ indent }/g, '\n' if indent return doc if herecomment - doc = doc.replace(/^\n/, '').replace(/#{ options.quote }/g, '\\$&') - doc = @escapeLines doc, yes if options.quote is "'" + {quote} = options + doc = doc.replace /^\n/, '' + doc = doc.replace /\\([\s\S])/g, (m, c) -> if c in ['\n', quote] then c else m + doc = doc.replace /#{quote}/g, '\\$&' + doc = @escapeLines doc, yes if quote is "'" doc # A source of ambiguity in our grammar used to be parameter lists in function diff --git a/test/test_literals.coffee b/test/test_literals.coffee index b8b2bb72..a2dd6831 100644 --- a/test/test_literals.coffee +++ b/test/test_literals.coffee @@ -34,11 +34,27 @@ func = -> ok func() is null +eq /\\/.source, "\\\\" +eq '(((dollars)))', '\(\(\(dollars\)\)\)' +eq 'one two three', "one + two + three" +eq "four five", 'four -str = "\\" -reg = /\\/ + five' + +#647 +eq "''Hello, World\\''", ''' +'\'Hello, World\\\'' +''' +eq '""Hello, World\\""', """ +"\"Hello, World\\\"" +""" +eq 'Hello, World\n', ''' +Hello, World\ + +''' -ok reg(str) and str is '\\' trailingComma = [1, 2, 3,] ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3) @@ -54,18 +70,6 @@ trailingComma = {k1: "v1", k2: 4, k3: (-> true),} ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1") -money$ = '(((dollars)))' - -ok money$ is '\(\(\(dollars\)\)\)' - - -multiline = "one - two - three" - -ok multiline is 'one two three' - - ok {a: (num) -> num is 10 }.a 10 @@ -242,6 +246,6 @@ ok b is 100 # Inline JS -ok '\\`' is ` +eq '\\`', ` "\\\`" `