implemented for-from-to and removed dotted ranges

This commit is contained in:
satyr
2010-10-13 13:53:56 +09:00
parent 2f7c076a50
commit bd10c2f828
21 changed files with 582 additions and 877 deletions

View File

@@ -1,5 +1,5 @@
(function() {
var Accessor, ArrayLiteral, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, Literal, NO, NUMBER, ObjectLiteral, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, _ref, compact, del, ends, flatten, last, merge, starts, utility;
var Accessor, ArrayLiteral, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, Literal, NO, NUMBER, ObjectLiteral, Op, Param, Parens, Push, Return, SIMPLENUM, Scope, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, _ref, compact, del, ends, extend, flatten, last, merge, starts, utility;
var __extends = function(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
@@ -11,7 +11,8 @@
return -1;
};
Scope = require('./scope').Scope;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, extend = _ref.extend, merge = _ref.merge, del = _ref.del, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
exports.extend = extend;
YES = function() {
return true;
};
@@ -51,12 +52,12 @@
if (!this.isComplex()) {
return [this, this];
} else {
reference = new Literal(o.scope.freeVariable('ref'));
reference = new Literal(o.scope.freeVariable(((options != null) ? options.name : undefined) || 'ref'));
compiled = new Assign(reference, this);
return [compiled, reference];
}
}).call(this);
if ((options != null) ? options.precompile : undefined) {
if (((options != null) ? options.precompile : undefined)) {
for (i = 0, _len = pair.length; i < _len; i++) {
node = pair[i];
(pair[i] = node.compile(o));
@@ -188,9 +189,9 @@
};
Expressions.prototype.makeReturn = function() {
var end, idx;
end = this.expressions[idx = this.expressions.length - 1];
end = this.expressions[(idx = this.expressions.length - 1)];
if (end instanceof Comment) {
end = this.expressions[idx -= 1];
end = this.expressions[(idx -= 1)];
}
if (end && !(end instanceof Return)) {
this.expressions[idx] = end.makeReturn();
@@ -263,7 +264,7 @@
};
Literal.prototype.isStatement = function() {
var _ref2;
return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger';
return ((_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger');
};
Literal.prototype.isPureStatement = Literal.prototype.isStatement;
Literal.prototype.isComplex = NO;
@@ -301,7 +302,7 @@
Return.prototype.makeReturn = THIS;
Return.prototype.compile = function(o) {
var _ref2, expr;
expr = ((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined;
expr = (((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined);
if (expr && !(expr instanceof Return)) {
return expr.compile(o);
}
@@ -348,9 +349,6 @@
Value.prototype.isObject = function() {
return this.base instanceof ObjectLiteral && !this.properties.length;
};
Value.prototype.isSplice = function() {
return last(this.properties) instanceof Slice;
};
Value.prototype.isComplex = function() {
return this.base.isComplex() || this.hasProperties();
};
@@ -552,7 +550,7 @@
if (ifn = this.unfoldSoak(o)) {
return ifn.compile(o);
}
((_ref2 = this.variable) != null) ? _ref2.tags.front = this.tags.front : undefined;
(((_ref2 = this.variable) != null) ? _ref2.tags.front = this.tags.front : undefined);
for (_i = 0, _len = (_ref3 = this.args).length; _i < _len; _i++) {
arg = _ref3[_i];
if (arg instanceof Splat) {
@@ -576,7 +574,7 @@
var base, fun, idt, name, ref, splatargs;
splatargs = this.compileSplatArguments(o);
if (this.isSuper) {
return "" + (this.superReference(o)) + ".apply(this, " + splatargs + ")";
return ("" + (this.superReference(o)) + ".apply(this, " + splatargs + ")");
}
if (!this.isNew) {
base = Value.wrap(this.variable);
@@ -589,7 +587,7 @@
fun += name.compile(o);
}
}
return "" + fun + ".apply(" + ref + ", " + splatargs + ")";
return ("" + fun + ".apply(" + ref + ", " + splatargs + ")");
}
idt = this.idt(1);
return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return typeof result === \"object\" ? result : child;\n" + (this.tab) + "})(" + (this.variable.compile(o)) + ", " + splatargs + ", function() {})";
@@ -653,117 +651,6 @@
};
return Index;
})();
exports.Range = (function() {
Range = (function() {
function Range(_arg, _arg2, tag) {
this.to = _arg2;
this.from = _arg;
Range.__super__.constructor.call(this);
this.exclusive = tag === 'exclusive';
this.equals = this.exclusive ? '' : '=';
return this;
};
return Range;
})();
__extends(Range, Base);
Range.prototype.children = ['from', 'to'];
Range.prototype.compileVariables = function(o) {
var _ref2, _ref3, _ref4, parts;
o = merge(o, {
top: true
});
_ref2 = this.from.compileReference(o, {
precompile: true
}), this.from = _ref2[0], this.fromVar = _ref2[1];
_ref3 = this.to.compileReference(o, {
precompile: true
}), this.to = _ref3[0], this.toVar = _ref3[1];
_ref4 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref4[0], this.toNum = _ref4[1];
parts = [];
if (this.from !== this.fromVar) {
parts.push(this.from);
}
return this.to !== this.toVar ? parts.push(this.to) : undefined;
};
Range.prototype.compileNode = function(o) {
var compare, idx, incr, intro, step, stepPart, vars;
this.compileVariables(o);
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.from)) + (this.to !== this.toVar ? ", " + (this.to) : '');
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;
};
Range.prototype.compileSimple = function(o) {
var _ref2, from, idx, step, to;
_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)));
return from <= to ? "" + idx + " = " + from + "; " + idx + " <" + (this.equals) + " " + to + "; " + (step || ("" + idx + "++")) : "" + idx + " = " + from + "; " + idx + " >" + (this.equals) + " " + to + "; " + (step || ("" + idx + "--"));
};
Range.prototype.compileArray = function(o) {
var _i, _ref2, _ref3, _result, body, clause, i, idt, post, pre, range, result, vars;
if (this.fromNum && this.toNum && Math.abs(this.fromNum - this.toNum) <= 20) {
range = (function() {
_result = [];
for (var _i = _ref2 = +this.fromNum, _ref3 = +this.toNum; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i += 1 : _i -= 1){ _result.push(_i); }
return _result;
}).call(this);
if (this.exclusive) {
range.pop();
}
return "[" + (range.join(', ')) + "]";
}
idt = this.idt(1);
i = o.scope.freeVariable('i');
result = o.scope.freeVariable('result');
pre = "\n" + idt + result + " = [];";
if (this.fromNum && this.toNum) {
o.index = i;
body = this.compileSimple(o);
} else {
vars = ("" + i + " = " + (this.from)) + (this.to !== this.toVar ? ", " + (this.to) : '');
clause = "" + (this.fromVar) + " <= " + (this.toVar) + " ?";
body = "var " + vars + "; " + 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)";
};
return Range;
})();
exports.Slice = (function() {
Slice = (function() {
function Slice(_arg) {
this.range = _arg;
Slice.__super__.constructor.call(this);
return this;
};
return Slice;
})();
__extends(Slice, Base);
Slice.prototype.children = ['range'];
Slice.prototype.compileNode = function(o) {
var from, to;
from = this.range.from ? this.range.from.compile(o) : '0';
to = this.range.to ? this.range.to.compile(o) : '';
to += !to || this.range.exclusive ? '' : ' + 1';
if (to) {
to = ', ' + to;
}
return ".slice(" + from + to + ")";
};
return Slice;
})();
exports.ObjectLiteral = (function() {
ObjectLiteral = (function() {
function ObjectLiteral(props) {
@@ -993,7 +880,7 @@
delete o.top;
return ifn.compile(o);
}
if ((_ref2 = this.context, __indexOf.call(this.CONDITIONAL, _ref2) >= 0)) {
if (_ref2 = this.context, __indexOf.call(this.CONDITIONAL, _ref2) >= 0) {
return this.compileConditional(o);
}
}
@@ -1006,14 +893,14 @@
}
val = this.value.compileBare(o);
if (this.context === 'object') {
return "" + name + ": " + val;
return ("" + name + ": " + val);
}
if (!(isValue && (this.variable.hasProperties() || this.variable.namespaced))) {
o.scope.find(name);
}
val = name + (" " + (this.context || '=') + " ") + val;
if (stmt) {
return "" + (this.tab) + val + ";";
return ("" + (this.tab) + val + ";");
}
return top || this.parenthetical ? val : "(" + val + ")";
};
@@ -1079,22 +966,6 @@
code = assigns.join(', ');
return top || this.parenthetical ? code : "(" + code + ")";
};
Assign.prototype.compileSplice = function(o) {
var from, name, plus, range, ref, to, val;
range = this.variable.properties.pop().range;
name = this.variable.compile(o);
plus = range.exclusive ? '' : ' + 1';
from = range.from ? range.from.compile(o) : '0';
to = range.to ? range.to.compile(o) + ' - ' + from + plus : "" + name + ".length";
ref = o.scope.freeVariable('ref');
val = this.value.compile(o);
return "([].splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + ref + " = " + val + ")), " + ref + ")";
};
Assign.prototype.compileConditional = function(o) {
var _ref2, left, rite;
_ref2 = this.variable.cacheReference(o), left = _ref2[0], rite = _ref2[1];
return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value)).compile(o);
};
Assign.prototype.assigns = function(name) {
return this[this.context === 'object' ? 'value' : 'variable'].assigns(name);
};
@@ -1181,7 +1052,7 @@
func = "" + open + (params.join(', ')) + ") {" + code + close;
o.scope.endLevel();
if (this.bound) {
return "" + (utility('bind')) + "(" + func + ", " + (this.context) + ")";
return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")");
}
return this.tags.front ? "(" + func + ")" : func;
};
@@ -1296,7 +1167,7 @@
function While(condition, opts) {
While.__super__.constructor.call(this);
this.condition = ((opts != null) ? opts.invert : undefined) ? condition.invert() : condition;
this.guard = (opts != null) ? opts.guard : undefined;
this.guard = ((opts != null) ? opts.guard : undefined);
return this;
};
return While;
@@ -1467,7 +1338,13 @@
_ref2 = this.object.compileReference(o, {
precompile: true
}), sub = _ref2[0], ref = _ref2[1];
_ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1];
_ref3 = (function() {
if (this.negated) {
return [' !== ', ' && '];
} else {
return [' === ', ' || '];
}
}).call(this), cmp = _ref3[0], cnj = _ref3[1];
tests = (function() {
_result = [];
for (i = 0, _len = (_ref4 = this.array.base.objects).length; i < _len; i++) {
@@ -1486,7 +1363,7 @@
}), {
precompile: true
}), sub = _ref2[0], ref = _ref2[1];
code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") ") + (this.negated ? '< 0' : '>= 0');
code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") ")(+(this.negated ? '< 0' : '>= 0'));
return sub === ref ? code : "(" + sub + ", " + code + ")";
};
In.prototype.toString = function(idt) {
@@ -1604,22 +1481,16 @@
})();
exports.For = (function() {
For = (function() {
function For(_arg, source, _arg2, _arg3) {
var _ref2;
this.index = _arg3;
this.name = _arg2;
function For(_arg, head) {
this.body = _arg;
For.__super__.constructor.call(this);
this.source = source.source, this.guard = source.guard, this.step = source.step;
this.raw = !!source.raw;
this.object = !!source.object;
if (this.object) {
_ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1];
}
if (this.index instanceof Value) {
if (head.index instanceof Value) {
throw SyntaxError('index cannot be a pattern matching expression');
}
this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length;
For.__super__.constructor.call(this);
extend(this, head);
if (!this.object) {
this.step || (this.step = new Literal(1));
}
this.pattern = this.name instanceof Value;
if (this.range && this.pattern) {
throw SyntaxError('cannot pattern match a range loop');
@@ -1630,7 +1501,7 @@
return For;
})();
__extends(For, Base);
For.prototype.children = ['body', 'source', 'guard'];
For.prototype.children = ['body', 'source', 'guard', 'step', 'from', 'to'];
For.prototype.topSensitive = YES;
For.prototype.isStatement = YES;
For.prototype.makeReturn = function() {
@@ -1647,16 +1518,26 @@
return '';
};
For.prototype.compileNode = function(o) {
var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars;
topLevel = del(o, 'top') && !this.returns;
source = this.range ? this.source.base : this.source;
codeInBody = !this.body.containsPureStatement() && this.body.contains(function(node) {
var _ref2, _ref3, _ref4, _ref5, _ref6, body, codeInBody, cond, forPart, guardPart, head, hvar, idt, incr, index, ivar, lastLine, lvar, name, namePart, pvar, ref, resultDef, resultRet, rvar, scope, sourcePart, step, svar, tail, top, tvar, varPart, vars;
if (this.step) {
o.top = true;
_ref2 = this.step.compileReference(o, {
precompile: true,
name: 'step'
}), step = _ref2[0], pvar = _ref2[1];
}
top = del(o, 'top') && !this.returns;
codeInBody = this.body.contains(function(node) {
return node instanceof Code;
});
scope = o.scope;
name = this.name && this.name.compile(o);
index = this.index && this.index.compile(o);
if (name && !this.pattern && (this.range || !codeInBody)) {
name = !this.pattern && (((_ref3 = this.name) != null) ? _ref3.compile(o) : undefined);
index = (((_ref4 = this.index) != null) ? _ref4.compile(o) : undefined);
ivar = !index || codeInBody ? scope.freeVariable('i') : index;
varPart = '';
body = Expressions.wrap([this.body]);
idt = this.idt(1);
if (name && !codeInBody) {
scope.find(name, {
immediate: true
});
@@ -1666,26 +1547,36 @@
immediate: true
});
}
if (!topLevel) {
rvar = scope.freeVariable('result');
if (!this.object) {
switch (+pvar) {
case 1:
incr = '++' + ivar;
break;
case -1:
incr = '--' + ivar;
break;
default:
incr = ivar + (pvar < 0 ? ' -= ' + pvar.slice(1) : ' += ' + pvar);
}
}
ivar = this.range ? name : index;
if (!ivar || codeInBody) {
ivar = scope.freeVariable('i');
}
if (name && !this.range && codeInBody) {
nvar = scope.freeVariable('i');
}
varPart = '';
guardPart = '';
unstepPart = '';
body = Expressions.wrap([this.body]);
idt1 = this.idt(1);
if (this.range) {
forPart = source.compile(merge(o, {
index: ivar,
step: this.step
}));
if (this.from) {
_ref5 = this.from.compileReference(o, {
precompile: true,
name: 'from'
}), head = _ref5[0], hvar = _ref5[1];
_ref6 = this.to.compileReference(o, {
precompile: true,
name: 'to'
}), tail = _ref6[0], tvar = _ref6[1];
vars = "" + ivar + " = " + head;
if (tail !== tvar) {
vars += ", " + tail;
}
if (step !== pvar) {
vars += ", " + step;
}
cond = isNaN(step) ? "" + pvar + " < 0 ? " + ivar + " >= " + tvar + " : " + ivar + " <= " + tvar : "" + ivar + " " + (step < 0 ? '>=' : '<=') + " " + tvar;
forPart = "" + vars + "; " + cond + "; " + incr;
} else {
svar = sourcePart = this.source.compile(o);
if ((name || !this.raw) && !(IDENTIFIER.test(svar) && scope.check(svar, {
@@ -1701,21 +1592,31 @@
top: true
})) : name ? "" + name + " = " + svar + "[" + ivar + "]" : undefined;
if (!this.object) {
lvar = scope.freeVariable('len');
stepPart = this.step ? "" + ivar + " += " + (this.step.compile(o)) : "" + ivar + "++";
forPart = "" + ivar + " = 0, " + lvar + " = " + sourcePart + ".length; " + ivar + " < " + lvar + "; " + stepPart;
if (0 > pvar && (pvar | 0) === +pvar) {
vars = "" + ivar + " = " + sourcePart + ".length - 1";
cond = "" + ivar + " >= 0";
} else {
lvar = scope.freeVariable('len');
vars = "" + ivar + " = 0, " + lvar + " = " + sourcePart + ".length";
cond = "" + ivar + " < " + lvar;
}
if (step !== pvar) {
vars += ", " + step;
}
forPart = "" + vars + "; " + cond + "; " + incr;
}
}
resultPart = rvar ? "" + (this.tab) + rvar + " = [];\n" : '';
returnResult = this.compileReturnValue(rvar, o);
if (!topLevel) {
if (!top) {
rvar = scope.freeVariable('result');
resultDef = "" + (this.tab) + rvar + " = [];\n";
resultRet = this.compileReturnValue(rvar, o);
body = Push.wrap(rvar, body);
}
if (this.guard) {
body = Expressions.wrap([new If(this.guard, body)]);
}
if (codeInBody) {
if (this.range) {
if (this.from) {
body.unshift(new Literal("var " + name + " = " + ivar));
}
if (namePart) {
@@ -1735,32 +1636,24 @@
o.indent = this.idt(1);
body = Expressions.wrap([new Literal(body.compile(o))]);
if (index) {
body.push(new Assign(this.index, new Literal(ivar)));
body.push(new Assign(new Literal(index), new Literal(ivar)));
}
if (name) {
body.push(new Assign(this.name, new Literal(nvar || ivar)));
body.push(new Assign(new Literal(name), new Literal(nvar || ivar)));
}
} else {
if (namePart) {
varPart = "" + idt1 + namePart + ";\n";
}
if (forPart && name === ivar) {
unstepPart = this.step ? "" + name + " -= " + (this.step.compile(o)) + ";" : "" + name + "--;";
unstepPart = ("\n" + (this.tab)) + unstepPart;
varPart = "" + idt + namePart + ";\n";
}
}
if (this.object) {
forPart = "" + ivar + " in " + sourcePart;
if (!this.raw) {
guardPart = "\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;";
}
guardPart = !this.raw && ("" + idt + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;\n");
}
body = body.compile(merge(o, {
indent: idt1,
return "" + (resultDef || '') + (this.tab) + "for (" + forPart + ") {\n" + (guardPart || '') + varPart + (body.compile(merge(o, {
indent: idt,
top: true
}));
vars = this.range ? name : "" + name + ", " + ivar;
return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + unstepPart + returnResult;
}))) + "\n" + (this.tab) + "}" + (resultRet || '');
};
return For;
})();
@@ -1835,11 +1728,11 @@
If.prototype.topSensitive = YES;
If.prototype.bodyNode = function() {
var _ref2;
return ((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined;
return (((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined);
};
If.prototype.elseBodyNode = function() {
var _ref2;
return ((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined;
return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined);
};
If.prototype.addElse = function(elseBody) {
if (this.isChain) {