From 29b9c3bb29af88ccf7fcbcb65ff472511f27d4dc Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Wed, 16 May 2012 10:30:55 -0400 Subject: [PATCH] correcting broken fix for #2333 regarding string escape sequences Sorry for all the commits! It should really be done this time. --- lib/coffee-script/nodes.js | 40 +++++++++++++++++++++++++++----------- src/nodes.coffee | 17 ++++++++++------ test/strict.coffee | 4 ++++ 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 9b2b43c879..05c526aa15 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1172,16 +1172,34 @@ Obj.prototype.children = ['properties']; Obj.prototype.compileNode = function(o) { - var i, idt, indent, isDuplicate, join, lastNoncom, node, normalise, obj, prop, propName, propNames, props, _i, _j, _len, _len1, _ref2; + var i, idt, indent, isDuplicate, join, lastNoncom, node, normaliseString, obj, prop, propName, propNames, props, _i, _j, _len, _len1, _ref2; props = this.properties; propNames = []; - normalise = function(s) { - switch (s[0]) { - case '"': - return s.slice(1, -1).replace(/\\"/g, '"'); - case "'": - return s.slice(1, -1).replace(/\\'/g, "'"); - } + normaliseString = function(s) { + var octalNormalised, quoteNormalised; + quoteNormalised = (function() { + switch (s[0]) { + case '"': + return s.slice(1, -1).replace(/\\"/g, '"'); + case "'": + return s.slice(1, -1).replace(/\\'/g, "'"); + } + })(); + octalNormalised = quoteNormalised.replace(/\\([0btnvfr\\])/, function(match, c) { + return { + 0: "\0", + b: "\b", + t: "\t", + n: "\n", + v: "\v", + f: "\f", + r: "\r", + "\\": "\\" + }[c]; + }); + return octalNormalised.replace(/\\x([0-9a-f]{2})|\\u([0-9a-f]{4})/i, function(match, h, u) { + return String.fromCharCode(parseInt(h != null ? h : u, 16)); + }); }; isDuplicate = function(x) { var mx; @@ -1193,15 +1211,15 @@ } my = y.match(/^['"]/); if (mx && my) { - if (normalise(x) === normalise(y)) { + if (normaliseString(x) === normaliseString(y)) { return true; } } else if (mx) { - if (y === x.slice(1, -1)) { + if (y === normaliseString(x)) { return true; } } else if (my) { - if (x === y.slice(1, -1)) { + if (x === normaliseString(y)) { return true; } } diff --git a/src/nodes.coffee b/src/nodes.coffee index 5e96bae60c..08f6de08dd 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -802,20 +802,25 @@ exports.Obj = class Obj extends Base compileNode: (o) -> props = @properties propNames = [] - normalise = (s) -> switch s[0] - when '"' then s[1...-1].replace /\\"/g, '"' - when "'" then s[1...-1].replace /\\'/g, "'" + normaliseString = (s) -> + quoteNormalised = switch s[0] + when '"' then s[1...-1].replace /\\"/g, '"' + when "'" then s[1...-1].replace /\\'/g, "'" + octalNormalised = quoteNormalised.replace /\\([0btnvfr\\])/, (match, c) -> + {0:"\0", b:"\b", t:"\t", n:"\n", v:"\v", f:"\f", r:"\r", "\\":"\\"}[c] + octalNormalised.replace /\\x([0-9a-f]{2})|\\u([0-9a-f]{4})/i, (match, h, u) -> + String.fromCharCode parseInt (h ? u), 16 isDuplicate = (x) -> mx = x.match /^['"]/ (y) -> return true if y is x or +y is +x my = y.match /^['"]/ if mx and my - return true if normalise(x) is normalise y + return true if normaliseString(x) is normaliseString y else if mx - return true if y is x[1...-1] + return true if y is normaliseString x else if my - return true if x is y[1...-1] + return true if x is normaliseString y false for prop in @properties prop = prop.variable if prop.isComplex() diff --git a/test/strict.coffee b/test/strict.coffee index 1ca3a57b11..7fe1e98947 100644 --- a/test/strict.coffee +++ b/test/strict.coffee @@ -70,7 +70,11 @@ test "#2333: more duplicate property prohibitions", -> strict '{.1:0, 1e-1:0}' strict '{100:0, 1e2:0}' strict '{"\\0":0, "\\x00":0}' + strict '{"\\n":0, "\\x0A":0}' + strict '{"\\\\":0, "\\x5c":0}' strict 'a = 0; {a, "a":0}' + strict "{'\\'a':0, \"'a\":0}" + strict "{'\\\\a':0, '\\\\a':0}" strictOk '{0:0, "0x0":0}' strictOk '{"a":0, "\'a\'":0}'