diff --git a/lib/nodes.js b/lib/nodes.js index 623971d9..3debc227 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1650,7 +1650,7 @@ return ''; }; For.prototype.compileNode = function(o) { - var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, varPart, vars; + var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars; topLevel = del(o, 'top') && !this.returns; range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; source = range ? this.source.base : this.source; @@ -1682,6 +1682,7 @@ } varPart = ''; guardPart = ''; + unstepPart = ''; body = Expressions.wrap([this.body]); idt1 = this.idt(1); if (range) { @@ -1717,10 +1718,12 @@ if (this.guard) { body = Expressions.wrap([new If(this.guard, body)]); } - if (codeInBody && !body.containsPureStatement()) { + if (codeInBody) { if (range) { body.unshift(new Literal("var " + name + " = " + ivar)); } + } + if (codeInBody && !body.containsPureStatement()) { if (namePart) { body.unshift(new Literal("var " + namePart)); } @@ -1747,6 +1750,10 @@ if (namePart) { varPart = ("" + idt1 + namePart + ";\n"); } + if (forPart && name === ivar) { + unstepPart = this.step ? ("" + name + " -= " + (this.step.compile(o)) + ";") : ("" + name + "--;"); + unstepPart = ("\n" + (this.tab)) + unstepPart; + } } if (this.object) { forPart = ("" + ivar + " in " + sourcePart); @@ -1759,7 +1766,7 @@ top: true })); vars = range ? name : ("" + name + ", " + ivar); - return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + returnResult; + return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + unstepPart + returnResult; }; return For; })(); diff --git a/src/nodes.coffee b/src/nodes.coffee index 1c53a310..30107768 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1425,6 +1425,7 @@ exports.For = class For extends Base nvar = scope.freeVariable 'i' if name and not range and codeInBody varPart = '' guardPart = '' + unstepPart = '' body = Expressions.wrap([@body]) idt1 = @idt 1 if range @@ -1449,8 +1450,9 @@ exports.For = class For extends Base body = Push.wrap(rvar, body) unless topLevel if @guard body = Expressions.wrap([new If(@guard, body)]) - if codeInBody and not body.containsPureStatement() + if codeInBody body.unshift new Literal "var #{name} = #{ivar}" if range + if codeInBody and not body.containsPureStatement() body.unshift new Literal "var #{namePart}" if namePart body.unshift new Literal "var #{index} = #{ivar}" if index lastLine = body.expressions.pop() @@ -1463,6 +1465,9 @@ exports.For = class For extends Base body.push new Assign new Literal(name), new Literal nvar or ivar if name else varPart = "#{idt1}#{namePart};\n" if namePart + if forPart and name is ivar + unstepPart = if @step then "#{name} -= #{ @step.compile(o) };" else "#{name}--;" + unstepPart = "\n#{@tab}" + unstepPart if @object forPart = "#{ivar} in #{sourcePart}" guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw @@ -1471,7 +1476,7 @@ exports.For = class For extends Base """ #{resultPart}#{@tab}for (#{forPart}) {#{guardPart} #{varPart}#{body} - #{@tab}}#{returnResult} + #{@tab}}#{unstepPart}#{returnResult} """ #### Switch diff --git a/test/test_comprehensions.coffee b/test/test_comprehensions.coffee index d122256f..2aff0bff 100644 --- a/test/test_comprehensions.coffee +++ b/test/test_comprehensions.coffee @@ -23,6 +23,8 @@ negs = negs[0..2] result = nums.concat(negs).join(', ') ok result is '3, 6, 9, -20, -19, -18' +ok i is 3 +ok x is -10 # With range comprehensions, you can loop in steps. @@ -70,17 +72,22 @@ 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 in [1..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. -ok i is 3 - for i in [0] count = 0 i = 50