#733: streamlined soak compilations and improved reference cachings

This commit is contained in:
satyr
2010-10-02 07:17:35 +09:00
parent 54f162e523
commit 341f511bbd
9 changed files with 459 additions and 409 deletions

View File

@@ -26,7 +26,7 @@
};
BaseNode.prototype.compile = function(o) {
var closure, code, top;
this.options = merge(o || {});
this.options = o ? merge(o) : {};
this.tab = o.indent;
if (!(this instanceof AccessorNode || this instanceof IndexNode)) {
del(this.options, 'chainRoot');
@@ -48,21 +48,22 @@
return ClosureNode.wrap(this).compile(o);
};
BaseNode.prototype.compileReference = function(o, options) {
var compiled, pair, reference;
options || (options = {});
var _len, _ref2, compiled, i, node, pair, reference;
pair = (function() {
if (!this.isComplex()) {
if (!(this.isComplex())) {
return [this, this];
} else if (this instanceof ValueNode && options.assignment) {
return this.cacheIndexes(o);
} else {
reference = literal(o.scope.freeVariable('ref'));
compiled = new AssignNode(reference, this);
return [compiled, reference];
}
}).call(this);
if (options.precompile) {
return [pair[0].compile(o), pair[1].compile(o)];
if (((options != null) ? options.precompile : null)) {
_ref2 = pair;
for (i = 0, _len = _ref2.length; i < _len; i++) {
node = _ref2[i];
(pair[i] = node.compile(o));
}
}
return pair;
};
@@ -96,7 +97,7 @@
};
BaseNode.prototype.containsPureStatement = function() {
return this.isPureStatement() || this.contains(function(n) {
return n.isPureStatement && n.isPureStatement();
return (typeof n.isPureStatement !== "function" ? undefined : n.isPureStatement());
});
};
BaseNode.prototype.traverse = function(block) {
@@ -146,8 +147,10 @@
};
BaseNode.prototype.traverseChildren = function(crossScope, func) {
return this.eachChild(function(child) {
func.apply(this, arguments);
return child instanceof BaseNode ? child.traverseChildren(crossScope, func) : null;
if (func(child) === false) {
return false;
}
return child instanceof BaseNode && (crossScope || !(child instanceof CodeNode)) ? child.traverseChildren(crossScope, func) : null;
});
};
BaseNode.prototype["class"] = 'BaseNode';
@@ -319,10 +322,10 @@
return !!this.properties.length;
};
ValueNode.prototype.isArray = function() {
return this.base instanceof ArrayNode && !this.hasProperties();
return this.base instanceof ArrayNode && !this.properties.length;
};
ValueNode.prototype.isObject = function() {
return this.base instanceof ObjectNode && !this.hasProperties();
return this.base instanceof ObjectNode && !this.properties.length;
};
ValueNode.prototype.isSplice = function() {
return last(this.properties) instanceof SliceNode;
@@ -331,7 +334,7 @@
return this.base.isComplex() || this.hasProperties();
};
ValueNode.prototype.makeReturn = function() {
return this.hasProperties() ? ValueNode.__super__.makeReturn.call(this) : this.base.makeReturn();
return this.properties.length ? ValueNode.__super__.makeReturn.call(this) : this.base.makeReturn();
};
ValueNode.prototype.unwrap = function() {
return this.properties.length ? this : this.base;
@@ -342,76 +345,95 @@
ValueNode.prototype.isNumber = function() {
return this.base instanceof LiteralNode && NUMBER.test(this.base.value);
};
ValueNode.prototype.cacheIndexes = function(o) {
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];
ValueNode.prototype.cacheReference = function(o) {
var base, bref, name, nref;
name = last(this.properties);
if (!this.base.isComplex() && this.properties.length < 2 && !((name != null) ? name.isComplex() : null)) {
return [this, this];
}
_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];
this.properties[i] = (first = new IndexNode(index));
copy.properties[i] = new IndexNode(indexVar);
if (prop.soakNode) {
first.soakNode = true;
}
}
base = new ValueNode(this.base, this.properties.slice(0, -1));
if (base.isComplex()) {
bref = literal(o.scope.freeVariable('base'));
base = new ValueNode(new ParentheticalNode(new AssignNode(bref, base)));
}
return [this, copy];
if (!(name)) {
return [base, bref];
}
if (name.isComplex()) {
nref = literal(o.scope.freeVariable('name'));
name = new IndexNode(new AssignNode(nref, name.index));
nref = new IndexNode(nref);
}
return [base.push(name), new ValueNode(bref || base.base, [nref || name])];
};
ValueNode.prototype.compile = function(o) {
return !o.top || this.properties.length ? ValueNode.__super__.compile.call(this, o) : this.base.compile(o);
};
ValueNode.prototype.compileNode = function(o) {
var _i, _len, _ref2, baseline, complete, copy, hasSoak, i, me, only, op, part, prop, props, temp;
only = del(o, 'onlyFirst');
op = this.tags.operation;
props = only ? this.properties.slice(0, -1) : this.properties;
var _i, _len, _ref2, code, ex, prop, props;
if (ex = this.unfoldSoak(o)) {
return ex.compile(o);
}
props = this.properties;
o.chainRoot || (o.chainRoot = this);
_ref2 = props;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
prop = _ref2[_i];
if (prop.soakNode) {
hasSoak = true;
break;
}
}
if (hasSoak && this.isComplex()) {
_ref2 = this.cacheIndexes(o), me = _ref2[0], copy = _ref2[1];
}
if (this.parenthetical && !props.length) {
this.base.parenthetical = true;
}
baseline = this.base.compile(o);
if (this.hasProperties() && (this.base instanceof ObjectNode || this.isNumber())) {
baseline = ("(" + (baseline) + ")");
code = this.base.compile(o);
if (props[0] instanceof AccessorNode && this.isNumber() || o.top && this.base instanceof ObjectNode) {
code = ("(" + (code) + ")");
}
complete = (this.last = baseline);
_ref2 = props;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
prop = _ref2[_i];
(code += prop.compile(o));
}
return code;
};
ValueNode.prototype.unfoldSoak = function(o) {
var _len, _ref2, fst, i, ifn, prop, ref, snd;
if (this.base.soakNode) {
Array.prototype.push.apply(this.base.body.properties, this.properties);
return this.base;
}
_ref2 = this.properties;
for (i = 0, _len = _ref2.length; i < _len; i++) {
prop = _ref2[i];
this.source = baseline;
if (prop.soakNode) {
if (i === 0 && this.base.isComplex()) {
temp = o.scope.freeVariable('ref');
complete = ("(" + (baseline = temp) + " = (" + (complete) + "))");
prop.soakNode = false;
fst = new ValueNode(this.base, this.properties.slice(0, i));
snd = new ValueNode(this.base, this.properties.slice(i));
if (fst.isComplex()) {
ref = literal(o.scope.freeVariable('ref'));
fst = new ParentheticalNode(new AssignNode(ref, fst));
snd.base = ref;
}
complete = i === 0 && !o.scope.check(complete) ? ("(typeof " + (complete) + " === \"undefined\" || " + (baseline) + " === null)") : ("" + (complete) + " == null");
complete += ' ? undefined : ' + (baseline += prop.compile(o));
} else {
part = prop.compile(o);
baseline += (hasSoak && prop.isComplex() ? copy.properties[i].compile(o) : part);
complete += part;
this.last = part;
ifn = new IfNode(new ExistenceNode(fst), snd, {
operation: true
});
ifn.soakNode = true;
return ifn;
}
}
return op && this.wrapped ? ("(" + (complete) + ")") : complete;
return null;
};
ValueNode.unfoldSoak = function(o, parent, name) {
var ifnode, node;
node = parent[name];
if (node instanceof IfNode && node.soakNode) {
ifnode = node;
} else if (node instanceof ValueNode) {
ifnode = node.unfoldSoak(o);
}
if (!(ifnode)) {
return null;
}
parent[name] = ifnode.body;
ifnode.body = new ValueNode(parent);
return ifnode;
};
return ValueNode;
})();
}).call(this);
exports.CommentNode = (function() {
CommentNode = function(_arg) {
this.comment = _arg;
@@ -436,15 +458,14 @@
this.isSuper = variable === 'super';
this.variable = this.isSuper ? null : variable;
this.args || (this.args = []);
this.first = (this.last = '');
this.compileSplatArguments = function(o) {
return SplatNode.compileSplattedArray.call(this, this.args, o);
};
return this;
};
__extends(CallNode, BaseNode);
CallNode.prototype["class"] = 'CallNode';
CallNode.prototype.children = ['variable', 'args'];
CallNode.prototype.compileSplatArguments = function(o) {
return SplatNode.compileSplattedArray(this.args, o);
};
CallNode.prototype.newInstance = function() {
this.isNew = true;
return this;
@@ -453,97 +474,128 @@
return this.isNew ? 'new ' : '';
};
CallNode.prototype.superReference = function(o) {
var meth, methname;
if (!(o.scope.method)) {
throw new Error("cannot call super outside of a function");
var method, name;
method = o.scope.method;
if (!(method)) {
throw Error("cannot call super outside of a function");
}
methname = o.scope.method.name;
return (meth = (function() {
if (o.scope.method.proto) {
return "" + (o.scope.method.proto) + ".__super__." + (methname);
} else if (methname) {
return "" + (methname) + ".__super__.constructor";
} else {
throw new Error("cannot call super on an anonymous function.");
name = method.name;
if (!(name)) {
throw Error("cannot call super on an anonymous function.");
}
return method.klass ? ("" + (method.klass) + ".__super__." + (name)) : ("" + (name) + ".__super__.constructor");
};
CallNode.prototype.unfoldSoak = function(o) {
var _i, _len, _ref2, call, list, node;
call = this;
list = [];
while (true) {
if (call.variable instanceof CallNode) {
list.push(call);
call = call.variable;
continue;
}
})());
if (!(call.variable instanceof ValueNode)) {
break;
}
list.push(call);
if (!((call = call.variable.base) instanceof CallNode)) {
break;
}
}
_ref2 = list.reverse();
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
call = _ref2[_i];
if (node) {
if (call.variable instanceof CallNode) {
call.variable = node;
} else {
call.variable.base = node;
}
}
node = ValueNode.unfoldSoak(o, call, 'variable');
}
return node;
};
CallNode.prototype.compileNode = function(o) {
var _i, _len, _ref2, _result, arg, args, code, first, meth, methodAccessor, op;
if (!(o.chainRoot)) {
o.chainRoot = this;
var _i, _len, _ref2, _result, arg, args, left, node, rite, val;
if (node = this.unfoldSoak(o)) {
return node.compile(o);
}
op = this.tags.operation;
o.chainRoot || (o.chainRoot = this);
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];
this.first = new ValueNode(first, [methodAccessor]).compile(o);
this.meth = new ValueNode(meth, [methodAccessor]).compile(o);
if (val = this.variable) {
if (!(val instanceof ValueNode)) {
val = new ValueNode(val);
}
_ref2 = val.cacheReference(o), left = _ref2[0], rite = _ref2[1];
rite = new CallNode(rite, this.args);
} else {
_ref2 = this.variable.compileReference(o, {
precompile: true
}), this.first = _ref2[0], this.meth = _ref2[1];
left = literal(this.superReference(o));
rite = new CallNode(new ValueNode(left), this.args);
rite.isNew = this.isNew;
}
this.first = ("(typeof " + (this.first) + " === \"function\" ? ");
this.last = " : undefined)";
} else if (this.variable) {
this.meth = this.variable.compile(o);
left = ("typeof " + (left.compile(o)) + " !== \"function\"");
rite = rite.compile(o);
return ("(" + (left) + " ? undefined : " + (rite) + ")");
}
_ref2 = this.args;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
arg = _ref2[_i];
if (arg instanceof SplatNode) {
code = this.compileSplat(o);
return this.compileSplat(o);
}
}
if (!code) {
args = (function() {
_result = []; _ref2 = this.args;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
arg = _ref2[_i];
_result.push((function() {
arg.parenthetical = true;
return arg.compile(o);
})());
}
return _result;
}).call(this);
code = this.isSuper ? this.compileSuper(args.join(', '), o) : ("" + (this.first) + (this.prefix()) + (this.meth) + "(" + (args.join(', ')) + ")" + (this.last));
}
return op && this.variable && this.variable.wrapped ? ("(" + (code) + ")") : code;
args = (function() {
_result = []; _ref2 = this.args;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
arg = _ref2[_i];
_result.push((arg.parenthetical = true) && arg.compile(o));
}
return _result;
}).call(this).join(', ');
return this.isSuper ? this.compileSuper(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + (args) + ")");
};
CallNode.prototype.compileSuper = function(args, o) {
return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + (args) + ")";
};
CallNode.prototype.compileSplat = function(o) {
var _i, _len, _ref2, a, b, c, mentionsArgs, meth, obj, temp;
meth = this.meth || this.superReference(o);
obj = this.variable && this.variable.source || 'this';
if (!(IDENTIFIER.test(obj) || NUMBER.test(obj))) {
temp = o.scope.freeVariable('ref');
obj = temp;
meth = ("(" + (temp) + " = " + (this.variable.source) + ")" + (this.variable.last));
var _i, _len, _ref2, a, arg, argvar, b, base, c, call, fun, idt, name, ref, splatargs;
splatargs = this.compileSplatArguments(o);
if (this.isSuper) {
return ("" + (this.superReference(o)) + ".apply(this, " + (splatargs) + ")");
}
if (this.isNew) {
mentionsArgs = false;
_ref2 = this.args;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
(function() {
var arg = _ref2[_i];
return arg.contains(function(n) {
return mentionsArgs || (mentionsArgs = (n instanceof LiteralNode && (n.value === 'arguments')));
});
})();
if (!(this.isNew)) {
if (!((base = this.variable) instanceof ValueNode)) {
base = new ValueNode(base);
}
utility('extends');
a = o.scope.freeVariable('ctor');
b = o.scope.freeVariable('ref');
c = o.scope.freeVariable('result');
return "" + (this.first) + "(function() {\n" + (this.idt(1)) + "var ctor = function(){};\n" + (this.idt(1)) + "__extends(ctor, " + (a) + " = " + (meth) + ");\n" + (this.idt(1)) + "return typeof (" + (c) + " = " + (a) + ".apply(" + (b) + " = new ctor, " + (this.compileSplatArguments(o)) + ")) === \"object\" ? " + (c) + " : " + (b) + ";\n" + (this.tab) + "})." + (mentionsArgs ? 'apply(this, arguments)' : 'call(this)') + (this.last);
} else {
return "" + (this.first) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")" + (this.last);
if ((name = base.properties.pop()) && base.isComplex()) {
ref = o.scope.freeVariable('this');
fun = ("(" + (ref) + " = " + (base.compile(o)) + ")" + (name.compile(o)));
} else {
fun = (ref = base.compile(o));
if (name) {
fun += name.compile(o);
}
}
return ("" + (fun) + ".apply(" + (ref) + ", " + (splatargs) + ")");
}
call = 'call(this)';
argvar = function(n) {
return n instanceof LiteralNode && n.value === 'arguments';
};
_ref2 = this.args;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
arg = _ref2[_i];
if (arg.contains(argvar)) {
call = 'apply(this, arguments)';
break;
}
}
a = o.scope.freeVariable('ctor');
b = o.scope.freeVariable('ref');
c = o.scope.freeVariable('result');
return "(function() {\n" + (idt = this.idt(1)) + "var ctor = function() {};\n" + (idt) + (utility('extends')) + "(ctor, " + (a) + " = " + (this.variable.compile(o)) + ");\n" + (idt) + "return typeof (" + (c) + " = " + (a) + ".apply(" + (b) + " = new ctor, " + (splatargs) + ")) === \"object\" ? " + (c) + " : " + (b) + ";\n" + (this.tab) + "})." + (call);
};
return CallNode;
})();
@@ -576,9 +628,9 @@
AccessorNode.prototype["class"] = 'AccessorNode';
AccessorNode.prototype.children = ['name'];
AccessorNode.prototype.compileNode = function(o) {
var name, namePart;
var _base, name, namePart;
name = this.name.compile(o);
o.chainRoot.wrapped || (o.chainRoot.wrapped = this.soakNode);
(_base = o.chainRoot).wrapped || (_base.wrapped = this.soakNode);
namePart = name.match(IS_STRING) ? ("[" + (name) + "]") : ("." + (name));
return this.prototype + namePart;
};
@@ -595,8 +647,8 @@
IndexNode.prototype["class"] = 'IndexNode';
IndexNode.prototype.children = ['index'];
IndexNode.prototype.compileNode = function(o) {
var idx, prefix;
o.chainRoot.wrapped || (o.chainRoot.wrapped = this.soakNode);
var _base, idx, prefix;
(_base = o.chainRoot).wrapped || (_base.wrapped = this.soakNode);
idx = this.index.compile(o);
prefix = this.proto ? '.prototype' : '';
return "" + (prefix) + "[" + (idx) + "]";
@@ -774,14 +826,14 @@
this.objects = _arg;
ArrayNode.__super__.constructor.call(this);
this.objects || (this.objects = []);
this.compileSplatLiteral = function(o) {
return SplatNode.compileSplattedArray.call(this, this.objects, o);
};
return this;
};
__extends(ArrayNode, BaseNode);
ArrayNode.prototype["class"] = 'ArrayNode';
ArrayNode.prototype.children = ['objects'];
ArrayNode.prototype.compileSplatLiteral = function(o) {
return SplatNode.compileSplattedArray(this.objects, o);
};
ArrayNode.prototype.compileNode = function(o) {
var _len, _ref2, code, i, obj, objects;
o.indent = this.idt(1);
@@ -898,8 +950,7 @@
return this;
};
__extends(AssignNode, BaseNode);
AssignNode.prototype.PROTO_ASSIGN = /^(\S+)\.prototype/;
AssignNode.prototype.LEADING_DOT = /^\.(?:prototype\.)?/;
AssignNode.prototype.METHOD_DEF = /^(?:(\S+)\.prototype\.)?([$A-Za-z_][$\w]*)$/;
AssignNode.prototype["class"] = 'AssignNode';
AssignNode.prototype.children = ['variable', 'value'];
AssignNode.prototype.topSensitive = YES;
@@ -907,7 +958,7 @@
return this.variable instanceof ValueNode;
};
AssignNode.prototype.compileNode = function(o) {
var end, isValue, match, name, proto, stmt, top, val;
var isValue, match, name, node, stmt, top, val;
if (isValue = this.isValue()) {
if (this.variable.isArray() || this.variable.isObject()) {
return this.compilePatternMatch(o);
@@ -915,20 +966,16 @@
if (this.variable.isSplice()) {
return this.compileSplice(o);
}
if (node = ValueNode.unfoldSoak(o, this, 'variable')) {
return node.compile(o);
}
}
top = del(o, 'top');
stmt = del(o, 'asStatement');
name = this.variable.compile(o);
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) {
if (IDENTIFIER.test(end)) {
this.value.name = end;
}
if (proto) {
this.value.proto = proto;
}
if (this.value instanceof CodeNode && (match = this.METHOD_DEF.exec(name))) {
this.value.name = match[2];
this.value.klass = match[1];
}
val = this.value.compile(o);
if (this.context === 'object') {
@@ -1005,17 +1052,15 @@
return top || this.parenthetical ? code : ("(" + (code) + ")");
};
AssignNode.prototype.compileSplice = function(o) {
var from, l, name, plus, range, to, val;
name = this.variable.compile(merge(o, {
onlyFirst: true
}));
l = this.variable.properties.length;
range = this.variable.properties[l - 1].range;
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(" + (val) + "))";
return "([].splice.apply(" + (name) + ", [" + (from) + ", " + (to) + "].concat(" + (ref) + " = " + (val) + ")), " + (ref) + ")";
};
return AssignNode;
})();
@@ -1025,7 +1070,7 @@
this.params = _arg;
CodeNode.__super__.constructor.call(this);
this.params || (this.params = []);
this.body || (this.body = (new Expressions));
this.body || (this.body = new Expressions);
this.bound = tag === 'boundfunc';
if (this.bound) {
this.context = 'this';
@@ -1143,8 +1188,7 @@
SplatNode.prototype["class"] = 'SplatNode';
SplatNode.prototype.children = ['name'];
SplatNode.prototype.compileNode = function(o) {
var _ref2;
return (typeof (_ref2 = this.index) !== "undefined" && _ref2 !== null) ? this.compileParam(o) : this.name.compile(o);
return (this.index != null) ? this.compileParam(o) : this.name.compile(o);
};
SplatNode.prototype.compileParam = function(o) {
var _len, _ref2, assign, end, idx, len, name, pos, trailing, variadic;
@@ -1205,14 +1249,14 @@
exports.WhileNode = (function() {
WhileNode = function(condition, opts) {
WhileNode.__super__.constructor.call(this);
if (opts == null ? undefined : opts.invert) {
if (((opts != null) ? opts.invert : null)) {
if (condition instanceof OpNode) {
condition = new ParentheticalNode(condition);
}
condition = new OpNode('!', condition);
}
this.condition = condition;
this.guard = opts == null ? undefined : opts.guard;
this.guard = ((opts != null) ? opts.guard : null);
return this;
};
__extends(WhileNode, BaseNode);
@@ -1315,6 +1359,10 @@
return OpNode.__super__.toString.call(this, idt, this["class"] + ' ' + this.operator);
};
OpNode.prototype.compileNode = function(o) {
var node;
if (node = ValueNode.unfoldSoak(o, this, 'first')) {
return node.compile(o);
}
if (this.isChainable() && this.first.unwrap() instanceof OpNode && this.first.unwrap().isChainable()) {
return this.compileChain(o);
}
@@ -1343,7 +1391,10 @@
return "(" + (first) + ") && (" + (shared) + " " + (this.operator) + " " + (second) + ")";
};
OpNode.prototype.compileAssignment = function(o) {
var _ref2, first, firstVar, second;
var _ref2, first, firstVar, left, rite, second;
_ref2 = this.first.cacheReference(o), left = _ref2[0], rite = _ref2[1];
rite = new AssignNode(rite, this.second);
return new OpNode(this.operator.slice(0, -1), left, rite).compile(o);
_ref2 = this.first.compileReference(o, {
precompile: true,
assignment: true
@@ -1361,9 +1412,15 @@
return "" + (first) + " " + (this.operator.substr(0, 2)) + " (" + (firstVar) + " = " + (second) + ")";
};
OpNode.prototype.compileExistence = function(o) {
var _ref2, ref, test;
_ref2 = ExistenceNode.compileTest(o, this.first), test = _ref2[0], ref = _ref2[1];
return "" + (test) + " ? " + (ref) + " : " + (this.second.compile(o));
var fst, ref;
if (this.first.isComplex()) {
ref = o.scope.freeVariable('ref');
fst = new ParentheticalNode(new AssignNode(literal(ref), this.first));
} else {
fst = this.first;
ref = fst.compile(o);
}
return new ExistenceNode(fst).compile(o) + (" ? " + (ref) + " : " + (this.second.compile(o)));
};
OpNode.prototype.compileUnary = function(o) {
var parts, space;
@@ -1479,20 +1536,13 @@
ExistenceNode.prototype["class"] = 'ExistenceNode';
ExistenceNode.prototype.children = ['expression'];
ExistenceNode.prototype.compileNode = function(o) {
var test;
test = ExistenceNode.compileTest(o, this.expression)[0];
return this.parenthetical ? test.slice(1, -1) : test;
};
ExistenceNode.compileTest = function(o, variable) {
var _ref2, first, second;
_ref2 = variable.compileReference(o, {
precompile: true
}), first = _ref2[0], second = _ref2[1];
first = first === second && o.scope.check(first) ? ("(" + (first) + " != null)") : ("(typeof " + (first) + " !== \"undefined\" && " + (second) + " !== null)");
return [first, second];
var code;
code = this.expression.compile(o);
code = IDENTIFIER.test(code) && !o.scope.check(code) ? ("typeof " + (code) + " !== \"undefined\" && " + (code) + " !== null") : ("" + (code) + " != null");
return this.parenthetical ? code : ("(" + (code) + ")");
};
return ExistenceNode;
}).call(this);
})();
exports.ParentheticalNode = (function() {
ParentheticalNode = function(_arg) {
this.expression = _arg;
@@ -1742,10 +1792,12 @@
IfNode.prototype.children = ['condition', 'body', 'elseBody', 'assigner'];
IfNode.prototype.topSensitive = YES;
IfNode.prototype.bodyNode = function() {
return this.body == null ? undefined : this.body.unwrap();
var _ref2;
return (((_ref2 = this.body) != null) ? _ref2.unwrap() : null);
};
IfNode.prototype.elseBodyNode = function() {
return this.elseBody == null ? undefined : this.elseBody.unwrap();
var _ref2;
return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : null);
};
IfNode.prototype.addElse = function(elseBody, statement) {
if (this.isChain) {
@@ -1757,7 +1809,7 @@
return this;
};
IfNode.prototype.isStatement = function(o) {
return this.statement || (this.statement = (!!((o && o.top) || this.bodyNode().isStatement(o) || (this.elseBody && this.elseBodyNode().isStatement(o)))));
return this.statement || (this.statement = !!((o && o.top) || this.bodyNode().isStatement(o) || (this.elseBody && this.elseBodyNode().isStatement(o))));
};
IfNode.prototype.compileCondition = function(o) {
var _i, _len, _ref2, _result, cond, conditions;