1
0
Fork 0
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:
Gerald Lewis 2011-05-04 13:12:05 -04:00
parent 71bcdb91c8
commit ac46ede170
3 changed files with 73 additions and 30 deletions

View file

@ -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) {

View file

@ -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};"

View file

@ -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'