#713: destructuring assignment is no longer statement and correctly returns RHS value

This commit is contained in:
satyr
2010-09-29 05:47:12 +09:00
parent b2313beaf4
commit 7450df8104
9 changed files with 206 additions and 301 deletions

View File

@@ -8,18 +8,8 @@
if (typeof parent.extended === "function") parent.extended(child);
child.__super__ = parent.prototype;
};
_ref = require('./scope');
Scope = _ref.Scope;
_ref = require('./helpers');
compact = _ref.compact;
flatten = _ref.flatten;
merge = _ref.merge;
del = _ref.del;
include = _ref.include;
indexOf = _ref.indexOf;
starts = _ref.starts;
ends = _ref.ends;
last = _ref.last;
Scope = require('./scope').Scope;
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, indexOf = _ref.indexOf, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
YES = function() {
return true;
};
@@ -264,7 +254,8 @@
return this.isStatement() ? this : LiteralNode.__super__.makeReturn.call(this);
};
LiteralNode.prototype.isStatement = function() {
return this.value === 'break' || this.value === 'continue' || this.value === 'debugger';
var _ref2;
return ('break' === (_ref2 = this.value) || 'continue' === _ref2 || 'debugger' === _ref2);
};
LiteralNode.prototype.isPureStatement = LiteralNode.prototype.isStatement;
LiteralNode.prototype.isComplex = NO;
@@ -355,17 +346,13 @@
var _len, _ref2, _ref3, copy, first, i, index, indexVar, prop;
copy = new ValueNode(this.base, this.properties.slice(0));
if (this.base.isComplex()) {
_ref2 = this.base.compileReference(o);
this.base = _ref2[0];
copy.base = _ref2[1];
_ref2 = this.base.compileReference(o), this.base = _ref2[0], copy.base = _ref2[1];
}
_ref2 = copy.properties;
for (i = 0, _len = _ref2.length; i < _len; i++) {
prop = _ref2[i];
if (prop instanceof IndexNode && prop.index.isComplex()) {
_ref3 = prop.index.compileReference(o);
index = _ref3[0];
indexVar = _ref3[1];
_ref3 = prop.index.compileReference(o), index = _ref3[0], indexVar = _ref3[1];
this.properties[i] = (first = new IndexNode(index));
copy.properties[i] = new IndexNode(indexVar);
if (prop.soakNode) {
@@ -393,9 +380,7 @@
}
}
if (hasSoak && this.isComplex()) {
_ref2 = this.cacheIndexes(o);
me = _ref2[0];
copy = _ref2[1];
_ref2 = this.cacheIndexes(o), me = _ref2[0], copy = _ref2[1];
}
if (this.parenthetical && !props.length) {
this.base.parenthetical = true;
@@ -494,17 +479,13 @@
if (this.exist) {
if (this.variable instanceof ValueNode && last(this.variable.properties) instanceof AccessorNode) {
methodAccessor = this.variable.properties.pop();
_ref2 = this.variable.compileReference(o);
first = _ref2[0];
meth = _ref2[1];
_ref2 = this.variable.compileReference(o), first = _ref2[0], meth = _ref2[1];
this.first = new ValueNode(first, [methodAccessor]).compile(o);
this.meth = new ValueNode(meth, [methodAccessor]).compile(o);
} else {
_ref2 = this.variable.compileReference(o, {
precompile: true
});
this.first = _ref2[0];
this.meth = _ref2[1];
}), this.first = _ref2[0], this.meth = _ref2[1];
}
this.first = ("(typeof " + (this.first) + " === \"function\" ? ");
this.last = " : undefined)";
@@ -646,17 +627,11 @@
});
_ref2 = this.from.compileReference(o, {
precompile: true
});
this.from = _ref2[0];
this.fromVar = _ref2[1];
}), this.from = _ref2[0], this.fromVar = _ref2[1];
_ref2 = this.to.compileReference(o, {
precompile: true
});
this.to = _ref2[0];
this.toVar = _ref2[1];
_ref2 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)];
this.fromNum = _ref2[0];
this.toNum = _ref2[1];
}), this.to = _ref2[0], this.toVar = _ref2[1];
_ref2 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref2[0], this.toNum = _ref2[1];
parts = [];
if (this.from !== this.fromVar) {
parts.push(this.from);
@@ -685,9 +660,7 @@
};
RangeNode.prototype.compileSimple = function(o) {
var _ref2, from, idx, step, to;
_ref2 = [+this.fromNum, +this.toNum];
from = _ref2[0];
to = _ref2[1];
_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))));
@@ -872,9 +845,7 @@
_ref2 = this.properties;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
prop = _ref2[_i];
_ref3 = [prop.variable, prop.value];
pvar = _ref3[0];
func = _ref3[1];
_ref3 = [prop.variable, prop.value], pvar = _ref3[0], func = _ref3[1];
if (pvar && pvar.base.value === 'constructor' && func instanceof CodeNode) {
if (func.bound) {
throw new Error("cannot define a constructor as a bound function.");
@@ -937,28 +908,20 @@
AssignNode.prototype.isValue = function() {
return this.variable instanceof ValueNode;
};
AssignNode.prototype.makeReturn = function() {
if (this.isStatement()) {
return new Expressions([this, new ReturnNode(this.variable)]);
} else {
return AssignNode.__super__.makeReturn.call(this);
}
};
AssignNode.prototype.isStatement = function() {
return this.isValue() && (this.variable.isArray() || this.variable.isObject());
};
AssignNode.prototype.compileNode = function(o) {
var end, match, name, proto, stmt, top, val;
var end, isValue, match, name, proto, stmt, top, val;
if (isValue = this.isValue()) {
if (this.variable.isArray() || this.variable.isObject()) {
return this.compilePatternMatch(o);
}
if (this.variable.isSplice()) {
return this.compileSplice(o);
}
}
top = del(o, 'top');
if (this.isStatement(o)) {
return this.compilePatternMatch(o);
}
if (this.isValue() && this.variable.isSplice()) {
return this.compileSplice(o);
}
stmt = del(o, 'asStatement');
name = this.variable.compile(o);
end = this.isValue() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
end = isValue ? this.variable.last.replace(this.LEADING_DOT, '') : name;
match = name.match(this.PROTO_ASSIGN);
proto = match && match[1];
if (this.value instanceof CodeNode) {
@@ -973,7 +936,7 @@
if (this.context === 'object') {
return ("" + (name) + ": " + (val));
}
if (!(this.isValue() && (this.variable.hasProperties() || this.variable.namespaced))) {
if (!(isValue && (this.variable.hasProperties() || this.variable.namespaced))) {
o.scope.find(name);
}
val = ("" + (name) + " = " + (val));
@@ -983,22 +946,41 @@
return top || this.parenthetical ? val : ("(" + (val) + ")");
};
AssignNode.prototype.compilePatternMatch = function(o) {
var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isString, obj, oindex, olength, splat, val, valVar, value;
var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isObject, obj, objects, oindex, olength, otop, splat, top, val, valVar, value;
if ((value = this.value).isStatement(o)) {
value = ClosureNode.wrap(value);
}
objects = this.variable.base.objects;
if (!(objects.length)) {
return value.compile(o);
}
if ((isObject = this.variable.isObject()) && objects.length === 1) {
if ((obj = objects[0]) instanceof AssignNode) {
_ref2 = obj, idx = _ref2.variable.base, obj = _ref2.value;
} else {
idx = obj;
}
if (!(value instanceof ValueNode)) {
value = new ValueNode(value);
}
accessClass = IDENTIFIER.test(idx.value) ? AccessorNode : IndexNode;
value.properties.push(new accessClass(idx));
return new AssignNode(obj, value).compile(o);
}
top = del(o, 'top');
otop = merge(o, {
top: true
});
valVar = o.scope.freeVariable('ref');
value = this.value.isStatement(o) ? ClosureNode.wrap(this.value) : this.value;
assigns = [("" + (this.tab) + (valVar) + " = " + (value.compile(o)) + ";")];
o.top = true;
o.asStatement = true;
assigns = [("" + (valVar) + " = " + (value.compile(o)))];
splat = false;
_ref2 = this.variable.base.objects;
_ref2 = objects;
for (i = 0, _len = _ref2.length; i < _len; i++) {
obj = _ref2[i];
idx = i;
if (this.variable.isObject()) {
if (isObject) {
if (obj instanceof AssignNode) {
_ref3 = [obj.value, obj.variable.base];
obj = _ref3[0];
idx = _ref3[1];
_ref3 = [obj.value, obj.variable.base], obj = _ref3[0], idx = _ref3[1];
} else {
idx = obj;
}
@@ -1006,10 +988,9 @@
if (!(obj instanceof ValueNode || obj instanceof SplatNode)) {
throw new Error('pattern matching must use only identifiers on the left-hand side.');
}
isString = idx.value && idx.value.match(IS_STRING);
accessClass = isString || this.variable.isArray() ? IndexNode : AccessorNode;
if (obj instanceof SplatNode && !splat) {
val = literal(obj.compileValue(o, valVar, oindex = indexOf(this.variable.base.objects, obj), (olength = this.variable.base.objects.length) - oindex - 1));
accessClass = isObject && IDENTIFIER.test(idx.value) ? AccessorNode : IndexNode;
if (!splat && obj instanceof SplatNode) {
val = literal(obj.compileValue(o, valVar, oindex = indexOf(objects, obj), (olength = objects.length) - oindex - 1));
splat = true;
} else {
if (typeof idx !== 'object') {
@@ -1017,10 +998,13 @@
}
val = new ValueNode(literal(valVar), [new accessClass(idx)]);
}
assigns.push(new AssignNode(obj, val).compile(o));
assigns.push(new AssignNode(obj, val).compile(otop));
}
code = assigns.join("\n");
return code;
if (!(top)) {
assigns.push(valVar);
}
code = assigns.join(', ');
return top || this.parenthetical ? code : ("(" + (code) + ")");
};
AssignNode.prototype.compileSplice = function(o) {
var from, l, name, plus, range, to, val;
@@ -1076,11 +1060,8 @@
splat.trailings.push(param);
} else {
if (param.attach) {
_ref3 = param;
value = _ref3.value;
_ref3 = [literal(o.scope.freeVariable('arg')), param.splat];
param = _ref3[0];
param.splat = _ref3[1];
value = param.value;
_ref3 = [literal(o.scope.freeVariable('arg')), param.splat], param = _ref3[0], param.splat = _ref3[1];
this.body.unshift(new AssignNode(new ValueNode(literal('this'), [new AccessorNode(value)]), param));
}
if (param.splat) {
@@ -1117,9 +1098,7 @@
}
return top ? ("(" + (func) + ")") : func;
};
CodeNode.prototype.topSensitive = function() {
return true;
};
CodeNode.prototype.topSensitive = YES;
CodeNode.prototype.traverseChildren = function(crossScope, func) {
return crossScope ? CodeNode.__super__.traverseChildren.call(this, crossScope, func) : null;
};
@@ -1141,9 +1120,8 @@
return this.value.compile(o);
};
ParamNode.prototype.toString = function() {
var _ref2, name;
_ref2 = this;
name = _ref2.name;
var name;
name = this.name;
if (this.attach) {
name = '@' + name;
}
@@ -1251,9 +1229,7 @@
this.returns = true;
return this;
};
WhileNode.prototype.topSensitive = function() {
return true;
};
WhileNode.prototype.topSensitive = YES;
WhileNode.prototype.compileNode = function(o) {
var cond, post, pre, rvar, set, top;
top = del(o, 'top') && !this.returns;
@@ -1364,13 +1340,8 @@
OpNode.prototype.compileChain = function(o) {
var _ref2, first, second, shared;
shared = this.first.unwrap().second;
_ref2 = shared.compileReference(o);
this.first.second = _ref2[0];
shared = _ref2[1];
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)];
first = _ref2[0];
second = _ref2[1];
shared = _ref2[2];
_ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref2[0], second = _ref2[1], shared = _ref2[2];
return "(" + (first) + ") && (" + (shared) + " " + (this.operator) + " " + (second) + ")";
};
OpNode.prototype.compileAssignment = function(o) {
@@ -1378,9 +1349,7 @@
_ref2 = this.first.compileReference(o, {
precompile: true,
assignment: true
});
first = _ref2[0];
firstVar = _ref2[1];
}), first = _ref2[0], firstVar = _ref2[1];
second = this.second.compile(o);
if (this.second instanceof OpNode) {
second = ("(" + (second) + ")");
@@ -1395,9 +1364,7 @@
};
OpNode.prototype.compileExistence = function(o) {
var _ref2, ref, test;
_ref2 = ExistenceNode.compileTest(o, this.first);
test = _ref2[0];
ref = _ref2[1];
_ref2 = ExistenceNode.compileTest(o, this.first), test = _ref2[0], ref = _ref2[1];
return "" + (test) + " ? " + (ref) + " : " + (this.second.compile(o));
};
OpNode.prototype.compileUnary = function(o) {
@@ -1428,9 +1395,7 @@
var _ref2;
_ref2 = this.object.compileReference(o, {
precompile: true
});
this.obj1 = _ref2[0];
this.obj2 = _ref2[1];
}), this.obj1 = _ref2[0], this.obj2 = _ref2[1];
return this.isArray() ? this.compileOrTest(o) : this.compileLoopTest(o);
};
InNode.prototype.compileOrTest = function(o) {
@@ -1449,12 +1414,8 @@
var _ref2, i, l, prefix;
_ref2 = this.array.compileReference(o, {
precompile: true
});
this.arr1 = _ref2[0];
this.arr2 = _ref2[1];
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')];
i = _ref2[0];
l = _ref2[1];
}), this.arr1 = _ref2[0], this.arr2 = _ref2[1];
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')], i = _ref2[0], l = _ref2[1];
prefix = this.obj1 !== this.obj2 ? this.obj1 + '; ' : '';
return "(function(){ " + (prefix) + "for (var " + (i) + "=0, " + (l) + "=" + (this.arr1) + ".length; " + (i) + "<" + (l) + "; " + (i) + "++) { if (" + (this.arr2) + "[" + (i) + "] === " + (this.obj2) + ") return true; } return false; }).call(this)";
};
@@ -1530,9 +1491,7 @@
var _ref2, first, second;
_ref2 = variable.compileReference(o, {
precompile: true
});
first = _ref2[0];
second = _ref2[1];
}), first = _ref2[0], second = _ref2[1];
return [("(typeof " + (first) + " !== \"undefined\" && " + (second) + " !== null)"), second];
};
return ExistenceNode;
@@ -1585,9 +1544,7 @@
this.raw = !!source.raw;
this.object = !!source.object;
if (this.object) {
_ref2 = [this.index, this.name];
this.name = _ref2[0];
this.index = _ref2[1];
_ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1];
}
this.pattern = this.name instanceof ValueNode;
if (this.index instanceof ValueNode) {
@@ -1743,9 +1700,7 @@
_ref2 = this.cases;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
pair = _ref2[_i];
_ref3 = pair;
conditions = _ref3[0];
block = _ref3[1];
_ref3 = pair, conditions = _ref3[0], block = _ref3[1];
exprs = block.expressions;
_ref3 = flatten([conditions]);
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {