enhancements to range comprehensions, back to being safe -- and usable downwards without a 'by' clause, and optimized when working with integer literals.

This commit is contained in:
Jeremy Ashkenas
2010-07-17 18:45:29 -04:00
parent 96f076983e
commit 5a34f53689
7 changed files with 88 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
(function(){
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, ends, flatten, helpers, include, indexOf, literal, merge, starts, utility;
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, ends, flatten, helpers, include, indexOf, literal, merge, starts, utility;
var __extends = function(child, parent) {
var ctor = function(){ };
ctor.prototype = parent.prototype;
@@ -558,55 +558,79 @@
this.from = from;
this.to = to;
this.exclusive = !!exclusive;
this.equals = this.exclusive ? '' : '=';
return this;
};
__extends(RangeNode, BaseNode);
RangeNode.prototype['class'] = 'RangeNode';
RangeNode.prototype.children = ['from', 'to'];
RangeNode.prototype.compileVariables = function(o) {
var _b, _c, parts;
_b = this.from.compileReference(o);
var _b, _c, _d, parts;
_b = this.from.compileReference(o, {
precompile: true
});
this.from = _b[0];
this.fromVar = _b[1];
_c = this.to.compileReference(o);
_c = this.to.compileReference(o, {
precompile: true
});
this.to = _c[0];
this.toVar = _c[1];
_d = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)];
this.fromNum = _d[0];
this.toNum = _d[1];
parts = [];
if (this.from !== this.fromVar) {
parts.push(this.from.compile(o));
parts.push(this.from);
}
if (this.to !== this.toVar) {
parts.push(this.to.compile(o));
parts.push(this.to);
}
return parts.length ? ("" + (parts.join('; ')) + ";") : '';
return parts.length ? ("" + (parts.join('; ')) + "; ") : '';
};
RangeNode.prototype.compileNode = function(o) {
var equals, idx, op, step, vars;
var compare, idx, incr, intro, step, stepPart, vars;
if (!(o.index)) {
return this.compileArray(o);
}
if (this.fromNum && this.toNum) {
return this.compileSimple(o);
}
idx = del(o, 'index');
step = del(o, 'step');
vars = ("" + idx + " = " + (this.fromVar.compile(o)));
step = step ? step.compile(o) : '1';
equals = this.exclusive ? '' : '=';
op = starts(step, '-') ? (">" + equals) : ("<" + equals);
return "" + vars + "; " + (idx) + " " + op + " " + (this.toVar.compile(o)) + "; " + idx + " += " + step;
vars = ("" + idx + " = " + this.fromVar);
intro = ("(" + this.fromVar + " <= " + this.toVar + " ? " + idx);
compare = ("" + intro + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar + ")");
stepPart = step ? step.compile(o) : '1';
incr = step ? ("" + idx + " += " + stepPart) : ("" + intro + " += " + stepPart + " : " + idx + " -= " + stepPart + ")");
return "" + vars + "; " + compare + "; " + incr;
};
RangeNode.prototype.compileSimple = function(o) {
var _b, from, idx, step, to;
_b = [parseInt(this.fromNum, 10), parseInt(this.toNum, 10)];
from = _b[0];
to = _b[1];
idx = del(o, 'index');
step = del(o, 'step');
step = step && ("" + idx + " += " + (step.compile(o)));
return from <= to ? ("" + idx + " = " + from + "; " + idx + " <" + this.equals + " " + to + "; " + (step || ("" + idx + "++"))) : ("" + idx + " = " + from + "; " + idx + " >" + this.equals + " " + to + "; " + (step || ("" + idx + "--")));
};
RangeNode.prototype.compileArray = function(o) {
var body, clause, equals, from, i, idt, post, pre, result, to, vars;
var body, clause, i, idt, post, pre, result, vars;
idt = this.idt(1);
vars = this.compileVariables(merge(o, {
indent: idt
}));
equals = this.exclusive ? '' : '=';
from = this.fromVar.compile(o);
to = this.toVar.compile(o);
result = o.scope.freeVariable();
i = o.scope.freeVariable();
clause = ("" + from + " <= " + to + " ?");
pre = ("\n" + (idt) + (result) + " = []; " + (vars));
body = ("var " + i + " = " + from + "; " + clause + " " + i + " <" + equals + " " + to + " : " + i + " >" + equals + " " + to + "; " + clause + " " + i + " += 1 : " + i + " -= 1");
if (this.fromNum && this.toNum) {
o.index = i;
body = this.compileSimple(o);
} else {
clause = ("" + this.fromVar + " <= " + this.toVar + " ?");
body = ("var " + i + " = " + this.fromVar + "; " + clause + " " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + clause + " " + i + " += 1 : " + i + " -= 1");
}
post = ("{ " + (result) + ".push(" + i + ") };\n" + (idt) + "return " + result + ";\n" + o.indent);
return "(function(){" + (pre) + "\n" + (idt) + "for (" + body + ")" + post + "}).call(this)";
};
@@ -1426,9 +1450,6 @@
body = Expressions.wrap([this.body]);
if (range) {
sourcePart = source.compileVariables(o);
if (sourcePart) {
sourcePart += ("\n" + o.indent);
}
forPart = source.compile(merge(o, {
index: ivar,
step: this.step
@@ -1656,6 +1677,7 @@
DOUBLE_PARENS = /\(\(([^\(\)\n]*)\)\)/g;
IDENTIFIER = /^[a-zA-Z\$_](\w|\$)*$/;
NUMBER = /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b$/i;
SIMPLENUM = /^-?\d+/;
IS_STRING = /^['"]/;
literal = function(name) {
return new LiteralNode(name);