mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Fix for #1326 by value is uncached
This commit is contained in:
parent
71bcdb91c8
commit
ac46ede170
3 changed files with 73 additions and 30 deletions
44
lib/nodes.js
44
lib/nodes.js
|
@ -789,7 +789,7 @@
|
|||
}
|
||||
};
|
||||
Range.prototype.compileNode = function(o) {
|
||||
var compare, cond, idx, incr, step, vars;
|
||||
var byvar, cond, condPart, idx, step, stepPart, varPart;
|
||||
this.compileVariables(o);
|
||||
if (!o.index) {
|
||||
return this.compileArray(o);
|
||||
|
@ -799,23 +799,35 @@
|
|||
}
|
||||
idx = del(o, 'index');
|
||||
step = del(o, 'step');
|
||||
vars = ("" + idx + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '');
|
||||
if (step) {
|
||||
byvar = o.scope.freeVariable("by");
|
||||
}
|
||||
varPart = ("" + idx + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '') + (step ? ", " + byvar + " = " + (step.compile(o)) : '');
|
||||
cond = "" + this.fromVar + " <= " + this.toVar;
|
||||
compare = "" + cond + " ? " + idx + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar;
|
||||
incr = step ? "" + idx + " += " + (step.compile(o)) : "" + cond + " ? " + idx + "++ : " + idx + "--";
|
||||
return "" + vars + "; " + compare + "; " + incr;
|
||||
condPart = "" + cond + " ? " + idx + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar;
|
||||
stepPart = step ? "" + idx + " += " + byvar : "" + cond + " ? " + idx + "++ : " + idx + "--";
|
||||
return "" + varPart + "; " + condPart + "; " + stepPart;
|
||||
};
|
||||
Range.prototype.compileSimple = function(o) {
|
||||
var from, idx, step, to, _ref2;
|
||||
var byvar, condPart, from, idx, step, stepPart, to, varPart, _ref2;
|
||||
_ref2 = [+this.fromNum, +this.toNum], from = _ref2[0], to = _ref2[1];
|
||||
idx = del(o, 'index');
|
||||
step = del(o, 'step');
|
||||
step && (step = "" + idx + " += " + (step.compile(o)));
|
||||
if (from <= to) {
|
||||
return "" + idx + " = " + from + "; " + idx + " <" + this.equals + " " + to + "; " + (step || ("" + idx + "++"));
|
||||
} else {
|
||||
return "" + idx + " = " + from + "; " + idx + " >" + this.equals + " " + to + "; " + (step || ("" + idx + "--"));
|
||||
if (step) {
|
||||
byvar = o.scope.freeVariable("by");
|
||||
}
|
||||
varPart = "" + idx + " = " + from;
|
||||
if (step) {
|
||||
varPart += ", " + byvar + " = " + (step.compile(o));
|
||||
}
|
||||
condPart = from <= to ? "" + idx + " <" + this.equals + " " + to : "" + idx + " >" + this.equals + " " + to;
|
||||
if (step) {
|
||||
stepPart = "" + idx + " += " + byvar;
|
||||
}
|
||||
if (!step) {
|
||||
stepPart = (from <= to ? "" + idx + "++" : "" + idx + "--");
|
||||
}
|
||||
return "" + varPart + "; " + condPart + "; " + stepPart;
|
||||
};
|
||||
Range.prototype.compileArray = function(o) {
|
||||
var body, cond, i, idt, post, pre, range, result, vars, _i, _ref2, _ref3, _results;
|
||||
|
@ -1881,7 +1893,7 @@
|
|||
return this;
|
||||
};
|
||||
For.prototype.compileNode = function(o) {
|
||||
var body, defPart, forPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, svar, varPart, _ref2;
|
||||
var body, byvar, defPart, forPart, forVarPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, svar, varPart, _ref2;
|
||||
body = Block.wrap([this.body]);
|
||||
lastJumps = (_ref2 = last(body.expressions)) != null ? _ref2.jumps() : void 0;
|
||||
if (lastJumps && lastJumps instanceof Return) {
|
||||
|
@ -1905,6 +1917,9 @@
|
|||
rvar = scope.freeVariable('results');
|
||||
}
|
||||
ivar = (this.range ? name : index) || scope.freeVariable('i');
|
||||
if (this.step && !this.range) {
|
||||
byvar = scope.freeVariable('by');
|
||||
}
|
||||
if (this.pattern) {
|
||||
name = ivar;
|
||||
}
|
||||
|
@ -1928,8 +1943,9 @@
|
|||
}
|
||||
if (!this.object) {
|
||||
lvar = scope.freeVariable('len');
|
||||
stepPart = this.step ? "" + ivar + " += " + (this.step.compile(o, LEVEL_OP)) : "" + ivar + "++";
|
||||
forPart = "" + ivar + " = 0, " + lvar + " = " + svar + ".length; " + ivar + " < " + lvar + "; " + stepPart;
|
||||
forVarPart = ("" + ivar + " = 0, " + lvar + " = " + svar + ".length") + (this.step ? ", " + byvar + " = " + (this.step.compile(o, LEVEL_OP)) : '');
|
||||
stepPart = this.step ? "" + ivar + " += " + byvar : "" + ivar + "++";
|
||||
forPart = "" + forVarPart + "; " + ivar + " < " + lvar + "; " + stepPart;
|
||||
}
|
||||
}
|
||||
if (this.returns) {
|
||||
|
|
|
@ -640,26 +640,29 @@ exports.Range = class Range extends Base
|
|||
# needed to iterate over the values in the range. Used by comprehensions.
|
||||
compileNode: (o) ->
|
||||
@compileVariables o
|
||||
return @compileArray(o) unless o.index
|
||||
return @compileSimple(o) if @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
compare = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
incr = if step then "#{idx} += #{step.compile(o)}" else "#{cond} ? #{idx}++ : #{idx}--"
|
||||
"#{vars}; #{compare}; #{incr}"
|
||||
return @compileArray(o) unless o.index
|
||||
return @compileSimple(o) if @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
byvar = o.scope.freeVariable "by" if step
|
||||
varPart = "#{idx} = #{@from}" + ( if @to isnt @toVar then ", #{@to}" else '' ) + if step then ", #{byvar} = #{step.compile(o)}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
stepPart = if step then "#{idx} += #{byvar}" else "#{cond} ? #{idx}++ : #{idx}--"
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
# Compile a simple range comprehension, with integers.
|
||||
compileSimple: (o) ->
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
step and= "#{idx} += #{step.compile(o)}"
|
||||
if from <= to
|
||||
"#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}"
|
||||
else
|
||||
"#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}"
|
||||
byvar = o.scope.freeVariable "by" if step
|
||||
varPart = "#{idx} = #{from}"
|
||||
varPart += ", #{byvar} = #{step.compile(o)}" if step
|
||||
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
||||
stepPart = "#{idx} += #{byvar}" if step
|
||||
stepPart = ( if from <= to then "#{idx}++" else "#{idx}--" ) if not step
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
# When used as a value, expand the range into the equivalent array.
|
||||
compileArray: (o) ->
|
||||
|
@ -1503,6 +1506,8 @@ exports.For = class For extends Base
|
|||
scope.find(index, immediate: yes) if index
|
||||
rvar = scope.freeVariable 'results' if @returns
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
# the `_by` variable is created twice in `Range`s if we don't prevent it from being declared here
|
||||
byvar = scope.freeVariable 'by' if @step and not @range
|
||||
name = ivar if @pattern
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
|
@ -1519,8 +1524,9 @@ exports.For = class For extends Base
|
|||
namePart = "#{name} = #{svar}[#{ivar}]"
|
||||
unless @object
|
||||
lvar = scope.freeVariable 'len'
|
||||
stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
|
||||
forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
|
||||
forVarPart = "#{ivar} = 0, #{lvar} = #{svar}.length" + if @step then ", #{byvar} = #{@step.compile(o, LEVEL_OP)}" else ''
|
||||
stepPart = if @step then "#{ivar} += #{byvar}" else "#{ivar}++"
|
||||
forPart = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}"
|
||||
if @returns
|
||||
resultPart = "#{@tab}#{rvar} = [];\n"
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
|
|
|
@ -407,3 +407,24 @@ test "issue #1124: don't assign a variable in two scopes", ->
|
|||
lista = [1, 2, 3, 4, 5]
|
||||
listb = (_i + 1 for _i in lista)
|
||||
arrayEq [2, 3, 4, 5, 6], listb
|
||||
|
||||
test "Issue #1326. `by` value is uncached", ->
|
||||
a = [0,1,2]
|
||||
fi = gi = hi = 0
|
||||
f = -> ++fi
|
||||
g = -> ++gi
|
||||
h = -> ++hi
|
||||
|
||||
forCompile = []
|
||||
rangeCompileSimple = []
|
||||
|
||||
#exercises For.compile
|
||||
for v,i in a by f() then forCompile.push i
|
||||
|
||||
#exercises Range.compileSimple
|
||||
rangeCompileSimple = (i for i in [0..2] by g())
|
||||
|
||||
arrayEq a, forCompile
|
||||
arrayEq a, rangeCompileSimple
|
||||
#exercises Range.compile
|
||||
eq "#{i for i in [0..2] by h()}", '0,1,2'
|
Loading…
Reference in a new issue