1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

first draft of safe range comprehensions, upwards and downwards.

This commit is contained in:
Jeremy Ashkenas 2010-11-04 21:53:23 -04:00
parent 09b243e689
commit 76685e6e51
3 changed files with 55 additions and 18 deletions

View file

@ -1507,9 +1507,6 @@
}
extend(this, head);
this.body = Expressions.wrap([body]);
if (!this.object) {
this.step || (this.step = new Literal(1));
}
this.pattern = this.name instanceof Value;
this.returns = false;
return this;
@ -1534,7 +1531,7 @@
return '';
};
For.prototype.compileNode = function(o) {
var body, code, cond, defPart, forPart, guardPart, hasCode, idt, index, ivar, lvar, name, namePart, pvar, retPart, rvar, scope, sourcePart, step, svar, tail, tvar, varPart, vars, _ref, _ref2, _ref3, _ref4, _ref5;
var body, code, cond, defPart, forPart, fvar, guardPart, hasCode, head, idt, incr, index, intro, ivar, lvar, name, namePart, pvar, retPart, rvar, scope, sourcePart, step, svar, tail, tvar, varPart, vars, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
scope = o.scope;
body = this.body;
hasCode = this.body.contains(function(node) {
@ -1557,15 +1554,31 @@
_ref3 = this.step.compileLoopReference(o, 'step'), step = _ref3[0], pvar = _ref3[1];
}
if (this.from) {
_ref4 = this.to.compileLoopReference(o, 'to'), tail = _ref4[0], tvar = _ref4[1];
vars = ivar + ' = ' + this.from.compile(o);
_ref4 = this.from.compileLoopReference(o, 'from'), head = _ref4[0], fvar = _ref4[1];
_ref5 = this.to.compileLoopReference(o, 'to'), tail = _ref5[0], tvar = _ref5[1];
vars = ivar + ' = ' + head;
if (tail !== tvar) {
vars += ', ' + tail;
}
cond = +pvar ? "" + ivar + " " + (pvar < 0 ? '>' : '<') + "= " + tvar : "" + pvar + " < 0 ? " + ivar + " >= " + tvar + " : " + ivar + " <= " + tvar;
if (SIMPLENUM.test(head) && SIMPLENUM.test(tail)) {
if (+head <= +tail) {
cond = "" + ivar + " <= " + tail;
} else {
pvar || (pvar = -1);
cond = "" + ivar + " >= " + tail;
}
} else {
if (+pvar) {
cond = "" + ivar + " " + (pvar < 0 ? '>' : '<') + "= " + tvar;
} else {
intro = "" + fvar + " <= " + tvar + " ? " + ivar;
cond = "" + intro + " <= " + tvar + " : " + ivar + " >= " + tvar;
incr = pvar ? "" + ivar + " += " + pvar : "" + intro + "++ : " + ivar + "--";
}
}
} else {
if (name || this.object && !this.raw) {
_ref5 = this.source.compileLoopReference(o, 'ref'), sourcePart = _ref5[0], svar = _ref5[1];
_ref6 = this.source.compileLoopReference(o, 'ref'), sourcePart = _ref6[0], svar = _ref6[1];
} else {
sourcePart = svar = this.source.compile(o, LEVEL_PAREN);
}
@ -1585,13 +1598,14 @@
forPart = ivar + ' in ' + sourcePart;
guardPart = this.raw ? '' : idt + ("if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n");
} else {
if (step !== pvar) {
pvar || (pvar = 1);
if (step && (step !== pvar)) {
vars += ', ' + step;
}
if (svar !== sourcePart) {
defPart = this.tab + sourcePart + ';\n';
}
forPart = vars + ("; " + cond + "; ") + ivar + (function() {
forPart = vars + ("; " + cond + "; ") + (incr || (ivar + (function() {
switch (+pvar) {
case 1:
return '++';
@ -1600,7 +1614,7 @@
default:
return pvar < 0 ? ' -= ' + pvar.slice(1) : ' += ' + pvar;
}
})();
})()));
}
if (hasCode) {
body = Closure.wrap(body, true);

View file

@ -1268,7 +1268,6 @@ exports.For = class For extends Base
throw SyntaxError 'index cannot be a pattern matching expression'
extend this, head
@body = Expressions.wrap [body]
@step or= new Literal 1 unless @object
@pattern = @name instanceof Value
@returns = false
@ -1301,13 +1300,23 @@ exports.For = class For extends Base
scope.find(index, yes) if index
[step, pvar] = @step.compileLoopReference o, 'step' if @step
if @from
[head, fvar] = @from.compileLoopReference o, 'from'
[tail, tvar] = @to.compileLoopReference o, 'to'
vars = ivar + ' = ' + @from.compile o
vars = ivar + ' = ' + head
vars += ', ' + tail if tail isnt tvar
cond = if +pvar
"#{ivar} #{ if pvar < 0 then '>' else '<' }= #{tvar}"
if SIMPLENUM.test(head) and SIMPLENUM.test(tail)
if +head <= +tail
cond = "#{ivar} <= #{tail}"
else
pvar or= -1
cond = "#{ivar} >= #{tail}"
else
"#{pvar} < 0 ? #{ivar} >= #{tvar} : #{ivar} <= #{tvar}"
if +pvar
cond = "#{ivar} #{ if pvar < 0 then '>' else '<' }= #{tvar}"
else
intro = "#{fvar} <= #{tvar} ? #{ivar}"
cond = "#{intro} <= #{tvar} : #{ivar} >= #{tvar}"
incr = if pvar then "#{ivar} += #{pvar}" else "#{intro}++ : #{ivar}--"
else
if name or @object and not @raw
[sourcePart, svar] = @source.compileLoopReference o, 'ref'
@ -1330,12 +1339,14 @@ exports.For = class For extends Base
guardPart = if @raw then '' else
idt + "if (!#{ utility 'hasProp' }.call(#{svar}, #{ivar})) continue;\n"
else
vars += ', ' + step if step isnt pvar
pvar or= 1
vars += ', ' + step if step and (step isnt pvar)
defPart = @tab + sourcePart + ';\n' if svar isnt sourcePart
forPart = vars + "; #{cond}; " + ivar + switch +pvar
forPart = vars + "; #{cond}; " + (incr or (ivar + switch +pvar
when 1 then '++'
when -1 then '--'
else (if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar)
))
body = Closure.wrap(body, yes) if hasCode
varPart = idt + namePart + ';\n' if namePart
defPart += @pluckDirectCall o, body, name, index unless @pattern

View file

@ -26,6 +26,18 @@ eq "#{ x for x from 9 to 0 by -3 }", '9,6,3,0'
eq "#{ x for x from 3*3 to 0*0 by 0-3 }", '9,6,3,0'
# Range comprehension gymnastics.
eq "#{i for i from 5 to 1}", '5,4,3,2,1'
eq "#{i for i from 5 to -5 by -5}", '5,0,-5'
a = 6
b = 0
c = -2
eq "#{i for i from a to b}", '6,5,4,3,2,1,0'
eq "#{i for i from a to b by c}", '6,4,2,0'
# Multiline array comprehension with filter.
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
num *= -1