diff --git a/lib/nodes.js b/lib/nodes.js index cf23115d..15c75ce3 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1463,9 +1463,6 @@ this.step || (this.step = new Literal(1)); } this.pattern = this.name instanceof Value; - if (this.range && this.pattern) { - throw SyntaxError('cannot pattern match a range loop'); - } this.returns = false; return this; }; @@ -1488,12 +1485,12 @@ return ''; }; For.prototype.compileNode = function(o) { - var _ref2, _ref3, _ref4, _ref5, _ref6, body, cond, defPart, forPart, guardPart, idt, index, ivar, lvar, name, namePart, pvar, resultRet, rvar, scope, sourcePart, step, svar, tail, tvar, varPart, vars; + var _ref2, _ref3, _ref4, _ref5, _ref6, body, cond, defPart, forPart, guardPart, idt, index, ivar, lvar, name, namePart, pvar, retPart, rvar, scope, sourcePart, step, svar, tail, tvar, varPart, vars; scope = o.scope; 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 = ''; + varPart = guardPart = defPart = retPart = ''; body = Expressions.wrap([this.body]); idt = this.idt(1); if (name) { @@ -1511,13 +1508,13 @@ } if (this.from) { _ref5 = this.to.compileLoopReference(o, 'to'), tail = _ref5[0], tvar = _ref5[1]; - vars = "" + ivar + " = " + (this.from.compile(o)); + vars = ivar + ' = ' + this.from.compile(o); if (tail !== tvar) { - vars += ", " + tail; + vars += ', ' + tail; } cond = +pvar ? "" + ivar + " " + (pvar < 0 ? '>' : '<') + "= " + tvar : "" + pvar + " < 0 ? " + ivar + " >= " + tvar + " : " + ivar + " <= " + tvar; } else { - if (name) { + if (name || this.object && !this.raw) { _ref6 = this.source.compileLoopReference(o, 'ref'), sourcePart = _ref6[0], svar = _ref6[1]; } else { sourcePart = svar = this.source.compile(o, LVL_PAREN); @@ -1534,18 +1531,17 @@ } } } - defPart = ''; if (this.object) { - forPart = "" + ivar + " in " + sourcePart; - guardPart = !this.raw && ("" + idt + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n"); + forPart = ivar + ' in ' + sourcePart; + guardPart = this.raw ? '' : idt + ("if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n"); } else { if (step !== pvar) { - vars += ", " + step; + vars += ', ' + step; } if (svar !== sourcePart) { - defPart = "" + this.tab + sourcePart + ";\n"; + defPart = this.tab + sourcePart + ';\n'; } - forPart = ("" + vars + "; " + cond + "; ") + ivar + (function() { + forPart = vars + ("; " + cond + "; ") + ivar + (function() { switch (+pvar) { case 1: return '++'; @@ -1558,18 +1554,18 @@ } if (o.level > LVL_TOP || this.returns) { rvar = scope.freeVariable('result'); - defPart += "" + this.tab + rvar + " = [];\n"; - resultRet = this.compileReturnValue(rvar, o); + defPart += this.tab + rvar + ' = [];\n'; + retPart = this.compileReturnValue(rvar, o); body = Push.wrap(rvar, body); } if (this.guard) { body = Expressions.wrap([new If(this.guard, body)]); } if (namePart) { - varPart = "" + idt + namePart + ";\n"; + varPart = idt + namePart + ';\n'; } o.indent = idt; - return "" + (defPart || '') + this.tab + "for (" + forPart + ") {\n" + (guardPart || '') + varPart + (body.compile(o, LVL_TOP)) + "\n" + this.tab + "}" + (resultRet || ''); + return defPart + ("" + this.tab + "for (" + forPart + ") {\n" + (guardPart || '') + varPart + (body.compile(o, LVL_TOP)) + "\n" + this.tab + "}") + retPart; }; return For; })(); diff --git a/src/nodes.coffee b/src/nodes.coffee index 31cb04bd..1d41691e 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1263,7 +1263,6 @@ exports.For = class For extends Base extend this, head @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 makeReturn: -> @@ -1284,7 +1283,7 @@ exports.For = class For extends Base name = not @pattern and @name?.compile o index = @index?.compile o ivar = if not index then scope.freeVariable 'i' else index - varPart = '' + varPart = guardPart = defPart = retPart = '' body = Expressions.wrap [@body] idt = @idt 1 scope.find(name, immediate: yes) if name @@ -1292,14 +1291,14 @@ exports.For = class For extends Base [step, pvar] = @step.compileLoopReference o, 'step' if @step if @from [tail, tvar] = @to.compileLoopReference o, 'to' - vars = "#{ivar} = #{ @from.compile o }" - vars += ", #{tail}" if tail isnt tvar + vars = ivar + ' = ' + @from.compile o + vars += ', ' + tail if tail isnt tvar cond = if +pvar "#{ivar} #{ if pvar < 0 then '>' else '<' }= #{tvar}" else "#{pvar} < 0 ? #{ivar} >= #{tvar} : #{ivar} <= #{tvar}" else - if name + if name or @object and not @raw [sourcePart, svar] = @source.compileLoopReference o, 'ref' else sourcePart = svar = @source.compile o, LVL_PAREN @@ -1315,31 +1314,30 @@ exports.For = class For extends Base lvar = scope.freeVariable 'len' vars = "#{ivar} = 0, #{lvar} = #{svar}.length" cond = "#{ivar} < #{lvar}" - defPart = '' if @object - forPart = "#{ivar} in #{sourcePart}" - guardPart = not @raw and - "#{idt}if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n" + forPart = ivar + ' in ' + sourcePart + guardPart = if @raw then '' else + idt + "if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n" else - vars += ", #{step}" if step isnt pvar - defPart = "#{@tab}#{sourcePart};\n" if svar isnt sourcePart - forPart = "#{vars}; #{cond}; " + ivar + switch +pvar + vars += ', ' + step if step isnt pvar + defPart = @tab + sourcePart + ';\n' if svar isnt sourcePart + forPart = vars + "; #{cond}; " + ivar + switch +pvar when 1 then '++' when -1 then '--' else (if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar) if o.level > LVL_TOP or @returns - rvar = scope.freeVariable 'result' - defPart += "#{@tab}#{rvar} = [];\n" - resultRet = @compileReturnValue rvar, o - body = Push.wrap rvar, body + rvar = scope.freeVariable 'result' + defPart += @tab + rvar + ' = [];\n' + retPart = @compileReturnValue rvar, o + body = Push.wrap rvar, body body = Expressions.wrap [new If @guard, body] if @guard - varPart = "#{idt}#{namePart};\n" if namePart + varPart = idt + namePart + ';\n' if namePart o.indent = idt - """ - #{ defPart or '' }#{@tab}for (#{forPart}) { + defPart + """ + #{@tab}for (#{forPart}) { #{ guardPart or '' }#{varPart}#{ body.compile o, LVL_TOP } - #{@tab}}#{ resultRet or '' } - """ + #{@tab}} + """ + retPart #### Switch diff --git a/test/test_classes.coffee b/test/test_classes.coffee index e165d1dd..1d89df9d 100644 --- a/test/test_classes.coffee +++ b/test/test_classes.coffee @@ -182,7 +182,7 @@ class Mini @num m = new Mini -ok (func() for func in m.generate()).join(' ') is '10 10 10' +eq (func() for func in m.generate()).join(' '), '10 10 10' # Testing a contructor called with varargs. diff --git a/test/test_comprehensions.coffee b/test/test_comprehensions.coffee index cebe40d7..769c86af 100644 --- a/test/test_comprehensions.coffee +++ b/test/test_comprehensions.coffee @@ -99,3 +99,6 @@ learn = -> ok learn().join(' ') is '1 2 3' ok rule(101) is 101 + +f = -> [-> ok no, 'should cache source'] +ok yes for k of [f] = f()