mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
made nodes cache more aggressively, fixing #653
This commit is contained in:
parent
72c83f5e43
commit
3bba51d5d9
4 changed files with 149 additions and 163 deletions
|
@ -380,7 +380,7 @@
|
||||||
if (!(herecomment)) {
|
if (!(herecomment)) {
|
||||||
while ((match = HEREDOC_INDENT.exec(doc))) {
|
while ((match = HEREDOC_INDENT.exec(doc))) {
|
||||||
attempt = match[1];
|
attempt = match[1];
|
||||||
if (indent === null || (0 < attempt.length) && (attempt.length < indent.length)) {
|
if (indent === null || (0 < (_ref2 = attempt.length)) && (_ref2 < indent.length)) {
|
||||||
indent = attempt;
|
indent = attempt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
180
lib/nodes.js
180
lib/nodes.js
|
@ -1,5 +1,5 @@
|
||||||
(function() {
|
(function() {
|
||||||
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _ref, compact, del, ends, flatten, include, indexOf, literal, merge, starts, utility;
|
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, literal, merge, starts, utility;
|
||||||
var __extends = function(child, parent) {
|
var __extends = function(child, parent) {
|
||||||
var ctor = function(){};
|
var ctor = function(){};
|
||||||
ctor.prototype = parent.prototype;
|
ctor.prototype = parent.prototype;
|
||||||
|
@ -19,6 +19,12 @@
|
||||||
indexOf = _ref.indexOf;
|
indexOf = _ref.indexOf;
|
||||||
starts = _ref.starts;
|
starts = _ref.starts;
|
||||||
ends = _ref.ends;
|
ends = _ref.ends;
|
||||||
|
YES = function() {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
NO = function() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
exports.BaseNode = (function() {
|
exports.BaseNode = (function() {
|
||||||
BaseNode = function() {
|
BaseNode = function() {
|
||||||
this.tags = {};
|
this.tags = {};
|
||||||
|
@ -51,7 +57,7 @@
|
||||||
var compiled, pair, reference;
|
var compiled, pair, reference;
|
||||||
options || (options = {});
|
options || (options = {});
|
||||||
pair = (function() {
|
pair = (function() {
|
||||||
if (!(this.containsType(CallNode) || (this instanceof ValueNode && (!(this.base instanceof LiteralNode) || this.hasProperties())))) {
|
if (!(this.isComplex())) {
|
||||||
return [this, this];
|
return [this, this];
|
||||||
} else if (this instanceof ValueNode && options.assignment) {
|
} else if (this instanceof ValueNode && options.assignment) {
|
||||||
return this.cacheIndexes(o);
|
return this.cacheIndexes(o);
|
||||||
|
@ -154,15 +160,10 @@
|
||||||
BaseNode.prototype.unwrap = function() {
|
BaseNode.prototype.unwrap = function() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
BaseNode.prototype.isStatement = function() {
|
BaseNode.prototype.isStatement = NO;
|
||||||
return false;
|
BaseNode.prototype.isPureStatement = NO;
|
||||||
};
|
BaseNode.prototype.isComplex = YES;
|
||||||
BaseNode.prototype.isPureStatement = function() {
|
BaseNode.prototype.topSensitive = NO;
|
||||||
return false;
|
|
||||||
};
|
|
||||||
BaseNode.prototype.topSensitive = function() {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
return BaseNode;
|
return BaseNode;
|
||||||
})();
|
})();
|
||||||
exports.Expressions = (function() {
|
exports.Expressions = (function() {
|
||||||
|
@ -174,9 +175,7 @@
|
||||||
__extends(Expressions, BaseNode);
|
__extends(Expressions, BaseNode);
|
||||||
Expressions.prototype["class"] = 'Expressions';
|
Expressions.prototype["class"] = 'Expressions';
|
||||||
Expressions.prototype.children = ['expressions'];
|
Expressions.prototype.children = ['expressions'];
|
||||||
Expressions.prototype.isStatement = function() {
|
Expressions.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
Expressions.prototype.push = function(node) {
|
Expressions.prototype.push = function(node) {
|
||||||
this.expressions.push(node);
|
this.expressions.push(node);
|
||||||
return this;
|
return this;
|
||||||
|
@ -269,6 +268,7 @@
|
||||||
return this.value === 'break' || this.value === 'continue' || this.value === 'debugger';
|
return this.value === 'break' || this.value === 'continue' || this.value === 'debugger';
|
||||||
};
|
};
|
||||||
LiteralNode.prototype.isPureStatement = LiteralNode.prototype.isStatement;
|
LiteralNode.prototype.isPureStatement = LiteralNode.prototype.isStatement;
|
||||||
|
LiteralNode.prototype.isComplex = NO;
|
||||||
LiteralNode.prototype.compileNode = function(o) {
|
LiteralNode.prototype.compileNode = function(o) {
|
||||||
var end, idt;
|
var end, idt;
|
||||||
idt = this.isStatement(o) ? this.idt() : '';
|
idt = this.isStatement(o) ? this.idt() : '';
|
||||||
|
@ -288,12 +288,8 @@
|
||||||
};
|
};
|
||||||
__extends(ReturnNode, BaseNode);
|
__extends(ReturnNode, BaseNode);
|
||||||
ReturnNode.prototype["class"] = 'ReturnNode';
|
ReturnNode.prototype["class"] = 'ReturnNode';
|
||||||
ReturnNode.prototype.isStatement = function() {
|
ReturnNode.prototype.isStatement = YES;
|
||||||
return true;
|
ReturnNode.prototype.isPureStatement = YES;
|
||||||
};
|
|
||||||
ReturnNode.prototype.isPureStatement = function() {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ReturnNode.prototype.children = ['expression'];
|
ReturnNode.prototype.children = ['expression'];
|
||||||
ReturnNode.prototype.makeReturn = function() {
|
ReturnNode.prototype.makeReturn = function() {
|
||||||
return this;
|
return this;
|
||||||
|
@ -341,6 +337,9 @@
|
||||||
ValueNode.prototype.isSplice = function() {
|
ValueNode.prototype.isSplice = function() {
|
||||||
return this.hasProperties() && this.properties[this.properties.length - 1] instanceof SliceNode;
|
return this.hasProperties() && this.properties[this.properties.length - 1] instanceof SliceNode;
|
||||||
};
|
};
|
||||||
|
ValueNode.prototype.isComplex = function() {
|
||||||
|
return this.base.isComplex() || this.properties.length;
|
||||||
|
};
|
||||||
ValueNode.prototype.makeReturn = function() {
|
ValueNode.prototype.makeReturn = function() {
|
||||||
return this.hasProperties() ? ValueNode.__super__.makeReturn.call(this) : this.base.makeReturn();
|
return this.hasProperties() ? ValueNode.__super__.makeReturn.call(this) : this.base.makeReturn();
|
||||||
};
|
};
|
||||||
|
@ -354,29 +353,23 @@
|
||||||
return this.base instanceof LiteralNode && this.base.value.match(NUMBER);
|
return this.base instanceof LiteralNode && this.base.value.match(NUMBER);
|
||||||
};
|
};
|
||||||
ValueNode.prototype.cacheIndexes = function(o) {
|
ValueNode.prototype.cacheIndexes = function(o) {
|
||||||
var _i, _len, _ref2, copy, i;
|
var _len, _ref2, _ref3, copy, i, index, indexVar, prop;
|
||||||
copy = new ValueNode(this.base, this.properties.slice(0));
|
copy = new ValueNode(this.base, this.properties.slice(0));
|
||||||
if (this.base instanceof CallNode) {
|
if (this.base.isComplex()) {
|
||||||
_ref2 = this.base.compileReference(o);
|
_ref2 = this.base.compileReference(o);
|
||||||
this.base = _ref2[0];
|
this.base = _ref2[0];
|
||||||
copy.base = _ref2[1];
|
copy.base = _ref2[1];
|
||||||
}
|
}
|
||||||
_ref2 = copy.properties;
|
_ref2 = copy.properties;
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||||
(function() {
|
prop = _ref2[i];
|
||||||
var _ref3, index, indexVar;
|
if (prop instanceof IndexNode && prop.index.isComplex()) {
|
||||||
var i = _i;
|
_ref3 = prop.index.compileReference(o);
|
||||||
var prop = _ref2[_i];
|
index = _ref3[0];
|
||||||
if (prop instanceof IndexNode && prop.contains(function(n) {
|
indexVar = _ref3[1];
|
||||||
return n instanceof CallNode;
|
this.properties[i] = new IndexNode(index);
|
||||||
})) {
|
copy.properties[i] = new IndexNode(indexVar);
|
||||||
_ref3 = prop.index.compileReference(o);
|
}
|
||||||
index = _ref3[0];
|
|
||||||
indexVar = _ref3[1];
|
|
||||||
this.properties[i] = new IndexNode(index);
|
|
||||||
return (copy.properties[i] = new IndexNode(indexVar));
|
|
||||||
}
|
|
||||||
}).call(this);
|
|
||||||
}
|
}
|
||||||
return [this, copy];
|
return [this, copy];
|
||||||
};
|
};
|
||||||
|
@ -384,19 +377,20 @@
|
||||||
return !o.top || this.properties.length ? ValueNode.__super__.compile.call(this, o) : this.base.compile(o);
|
return !o.top || this.properties.length ? ValueNode.__super__.compile.call(this, o) : this.base.compile(o);
|
||||||
};
|
};
|
||||||
ValueNode.prototype.compileNode = function(o) {
|
ValueNode.prototype.compileNode = function(o) {
|
||||||
var _i, _len, _ref2, baseline, complete, copy, hasSoak, i, me, only, op, part, prop, props, temp;
|
var _i, _len, _ref2, baseline, complete, copy, hasSoak, i, me, only, op, part, prevcomp, prop, props, temp;
|
||||||
only = del(o, 'onlyFirst');
|
only = del(o, 'onlyFirst');
|
||||||
op = this.tags.operation;
|
op = this.tags.operation;
|
||||||
props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties;
|
props = only ? this.properties.slice(0, -1) : this.properties;
|
||||||
o.chainRoot || (o.chainRoot = this);
|
o.chainRoot || (o.chainRoot = this);
|
||||||
_ref2 = props;
|
_ref2 = props;
|
||||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||||
prop = _ref2[_i];
|
prop = _ref2[_i];
|
||||||
if (prop.soakNode) {
|
if (prop.soakNode) {
|
||||||
hasSoak = true;
|
hasSoak = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasSoak && this.containsType(CallNode)) {
|
if (hasSoak && this.isComplex()) {
|
||||||
_ref2 = this.cacheIndexes(o);
|
_ref2 = this.cacheIndexes(o);
|
||||||
me = _ref2[0];
|
me = _ref2[0];
|
||||||
copy = _ref2[1];
|
copy = _ref2[1];
|
||||||
|
@ -414,19 +408,15 @@
|
||||||
prop = _ref2[i];
|
prop = _ref2[i];
|
||||||
this.source = baseline;
|
this.source = baseline;
|
||||||
if (prop.soakNode) {
|
if (prop.soakNode) {
|
||||||
if (this.base.containsType(CallNode) && i === 0) {
|
if (i === 0 && this.base.isComplex()) {
|
||||||
temp = o.scope.freeVariable('ref');
|
temp = o.scope.freeVariable('ref');
|
||||||
complete = ("(" + (baseline = temp) + " = (" + (complete) + "))");
|
complete = ("(" + (baseline = temp) + " = (" + (prevcomp = complete) + "))");
|
||||||
}
|
}
|
||||||
complete = i === 0 ? ("(typeof " + (complete) + " === \"undefined\" || " + (baseline) + " === null) ? undefined : ") : ("" + (complete) + " == null ? undefined : ");
|
complete = i === 0 && !o.scope.check(complete) ? ("(typeof " + (complete) + " === \"undefined\" || " + (baseline) + " === null)") : ("" + (complete) + " == null");
|
||||||
complete += (baseline += prop.compile(o));
|
complete += ' ? undefined : ' + (baseline += prop.compile(o));
|
||||||
} else {
|
} else {
|
||||||
part = prop.compile(o);
|
part = prop.compile(o);
|
||||||
if (hasSoak && prop.containsType(CallNode)) {
|
baseline += (hasSoak && prop.isComplex() ? copy.properties[i].compile(o) : part);
|
||||||
baseline += copy.properties[i].compile(o);
|
|
||||||
} else {
|
|
||||||
baseline += part;
|
|
||||||
}
|
|
||||||
complete += part;
|
complete += part;
|
||||||
this.last = part;
|
this.last = part;
|
||||||
}
|
}
|
||||||
|
@ -443,14 +433,12 @@
|
||||||
};
|
};
|
||||||
__extends(CommentNode, BaseNode);
|
__extends(CommentNode, BaseNode);
|
||||||
CommentNode.prototype["class"] = 'CommentNode';
|
CommentNode.prototype["class"] = 'CommentNode';
|
||||||
CommentNode.prototype.isStatement = function() {
|
CommentNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
CommentNode.prototype.makeReturn = function() {
|
CommentNode.prototype.makeReturn = function() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
CommentNode.prototype.compileNode = function(o) {
|
CommentNode.prototype.compileNode = function(o) {
|
||||||
return this.tab + '/*' + this.comment.replace(/\r?\n/g, '\n' + this.tab) + '*/';
|
return this.tab + '/*' + this.comment.replace(/\n/g, '\n' + this.tab) + '*/';
|
||||||
};
|
};
|
||||||
return CommentNode;
|
return CommentNode;
|
||||||
})();
|
})();
|
||||||
|
@ -551,7 +539,7 @@
|
||||||
var _i, _len, _ref2, a, b, c, mentionsArgs, meth, obj, temp;
|
var _i, _len, _ref2, a, b, c, mentionsArgs, meth, obj, temp;
|
||||||
meth = this.meth || this.superReference(o);
|
meth = this.meth || this.superReference(o);
|
||||||
obj = this.variable && this.variable.source || 'this';
|
obj = this.variable && this.variable.source || 'this';
|
||||||
if (obj.match(/\(/)) {
|
if (!(IDENTIFIER.test(obj) || NUMBER.test(obj))) {
|
||||||
temp = o.scope.freeVariable('ref');
|
temp = o.scope.freeVariable('ref');
|
||||||
obj = temp;
|
obj = temp;
|
||||||
meth = ("(" + (temp) + " = " + (this.variable.source) + ")" + (this.variable.last));
|
meth = ("(" + (temp) + " = " + (this.variable.source) + ")" + (this.variable.last));
|
||||||
|
@ -573,7 +561,7 @@
|
||||||
c = o.scope.freeVariable('result');
|
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);
|
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 {
|
} else {
|
||||||
return "" + (this.first) + (this.prefix()) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")" + (this.last);
|
return "" + (this.first) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")" + (this.last);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return CallNode;
|
return CallNode;
|
||||||
|
@ -613,6 +601,7 @@
|
||||||
namePart = name.match(IS_STRING) ? ("[" + (name) + "]") : ("." + (name));
|
namePart = name.match(IS_STRING) ? ("[" + (name) + "]") : ("." + (name));
|
||||||
return this.prototype + namePart;
|
return this.prototype + namePart;
|
||||||
};
|
};
|
||||||
|
AccessorNode.prototype.isComplex = NO;
|
||||||
return AccessorNode;
|
return AccessorNode;
|
||||||
})();
|
})();
|
||||||
exports.IndexNode = (function() {
|
exports.IndexNode = (function() {
|
||||||
|
@ -631,6 +620,9 @@
|
||||||
prefix = this.proto ? '.prototype' : '';
|
prefix = this.proto ? '.prototype' : '';
|
||||||
return "" + (prefix) + "[" + (idx) + "]";
|
return "" + (prefix) + "[" + (idx) + "]";
|
||||||
};
|
};
|
||||||
|
IndexNode.prototype.isComplex = function() {
|
||||||
|
return this.index.isComplex();
|
||||||
|
};
|
||||||
return IndexNode;
|
return IndexNode;
|
||||||
})();
|
})();
|
||||||
exports.RangeNode = (function() {
|
exports.RangeNode = (function() {
|
||||||
|
@ -691,7 +683,7 @@
|
||||||
};
|
};
|
||||||
RangeNode.prototype.compileSimple = function(o) {
|
RangeNode.prototype.compileSimple = function(o) {
|
||||||
var _ref2, from, idx, step, to;
|
var _ref2, from, idx, step, to;
|
||||||
_ref2 = [parseInt(this.fromNum, 10), parseInt(this.toNum, 10)];
|
_ref2 = [+this.fromNum, +this.toNum];
|
||||||
from = _ref2[0];
|
from = _ref2[0];
|
||||||
to = _ref2[1];
|
to = _ref2[1];
|
||||||
idx = del(o, 'index');
|
idx = del(o, 'index');
|
||||||
|
@ -700,15 +692,15 @@
|
||||||
return from <= to ? ("" + (idx) + " = " + (from) + "; " + (idx) + " <" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "++"))) : ("" + (idx) + " = " + (from) + "; " + (idx) + " >" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "--")));
|
return from <= to ? ("" + (idx) + " = " + (from) + "; " + (idx) + " <" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "++"))) : ("" + (idx) + " = " + (from) + "; " + (idx) + " >" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "--")));
|
||||||
};
|
};
|
||||||
RangeNode.prototype.compileArray = function(o) {
|
RangeNode.prototype.compileArray = function(o) {
|
||||||
var _i, _result, body, clause, i, idt, post, pre, range, result, vars;
|
var _i, _ref2, _ref3, _result, body, clause, i, idt, post, pre, range, result, vars;
|
||||||
idt = this.idt(1);
|
idt = this.idt(1);
|
||||||
vars = this.compileVariables(merge(o, {
|
vars = this.compileVariables(merge(o, {
|
||||||
indent: idt
|
indent: idt
|
||||||
}));
|
}));
|
||||||
if (this.fromNum && this.toNum && (Math.abs(+this.fromNum - +this.toNum) <= 20)) {
|
if (this.fromNum && this.toNum && (Math.abs(+this.fromNum - +this.toNum) <= 20)) {
|
||||||
range = (function() {
|
range = (function() {
|
||||||
_result = [];
|
_result = []; _ref2 = +this.fromNum; _ref3 = +this.toNum;
|
||||||
for (var _i = +this.fromNum; +this.fromNum <= +this.toNum ? _i <= +this.toNum : _i >= +this.toNum; +this.fromNum <= +this.toNum ? _i += 1 : _i -= 1){ _result.push(_i); }
|
for (var _i = _ref2; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i += 1 : _i -= 1){ _result.push(_i); }
|
||||||
return _result;
|
return _result;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
if (this.exclusive) {
|
if (this.exclusive) {
|
||||||
|
@ -761,9 +753,7 @@
|
||||||
__extends(ObjectNode, BaseNode);
|
__extends(ObjectNode, BaseNode);
|
||||||
ObjectNode.prototype["class"] = 'ObjectNode';
|
ObjectNode.prototype["class"] = 'ObjectNode';
|
||||||
ObjectNode.prototype.children = ['properties'];
|
ObjectNode.prototype.children = ['properties'];
|
||||||
ObjectNode.prototype.topSensitive = function() {
|
ObjectNode.prototype.topSensitive = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ObjectNode.prototype.compileNode = function(o) {
|
ObjectNode.prototype.compileNode = function(o) {
|
||||||
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
||||||
top = del(o, 'top');
|
top = del(o, 'top');
|
||||||
|
@ -855,9 +845,7 @@
|
||||||
__extends(ClassNode, BaseNode);
|
__extends(ClassNode, BaseNode);
|
||||||
ClassNode.prototype["class"] = 'ClassNode';
|
ClassNode.prototype["class"] = 'ClassNode';
|
||||||
ClassNode.prototype.children = ['variable', 'parent', 'properties'];
|
ClassNode.prototype.children = ['variable', 'parent', 'properties'];
|
||||||
ClassNode.prototype.isStatement = function() {
|
ClassNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ClassNode.prototype.makeReturn = function() {
|
ClassNode.prototype.makeReturn = function() {
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
return this;
|
||||||
|
@ -940,12 +928,10 @@
|
||||||
};
|
};
|
||||||
__extends(AssignNode, BaseNode);
|
__extends(AssignNode, BaseNode);
|
||||||
AssignNode.prototype.PROTO_ASSIGN = /^(\S+)\.prototype/;
|
AssignNode.prototype.PROTO_ASSIGN = /^(\S+)\.prototype/;
|
||||||
AssignNode.prototype.LEADING_DOT = /^\.(prototype\.)?/;
|
AssignNode.prototype.LEADING_DOT = /^\.(?:prototype\.)?/;
|
||||||
AssignNode.prototype["class"] = 'AssignNode';
|
AssignNode.prototype["class"] = 'AssignNode';
|
||||||
AssignNode.prototype.children = ['variable', 'value'];
|
AssignNode.prototype.children = ['variable', 'value'];
|
||||||
AssignNode.prototype.topSensitive = function() {
|
AssignNode.prototype.topSensitive = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
AssignNode.prototype.isValue = function() {
|
AssignNode.prototype.isValue = function() {
|
||||||
return this.variable instanceof ValueNode;
|
return this.variable instanceof ValueNode;
|
||||||
};
|
};
|
||||||
|
@ -1045,7 +1031,7 @@
|
||||||
from = range.from ? range.from.compile(o) : '0';
|
from = range.from ? range.from.compile(o) : '0';
|
||||||
to = range.to ? range.to.compile(o) + ' - ' + from + plus : ("" + (name) + ".length");
|
to = range.to ? range.to.compile(o) + ' - ' + from + plus : ("" + (name) + ".length");
|
||||||
val = this.value.compile(o);
|
val = this.value.compile(o);
|
||||||
return "" + (name) + ".splice.apply(" + (name) + ", [" + (from) + ", " + (to) + "].concat(" + (val) + "))";
|
return "[].splice.apply(" + (name) + ", [" + (from) + ", " + (to) + "].concat(" + (val) + "))";
|
||||||
};
|
};
|
||||||
return AssignNode;
|
return AssignNode;
|
||||||
})();
|
})();
|
||||||
|
@ -1222,10 +1208,10 @@
|
||||||
prev = args[(last = args.length - 1)];
|
prev = args[(last = args.length - 1)];
|
||||||
if (!(arg instanceof SplatNode)) {
|
if (!(arg instanceof SplatNode)) {
|
||||||
if (prev && starts(prev, '[') && ends(prev, ']')) {
|
if (prev && starts(prev, '[') && ends(prev, ']')) {
|
||||||
args[last] = ("" + (prev.substr(0, prev.length - 1)) + ", " + (code) + "]");
|
args[last] = ("" + (prev.slice(0, -1)) + ", " + (code) + "]");
|
||||||
continue;
|
continue;
|
||||||
} else if (prev && starts(prev, '.concat([') && ends(prev, '])')) {
|
} else if (prev && starts(prev, '.concat([') && ends(prev, '])')) {
|
||||||
args[last] = ("" + (prev.substr(0, prev.length - 2)) + ", " + (code) + "])");
|
args[last] = ("" + (prev.slice(0, -2)) + ", " + (code) + "])");
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
code = ("[" + (code) + "]");
|
code = ("[" + (code) + "]");
|
||||||
|
@ -1253,9 +1239,7 @@
|
||||||
__extends(WhileNode, BaseNode);
|
__extends(WhileNode, BaseNode);
|
||||||
WhileNode.prototype["class"] = 'WhileNode';
|
WhileNode.prototype["class"] = 'WhileNode';
|
||||||
WhileNode.prototype.children = ['condition', 'guard', 'body'];
|
WhileNode.prototype.children = ['condition', 'guard', 'body'];
|
||||||
WhileNode.prototype.isStatement = function() {
|
WhileNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
WhileNode.prototype.addBody = function(body) {
|
WhileNode.prototype.addBody = function(body) {
|
||||||
this.body = body;
|
this.body = body;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1335,6 +1319,9 @@
|
||||||
var _ref2;
|
var _ref2;
|
||||||
return (('===' === (_ref2 = this.operator) || '!==' === _ref2)) && !(this.first instanceof OpNode) && !(this.second instanceof OpNode);
|
return (('===' === (_ref2 = this.operator) || '!==' === _ref2)) && !(this.first instanceof OpNode) && !(this.second instanceof OpNode);
|
||||||
};
|
};
|
||||||
|
OpNode.prototype.isComplex = function() {
|
||||||
|
return this.operator !== '!' || this.first.isComplex();
|
||||||
|
};
|
||||||
OpNode.prototype.isMutator = function() {
|
OpNode.prototype.isMutator = function() {
|
||||||
var _ref2;
|
var _ref2;
|
||||||
return ends(this.operator, '=') && !(('===' === (_ref2 = this.operator) || '!==' === _ref2));
|
return ends(this.operator, '=') && !(('===' === (_ref2 = this.operator) || '!==' === _ref2));
|
||||||
|
@ -1372,11 +1359,9 @@
|
||||||
OpNode.prototype.compileChain = function(o) {
|
OpNode.prototype.compileChain = function(o) {
|
||||||
var _ref2, first, second, shared;
|
var _ref2, first, second, shared;
|
||||||
shared = this.first.unwrap().second;
|
shared = this.first.unwrap().second;
|
||||||
if (shared.containsType(CallNode)) {
|
_ref2 = shared.compileReference(o);
|
||||||
_ref2 = shared.compileReference(o);
|
this.first.second = _ref2[0];
|
||||||
this.first.second = _ref2[0];
|
shared = _ref2[1];
|
||||||
shared = _ref2[1];
|
|
||||||
}
|
|
||||||
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)];
|
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)];
|
||||||
first = _ref2[0];
|
first = _ref2[0];
|
||||||
second = _ref2[1];
|
second = _ref2[1];
|
||||||
|
@ -1482,9 +1467,7 @@
|
||||||
__extends(TryNode, BaseNode);
|
__extends(TryNode, BaseNode);
|
||||||
TryNode.prototype["class"] = 'TryNode';
|
TryNode.prototype["class"] = 'TryNode';
|
||||||
TryNode.prototype.children = ['attempt', 'recovery', 'ensure'];
|
TryNode.prototype.children = ['attempt', 'recovery', 'ensure'];
|
||||||
TryNode.prototype.isStatement = function() {
|
TryNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
TryNode.prototype.makeReturn = function() {
|
TryNode.prototype.makeReturn = function() {
|
||||||
if (this.attempt) {
|
if (this.attempt) {
|
||||||
this.attempt = this.attempt.makeReturn();
|
this.attempt = this.attempt.makeReturn();
|
||||||
|
@ -1515,9 +1498,7 @@
|
||||||
__extends(ThrowNode, BaseNode);
|
__extends(ThrowNode, BaseNode);
|
||||||
ThrowNode.prototype["class"] = 'ThrowNode';
|
ThrowNode.prototype["class"] = 'ThrowNode';
|
||||||
ThrowNode.prototype.children = ['expression'];
|
ThrowNode.prototype.children = ['expression'];
|
||||||
ThrowNode.prototype.isStatement = function() {
|
ThrowNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ThrowNode.prototype.makeReturn = function() {
|
ThrowNode.prototype.makeReturn = function() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -1563,12 +1544,13 @@
|
||||||
ParentheticalNode.prototype.isStatement = function(o) {
|
ParentheticalNode.prototype.isStatement = function(o) {
|
||||||
return this.expression.isStatement(o);
|
return this.expression.isStatement(o);
|
||||||
};
|
};
|
||||||
|
ParentheticalNode.prototype.isComplex = function() {
|
||||||
|
return this.expression.isComplex();
|
||||||
|
};
|
||||||
|
ParentheticalNode.prototype.topSensitive = YES;
|
||||||
ParentheticalNode.prototype.makeReturn = function() {
|
ParentheticalNode.prototype.makeReturn = function() {
|
||||||
return this.expression.makeReturn();
|
return this.expression.makeReturn();
|
||||||
};
|
};
|
||||||
ParentheticalNode.prototype.topSensitive = function() {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ParentheticalNode.prototype.compileNode = function(o) {
|
ParentheticalNode.prototype.compileNode = function(o) {
|
||||||
var code, top;
|
var code, top;
|
||||||
top = del(o, 'top');
|
top = del(o, 'top');
|
||||||
|
@ -1612,12 +1594,8 @@
|
||||||
__extends(ForNode, BaseNode);
|
__extends(ForNode, BaseNode);
|
||||||
ForNode.prototype["class"] = 'ForNode';
|
ForNode.prototype["class"] = 'ForNode';
|
||||||
ForNode.prototype.children = ['body', 'source', 'guard'];
|
ForNode.prototype.children = ['body', 'source', 'guard'];
|
||||||
ForNode.prototype.isStatement = function() {
|
ForNode.prototype.isStatement = YES;
|
||||||
return true;
|
ForNode.prototype.topSensitive = YES;
|
||||||
};
|
|
||||||
ForNode.prototype.topSensitive = function() {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ForNode.prototype.makeReturn = function() {
|
ForNode.prototype.makeReturn = function() {
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1739,9 +1717,7 @@
|
||||||
__extends(SwitchNode, BaseNode);
|
__extends(SwitchNode, BaseNode);
|
||||||
SwitchNode.prototype["class"] = 'SwitchNode';
|
SwitchNode.prototype["class"] = 'SwitchNode';
|
||||||
SwitchNode.prototype.children = ['subject', 'cases', 'otherwise'];
|
SwitchNode.prototype.children = ['subject', 'cases', 'otherwise'];
|
||||||
SwitchNode.prototype.isStatement = function() {
|
SwitchNode.prototype.isStatement = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
SwitchNode.prototype.makeReturn = function() {
|
SwitchNode.prototype.makeReturn = function() {
|
||||||
var _i, _len, _ref2, pair;
|
var _i, _len, _ref2, pair;
|
||||||
_ref2 = this.cases;
|
_ref2 = this.cases;
|
||||||
|
@ -1807,9 +1783,7 @@
|
||||||
__extends(IfNode, BaseNode);
|
__extends(IfNode, BaseNode);
|
||||||
IfNode.prototype["class"] = 'IfNode';
|
IfNode.prototype["class"] = 'IfNode';
|
||||||
IfNode.prototype.children = ['condition', 'body', 'elseBody', 'assigner'];
|
IfNode.prototype.children = ['condition', 'body', 'elseBody', 'assigner'];
|
||||||
IfNode.prototype.topSensitive = function() {
|
IfNode.prototype.topSensitive = YES;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
IfNode.prototype.bodyNode = function() {
|
IfNode.prototype.bodyNode = function() {
|
||||||
return this.body == null ? undefined : this.body.unwrap();
|
return this.body == null ? undefined : this.body.unwrap();
|
||||||
};
|
};
|
||||||
|
@ -1935,8 +1909,8 @@
|
||||||
};
|
};
|
||||||
TAB = ' ';
|
TAB = ' ';
|
||||||
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
||||||
IDENTIFIER = /^[a-zA-Z\$_](\w|\$)*$/;
|
IDENTIFIER = /^[$A-Za-zA-Z_][$\w]*$/;
|
||||||
NUMBER = /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b$/i;
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
||||||
SIMPLENUM = /^-?\d+$/;
|
SIMPLENUM = /^-?\d+$/;
|
||||||
IS_STRING = /^['"]/;
|
IS_STRING = /^['"]/;
|
||||||
literal = function(name) {
|
literal = function(name) {
|
||||||
|
|
|
@ -66,14 +66,14 @@
|
||||||
after = _ref2[3];
|
after = _ref2[3];
|
||||||
if (after && after[0] === 'INDENT') {
|
if (after && after[0] === 'INDENT') {
|
||||||
this.tokens.splice(i + 2, 1);
|
this.tokens.splice(i + 2, 1);
|
||||||
if (before && before[0] === 'OUTDENT' && post && (prev[0] === post[0]) && (post[0] === 'TERMINATOR')) {
|
if (before && before[0] === 'OUTDENT' && post && (prev[0] === (_ref2 = post[0])) && (_ref2 === 'TERMINATOR')) {
|
||||||
this.tokens.splice(i - 2, 1);
|
this.tokens.splice(i - 2, 1);
|
||||||
} else {
|
} else {
|
||||||
this.tokens.splice(i, 0, after);
|
this.tokens.splice(i, 0, after);
|
||||||
}
|
}
|
||||||
} else if (prev && !('TERMINATOR' === (_ref2 = prev[0]) || 'INDENT' === _ref2 || 'OUTDENT' === _ref2)) {
|
} else if (prev && !('TERMINATOR' === (_ref2 = prev[0]) || 'INDENT' === _ref2 || 'OUTDENT' === _ref2)) {
|
||||||
if (post && post[0] === 'TERMINATOR' && after && after[0] === 'OUTDENT') {
|
if (post && post[0] === 'TERMINATOR' && after && after[0] === 'OUTDENT') {
|
||||||
this.tokens.splice.apply(this.tokens, [i + 2, 0].concat(this.tokens.splice(i, 2)));
|
(_ref2 = this.tokens).splice.apply(_ref2, [i + 2, 0].concat(this.tokens.splice(i, 2)));
|
||||||
if (this.tokens[i + 2][0] !== 'TERMINATOR') {
|
if (this.tokens[i + 2][0] !== 'TERMINATOR') {
|
||||||
this.tokens.splice(i + 2, 0, ['TERMINATOR', "\n", prev[2]]);
|
this.tokens.splice(i + 2, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||||
}
|
}
|
||||||
|
@ -229,11 +229,11 @@
|
||||||
return this.scanTokens(function(token, i) {
|
return this.scanTokens(function(token, i) {
|
||||||
var _ref2, action, condition, indent, outdent, starter;
|
var _ref2, action, condition, indent, outdent, starter;
|
||||||
if (token[0] === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
if (token[0] === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||||
this.tokens.splice.apply(this.tokens, [i, 0].concat(this.indentation(token)));
|
(_ref2 = this.tokens).splice.apply(_ref2, [i, 0].concat(this.indentation(token)));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (token[0] === 'CATCH' && (this.tag(i + 2) === 'TERMINATOR' || this.tag(i + 2) === 'FINALLY')) {
|
if (token[0] === 'CATCH' && (this.tag(i + 2) === 'TERMINATOR' || this.tag(i + 2) === 'FINALLY')) {
|
||||||
this.tokens.splice.apply(this.tokens, [i + 2, 0].concat(this.indentation(token)));
|
(_ref2 = this.tokens).splice.apply(_ref2, [i + 2, 0].concat(this.indentation(token)));
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (include(SINGLE_LINERS, token[0]) && this.tag(i + 1) !== 'INDENT' && !(token[0] === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
if (include(SINGLE_LINERS, token[0]) && this.tag(i + 1) !== 'INDENT' && !(token[0] === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||||
|
@ -337,7 +337,7 @@
|
||||||
(debt[key] = 0);
|
(debt[key] = 0);
|
||||||
}
|
}
|
||||||
return this.scanTokens(function(token, i) {
|
return this.scanTokens(function(token, i) {
|
||||||
var inv, match, mtag, oppos, tag;
|
var _ref3, inv, match, mtag, oppos, tag;
|
||||||
tag = token[0];
|
tag = token[0];
|
||||||
inv = INVERSES[token[0]];
|
inv = INVERSES[token[0]];
|
||||||
if (include(EXPRESSION_START, tag)) {
|
if (include(EXPRESSION_START, tag)) {
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
}
|
}
|
||||||
debt[mtag] += 1;
|
debt[mtag] += 1;
|
||||||
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
||||||
if ((this.tokens[i + 2] == null ? undefined : this.tokens[i + 2][0]) === mtag) {
|
if ((this.tokens[(_ref3 = i + 2)] == null ? undefined : this.tokens[_ref3][0]) === mtag) {
|
||||||
this.tokens.splice(i + 3, 0, val);
|
this.tokens.splice(i + 3, 0, val);
|
||||||
stack.push(match);
|
stack.push(match);
|
||||||
} else {
|
} else {
|
||||||
|
|
118
src/nodes.coffee
118
src/nodes.coffee
|
@ -8,6 +8,9 @@
|
||||||
# Import the helpers we plan to use.
|
# Import the helpers we plan to use.
|
||||||
{compact, flatten, merge, del, include, indexOf, starts, ends} = require './helpers'
|
{compact, flatten, merge, del, include, indexOf, starts, ends} = require './helpers'
|
||||||
|
|
||||||
|
YES = -> yes
|
||||||
|
NO = -> no
|
||||||
|
|
||||||
#### BaseNode
|
#### BaseNode
|
||||||
|
|
||||||
# The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
# The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
||||||
|
@ -59,8 +62,7 @@ exports.BaseNode = class BaseNode
|
||||||
# by assigning it to a temporary variable.
|
# by assigning it to a temporary variable.
|
||||||
compileReference: (o, options) ->
|
compileReference: (o, options) ->
|
||||||
options or= {}
|
options or= {}
|
||||||
pair = if not (@containsType(CallNode) or
|
pair = unless @isComplex()
|
||||||
(this instanceof ValueNode and (not (@base instanceof LiteralNode) or @hasProperties())))
|
|
||||||
[this, this]
|
[this, this]
|
||||||
else if this instanceof ValueNode and options.assignment
|
else if this instanceof ValueNode and options.assignment
|
||||||
this.cacheIndexes(o)
|
this.cacheIndexes(o)
|
||||||
|
@ -137,9 +139,10 @@ exports.BaseNode = class BaseNode
|
||||||
children: []
|
children: []
|
||||||
|
|
||||||
unwrap : -> this
|
unwrap : -> this
|
||||||
isStatement : -> no
|
isStatement : NO
|
||||||
isPureStatement : -> no
|
isPureStatement : NO
|
||||||
topSensitive : -> no
|
isComplex : YES
|
||||||
|
topSensitive : NO
|
||||||
|
|
||||||
#### Expressions
|
#### Expressions
|
||||||
|
|
||||||
|
@ -150,7 +153,7 @@ exports.Expressions = class Expressions extends BaseNode
|
||||||
|
|
||||||
class: 'Expressions'
|
class: 'Expressions'
|
||||||
children: ['expressions']
|
children: ['expressions']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (nodes) ->
|
constructor: (nodes) ->
|
||||||
super()
|
super()
|
||||||
|
@ -247,6 +250,8 @@ exports.LiteralNode = class LiteralNode extends BaseNode
|
||||||
@value is 'break' or @value is 'continue' or @value is 'debugger'
|
@value is 'break' or @value is 'continue' or @value is 'debugger'
|
||||||
isPureStatement: LiteralNode::isStatement
|
isPureStatement: LiteralNode::isStatement
|
||||||
|
|
||||||
|
isComplex: NO
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
idt = if @isStatement(o) then @idt() else ''
|
idt = if @isStatement(o) then @idt() else ''
|
||||||
end = if @isStatement(o) then ';' else ''
|
end = if @isStatement(o) then ';' else ''
|
||||||
|
@ -261,8 +266,8 @@ exports.LiteralNode = class LiteralNode extends BaseNode
|
||||||
exports.ReturnNode = class ReturnNode extends BaseNode
|
exports.ReturnNode = class ReturnNode extends BaseNode
|
||||||
|
|
||||||
class: 'ReturnNode'
|
class: 'ReturnNode'
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
isPureStatement: -> yes
|
isPureStatement: YES
|
||||||
children: ['expression']
|
children: ['expression']
|
||||||
|
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
|
@ -313,6 +318,9 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||||
isSplice: ->
|
isSplice: ->
|
||||||
@hasProperties() and @properties[@properties.length - 1] instanceof SliceNode
|
@hasProperties() and @properties[@properties.length - 1] instanceof SliceNode
|
||||||
|
|
||||||
|
isComplex: ->
|
||||||
|
@base.isComplex() or @properties.length
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
if @hasProperties() then super() else @base.makeReturn()
|
if @hasProperties() then super() else @base.makeReturn()
|
||||||
|
|
||||||
|
@ -333,10 +341,10 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||||
# the value of the indexes.
|
# the value of the indexes.
|
||||||
cacheIndexes: (o) ->
|
cacheIndexes: (o) ->
|
||||||
copy = new ValueNode @base, @properties[0..]
|
copy = new ValueNode @base, @properties[0..]
|
||||||
if @base instanceof CallNode
|
if @base.isComplex()
|
||||||
[@base, copy.base] = @base.compileReference o
|
[@base, copy.base] = @base.compileReference o
|
||||||
for prop, i in copy.properties
|
for prop, i in copy.properties
|
||||||
if prop instanceof IndexNode and prop.contains((n) -> n instanceof CallNode)
|
if prop instanceof IndexNode and prop.index.isComplex()
|
||||||
[index, indexVar] = prop.index.compileReference o
|
[index, indexVar] = prop.index.compileReference o
|
||||||
this.properties[i] = new IndexNode index
|
this.properties[i] = new IndexNode index
|
||||||
copy.properties[i] = new IndexNode indexVar
|
copy.properties[i] = new IndexNode indexVar
|
||||||
|
@ -353,11 +361,12 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
only = del o, 'onlyFirst'
|
only = del o, 'onlyFirst'
|
||||||
op = @tags.operation
|
op = @tags.operation
|
||||||
props = if only then @properties[0...@properties.length - 1] else @properties
|
props = if only then @properties[0...-1] else @properties
|
||||||
o.chainRoot or= this
|
o.chainRoot or= this
|
||||||
for prop in props
|
for prop in props when prop.soakNode
|
||||||
hasSoak = yes if prop.soakNode
|
hasSoak = yes
|
||||||
if hasSoak and @containsType CallNode
|
break
|
||||||
|
if hasSoak and @isComplex()
|
||||||
[me, copy] = @cacheIndexes o
|
[me, copy] = @cacheIndexes o
|
||||||
@base.parenthetical = yes if @parenthetical and not props.length
|
@base.parenthetical = yes if @parenthetical and not props.length
|
||||||
baseline = @base.compile o
|
baseline = @base.compile o
|
||||||
|
@ -367,20 +376,20 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||||
for prop, i in props
|
for prop, i in props
|
||||||
@source = baseline
|
@source = baseline
|
||||||
if prop.soakNode
|
if prop.soakNode
|
||||||
if @base.containsType(CallNode) and i is 0
|
if i is 0 and @base.isComplex()
|
||||||
temp = o.scope.freeVariable 'ref'
|
temp = o.scope.freeVariable 'ref'
|
||||||
complete = "(#{ baseline = temp } = (#{complete}))"
|
complete = "(#{ baseline = temp } = (#{prevcomp = complete}))"
|
||||||
complete = if i is 0
|
complete = if i is 0 and not o.scope.check complete
|
||||||
"(typeof #{complete} === \"undefined\" || #{baseline} === null) ? undefined : "
|
"(typeof #{complete} === \"undefined\" || #{baseline} === null)"
|
||||||
else
|
else
|
||||||
"#{complete} == null ? undefined : "
|
"#{complete} == null"
|
||||||
complete += (baseline += prop.compile(o))
|
complete += ' ? undefined : ' + baseline += prop.compile o
|
||||||
else
|
else
|
||||||
part = prop.compile(o)
|
part = prop.compile(o)
|
||||||
if hasSoak and prop.containsType CallNode
|
baseline += if hasSoak and prop.isComplex()
|
||||||
baseline += copy.properties[i].compile o
|
copy.properties[i].compile o
|
||||||
else
|
else
|
||||||
baseline += part
|
part
|
||||||
complete += part
|
complete += part
|
||||||
@last = part
|
@last = part
|
||||||
|
|
||||||
|
@ -393,7 +402,7 @@ exports.ValueNode = class ValueNode extends BaseNode
|
||||||
exports.CommentNode = class CommentNode extends BaseNode
|
exports.CommentNode = class CommentNode extends BaseNode
|
||||||
|
|
||||||
class: 'CommentNode'
|
class: 'CommentNode'
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@comment) ->
|
constructor: (@comment) ->
|
||||||
super()
|
super()
|
||||||
|
@ -402,7 +411,7 @@ exports.CommentNode = class CommentNode extends BaseNode
|
||||||
this
|
this
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
@tab + '/*' + @comment.replace(/\r?\n/g, '\n' + @tab) + '*/'
|
@tab + '/*' + @comment.replace(/\n/g, '\n' + @tab) + '*/'
|
||||||
|
|
||||||
#### CallNode
|
#### CallNode
|
||||||
|
|
||||||
|
@ -481,7 +490,7 @@ exports.CallNode = class CallNode extends BaseNode
|
||||||
compileSplat: (o) ->
|
compileSplat: (o) ->
|
||||||
meth = @meth or @superReference(o)
|
meth = @meth or @superReference(o)
|
||||||
obj = @variable and @variable.source or 'this'
|
obj = @variable and @variable.source or 'this'
|
||||||
if obj.match(/\(/)
|
unless IDENTIFIER.test(obj) or NUMBER.test(obj)
|
||||||
temp = o.scope.freeVariable 'ref'
|
temp = o.scope.freeVariable 'ref'
|
||||||
obj = temp
|
obj = temp
|
||||||
meth = "(#{temp} = #{ @variable.source })#{ @variable.last }"
|
meth = "(#{temp} = #{ @variable.source })#{ @variable.last }"
|
||||||
|
@ -501,7 +510,7 @@ exports.CallNode = class CallNode extends BaseNode
|
||||||
#{@tab}}).#{ if mentionsArgs then 'apply(this, arguments)' else 'call(this)'}#{@last}
|
#{@tab}}).#{ if mentionsArgs then 'apply(this, arguments)' else 'call(this)'}#{@last}
|
||||||
"""
|
"""
|
||||||
else
|
else
|
||||||
"#{@first}#{@prefix()}#{meth}.apply(#{obj}, #{ @compileSplatArguments(o) })#{@last}"
|
"#{@first}#{meth}.apply(#{obj}, #{ @compileSplatArguments(o) })#{@last}"
|
||||||
|
|
||||||
#### ExtendsNode
|
#### ExtendsNode
|
||||||
|
|
||||||
|
@ -541,6 +550,8 @@ exports.AccessorNode = class AccessorNode extends BaseNode
|
||||||
namePart = if name.match(IS_STRING) then "[#{name}]" else ".#{name}"
|
namePart = if name.match(IS_STRING) then "[#{name}]" else ".#{name}"
|
||||||
@prototype + namePart
|
@prototype + namePart
|
||||||
|
|
||||||
|
isComplex: NO
|
||||||
|
|
||||||
#### IndexNode
|
#### IndexNode
|
||||||
|
|
||||||
# A `[ ... ]` indexed accessor into an array or object.
|
# A `[ ... ]` indexed accessor into an array or object.
|
||||||
|
@ -558,6 +569,8 @@ exports.IndexNode = class IndexNode extends BaseNode
|
||||||
prefix = if @proto then '.prototype' else ''
|
prefix = if @proto then '.prototype' else ''
|
||||||
"#{prefix}[#{idx}]"
|
"#{prefix}[#{idx}]"
|
||||||
|
|
||||||
|
isComplex: -> @index.isComplex()
|
||||||
|
|
||||||
#### RangeNode
|
#### RangeNode
|
||||||
|
|
||||||
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||||
|
@ -601,7 +614,7 @@ exports.RangeNode = class RangeNode extends BaseNode
|
||||||
|
|
||||||
# Compile a simple range comprehension, with integers.
|
# Compile a simple range comprehension, with integers.
|
||||||
compileSimple: (o) ->
|
compileSimple: (o) ->
|
||||||
[from, to] = [parseInt(@fromNum, 10), parseInt(@toNum, 10)]
|
[from, to] = [+@fromNum, +@toNum]
|
||||||
idx = del o, 'index'
|
idx = del o, 'index'
|
||||||
step = del o, 'step'
|
step = del o, 'step'
|
||||||
step and= "#{idx} += #{step.compile(o)}"
|
step and= "#{idx} += #{step.compile(o)}"
|
||||||
|
@ -614,7 +627,7 @@ exports.RangeNode = class RangeNode extends BaseNode
|
||||||
compileArray: (o) ->
|
compileArray: (o) ->
|
||||||
idt = @idt 1
|
idt = @idt 1
|
||||||
vars = @compileVariables merge o, indent: idt
|
vars = @compileVariables merge o, indent: idt
|
||||||
if @fromNum and @toNum and Math.abs(+@fromNum - +@toNum) <= 20
|
if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20
|
||||||
range = [+@fromNum..+@toNum]
|
range = [+@fromNum..+@toNum]
|
||||||
range.pop() if @exclusive
|
range.pop() if @exclusive
|
||||||
return "[#{ range.join(', ') }]"
|
return "[#{ range.join(', ') }]"
|
||||||
|
@ -658,7 +671,7 @@ exports.ObjectNode = class ObjectNode extends BaseNode
|
||||||
class: 'ObjectNode'
|
class: 'ObjectNode'
|
||||||
children: ['properties']
|
children: ['properties']
|
||||||
|
|
||||||
topSensitive: -> true
|
topSensitive: YES
|
||||||
|
|
||||||
constructor: (props) ->
|
constructor: (props) ->
|
||||||
super()
|
super()
|
||||||
|
@ -720,7 +733,7 @@ exports.ClassNode = class ClassNode extends BaseNode
|
||||||
|
|
||||||
class: 'ClassNode'
|
class: 'ClassNode'
|
||||||
children: ['variable', 'parent', 'properties']
|
children: ['variable', 'parent', 'properties']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
# Initialize a **ClassNode** with its name, an optional superclass, and a
|
# Initialize a **ClassNode** with its name, an optional superclass, and a
|
||||||
# list of prototype property assignments.
|
# list of prototype property assignments.
|
||||||
|
@ -794,7 +807,7 @@ exports.AssignNode = class AssignNode extends BaseNode
|
||||||
|
|
||||||
# Matchers for detecting prototype assignments.
|
# Matchers for detecting prototype assignments.
|
||||||
PROTO_ASSIGN: /^(\S+)\.prototype/
|
PROTO_ASSIGN: /^(\S+)\.prototype/
|
||||||
LEADING_DOT: /^\.(prototype\.)?/
|
LEADING_DOT: /^\.(?:prototype\.)?/
|
||||||
|
|
||||||
class: 'AssignNode'
|
class: 'AssignNode'
|
||||||
children: ['variable', 'value']
|
children: ['variable', 'value']
|
||||||
|
@ -802,8 +815,7 @@ exports.AssignNode = class AssignNode extends BaseNode
|
||||||
constructor: (@variable, @value, @context) ->
|
constructor: (@variable, @value, @context) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
topSensitive: ->
|
topSensitive: YES
|
||||||
true
|
|
||||||
|
|
||||||
isValue: ->
|
isValue: ->
|
||||||
@variable instanceof ValueNode
|
@variable instanceof ValueNode
|
||||||
|
@ -887,7 +899,7 @@ exports.AssignNode = class AssignNode extends BaseNode
|
||||||
from = if range.from then range.from.compile(o) else '0'
|
from = if range.from then range.from.compile(o) else '0'
|
||||||
to = if range.to then range.to.compile(o) + ' - ' + from + plus else "#{name}.length"
|
to = if range.to then range.to.compile(o) + ' - ' + from + plus else "#{name}.length"
|
||||||
val = @value.compile(o)
|
val = @value.compile(o)
|
||||||
"#{name}.splice.apply(#{name}, [#{from}, #{to}].concat(#{val}))"
|
"[].splice.apply(#{name}, [#{from}, #{to}].concat(#{val}))"
|
||||||
|
|
||||||
#### CodeNode
|
#### CodeNode
|
||||||
|
|
||||||
|
@ -1032,10 +1044,10 @@ exports.SplatNode = class SplatNode extends BaseNode
|
||||||
prev = args[last = args.length - 1]
|
prev = args[last = args.length - 1]
|
||||||
if arg not instanceof SplatNode
|
if arg not instanceof SplatNode
|
||||||
if prev and starts(prev, '[') and ends(prev, ']')
|
if prev and starts(prev, '[') and ends(prev, ']')
|
||||||
args[last] = "#{prev.substr(0, prev.length - 1)}, #{code}]"
|
args[last] = "#{prev.slice 0, -1}, #{code}]"
|
||||||
continue
|
continue
|
||||||
else if prev and starts(prev, '.concat([') and ends(prev, '])')
|
else if prev and starts(prev, '.concat([') and ends(prev, '])')
|
||||||
args[last] = "#{prev.substr(0, prev.length - 2)}, #{code}])"
|
args[last] = "#{prev.slice 0, -2}, #{code}])"
|
||||||
continue
|
continue
|
||||||
else
|
else
|
||||||
code = "[#{code}]"
|
code = "[#{code}]"
|
||||||
|
@ -1051,7 +1063,7 @@ exports.WhileNode = class WhileNode extends BaseNode
|
||||||
|
|
||||||
class: 'WhileNode'
|
class: 'WhileNode'
|
||||||
children: ['condition', 'guard', 'body']
|
children: ['condition', 'guard', 'body']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (condition, opts) ->
|
constructor: (condition, opts) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1139,6 +1151,7 @@ exports.OpNode = class OpNode extends BaseNode
|
||||||
(@operator in ['===', '!==']) and
|
(@operator in ['===', '!==']) and
|
||||||
not (@first instanceof OpNode) and not (@second instanceof OpNode)
|
not (@first instanceof OpNode) and not (@second instanceof OpNode)
|
||||||
|
|
||||||
|
isComplex: -> @operator isnt '!' or @first.isComplex()
|
||||||
|
|
||||||
isMutator: ->
|
isMutator: ->
|
||||||
ends(@operator, '=') and not (@operator in ['===', '!=='])
|
ends(@operator, '=') and not (@operator in ['===', '!=='])
|
||||||
|
@ -1168,7 +1181,7 @@ exports.OpNode = class OpNode extends BaseNode
|
||||||
# true
|
# true
|
||||||
compileChain: (o) ->
|
compileChain: (o) ->
|
||||||
shared = @first.unwrap().second
|
shared = @first.unwrap().second
|
||||||
[@first.second, shared] = shared.compileReference(o) if shared.containsType CallNode
|
[@first.second, shared] = shared.compileReference o
|
||||||
[first, second, shared] = [@first.compile(o), @second.compile(o), shared.compile(o)]
|
[first, second, shared] = [@first.compile(o), @second.compile(o), shared.compile(o)]
|
||||||
"(#{first}) && (#{shared} #{@operator} #{second})"
|
"(#{first}) && (#{shared} #{@operator} #{second})"
|
||||||
|
|
||||||
|
@ -1230,7 +1243,7 @@ exports.TryNode = class TryNode extends BaseNode
|
||||||
|
|
||||||
class: 'TryNode'
|
class: 'TryNode'
|
||||||
children: ['attempt', 'recovery', 'ensure']
|
children: ['attempt', 'recovery', 'ensure']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@attempt, @error, @recovery, @ensure) ->
|
constructor: (@attempt, @error, @recovery, @ensure) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1258,7 +1271,7 @@ exports.ThrowNode = class ThrowNode extends BaseNode
|
||||||
|
|
||||||
class: 'ThrowNode'
|
class: 'ThrowNode'
|
||||||
children: ['expression']
|
children: ['expression']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1311,13 +1324,14 @@ exports.ParentheticalNode = class ParentheticalNode extends BaseNode
|
||||||
|
|
||||||
isStatement: (o) ->
|
isStatement: (o) ->
|
||||||
@expression.isStatement(o)
|
@expression.isStatement(o)
|
||||||
|
isComplex: ->
|
||||||
|
@expression.isComplex()
|
||||||
|
|
||||||
|
topSensitive: YES
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@expression.makeReturn()
|
@expression.makeReturn()
|
||||||
|
|
||||||
topSensitive: ->
|
|
||||||
yes
|
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
top = del o, 'top'
|
top = del o, 'top'
|
||||||
@expression.parenthetical = true
|
@expression.parenthetical = true
|
||||||
|
@ -1340,7 +1354,7 @@ exports.ForNode = class ForNode extends BaseNode
|
||||||
|
|
||||||
class: 'ForNode'
|
class: 'ForNode'
|
||||||
children: ['body', 'source', 'guard']
|
children: ['body', 'source', 'guard']
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@body, source, @name, @index) ->
|
constructor: (@body, source, @name, @index) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1355,8 +1369,7 @@ exports.ForNode = class ForNode extends BaseNode
|
||||||
throw new Error('index cannot be a pattern matching expression') if @index instanceof ValueNode
|
throw new Error('index cannot be a pattern matching expression') if @index instanceof ValueNode
|
||||||
@returns = false
|
@returns = false
|
||||||
|
|
||||||
topSensitive: ->
|
topSensitive: YES
|
||||||
true
|
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@returns = true
|
@returns = true
|
||||||
|
@ -1430,7 +1443,7 @@ exports.SwitchNode = class SwitchNode extends BaseNode
|
||||||
class: 'SwitchNode'
|
class: 'SwitchNode'
|
||||||
children: ['subject', 'cases', 'otherwise']
|
children: ['subject', 'cases', 'otherwise']
|
||||||
|
|
||||||
isStatement: -> yes
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@subject, @cases, @otherwise) ->
|
constructor: (@subject, @cases, @otherwise) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1471,7 +1484,7 @@ exports.IfNode = class IfNode extends BaseNode
|
||||||
class: 'IfNode'
|
class: 'IfNode'
|
||||||
children: ['condition', 'body', 'elseBody', 'assigner']
|
children: ['condition', 'body', 'elseBody', 'assigner']
|
||||||
|
|
||||||
topSensitive: -> true
|
topSensitive: YES
|
||||||
|
|
||||||
constructor: (@condition, @body, @tags) ->
|
constructor: (@condition, @body, @tags) ->
|
||||||
@tags or= {}
|
@tags or= {}
|
||||||
|
@ -1629,10 +1642,9 @@ TAB = ' '
|
||||||
# with Git.
|
# with Git.
|
||||||
TRAILING_WHITESPACE = /[ \t]+$/gm
|
TRAILING_WHITESPACE = /[ \t]+$/gm
|
||||||
|
|
||||||
# Keep these identifier regexes in sync with the Lexer.
|
IDENTIFIER = /^[$A-Za-zA-Z_][$\w]*$/
|
||||||
IDENTIFIER = /^[a-zA-Z\$_](\w|\$)*$/
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i
|
||||||
NUMBER = /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b$/i
|
SIMPLENUM = /^-?\d+$/
|
||||||
SIMPLENUM = /^-?\d+$/
|
|
||||||
|
|
||||||
# Is a literal value a string?
|
# Is a literal value a string?
|
||||||
IS_STRING = /^['"]/
|
IS_STRING = /^['"]/
|
||||||
|
|
Loading…
Add table
Reference in a new issue