From 7c7fa3daf1c1e1b720d6a8d7d984c821c1947533 Mon Sep 17 00:00:00 2001 From: Chris Connelly Date: Sat, 15 Oct 2016 23:06:50 +0100 Subject: [PATCH 1/2] Add missing compiled files --- lib/coffee-script/lexer.js | 25 ++++++++++++++++++++----- lib/coffee-script/nodes.js | 14 ++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index ee2d4b6c40..cb008ba731 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -22,6 +22,7 @@ this.indebt = 0; this.outdebt = 0; this.indents = []; + this.indentLiteral = ''; this.ends = []; this.tokens = []; this.seenFor = false; @@ -174,7 +175,7 @@ }; Lexer.prototype.numberToken = function() { - var base, lexedLength, match, number, numberValue, ref2, tag; + var base, lexedLength, match, number, numberValue, tag; if (!(match = NUMBER.exec(this.chunk))) { return 0; } @@ -214,9 +215,6 @@ } })(); numberValue = base != null ? parseInt(number.slice(2), base) : parseFloat(number); - if ((ref2 = number.charAt(1)) === 'b' || ref2 === 'o') { - number = "0x" + (numberValue.toString(16)); - } tag = numberValue === 2e308 ? 'INFINITY' : 'NUMBER'; this.token(tag, number, 0, lexedLength); return lexedLength; @@ -408,7 +406,7 @@ }; Lexer.prototype.lineToken = function() { - var diff, indent, match, noNewlines, size; + var diff, indent, match, minLiteralLength, newIndentLiteral, noNewlines, size; if (!(match = MULTI_DENT.exec(this.chunk))) { return 0; } @@ -416,6 +414,20 @@ this.seenFor = false; size = indent.length - 1 - indent.lastIndexOf('\n'); noNewlines = this.unfinished(); + newIndentLiteral = size > 0 ? indent.slice(-size) : ''; + if (!/^(.?)\1*$/.exec(newIndentLiteral)) { + this.error('mixed indentation', { + offset: indent.length + }); + return indent.length; + } + minLiteralLength = Math.min(newIndentLiteral.length, this.indentLiteral.length); + if (newIndentLiteral.slice(0, minLiteralLength) !== this.indentLiteral.slice(0, minLiteralLength)) { + this.error('indentation mismatch', { + offset: indent.length + }); + return indent.length; + } if (size - this.indebt === this.indent) { if (noNewlines) { this.suppressNewlines(); @@ -432,6 +444,7 @@ } if (!this.tokens.length) { this.baseIndent = this.indent = size; + this.indentLiteral = newIndentLiteral; return indent.length; } diff = size - this.indent + this.outdebt; @@ -442,6 +455,7 @@ }); this.outdebt = this.indebt = 0; this.indent = size; + this.indentLiteral = newIndentLiteral; } else if (size < this.baseIndent) { this.error('missing indentation', { offset: indent.length @@ -488,6 +502,7 @@ this.token('TERMINATOR', '\n', outdentLength, 0); } this.indent = decreasedIndent; + this.indentLiteral = this.indentLiteral.slice(0, decreasedIndent); return this; }; diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 0209be181e..fc76552128 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -2513,12 +2513,14 @@ o.scope.parameter(fragmentsToText(params[i])); } uniqs = []; - this.eachParamName(function(name, node) { - if (indexOf.call(uniqs, name) >= 0) { - node.error("multiple parameters named " + name); - } - return uniqs.push(name); - }); + this.eachParamName((function(_this) { + return function(name, node) { + if (indexOf.call(uniqs, name) >= 0) { + node.error("multiple parameters named '" + name + "'"); + } + return uniqs.push(name); + }; + })(this)); if (!(wasEmpty || this.noReturn)) { this.body.makeReturn(); } From 18722cb96387bdbafc0483ec9c804e0a50dca693 Mon Sep 17 00:00:00 2001 From: Chris Connelly Date: Sat, 15 Oct 2016 23:10:34 +0100 Subject: [PATCH 2/2] Compile computed properties to ES2015 equivalent This is a fairly small change that simplifies the code generation for computed properties as they're now generated in the object initializer like regular properties. --- lib/coffee-script/nodes.js | 64 +++++++++++--------------------------- src/nodes.coffee | 46 ++++++++++----------------- 2 files changed, 34 insertions(+), 76 deletions(-) diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index fc76552128..ca4f040b90 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1428,7 +1428,7 @@ Obj.prototype.children = ['properties']; Obj.prototype.compileNode = function(o) { - var answer, dynamicIndex, hasDynamic, i, idt, indent, j, join, k, key, l, lastNoncom, len1, len2, len3, node, oref, prop, props, ref3, value; + var answer, i, idt, indent, j, join, k, key, lastNoncom, len1, len2, node, prop, props, ref3, value; props = this.properties; if (this.generated) { for (j = 0, len1 = props.length; j < len1; j++) { @@ -1438,34 +1438,14 @@ } } } - for (dynamicIndex = k = 0, len2 = props.length; k < len2; dynamicIndex = ++k) { - prop = props[dynamicIndex]; - if ((prop.variable || prop).base instanceof Parens) { - break; - } - } - hasDynamic = dynamicIndex < props.length; idt = o.indent += TAB; lastNoncom = this.lastNonComment(this.properties); answer = []; - if (hasDynamic) { - oref = o.scope.freeVariable('obj'); - answer.push(this.makeCode("(\n" + idt + oref + " = ")); - } - answer.push(this.makeCode("{" + (props.length === 0 || dynamicIndex === 0 ? '}' : '\n'))); - for (i = l = 0, len3 = props.length; l < len3; i = ++l) { + answer.push(this.makeCode("{" + (props.length === 0 ? '}' : '\n'))); + for (i = k = 0, len2 = props.length; k < len2; i = ++k) { prop = props[i]; - if (i === dynamicIndex) { - if (i !== 0) { - answer.push(this.makeCode("\n" + idt + "}")); - } - answer.push(this.makeCode(',\n')); - } - join = i === props.length - 1 || i === dynamicIndex - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; + join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; indent = prop instanceof Comment ? '' : idt; - if (hasDynamic && i < dynamicIndex) { - indent += TAB; - } if (prop instanceof Assign) { if (prop.context !== 'object') { prop.operatorToken.error("unexpected " + prop.operatorToken.value); @@ -1477,22 +1457,15 @@ if (prop instanceof Value && prop["this"]) { prop = new Assign(prop.properties[0].name, prop, 'object'); } - if (!(prop instanceof Comment)) { - if (i < dynamicIndex) { - if (!(prop instanceof Assign)) { - prop = new Assign(prop, prop, 'object'); + if (!(prop instanceof Comment) && !(prop instanceof Assign)) { + if (prop.isComplex()) { + ref3 = prop.base.cache(o), key = ref3[0], value = ref3[1]; + if (key instanceof IdentifierLiteral) { + key = new PropertyName(key.value); } + prop = new Assign(key, value, 'object'); } else { - if (prop instanceof Assign) { - key = prop.variable; - value = prop.value; - } else { - ref3 = prop.base.cache(o), key = ref3[0], value = ref3[1]; - if (key instanceof IdentifierLiteral) { - key = new PropertyName(key.value); - } - } - prop = new Assign(new Value(new IdentifierLiteral(oref), [new Access(key)]), value); + prop = new Assign(prop, prop, 'object'); } } if (indent) { @@ -1503,14 +1476,10 @@ answer.push(this.makeCode(join)); } } - if (hasDynamic) { - answer.push(this.makeCode(",\n" + idt + oref + "\n" + this.tab + ")")); - } else { - if (props.length !== 0) { - answer.push(this.makeCode("\n" + this.tab + "}")); - } + if (props.length !== 0) { + answer.push(this.makeCode("\n" + this.tab + "}")); } - if (this.front && !hasDynamic) { + if (this.front) { return this.wrapInBraces(answer); } else { return answer; @@ -2190,7 +2159,10 @@ } compiledName = this.variable.compileToFragments(o, LEVEL_LIST); if (this.context === 'object') { - if (ref8 = fragmentsToText(compiledName), indexOf.call(JS_FORBIDDEN, ref8) >= 0) { + if (this.variable.isComplex()) { + compiledName.unshift(this.makeCode('[')); + compiledName.push(this.makeCode(']')); + } else if (ref8 = fragmentsToText(compiledName), indexOf.call(JS_FORBIDDEN, ref8) >= 0) { compiledName.unshift(this.makeCode('"')); compiledName.push(this.makeCode('"')); } diff --git a/src/nodes.coffee b/src/nodes.coffee index 91781f0f26..9e46341597 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -981,27 +981,18 @@ exports.Obj = class Obj extends Base if @generated for node in props when node instanceof Value node.error 'cannot have an implicit value in an implicit object' - break for prop, dynamicIndex in props when (prop.variable or prop).base instanceof Parens - hasDynamic = dynamicIndex < props.length - idt = o.indent += TAB - lastNoncom = @lastNonComment @properties + idt = o.indent += TAB + lastNoncom = @lastNonComment @properties answer = [] - if hasDynamic - oref = o.scope.freeVariable 'obj' - answer.push @makeCode "(\n#{idt}#{oref} = " - answer.push @makeCode "{#{if props.length is 0 or dynamicIndex is 0 then '}' else '\n'}" + answer.push @makeCode "{#{if props.length is 0 then '}' else '\n'}" for prop, i in props - if i is dynamicIndex - answer.push @makeCode "\n#{idt}}" unless i is 0 - answer.push @makeCode ',\n' - join = if i is props.length - 1 or i is dynamicIndex - 1 + join = if i is props.length - 1 '' else if prop is lastNoncom or prop instanceof Comment '\n' else ',\n' indent = if prop instanceof Comment then '' else idt - indent += TAB if hasDynamic and i < dynamicIndex if prop instanceof Assign if prop.context isnt 'object' prop.operatorToken.error "unexpected #{prop.operatorToken.value}" @@ -1009,26 +1000,18 @@ exports.Obj = class Obj extends Base prop.variable.error 'invalid object key' if prop instanceof Value and prop.this prop = new Assign prop.properties[0].name, prop, 'object' - if prop not instanceof Comment - if i < dynamicIndex - if prop not instanceof Assign - prop = new Assign prop, prop, 'object' + if prop not instanceof Comment and prop not instanceof Assign + if prop.isComplex() + [key, value] = prop.base.cache o + key = new PropertyName key.value if key instanceof IdentifierLiteral + prop = new Assign key, value, 'object' else - if prop instanceof Assign - key = prop.variable - value = prop.value - else - [key, value] = prop.base.cache o - key = new PropertyName key.value if key instanceof IdentifierLiteral - prop = new Assign (new Value (new IdentifierLiteral oref), [new Access key]), value + prop = new Assign prop, prop, 'object' if indent then answer.push @makeCode indent answer.push prop.compileToFragments(o, LEVEL_TOP)... if join then answer.push @makeCode join - if hasDynamic - answer.push @makeCode ",\n#{idt}#{oref}\n#{@tab})" - else - answer.push @makeCode "\n#{@tab}}" unless props.length is 0 - if @front and not hasDynamic then @wrapInBraces answer else answer + answer.push @makeCode "\n#{@tab}}" unless props.length is 0 + if @front then @wrapInBraces answer else answer assigns: (name) -> for prop in @properties when prop.assigns name then return yes @@ -1427,7 +1410,10 @@ exports.Assign = class Assign extends Base compiledName = @variable.compileToFragments o, LEVEL_LIST if @context is 'object' - if fragmentsToText(compiledName) in JS_FORBIDDEN + if @variable.isComplex() + compiledName.unshift @makeCode '[' + compiledName.push @makeCode ']' + else if fragmentsToText(compiledName) in JS_FORBIDDEN compiledName.unshift @makeCode '"' compiledName.push @makeCode '"' return compiledName.concat @makeCode(": "), val