From 79148d2940a82088f08771e1271de4d7d68e3551 Mon Sep 17 00:00:00 2001 From: satyr Date: Wed, 13 Oct 2010 20:29:22 +0900 Subject: [PATCH] refactored loop variable caching --- Cakefile | 4 +- lib/browser.js | 22 +-- lib/cake.js | 6 +- lib/coffee-script.js | 2 +- lib/command.js | 70 +++++----- lib/grammar.js | 18 +-- lib/helpers.js | 4 +- lib/lexer.js | 10 +- lib/nodes.js | 238 +++++++++++++------------------- lib/optparse.js | 14 +- lib/rewriter.js | 38 ++--- lib/scope.js | 16 +-- src/browser.coffee | 2 +- src/grammar.coffee | 18 +-- src/nodes.coffee | 106 +++++++------- test/test_comprehensions.coffee | 49 ------- 16 files changed, 257 insertions(+), 360 deletions(-) diff --git a/Cakefile b/Cakefile index 601bef19..2fa46891 100644 --- a/Cakefile +++ b/Cakefile @@ -99,8 +99,8 @@ task 'loc', 'count the lines of source code in the CoffeeScript compiler', -> runTests = (CoffeeScript) -> startTime = Date.now() passedTests = failedTests = 0 - for all name, func of require 'assert' - global[name] = -> ++passedTests; func arguments... + wrap = (name, func) -> global[name] = -> ++passedTests; func arguments... + wrap name, func for all name, func of require 'assert' global.eq = global.strictEqual global.CoffeeScript = CoffeeScript process.on 'exit', -> diff --git a/lib/browser.js b/lib/browser.js index e95f39f5..05d4ee2b 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -6,7 +6,7 @@ return eval(CoffeeScript.compile(code, options)); }; CoffeeScript.run = function(code, options) { - ((options != null) ? options.bare = true : undefined); + (options != null) ? options.bare = true : undefined; return Function(CoffeeScript.compile(code, options))(); }; if (!(typeof window !== "undefined" && window !== null)) { @@ -25,16 +25,16 @@ return xhr.send(null); }; runScripts = function() { - var _i, _j, _len, _ref, script; - for (_i = 0, _len = (_ref = document.getElementsByTagName('script')).length; _i < _len; _i++) { - (function() { - var script = _ref[_i]; - _j = script; - return script.type === 'text/coffeescript' ? script.src ? CoffeeScript.load(script.src) : setTimeout(function() { - return CoffeeScript.run(script.innerHTML); - }) : undefined; - })(); - script = _j; + var _i, _len, _ref, script; + for (_i = 0, _len = (_ref = document.getElementsByTagName('script')).length; _i < _len; ++_i) { + script = _ref[_i]; + if (script.type === 'text/coffeescript') { + if (script.src) { + CoffeeScript.load(script.src); + } else { + CoffeeScript.run(script.innerHTML); + } + } } return null; }; diff --git a/lib/cake.js b/lib/cake.js index 395a9a41..ebd90294 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -15,11 +15,11 @@ if (!action) { _ref = [description, action], action = _ref[0], description = _ref[1]; } - return (tasks[name] = { + return tasks[name] = { name: name, description: description, action: action - }); + }; }, option: function(letter, flag, description) { return switches.push([letter, flag, description]); @@ -47,7 +47,7 @@ } options = oparse.parse(args); _result = []; - for (_i = 0, _len = (_ref = options.arguments).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref = options.arguments).length; _i < _len; ++_i) { arg = _ref[_i]; _result.push(invoke(arg)); } diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 000acf46..7b3894bb 100755 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -64,7 +64,7 @@ }, setInput: function(tokens) { this.tokens = tokens; - return (this.pos = 0); + return this.pos = 0; }, upcomingInput: function() { return ""; diff --git a/lib/command.js b/lib/command.js index 9eb2aaa9..1cf8b242 100644 --- a/lib/command.js +++ b/lib/command.js @@ -48,43 +48,39 @@ return compileScripts(); }; compileScripts = function() { - var _i, _j, _len, _ref2, _result, base, compile, source; + var _i, _len, _ref2, _result, base, compile, source; _result = []; - for (_i = 0, _len = (_ref2 = sources).length; _i < _len; _i++) { - (function() { - var source = _ref2[_i]; - _j = source; - return _result.push((function() { - base = path.join(source); - compile = function(source, topLevel) { - return path.exists(source, function(exists) { - if (!exists) { - throw new Error("File not found: " + source); + for (_i = 0, _len = (_ref2 = sources).length; _i < _len; ++_i) { + source = _ref2[_i]; + _result.push((function() { + base = path.join(source); + compile = function(source, topLevel) { + return path.exists(source, function(exists) { + if (!exists) { + throw new Error("File not found: " + source); + } + return fs.stat(source, function(err, stats) { + if (stats.isDirectory()) { + return fs.readdir(source, function(err, files) { + var _j, _len2, _result2, file; + _result2 = []; + for (_j = 0, _len2 = files.length; _j < _len2; ++_j) { + file = files[_j]; + _result2.push(compile(path.join(source, file))); + } + return _result2; + }); + } else if (topLevel || path.extname(source) === '.coffee') { + fs.readFile(source, function(err, code) { + return compileScript(source, code.toString(), base); + }); + return opts.watch ? watch(source, base) : undefined; } - return fs.stat(source, function(err, stats) { - if (stats.isDirectory()) { - return fs.readdir(source, function(err, files) { - var _k, _len2, _result2, file; - _result2 = []; - for (_k = 0, _len2 = files.length; _k < _len2; _k++) { - file = files[_k]; - _result2.push(compile(path.join(source, file))); - } - return _result2; - }); - } else if (topLevel || path.extname(source) === '.coffee') { - fs.readFile(source, function(err, code) { - return compileScript(source, code.toString(), base); - }); - return opts.watch ? watch(source, base) : undefined; - } - }); }); - }; - return compile(source, true); - })()); - })(); - source = _j; + }); + }; + return compile(source, true); + })()); } return _result; }; @@ -93,7 +89,7 @@ o = opts; options = compileOptions(file); if (o.require) { - for (_i = 0, _len = (_ref2 = o.require).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = o.require).length; _i < _len; ++_i) { req = _ref2[_i]; require(helpers.starts(req, '.') ? fs.realpathSync(req) : req); } @@ -190,7 +186,7 @@ var _i, _len, _ref2, _result, strings, tag, token, value; strings = (function() { _result = []; - for (_i = 0, _len = tokens.length; _i < _len; _i++) { + for (_i = 0, _len = tokens.length; _i < _len; ++_i) { token = tokens[_i]; _result.push((function() { _ref2 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref2[0], value = _ref2[1]; @@ -208,7 +204,7 @@ o.compile || (o.compile = !!o.output); o.run = !(o.compile || o.print || o.lint); o.print = !!(o.print || (o.eval || o.stdio && o.compile)); - return (sources = o.arguments); + return sources = o.arguments; }; compileOptions = function(fileName) { return { diff --git a/lib/grammar.js b/lib/grammar.js index 4ddd29f0..4a11389b 100644 --- a/lib/grammar.js +++ b/lib/grammar.js @@ -11,7 +11,7 @@ action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())"; action = action.replace(/\bnew /g, '$&yy.'); action = action.replace(/\b(?:Expressions\.wrap|extend)\b/g, 'yy.$&'); - return [patternString, ("$$ = " + action + ";"), options]; + return [patternString, "$$ = " + action + ";", options]; }; grammar = { Root: [ @@ -77,17 +77,17 @@ }) ], AssignObj: [ - o("Identifier", function() { + o('Identifier', function() { return new Value($1); - }), o("AlphaNumeric"), o("ThisProperty"), o("Identifier : Expression", function() { + }), o('AlphaNumeric'), o('ThisProperty'), o('Identifier : Expression', function() { return new Assign(new Value($1), $3, 'object'); - }), o("AlphaNumeric : Expression", function() { + }), o('AlphaNumeric : Expression', function() { return new Assign(new Value($1), $3, 'object'); - }), o("Identifier : INDENT Expression OUTDENT", function() { + }), o('Identifier : INDENT Expression OUTDENT', function() { return new Assign(new Value($1), $4, 'object'); - }), o("AlphaNumeric : INDENT Expression OUTDENT", function() { + }), o('AlphaNumeric : INDENT Expression OUTDENT', function() { return new Assign(new Value($1), $4, 'object'); - }), o("Comment") + }), o('Comment') ], Return: [ o("RETURN Expression", function() { @@ -604,10 +604,10 @@ alternatives = grammar[name]; grammar[name] = (function() { _result = []; - for (_i = 0, _len = alternatives.length; _i < _len; _i++) { + for (_i = 0, _len = alternatives.length; _i < _len; ++_i) { alt = alternatives[_i]; _result.push((function() { - for (_j = 0, _len2 = (_ref = alt[0].split(' ')).length; _j < _len2; _j++) { + for (_j = 0, _len2 = (_ref = alt[0].split(' ')).length; _j < _len2; ++_j) { token = _ref[_j]; if (!grammar[token]) { tokens.push(token); diff --git a/lib/helpers.js b/lib/helpers.js index 1a716946..a971768f 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -11,7 +11,7 @@ exports.compact = function(array) { var _i, _len, _result, item; _result = []; - for (_i = 0, _len = array.length; _i < _len; _i++) { + for (_i = 0, _len = array.length; _i < _len; ++_i) { item = array[_i]; if (item) { _result.push(item); @@ -41,7 +41,7 @@ exports.flatten = flatten = function(array) { var _i, _len, element, flattened; flattened = []; - for (_i = 0, _len = array.length; _i < _len; _i++) { + for (_i = 0, _len = array.length; _i < _len; ++_i) { element = array[_i]; if (element instanceof Array) { flattened = flattened.concat(flatten(element)); diff --git a/lib/lexer.js b/lib/lexer.js index 80b5760c..3e41a3a2 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -59,7 +59,7 @@ } forcedIdentifier = colon || this.tagAccessor(); tag = 'IDENTIFIER'; - if ((__indexOf.call(JS_KEYWORDS, id) >= 0) || !forcedIdentifier && (__indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { + if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) { tag = id.toUpperCase(); if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) { tag = 'LEADING_WHEN'; @@ -228,7 +228,7 @@ tokens = []; for (_i = 0, _len = (_ref2 = this.interpolateString(body, { regex: true - })).length; _i < _len; _i++) { + })).length; _i < _len; ++_i) { _ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1]; if (tag === 'TOKENS') { tokens.push.apply(tokens, value); @@ -355,7 +355,7 @@ if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) { this.assignmentError(); } - if (((_ref3 = prev[1]) === '||' || _ref3 === '&&')) { + if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') { prev[0] = 'COMPOUND_ASSIGN'; prev[1] += '='; return true; @@ -480,7 +480,7 @@ if (levels.length && str.charAt(i) === '\\') { i += 1; } else { - for (_i = 0, _len = delimited.length; _i < _len; _i++) { + for (_i = 0, _len = delimited.length; _i < _len; ++_i) { pair = delimited[_i]; open = pair[0], close = pair[1]; if (levels.length && starts(str, close, i) && last(levels) === pair) { @@ -556,7 +556,7 @@ if (interpolated = tokens.length > 1) { this.token('(', '('); } - for (i = 0, _len = tokens.length; i < _len; i++) { + for (i = 0, _len = tokens.length; i < _len; ++i) { _ref3 = tokens[i], tag = _ref3[0], value = _ref3[1]; if (i) { this.token('+', '+'); diff --git a/lib/nodes.js b/lib/nodes.js index 92616bc4..891a7f88 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -52,13 +52,13 @@ if (!this.isComplex()) { return [this, this]; } else { - reference = new Literal(o.scope.freeVariable(((options != null) ? options.name : undefined) || 'ref')); + reference = new Literal(o.scope.freeVariable('ref')); compiled = new Assign(reference, this); return [compiled, reference]; } }).call(this); - if (((options != null) ? options.precompile : undefined)) { - for (i = 0, _len = pair.length; i < _len; i++) { + if ((options != null) ? options.precompile : undefined) { + for (i = 0, _len = pair.length; i < _len; ++i) { node = pair[i]; (pair[i] = node.compile(o)); } @@ -69,6 +69,16 @@ this.parenthetical = true; return this.compile(o); }; + Base.prototype.compileLoopReference = function(o, name) { + var src, tmp; + src = tmp = this.compile(o); + if (!(NUMBER.test(src) || IDENTIFIER.test(src) && o.scope.check(src, { + immediate: true + }))) { + src = "" + (tmp = o.scope.freeVariable(name)) + " = " + src; + } + return [src, tmp]; + }; Base.prototype.idt = function(tabs) { return (this.tab || '') + Array((tabs || 0) + 1).join(TAB); }; @@ -104,7 +114,7 @@ idt || (idt = ''); children = (function() { _result = []; - for (_i = 0, _len = (_ref2 = this.collectChildren()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.collectChildren()).length; _i < _len; ++_i) { child = _ref2[_i]; _result.push(child.toString(idt + TAB)); } @@ -118,10 +128,10 @@ if (!this.children) { return; } - for (_i = 0, _len = (_ref2 = this.children).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.children).length; _i < _len; ++_i) { attr = _ref2[_i]; if (this[attr]) { - for (_j = 0, _len2 = (_ref3 = flatten([this[attr]])).length; _j < _len2; _j++) { + for (_j = 0, _len2 = (_ref3 = flatten([this[attr]])).length; _j < _len2; ++_j) { child = _ref3[_j]; if (func(child) === false) { return; @@ -189,9 +199,9 @@ }; Expressions.prototype.makeReturn = function() { var end, idx; - end = this.expressions[(idx = this.expressions.length - 1)]; + end = this.expressions[idx = this.expressions.length - 1]; if (end instanceof Comment) { - end = this.expressions[(idx -= 1)]; + end = this.expressions[idx -= 1]; } if (end && !(end instanceof Return)) { this.expressions[idx] = end.makeReturn(); @@ -206,7 +216,7 @@ var _i, _len, _ref2, _result, node; return (function() { _result = []; - for (_i = 0, _len = (_ref2 = this.expressions).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.expressions).length; _i < _len; ++_i) { node = _ref2[_i]; _result.push(this.compileExpression(node, merge(o))); } @@ -264,7 +274,7 @@ }; Literal.prototype.isStatement = function() { var _ref2; - return ((_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'); + return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'; }; Literal.prototype.isPureStatement = Literal.prototype.isStatement; Literal.prototype.isComplex = NO; @@ -302,7 +312,7 @@ Return.prototype.makeReturn = THIS; Return.prototype.compile = function(o) { var _ref2, expr; - expr = (((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined); + expr = ((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined; if (expr && !(expr instanceof Return)) { return expr.compile(o); } @@ -405,7 +415,7 @@ if (props[0] instanceof Accessor && this.isSimpleNumber()) { code = "(" + code + ")"; } - for (_i = 0, _len = props.length; _i < _len; _i++) { + for (_i = 0, _len = props.length; _i < _len; ++_i) { prop = props[_i]; (code += prop.compile(o)); } @@ -417,7 +427,7 @@ Array.prototype.push.apply(ifn.body.properties, this.properties); return ifn; } - for (i = 0, _len = (_ref2 = this.properties).length; i < _len; i++) { + for (i = 0, _len = (_ref2 = this.properties).length; i < _len; ++i) { prop = _ref2[i]; if (prop.soakNode) { prop.soakNode = false; @@ -532,7 +542,7 @@ break; } } - for (_i = 0, _len = (_ref3 = list.reverse()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref3 = list.reverse()).length; _i < _len; ++_i) { call = _ref3[_i]; if (ifn) { if (call.variable instanceof Call) { @@ -550,8 +560,8 @@ if (ifn = this.unfoldSoak(o)) { return ifn.compile(o); } - (((_ref2 = this.variable) != null) ? _ref2.tags.front = this.tags.front : undefined); - for (_i = 0, _len = (_ref3 = this.args).length; _i < _len; _i++) { + ((_ref2 = this.variable) != null) ? _ref2.tags.front = this.tags.front : undefined; + for (_i = 0, _len = (_ref3 = this.args).length; _i < _len; ++_i) { arg = _ref3[_i]; if (arg instanceof Splat) { return this.compileSplat(o); @@ -559,7 +569,7 @@ } args = (function() { _result = []; - for (_j = 0, _len2 = (_ref4 = this.args).length; _j < _len2; _j++) { + for (_j = 0, _len2 = (_ref4 = this.args).length; _j < _len2; ++_j) { arg = _ref4[_j]; _result.push(arg.compileBare(o)); } @@ -574,7 +584,7 @@ var base, fun, idt, name, ref, splatargs; splatargs = this.compileSplatArguments(o); if (this.isSuper) { - return ("" + (this.superReference(o)) + ".apply(this, " + splatargs + ")"); + return "" + (this.superReference(o)) + ".apply(this, " + splatargs + ")"; } if (!this.isNew) { base = Value.wrap(this.variable); @@ -587,7 +597,7 @@ fun += name.compile(o); } } - return ("" + fun + ".apply(" + ref + ", " + splatargs + ")"); + return "" + fun + ".apply(" + ref + ", " + splatargs + ")"; } idt = this.idt(1); return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return typeof result === \"object\" ? result : child;\n" + (this.tab) + "})(" + (this.variable.compile(o)) + ", " + splatargs + ", function() {})"; @@ -668,7 +678,7 @@ o.indent = this.idt(1); nonComments = (function() { _result = []; - for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; ++_i) { prop = _ref2[_i]; if (!(prop instanceof Comment)) { _result.push(prop); @@ -679,7 +689,7 @@ lastNoncom = last(nonComments); props = (function() { _result = []; - for (i = 0, _len = (_ref2 = this.properties).length; i < _len; i++) { + for (i = 0, _len = (_ref2 = this.properties).length; i < _len; ++i) { prop = _ref2[i]; _result.push((function() { join = i === this.properties.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; @@ -700,7 +710,7 @@ }; ObjectLiteral.prototype.assigns = function(name) { var _i, _len, _ref2, prop; - for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; ++_i) { prop = _ref2[_i]; if (prop.assigns(name)) { return true; @@ -727,14 +737,14 @@ ArrayLiteral.prototype.compileNode = function(o) { var _i, _len, _len2, _ref2, _ref3, code, i, obj, objects; o.indent = this.idt(1); - for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; ++_i) { obj = _ref2[_i]; if (obj instanceof Splat) { return this.compileSplatLiteral(o); } } objects = []; - for (i = 0, _len2 = (_ref3 = this.objects).length; i < _len2; i++) { + for (i = 0, _len2 = (_ref3 = this.objects).length; i < _len2; ++i) { obj = _ref3[i]; code = obj.compileBare(o); objects.push(obj instanceof Comment ? "\n" + code + "\n" + (o.indent) : i === this.objects.length - 1 ? code : code + ', '); @@ -744,7 +754,7 @@ }; ArrayLiteral.prototype.assigns = function(name) { var _i, _len, _ref2, obj; - for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.objects).length; _i < _len; ++_i) { obj = _ref2[_i]; if (obj.assigns(name)) { return true; @@ -791,7 +801,7 @@ } else { constructor = new Code([], new Expressions([new Return(new Literal('this'))])); } - for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.properties).length; _i < _len; ++_i) { prop = _ref2[_i]; pvar = prop.variable, func = prop.value; if (pvar && pvar.base.value === 'constructor') { @@ -873,14 +883,11 @@ if (this.variable.isArray() || this.variable.isObject()) { return this.compilePatternMatch(o); } - if (this.variable.isSplice()) { - return this.compileSplice(o); - } if (ifn = If.unfoldSoak(o, this, 'variable')) { delete o.top; return ifn.compile(o); } - if (_ref2 = this.context, __indexOf.call(this.CONDITIONAL, _ref2) >= 0) { + if ((_ref2 = this.context, __indexOf.call(this.CONDITIONAL, _ref2) >= 0)) { return this.compileConditional(o); } } @@ -893,14 +900,14 @@ } val = this.value.compileBare(o); if (this.context === 'object') { - return ("" + name + ": " + val); + return "" + name + ": " + val; } if (!(isValue && (this.variable.hasProperties() || this.variable.namespaced))) { o.scope.find(name); } val = name + (" " + (this.context || '=') + " ") + val; if (stmt) { - return ("" + (this.tab) + val + ";"); + return "" + (this.tab) + val + ";"; } return top || this.parenthetical ? val : "(" + val + ")"; }; @@ -935,7 +942,7 @@ assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + valVar); valVar = ref; } - for (i = 0, _len = objects.length; i < _len; i++) { + for (i = 0, _len = objects.length; i < _len; ++i) { obj = objects[i]; idx = i; if (isObject) { @@ -966,6 +973,11 @@ code = assigns.join(', '); return top || this.parenthetical ? code : "(" + code + ")"; }; + Assign.prototype.compileConditional = function(o) { + var _ref2, left, rite; + _ref2 = this.variable.cacheReference(o), left = _ref2[0], rite = _ref2[1]; + return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value)).compile(o); + }; Assign.prototype.assigns = function(name) { return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); }; @@ -1001,7 +1013,7 @@ delete o.globals; splat = undefined; params = []; - for (i = 0, _len = (_ref2 = this.params).length; i < _len; i++) { + for (i = 0, _len = (_ref2 = this.params).length; i < _len; ++i) { param = _ref2[i]; if (splat) { if (param.attach) { @@ -1029,7 +1041,7 @@ o.scope.startLevel(); params = (function() { _result = []; - for (_i = 0, _len2 = params.length; _i < _len2; _i++) { + for (_i = 0, _len2 = params.length; _i < _len2; ++_i) { param = params[_i]; _result.push(param.compile(o)); } @@ -1038,7 +1050,7 @@ if (!(empty || this.noReturn)) { this.body.makeReturn(); } - for (_i = 0, _len2 = params.length; _i < _len2; _i++) { + for (_i = 0, _len2 = params.length; _i < _len2; ++_i) { param = params[_i]; o.scope.parameter(param); } @@ -1052,7 +1064,7 @@ func = "" + open + (params.join(', ')) + ") {" + code + close; o.scope.endLevel(); if (this.bound) { - return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")"); + return "" + (utility('bind')) + "(" + func + ", " + (this.context) + ")"; } return this.tags.front ? "(" + func + ")" : func; }; @@ -1119,7 +1131,7 @@ variadic = o.scope.freeVariable('result'); o.scope.assign(variadic, len + ' >= ' + this.arglength); end = this.trailings.length ? ", " + len + " - " + (this.trailings.length) : undefined; - for (idx = 0, _len = (_ref2 = this.trailings).length; idx < _len; idx++) { + for (idx = 0, _len = (_ref2 = this.trailings).length; idx < _len; ++idx) { trailing = _ref2[idx]; if (trailing.attach) { assign = trailing.assign; @@ -1141,7 +1153,7 @@ var _len, arg, args, code, end, i, prev; args = []; end = -1; - for (i = 0, _len = list.length; i < _len; i++) { + for (i = 0, _len = list.length; i < _len; ++i) { arg = list[i]; code = arg.compile(o); prev = args[end]; @@ -1167,7 +1179,7 @@ function While(condition, opts) { While.__super__.constructor.call(this); this.condition = ((opts != null) ? opts.invert : undefined) ? condition.invert() : condition; - this.guard = ((opts != null) ? opts.guard : undefined); + this.guard = (opts != null) ? opts.guard : undefined; return this; }; return While; @@ -1338,16 +1350,10 @@ _ref2 = this.object.compileReference(o, { precompile: true }), sub = _ref2[0], ref = _ref2[1]; - _ref3 = (function() { - if (this.negated) { - return [' !== ', ' && ']; - } else { - return [' === ', ' || ']; - } - }).call(this), cmp = _ref3[0], cnj = _ref3[1]; + _ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1]; tests = (function() { _result = []; - for (i = 0, _len = (_ref4 = this.array.base.objects).length; i < _len; i++) { + for (i = 0, _len = (_ref4 = this.array.base.objects).length; i < _len; ++i) { item = _ref4[i]; _result.push((i ? ref : sub) + cmp + item.compile(o)); } @@ -1363,7 +1369,7 @@ }), { precompile: true }), sub = _ref2[0], ref = _ref2[1]; - code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") ")(+(this.negated ? '< 0' : '>= 0')); + code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") ") + (this.negated ? '< 0' : '>= 0'); return sub === ref ? code : "(" + sub + ", " + code + ")"; }; In.prototype.toString = function(idt) { @@ -1518,26 +1524,16 @@ return ''; }; For.prototype.compileNode = function(o) { - var _ref2, _ref3, _ref4, _ref5, _ref6, body, codeInBody, cond, forPart, guardPart, head, hvar, idt, incr, index, ivar, lastLine, lvar, name, namePart, pvar, ref, resultDef, resultRet, rvar, scope, sourcePart, step, svar, tail, top, tvar, varPart, vars; - if (this.step) { - o.top = true; - _ref2 = this.step.compileReference(o, { - precompile: true, - name: 'step' - }), step = _ref2[0], pvar = _ref2[1]; - } - top = del(o, 'top') && !this.returns; - codeInBody = this.body.contains(function(node) { - return node instanceof Code; - }); + var _ref2, _ref3, _ref4, _ref5, _ref6, body, cond, forPart, guardPart, idt, index, ivar, lvar, name, namePart, pvar, resultDef, resultRet, rvar, scope, sourcePart, step, svar, tail, top, tvar, varPart, vars; scope = o.scope; - name = !this.pattern && (((_ref3 = this.name) != null) ? _ref3.compile(o) : undefined); - index = (((_ref4 = this.index) != null) ? _ref4.compile(o) : undefined); - ivar = !index || codeInBody ? scope.freeVariable('i') : index; + top = del(o, 'top') && !this.returns; + name = !this.pattern && (((_ref2 = this.name) != null) ? _ref2.compile(o) : undefined); + index = ((_ref3 = this.index) != null) ? _ref3.compile(o) : undefined; + ivar = !index ? scope.freeVariable('i') : index; varPart = ''; body = Expressions.wrap([this.body]); idt = this.idt(1); - if (name && !codeInBody) { + if (name) { scope.find(name, { immediate: true }); @@ -1547,46 +1543,24 @@ immediate: true }); } - if (!this.object) { - switch (+pvar) { - case 1: - incr = '++' + ivar; - break; - case -1: - incr = '--' + ivar; - break; - default: - incr = ivar + (pvar < 0 ? ' -= ' + pvar.slice(1) : ' += ' + pvar); - } + if (this.step) { + _ref4 = this.step.compileLoopReference(o, 'step'), step = _ref4[0], pvar = _ref4[1]; } if (this.from) { - _ref5 = this.from.compileReference(o, { - precompile: true, - name: 'from' - }), head = _ref5[0], hvar = _ref5[1]; - _ref6 = this.to.compileReference(o, { - precompile: true, - name: 'to' - }), tail = _ref6[0], tvar = _ref6[1]; - vars = "" + ivar + " = " + head; + _ref5 = this.to.compileLoopReference(o, 'to'), tail = _ref5[0], tvar = _ref5[1]; + vars = "" + ivar + " = " + (this.from.compile(o)); if (tail !== tvar) { vars += ", " + tail; } - if (step !== pvar) { - vars += ", " + step; - } - cond = isNaN(step) ? "" + pvar + " < 0 ? " + ivar + " >= " + tvar + " : " + ivar + " <= " + tvar : "" + ivar + " " + (step < 0 ? '>=' : '<=') + " " + tvar; - forPart = "" + vars + "; " + cond + "; " + incr; + cond = +pvar ? "" + ivar + " " + (pvar < 0 ? '>' : '<') + "= " + tvar : "" + pvar + " < 0 ? " + ivar + " >= " + tvar + " : " + ivar + " <= " + tvar; } else { - svar = sourcePart = this.source.compile(o); - if ((name || !this.raw) && !(IDENTIFIER.test(svar) && scope.check(svar, { - immediate: true - }))) { - sourcePart = "" + (ref = scope.freeVariable('ref')) + " = " + svar; - if (!this.object) { + if (name || !this.raw) { + _ref6 = this.source.compileLoopReference(o, 'ref'), sourcePart = _ref6[0], svar = _ref6[1]; + if (!(sourcePart === svar || this.object)) { sourcePart = "(" + sourcePart + ")"; } - svar = ref; + } else { + sourcePart = svar = this.source.compile(o); } namePart = this.pattern ? new Assign(this.name, new Literal("" + svar + "[" + ivar + "]")).compile(merge(o, { top: true @@ -1600,12 +1574,26 @@ vars = "" + ivar + " = 0, " + lvar + " = " + sourcePart + ".length"; cond = "" + ivar + " < " + lvar; } - if (step !== pvar) { - vars += ", " + step; - } - forPart = "" + vars + "; " + cond + "; " + incr; } } + if (this.object) { + forPart = "" + ivar + " in " + sourcePart; + guardPart = !this.raw && ("" + idt + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n"); + } else { + if (step !== pvar) { + vars += ", " + step; + } + forPart = ("" + vars + "; " + cond + "; ") + (function() { + switch (+pvar) { + case 1: + return '++' + ivar; + case -1: + return '--' + ivar; + default: + return ivar + (pvar < 0 ? ' -= ' + pvar.slice(1) : ' += ' + pvar); + } + })(); + } if (!top) { rvar = scope.freeVariable('result'); resultDef = "" + (this.tab) + rvar + " = [];\n"; @@ -1615,40 +1603,8 @@ if (this.guard) { body = Expressions.wrap([new If(this.guard, body)]); } - if (codeInBody) { - if (this.from) { - body.unshift(new Literal("var " + name + " = " + ivar)); - } - if (namePart) { - body.unshift(new Literal("var " + namePart)); - } - if (index) { - body.unshift(new Literal("var " + index + " = " + ivar)); - } - lastLine = body.expressions.pop(); - if (index) { - body.push(new Assign(new Literal(ivar), new Literal(index))); - } - if (nvar) { - body.push(new Assign(new Literal(nvar), new Literal(name))); - } - body.push(lastLine); - o.indent = this.idt(1); - body = Expressions.wrap([new Literal(body.compile(o))]); - if (index) { - body.push(new Assign(new Literal(index), new Literal(ivar))); - } - if (name) { - body.push(new Assign(new Literal(name), new Literal(nvar || ivar))); - } - } else { - if (namePart) { - varPart = "" + idt + namePart + ";\n"; - } - } - if (this.object) { - forPart = "" + ivar + " in " + sourcePart; - guardPart = !this.raw && ("" + idt + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n"); + if (namePart) { + varPart = "" + idt + namePart + ";\n"; } return "" + (resultDef || '') + (this.tab) + "for (" + forPart + ") {\n" + (guardPart || '') + varPart + (body.compile(merge(o, { indent: idt, @@ -1673,7 +1629,7 @@ Switch.prototype.isStatement = YES; Switch.prototype.makeReturn = function() { var _i, _len, _ref2, pair; - for (_i = 0, _len = (_ref2 = this.cases).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.cases).length; _i < _len; ++_i) { pair = _ref2[_i]; pair[1].makeReturn(); } @@ -1688,9 +1644,9 @@ idt2 = o.indent = this.idt(2); o.top = true; code = "" + (this.tab) + "switch (" + ((((_ref2 = this.subject) != null) ? _ref2.compile(o) : undefined) || true) + ") {"; - for (_i = 0, _len = (_ref3 = this.cases).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref3 = this.cases).length; _i < _len; ++_i) { _ref4 = _ref3[_i], conditions = _ref4[0], block = _ref4[1]; - for (_j = 0, _len2 = (_ref5 = flatten([conditions])).length; _j < _len2; _j++) { + for (_j = 0, _len2 = (_ref5 = flatten([conditions])).length; _j < _len2; ++_j) { condition = _ref5[_j]; if (!this.subject) { condition = condition.invert().invert(); @@ -1728,11 +1684,11 @@ If.prototype.topSensitive = YES; If.prototype.bodyNode = function() { var _ref2; - return (((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined); + return ((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined; }; If.prototype.elseBodyNode = function() { var _ref2; - return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined); + return ((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined; }; If.prototype.addElse = function(elseBody) { if (this.isChain) { @@ -1849,7 +1805,7 @@ TAB = ' '; TRAILING_WHITESPACE = /[ \t]+$/gm; IDENTIFIER = /^[$A-Za-z_][$\w]*$/; - NUMBER = /^0x[\da-f]+$|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i; + NUMBER = /^-?(?:0x[\da-f]+|(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?)$/i; SIMPLENUM = /^[+-]?\d+$/; IS_STRING = /^['"]/; utility = function(name) { diff --git a/lib/optparse.js b/lib/optparse.js index cd4e534e..d569528b 100755 --- a/lib/optparse.js +++ b/lib/optparse.js @@ -15,14 +15,14 @@ arguments: [] }; args = normalizeArguments(args); - for (i = 0, _len = args.length; i < _len; i++) { + for (i = 0, _len = args.length; i < _len; ++i) { arg = args[i]; isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG)); matchedRule = false; - for (_i = 0, _len2 = (_ref = this.rules).length; _i < _len2; _i++) { + for (_i = 0, _len2 = (_ref = this.rules).length; _i < _len2; ++_i) { rule = _ref[_i]; if (rule.shortFlag === arg || rule.longFlag === arg) { - value = rule.hasArgument ? args[(i += 1)] : true; + value = rule.hasArgument ? args[i += 1] : true; options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value; matchedRule = true; break; @@ -44,7 +44,7 @@ if (this.banner) { lines.unshift("" + (this.banner) + "\n"); } - for (_i = 0, _len = (_ref = this.rules).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref = this.rules).length; _i < _len; ++_i) { rule = _ref[_i]; spaces = 15 - rule.longFlag.length; spaces = spaces > 0 ? Array(spaces + 1).join(' ') : ''; @@ -62,7 +62,7 @@ buildRules = function(rules) { var _i, _len, _result, tuple; _result = []; - for (_i = 0, _len = rules.length; _i < _len; _i++) { + for (_i = 0, _len = rules.length; _i < _len; ++_i) { tuple = rules[_i]; _result.push((function() { if (tuple.length < 3) { @@ -91,10 +91,10 @@ var _i, _j, _len, _len2, _ref, arg, l, match, result; args = args.slice(0); result = []; - for (_i = 0, _len = args.length; _i < _len; _i++) { + for (_i = 0, _len = args.length; _i < _len; ++_i) { arg = args[_i]; if (match = arg.match(MULTI_FLAG)) { - for (_j = 0, _len2 = (_ref = match[1].split('')).length; _j < _len2; _j++) { + for (_j = 0, _len2 = (_ref = match[1].split('')).length; _j < _len2; ++_j) { l = _ref[_j]; result.push('-' + l); } diff --git a/lib/rewriter.js b/lib/rewriter.js index a5b41df6..8b99f26c 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -71,7 +71,7 @@ } else { tokens.splice(i, 0, after); } - } else if (prev && !((_ref = prev[0]) === 'TERMINATOR' || _ref === 'INDENT' || _ref === 'OUTDENT')) { + } else if (prev && ((_ref = prev[0]) !== 'TERMINATOR' && _ref !== 'INDENT' && _ref !== 'OUTDENT')) { if (((post != null) ? post[0] : undefined) === 'TERMINATOR' && ((after != null) ? after[0] : undefined) === 'OUTDENT') { tokens.splice.apply(tokens, [i + 2, 0].concat(tokens.splice(i, 2))); if (tokens[i + 2][0] !== 'TERMINATOR') { @@ -87,7 +87,7 @@ }; exports.Rewriter.prototype.removeLeadingNewlines = function() { var _len, _ref, i, tag; - for (i = 0, _len = (_ref = this.tokens).length; i < _len; i++) { + for (i = 0, _len = (_ref = this.tokens).length; i < _len; ++i) { tag = _ref[i][0]; if (tag !== 'TERMINATOR') { break; @@ -112,7 +112,7 @@ return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; }; action = function(token, i) { - return (this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'); + return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; }; return this.scanTokens(function(token, i) { if (token[0] === 'CALL_START') { @@ -125,10 +125,10 @@ var action, condition; condition = function(token, i) { var _ref; - return ((_ref = token[0]) === ']' || _ref === 'INDEX_END'); + return (_ref = token[0]) === ']' || _ref === 'INDEX_END'; }; action = function(token, i) { - return (token[0] = 'INDEX_END'); + return token[0] = 'INDEX_END'; }; return this.scanTokens(function(token, i) { if (token[0] === 'INDEX_START') { @@ -142,12 +142,12 @@ stack = []; condition = function(token, i) { var _ref, _ref2, one, tag, three, two; - if (('HERECOMMENT' === this.tag(i + 1) || 'HERECOMMENT' === this.tag(i - 1))) { + if ('HERECOMMENT' === this.tag(i + 1) || 'HERECOMMENT' === this.tag(i - 1)) { return false; } _ref = this.tokens.slice(i + 1, i + 4), one = _ref[0], two = _ref[1], three = _ref[2]; tag = token[0]; - return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !(((two != null) ? two[0] : undefined) === ':' || ((one != null) ? one[0] : undefined) === '@' && ((three != null) ? three[0] : undefined) === ':') || tag === ',' && !((_ref2 = ((one != null) ? one[0] : undefined)) === 'IDENTIFIER' || _ref2 === 'NUMBER' || _ref2 === 'STRING' || _ref2 === '@' || _ref2 === 'TERMINATOR' || _ref2 === 'OUTDENT'); + return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !(((two != null) ? two[0] : undefined) === ':' || ((one != null) ? one[0] : undefined) === '@' && ((three != null) ? three[0] : undefined) === ':') || tag === ',' && ((_ref2 = (one != null) ? one[0] : undefined) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'); }; action = function(token, i) { return this.tokens.splice(i, 0, ['}', '}', token[2]]); @@ -201,7 +201,7 @@ if (prev && !prev.spaced && tag === '?') { token.call = true; } - if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && ((__indexOf.call(IMPLICIT_CALL, tag) >= 0) || !(token.spaced || token.newLine) && (__indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0)))) { + if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) { return 1; } tokens.splice(i, 0, ['CALL_START', '(', token[2]]); @@ -211,13 +211,13 @@ return true; } tag = token[0]; - if ((tag === 'IF' || tag === 'ELSE' || tag === 'UNLESS' || tag === '->' || tag === '=>')) { + if (tag === 'IF' || tag === 'ELSE' || tag === 'UNLESS' || tag === '->' || tag === '=>') { seenSingle = true; } if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') { return true; } - return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !(_ref3 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref3) >= 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{'))); + return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref3 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref3) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{'))); }, action); if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; @@ -237,7 +237,7 @@ tokens.splice.apply(tokens, [i + 2, 0].concat(this.indentation(token))); return 4; } - if ((__indexOf.call(SINGLE_LINERS, tag) >= 0) && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { + if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { starter = tag; _ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1]; if (starter === 'THEN') { @@ -247,7 +247,7 @@ tokens.splice(i + 1, 0, indent); condition = function(token, i) { var _ref3; - return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && !(starter === 'IF' || starter === 'THEN')); + return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN')); }; action = function(token, i) { return this.tokens.splice(this.tag(i - 1) === ',' ? i - 1 : i, 0, outdent); @@ -265,11 +265,11 @@ var condition; condition = function(token, i) { var _ref; - return ((_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT'); + return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT'; }; return this.scanTokens(function(token, i) { var _ref, original; - if (!((_ref = token[0]) === 'IF' || _ref === 'UNLESS')) { + if ((_ref = token[0]) !== 'IF' && _ref !== 'UNLESS') { return 1; } original = token; @@ -286,7 +286,7 @@ this.scanTokens(function(token, i) { var _i, _len, _ref, _ref2, close, open, tag; tag = token[0]; - for (_i = 0, _len = (_ref = pairs).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref = pairs).length; _i < _len; ++_i) { _ref2 = _ref[_i], open = _ref2[0], close = _ref2[1]; levels[open] |= 0; if (tag === open) { @@ -330,10 +330,10 @@ stack.push(token); return 1; } - if (!(__indexOf.call(EXPRESSION_END, tag) >= 0)) { + if (__indexOf.call(EXPRESSION_END, tag) < 0) { return 1; } - if (debt[(inv = INVERSES[tag])] > 0) { + if (debt[inv = INVERSES[tag]] > 0) { debt[inv] -= 1; tokens.splice(i, 1); return 0; @@ -360,13 +360,13 @@ }; exports.Rewriter.prototype.tag = function(i) { var _ref; - return (((_ref = this.tokens[i]) != null) ? _ref[0] : undefined); + return ((_ref = this.tokens[i]) != null) ? _ref[0] : undefined; }; BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']]; INVERSES = {}; EXPRESSION_START = []; EXPRESSION_END = []; - for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) { + for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; ++_i) { _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1]; EXPRESSION_START.push(INVERSES[rite] = left); EXPRESSION_END.push(INVERSES[left] = rite); diff --git a/lib/scope.js b/lib/scope.js index 6fcef586..d19e2a3c 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -42,7 +42,7 @@ }; Scope.prototype.endLevel = function() { var _i, _len, _ref2, name; - for (_i = 0, _len = (_ref2 = this.garbage.pop()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.garbage.pop()).length; _i < _len; ++_i) { name = _ref2[_i]; if (this.type(name) === 'var') { this.add(name, 'reuse'); @@ -59,7 +59,7 @@ }; Scope.prototype.any = function(fn) { var _i, _len, _ref2, v; - for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; ++_i) { v = _ref2[_i]; if (fn(v)) { return true; @@ -83,7 +83,7 @@ }; Scope.prototype.type = function(name) { var _i, _len, _ref2, v; - for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; ++_i) { v = _ref2[_i]; if (v.name === name) { return v.type; @@ -98,7 +98,7 @@ index++; } this.add(temp, 'var'); - (((_ref2 = last(this.garbage)) != null) ? _ref2.push(temp) : undefined); + ((_ref2 = last(this.garbage)) != null) ? _ref2.push(temp) : undefined; return temp; }; Scope.prototype.assign = function(name, value) { @@ -110,7 +110,7 @@ Scope.prototype.hasDeclarations = function(body) { return body === this.expressions && this.any(function(v) { var _ref2; - return ((_ref2 = v.type) === 'var' || _ref2 === 'reuse'); + return (_ref2 = v.type) === 'var' || _ref2 === 'reuse'; }); }; Scope.prototype.hasAssignments = function(body) { @@ -122,9 +122,9 @@ var _i, _len, _ref2, _ref3, _result, v; return (function() { _result = []; - for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; ++_i) { v = _ref2[_i]; - if (((_ref3 = v.type) === 'var' || _ref3 === 'reuse')) { + if ((_ref3 = v.type) === 'var' || _ref3 === 'reuse') { _result.push(v.name); } } @@ -134,7 +134,7 @@ Scope.prototype.assignedVariables = function() { var _i, _len, _ref2, _result, v; _result = []; - for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; ++_i) { v = _ref2[_i]; if (v.type.assigned) { _result.push("" + (v.name) + " = " + (v.type.value)); diff --git a/src/browser.coffee b/src/browser.coffee index ddb7a0f1..05c6e018 100644 --- a/src/browser.coffee +++ b/src/browser.coffee @@ -33,7 +33,7 @@ runScripts = -> if script.src CoffeeScript.load script.src else - setTimeout -> CoffeeScript.run script.innerHTML + CoffeeScript.run script.innerHTML null if window.addEventListener addEventListener 'DOMContentLoaded', runScripts, no diff --git a/src/grammar.coffee b/src/grammar.coffee index 26a08242..d3573e4b 100644 --- a/src/grammar.coffee +++ b/src/grammar.coffee @@ -15,7 +15,7 @@ # from our rules and saves it into `lib/parser.js`. # The only dependency is on the **Jison.Parser**. -Parser = require('jison').Parser +{Parser} = require 'jison' # Jison DSL # --------- @@ -144,14 +144,14 @@ grammar = # Assignment when it happens within an object literal. The difference from # the ordinary **Assign** is that these allow numbers and strings as keys. AssignObj: [ - o "Identifier", -> new Value $1 - o "AlphaNumeric" - o "ThisProperty" - o "Identifier : Expression", -> new Assign new Value($1), $3, 'object' - o "AlphaNumeric : Expression", -> new Assign new Value($1), $3, 'object' - o "Identifier : INDENT Expression OUTDENT", -> new Assign new Value($1), $4, 'object' - o "AlphaNumeric : INDENT Expression OUTDENT", -> new Assign new Value($1), $4, 'object' - o "Comment" + o 'Identifier', -> new Value $1 + o 'AlphaNumeric' + o 'ThisProperty' + o 'Identifier : Expression', -> new Assign new Value($1), $3, 'object' + o 'AlphaNumeric : Expression', -> new Assign new Value($1), $3, 'object' + o 'Identifier : INDENT Expression OUTDENT', -> new Assign new Value($1), $4, 'object' + o 'AlphaNumeric : INDENT Expression OUTDENT', -> new Assign new Value($1), $4, 'object' + o 'Comment' ] # A return statement from a function body. diff --git a/src/nodes.coffee b/src/nodes.coffee index 8b1c4ac6..940f8f6e 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -64,7 +64,7 @@ exports.Base = class Base pair = unless @isComplex() [this, this] else - reference = new Literal o.scope.freeVariable options?.name or 'ref' + reference = new Literal o.scope.freeVariable 'ref' compiled = new Assign reference, this [compiled, reference] (pair[i] = node.compile o) for node, i in pair if options?.precompile @@ -75,6 +75,14 @@ exports.Base = class Base @parenthetical = on @compile o + # Compile to a source/variable pair suitable for looping. + compileLoopReference: (o, name) -> + src = tmp = @compile o + unless NUMBER.test(src) or + IDENTIFIER.test(src) and o.scope.check(src, immediate: on) + src = "#{ tmp = o.scope.freeVariable name } = #{src}" + [src, tmp] + # Convenience method to grab the current indentation level, plus tabbing in. idt: (tabs) -> (@tab or '') + Array((tabs or 0) + 1).join TAB @@ -767,7 +775,6 @@ exports.Assign = class Assign extends Base compileNode: (o) -> if isValue = @variable instanceof Value return @compilePatternMatch(o) if @variable.isArray() or @variable.isObject() - return @compileSplice(o) if @variable.isSplice() if ifn = If.unfoldSoak o, this, 'variable' delete o.top return ifn.compile o @@ -837,6 +844,13 @@ exports.Assign = class Assign extends Base code = assigns.join ', ' if top or @parenthetical then code else "(#{code})" + # When compiling a conditional assignment, take care to ensure that the + # operands are only evaluated once, even though we have to reference them + # more than once. + compileConditional: (o) -> + [left, rite] = @variable.cacheReference o + return new Op(@context.slice(0, -1), left, new Assign(rite, @value)).compile o + assigns: (name) -> @[if @context is 'object' then 'value' else 'variable'].assigns name @@ -1291,7 +1305,7 @@ exports.For = class For extends Base throw SyntaxError 'index cannot be a pattern matching expression' super() extend this, head - @step or= new Literal 1 unless @object + @step or= new Literal 1 unless @object @pattern = @name instanceof Value throw SyntaxError 'cannot pattern match a range loop' if @range and @pattern @returns = false @@ -1310,42 +1324,31 @@ exports.For = class For extends Base # comprehensions. Some of the generated code can be shared in common, and # some cannot. compileNode: (o) -> - if @step - o.top = on - [step, pvar] = @step.compileReference o, precompile: on, name: 'step' - top = del(o, 'top') and not @returns - codeInBody = @body.contains (node) -> node instanceof Code - scope = o.scope - name = not @pattern and @name?.compile o - index = @index?.compile o - ivar = if not index or codeInBody then scope.freeVariable 'i' else index - varPart = '' - body = Expressions.wrap [@body] - idt = @idt 1 - scope.find(name, immediate: yes) if name and not codeInBody + {scope} = o + top = del(o, 'top') and not @returns + name = not @pattern and @name?.compile o + index = @index?.compile o + ivar = if not index then scope.freeVariable 'i' else index + varPart = '' + body = Expressions.wrap [@body] + idt = @idt 1 + scope.find(name, immediate: yes) if name scope.find(index, immediate: yes) if index - unless @object then switch +pvar - when 1 then incr = '++' + ivar - when -1 then incr = '--' + ivar - else incr = ivar + if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar + [step, pvar] = @step.compileLoopReference o, 'step' if @step if @from - [head, hvar] = @from.compileReference o, precompile: on, name: 'from' - [tail, tvar] = @to .compileReference o, precompile: on, name: 'to' - vars = "#{ivar} = #{head}" + [tail, tvar] = @to.compileLoopReference o, 'to' + vars = "#{ivar} = #{ @from.compile o }" vars += ", #{tail}" if tail isnt tvar - vars += ", #{step}" if step isnt pvar - cond = if isNaN step - "#{pvar} < 0 ? #{ivar} >= #{tvar} : #{ivar} <= #{tvar}" + cond = if +pvar + "#{ivar} #{ if pvar < 0 then '>' else '<' }= #{tvar}" else - "#{ivar} #{ if step < 0 then '>=' else '<=' } #{tvar}" - forPart = "#{vars}; #{cond}; #{incr}" + "#{pvar} < 0 ? #{ivar} >= #{tvar} : #{ivar} <= #{tvar}" else - svar = sourcePart = @source.compile o - if (name or not @raw) and - not (IDENTIFIER.test(svar) and scope.check svar, immediate: on) - sourcePart = "#{ ref = scope.freeVariable 'ref' } = #{svar}" - sourcePart = "(#{sourcePart})" unless @object - svar = ref + if name or not @raw + [sourcePart, svar] = @source.compileLoopReference o, 'ref' + sourcePart = "(#{sourcePart})" unless sourcePart is svar or @object + else + sourcePart = svar = @source.compile o namePart = if @pattern new Assign(@name, new Literal "#{svar}[#{ivar}]").compile merge o, top: on else if name @@ -1358,35 +1361,26 @@ exports.For = class For extends Base lvar = scope.freeVariable 'len' vars = "#{ivar} = 0, #{lvar} = #{sourcePart}.length" cond = "#{ivar} < #{lvar}" - vars += ", #{step}" if step isnt pvar - forPart = "#{vars}; #{cond}; #{incr}" + if @object + forPart = "#{ivar} in #{sourcePart}" + guardPart = not @raw and + "#{idt}if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n" + else + vars += ", #{step}" if step isnt pvar + forPart = "#{vars}; #{cond}; " + switch +pvar + when 1 then '++' + ivar + when -1 then '--' + ivar + else ivar + if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar unless top rvar = scope.freeVariable 'result' resultDef = "#{@tab}#{rvar} = [];\n" resultRet = @compileReturnValue rvar, o body = Push.wrap rvar, body body = Expressions.wrap [new If @guard, body] if @guard - if codeInBody - body.unshift new Literal "var #{name} = #{ivar}" if @from - body.unshift new Literal "var #{namePart}" if namePart - body.unshift new Literal "var #{index} = #{ivar}" if index - lastLine = body.expressions.pop() - body.push new Assign new Literal(ivar), new Literal index if index - body.push new Assign new Literal(nvar), new Literal name if nvar - body.push lastLine - o.indent = @idt 1 - body = Expressions.wrap [new Literal body.compile o] - body.push new Assign new Literal(index), new Literal ivar if index - body.push new Assign new Literal(name ), new Literal nvar or ivar if name - else - varPart = "#{idt}#{namePart};\n" if namePart - if @object - forPart = "#{ivar} in #{sourcePart}" - guardPart = not @raw and - "#{idt}if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n" + varPart = "#{idt}#{namePart};\n" if namePart """ #{ resultDef or '' }#{@tab}for (#{forPart}) { - #{ guardPart or '' }#{varPart}#{ body.compile merge o, indent: idt, top: true } + #{ guardPart or '' }#{varPart}#{ body.compile merge o, indent: idt, top: on } #{@tab}}#{ resultRet or '' } """ @@ -1596,7 +1590,7 @@ TAB = ' ' TRAILING_WHITESPACE = /[ \t]+$/gm IDENTIFIER = /^[$A-Za-z_][$\w]*$/ -NUMBER = /^0x[\da-f]+$|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i +NUMBER = /// ^ -? (?: 0x[\da-f]+ | (?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)? ) $ ///i SIMPLENUM = /^[+-]?\d+$/ # Is a literal value a string? diff --git a/test/test_comprehensions.coffee b/test/test_comprehensions.coffee index 0c7c7e4c..cebe40d7 100644 --- a/test/test_comprehensions.coffee +++ b/test/test_comprehensions.coffee @@ -45,55 +45,6 @@ ok 2 of evens # all/from/to aren't reserved. all = from = to = 1 -# Ensure that the closure wrapper preserves local variables. -obj = {} - -for method in ['one', 'two', 'three'] - obj[method] = -> - "I'm " + method - -ok obj.one() is "I'm one" -ok obj.two() is "I'm two" -ok obj.three() is "I'm three" - -i = 0 -for i in [1..3] - -> 'func' - break if false -ok i is 3 - - -# Ensure that local variables are closed over for range comprehensions. -funcs = for i from 1 to 3 - -> -i - -ok (func() for func in funcs).join(' ') is '-1 -2 -3' -ok i is 3 - - -# Ensure that closing over local variables doesn't break scoping laws. -for i in [0] - count = 0 - i = 50 - -> -ok count is 0 -ok i is 50 - -for [a, b] in [[0, 1]] then -> -ok a is 0 -ok b is 1 - - -# Even when referenced in the filter. -list = ['one', 'two', 'three'] - -methods = for num, i in list when num isnt 'two' and i isnt 1 - -> num + ' ' + i - -ok methods.length is 2 -ok methods[0]() is 'one 0' -ok methods[1]() is 'three 2' - # Nested comprehensions. multiLiner =