mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 11:31:20 -05:00
#713: destructuring assignment is no longer statement and correctly returns RHS value
This commit is contained in:
203
lib/nodes.js
203
lib/nodes.js
@@ -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++) {
|
||||
|
||||
Reference in New Issue
Block a user