nodes: refactored to reduce parens
This commit is contained in:
parent
b0a4b7ab85
commit
e2a6f292a2
|
@ -413,7 +413,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 < (_ref2 = attempt.length)) && (_ref2 < indent.length)) {
|
if (indent === null || 0 < (_ref2 = attempt.length) && _ref2 < indent.length) {
|
||||||
indent = attempt;
|
indent = attempt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,7 +528,7 @@
|
||||||
i += expr.length;
|
i += expr.length;
|
||||||
pi = i + 1;
|
pi = i + 1;
|
||||||
}
|
}
|
||||||
if ((i > pi) && (pi < str.length)) {
|
if (i > pi && pi < str.length) {
|
||||||
tokens.push(['TO_BE_STRING', str.slice(pi)]);
|
tokens.push(['TO_BE_STRING', str.slice(pi)]);
|
||||||
}
|
}
|
||||||
if (regex) {
|
if (regex) {
|
||||||
|
|
109
lib/nodes.js
109
lib/nodes.js
|
@ -41,7 +41,7 @@
|
||||||
Base.prototype.compileClosure = function(o) {
|
Base.prototype.compileClosure = function(o) {
|
||||||
o.sharedScope = o.scope;
|
o.sharedScope = o.scope;
|
||||||
if (this.containsPureStatement()) {
|
if (this.containsPureStatement()) {
|
||||||
throw new Error('cannot include a pure statement in an expression.');
|
throw SyntaxError('cannot include a pure statement in an expression.');
|
||||||
}
|
}
|
||||||
return Closure.wrap(this).compile(o);
|
return Closure.wrap(this).compile(o);
|
||||||
};
|
};
|
||||||
|
@ -109,11 +109,10 @@
|
||||||
return '\n' + idt + klass + children;
|
return '\n' + idt + klass + children;
|
||||||
};
|
};
|
||||||
Base.prototype.eachChild = function(func) {
|
Base.prototype.eachChild = function(func) {
|
||||||
var _i, _j, _len, _len2, _ref2, _ref3, _result, attr, child;
|
var _i, _j, _len, _len2, _ref2, _ref3, attr, child;
|
||||||
if (!this.children) {
|
if (!this.children) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_result = [];
|
|
||||||
for (_i = 0, _len = (_ref2 = this.children).length; _i < _len; _i++) {
|
for (_i = 0, _len = (_ref2 = this.children).length; _i < _len; _i++) {
|
||||||
attr = _ref2[_i];
|
attr = _ref2[_i];
|
||||||
if (this[attr]) {
|
if (this[attr]) {
|
||||||
|
@ -125,7 +124,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _result;
|
return this;
|
||||||
};
|
};
|
||||||
Base.prototype.collectChildren = function() {
|
Base.prototype.collectChildren = function() {
|
||||||
var nodes;
|
var nodes;
|
||||||
|
@ -292,14 +291,14 @@
|
||||||
return Return;
|
return Return;
|
||||||
})();
|
})();
|
||||||
__extends(Return, Base);
|
__extends(Return, Base);
|
||||||
|
Return.prototype.children = ['expression'];
|
||||||
Return.prototype.isStatement = YES;
|
Return.prototype.isStatement = YES;
|
||||||
Return.prototype.isPureStatement = YES;
|
Return.prototype.isPureStatement = YES;
|
||||||
Return.prototype.children = ['expression'];
|
|
||||||
Return.prototype.makeReturn = THIS;
|
Return.prototype.makeReturn = THIS;
|
||||||
Return.prototype.compile = function(o) {
|
Return.prototype.compile = function(o) {
|
||||||
var _ref2, expr;
|
var _ref2, expr;
|
||||||
expr = (((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined);
|
expr = (((_ref2 = this.expression) != null) ? _ref2.makeReturn() : undefined);
|
||||||
if (expr && (!(expr instanceof Return))) {
|
if (expr && !(expr instanceof Return)) {
|
||||||
return expr.compile(o);
|
return expr.compile(o);
|
||||||
}
|
}
|
||||||
return Return.__super__.compile.call(this, o);
|
return Return.__super__.compile.call(this, o);
|
||||||
|
@ -319,11 +318,10 @@
|
||||||
})();
|
})();
|
||||||
exports.Value = (function() {
|
exports.Value = (function() {
|
||||||
Value = (function() {
|
Value = (function() {
|
||||||
function Value(_arg, _arg2, tag) {
|
function Value(_arg, props, tag) {
|
||||||
this.properties = _arg2;
|
|
||||||
this.base = _arg;
|
this.base = _arg;
|
||||||
Value.__super__.constructor.call(this);
|
Value.__super__.constructor.call(this);
|
||||||
this.properties || (this.properties = []);
|
this.properties = props || [];
|
||||||
if (tag) {
|
if (tag) {
|
||||||
this.tags[tag] = true;
|
this.tags[tag] = true;
|
||||||
}
|
}
|
||||||
|
@ -485,11 +483,11 @@
|
||||||
var method, name;
|
var method, name;
|
||||||
method = o.scope.method;
|
method = o.scope.method;
|
||||||
if (!method) {
|
if (!method) {
|
||||||
throw Error("cannot call super outside of a function.");
|
throw SyntaxError('cannot call super outside of a function.');
|
||||||
}
|
}
|
||||||
name = method.name;
|
name = method.name;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw Error("cannot call super on an anonymous function.");
|
throw SyntaxError('cannot call super on an anonymous function.');
|
||||||
}
|
}
|
||||||
return method.klass ? ("" + (method.klass) + ".__super__." + name) : ("" + name + ".__super__.constructor");
|
return method.klass ? ("" + (method.klass) + ".__super__." + name) : ("" + name + ".__super__.constructor");
|
||||||
};
|
};
|
||||||
|
@ -606,9 +604,7 @@
|
||||||
__extends(Extends, Base);
|
__extends(Extends, Base);
|
||||||
Extends.prototype.children = ['child', 'parent'];
|
Extends.prototype.children = ['child', 'parent'];
|
||||||
Extends.prototype.compileNode = function(o) {
|
Extends.prototype.compileNode = function(o) {
|
||||||
var ref;
|
return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compile(o);
|
||||||
ref = new Value(new Literal(utility('extends')));
|
|
||||||
return (new Call(ref, [this.child, this.parent])).compile(o);
|
|
||||||
};
|
};
|
||||||
return Extends;
|
return Extends;
|
||||||
})();
|
})();
|
||||||
|
@ -626,10 +622,9 @@
|
||||||
__extends(Accessor, Base);
|
__extends(Accessor, Base);
|
||||||
Accessor.prototype.children = ['name'];
|
Accessor.prototype.children = ['name'];
|
||||||
Accessor.prototype.compileNode = function(o) {
|
Accessor.prototype.compileNode = function(o) {
|
||||||
var name, namePart;
|
var name;
|
||||||
name = this.name.compile(o);
|
name = this.name.compile(o);
|
||||||
namePart = name.match(IS_STRING) ? ("[" + name + "]") : ("." + name);
|
return this.prototype + (IS_STRING.test(name) ? ("[" + name + "]") : ("." + name));
|
||||||
return this.prototype + namePart;
|
|
||||||
};
|
};
|
||||||
Accessor.prototype.isComplex = NO;
|
Accessor.prototype.isComplex = NO;
|
||||||
return Accessor;
|
return Accessor;
|
||||||
|
@ -646,10 +641,7 @@
|
||||||
__extends(Index, Base);
|
__extends(Index, Base);
|
||||||
Index.prototype.children = ['index'];
|
Index.prototype.children = ['index'];
|
||||||
Index.prototype.compileNode = function(o) {
|
Index.prototype.compileNode = function(o) {
|
||||||
var idx, prefix;
|
return "" + (this.proto ? '.prototype' : '') + "[" + (this.index.compile(o)) + "]";
|
||||||
idx = this.index.compile(o);
|
|
||||||
prefix = this.proto ? '.prototype' : '';
|
|
||||||
return "" + prefix + "[" + idx + "]";
|
|
||||||
};
|
};
|
||||||
Index.prototype.isComplex = function() {
|
Index.prototype.isComplex = function() {
|
||||||
return this.index.isComplex();
|
return this.index.isComplex();
|
||||||
|
@ -828,10 +820,9 @@
|
||||||
})();
|
})();
|
||||||
exports.ArrayLiteral = (function() {
|
exports.ArrayLiteral = (function() {
|
||||||
ArrayLiteral = (function() {
|
ArrayLiteral = (function() {
|
||||||
function ArrayLiteral(_arg) {
|
function ArrayLiteral(objs) {
|
||||||
this.objects = _arg;
|
|
||||||
ArrayLiteral.__super__.constructor.call(this);
|
ArrayLiteral.__super__.constructor.call(this);
|
||||||
this.objects || (this.objects = []);
|
this.objects = objs || [];
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
return ArrayLiteral;
|
return ArrayLiteral;
|
||||||
|
@ -873,12 +864,11 @@
|
||||||
})();
|
})();
|
||||||
exports.Class = (function() {
|
exports.Class = (function() {
|
||||||
Class = (function() {
|
Class = (function() {
|
||||||
function Class(variable, _arg, _arg2) {
|
function Class(variable, _arg, props) {
|
||||||
this.properties = _arg2;
|
|
||||||
this.parent = _arg;
|
this.parent = _arg;
|
||||||
Class.__super__.constructor.call(this);
|
Class.__super__.constructor.call(this);
|
||||||
this.variable = variable === '__temp__' ? new Literal(variable) : variable;
|
this.variable = variable === '__temp__' ? new Literal(variable) : variable;
|
||||||
this.properties || (this.properties = []);
|
this.properties = props || [];
|
||||||
this.returns = false;
|
this.returns = false;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -922,7 +912,7 @@
|
||||||
func = new Code([], new Expressions([apply]));
|
func = new Code([], new Expressions([apply]));
|
||||||
}
|
}
|
||||||
if (func.bound) {
|
if (func.bound) {
|
||||||
throw new Error("cannot define a constructor as a bound function.");
|
throw SyntaxError('cannot define a constructor as a bound function.');
|
||||||
}
|
}
|
||||||
func.name = className;
|
func.name = className;
|
||||||
func.body.push(new Return(new Literal('this')));
|
func.body.push(new Return(new Literal('this')));
|
||||||
|
@ -955,7 +945,7 @@
|
||||||
}
|
}
|
||||||
props.push(prop);
|
props.push(prop);
|
||||||
}
|
}
|
||||||
constructor.className = className.match(/[\w\d\$_]+$/);
|
constructor.className = className.match(/[$\w]+$/);
|
||||||
if (me) {
|
if (me) {
|
||||||
constructor.body.unshift(new Literal("" + me + " = this"));
|
constructor.body.unshift(new Literal("" + me + " = this"));
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1057,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(obj instanceof Value || obj instanceof Splat)) {
|
if (!(obj instanceof Value || obj instanceof Splat)) {
|
||||||
throw new Error('pattern matching must use only identifiers on the left-hand side.');
|
throw SyntaxError('pattern matching must use only identifiers on the left-hand side.');
|
||||||
}
|
}
|
||||||
accessClass = isObject && IDENTIFIER.test(idx.value) ? Accessor : Index;
|
accessClass = isObject && IDENTIFIER.test(idx.value) ? Accessor : Index;
|
||||||
if (!splat && obj instanceof Splat) {
|
if (!splat && obj instanceof Splat) {
|
||||||
|
@ -1177,7 +1167,7 @@
|
||||||
}
|
}
|
||||||
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
|
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
|
||||||
param = params[_i];
|
param = params[_i];
|
||||||
(o.scope.parameter(param));
|
o.scope.parameter(param);
|
||||||
}
|
}
|
||||||
comm = this.comment ? this.comment.compile(o) + '\n' : '';
|
comm = this.comment ? this.comment.compile(o) + '\n' : '';
|
||||||
if (this.className) {
|
if (this.className) {
|
||||||
|
@ -1311,6 +1301,7 @@
|
||||||
})();
|
})();
|
||||||
__extends(While, Base);
|
__extends(While, Base);
|
||||||
While.prototype.children = ['condition', 'guard', 'body'];
|
While.prototype.children = ['condition', 'guard', 'body'];
|
||||||
|
While.prototype.topSensitive = YES;
|
||||||
While.prototype.isStatement = YES;
|
While.prototype.isStatement = YES;
|
||||||
While.prototype.addBody = function(body) {
|
While.prototype.addBody = function(body) {
|
||||||
this.body = body;
|
this.body = body;
|
||||||
|
@ -1320,7 +1311,6 @@
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
While.prototype.topSensitive = YES;
|
|
||||||
While.prototype.compileNode = function(o) {
|
While.prototype.compileNode = function(o) {
|
||||||
var cond, post, pre, rvar, set, top;
|
var cond, post, pre, rvar, set, top;
|
||||||
top = del(o, 'top') && !this.returns;
|
top = del(o, 'top') && !this.returns;
|
||||||
|
@ -1398,9 +1388,9 @@
|
||||||
return (_ref2 = this.operator, __indexOf.call(this.CHAINABLE, _ref2) >= 0);
|
return (_ref2 = this.operator, __indexOf.call(this.CHAINABLE, _ref2) >= 0);
|
||||||
};
|
};
|
||||||
Op.prototype.invert = function() {
|
Op.prototype.invert = function() {
|
||||||
var _ref2;
|
var op;
|
||||||
if (((_ref2 = this.operator) === '===' || _ref2 === '!==')) {
|
if (op = this.INVERSIONS[this.operator]) {
|
||||||
this.operator = this.INVERSIONS[this.operator];
|
this.operator = op;
|
||||||
return this;
|
return this;
|
||||||
} else return this.second ? new Parens(this).invert() : Op.__super__.invert.call(this);
|
} else return this.second ? new Parens(this).invert() : Op.__super__.invert.call(this);
|
||||||
};
|
};
|
||||||
|
@ -1425,11 +1415,9 @@
|
||||||
return "" + (this.first.compile(o)) + " " + (this.operator) + " " + (this.second.compile(o));
|
return "" + (this.first.compile(o)) + " " + (this.operator) + " " + (this.second.compile(o));
|
||||||
};
|
};
|
||||||
Op.prototype.compileChain = function(o) {
|
Op.prototype.compileChain = function(o) {
|
||||||
var _ref2, _ref3, first, second, shared;
|
var _ref2, shared;
|
||||||
shared = this.first.unwrap().second;
|
_ref2 = this.first.unwrap().second.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
|
||||||
_ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
|
return "" + (this.first.compile(o)) + " && " + (shared.compile(o)) + " " + (this.operator) + " " + (this.second.compile(o));
|
||||||
_ref3 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref3[0], second = _ref3[1], shared = _ref3[2];
|
|
||||||
return "(" + first + ") && (" + shared + " " + (this.operator) + " " + second + ")";
|
|
||||||
};
|
};
|
||||||
Op.prototype.compileExistence = function(o) {
|
Op.prototype.compileExistence = function(o) {
|
||||||
var fst, ref;
|
var fst, ref;
|
||||||
|
@ -1580,13 +1568,13 @@
|
||||||
})();
|
})();
|
||||||
__extends(Parens, Base);
|
__extends(Parens, Base);
|
||||||
Parens.prototype.children = ['expression'];
|
Parens.prototype.children = ['expression'];
|
||||||
|
Parens.prototype.topSensitive = YES;
|
||||||
Parens.prototype.isStatement = function(o) {
|
Parens.prototype.isStatement = function(o) {
|
||||||
return this.expression.isStatement(o);
|
return this.expression.isStatement(o);
|
||||||
};
|
};
|
||||||
Parens.prototype.isComplex = function() {
|
Parens.prototype.isComplex = function() {
|
||||||
return this.expression.isComplex();
|
return this.expression.isComplex();
|
||||||
};
|
};
|
||||||
Parens.prototype.topSensitive = YES;
|
|
||||||
Parens.prototype.makeReturn = function() {
|
Parens.prototype.makeReturn = function() {
|
||||||
return this.expression.makeReturn();
|
return this.expression.makeReturn();
|
||||||
};
|
};
|
||||||
|
@ -1619,10 +1607,10 @@
|
||||||
if (this.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 Value;
|
|
||||||
if (this.index instanceof Value) {
|
if (this.index instanceof Value) {
|
||||||
throw new Error('index cannot be a pattern matching expression');
|
throw SyntaxError('index cannot be a pattern matching expression');
|
||||||
}
|
}
|
||||||
|
this.pattern = this.name instanceof Value;
|
||||||
this.returns = false;
|
this.returns = false;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -1630,8 +1618,8 @@
|
||||||
})();
|
})();
|
||||||
__extends(For, Base);
|
__extends(For, Base);
|
||||||
For.prototype.children = ['body', 'source', 'guard'];
|
For.prototype.children = ['body', 'source', 'guard'];
|
||||||
For.prototype.isStatement = YES;
|
|
||||||
For.prototype.topSensitive = YES;
|
For.prototype.topSensitive = YES;
|
||||||
|
For.prototype.isStatement = YES;
|
||||||
For.prototype.makeReturn = function() {
|
For.prototype.makeReturn = function() {
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1771,8 +1759,6 @@
|
||||||
this.cases = _arg2;
|
this.cases = _arg2;
|
||||||
this.subject = _arg;
|
this.subject = _arg;
|
||||||
Switch.__super__.constructor.call(this);
|
Switch.__super__.constructor.call(this);
|
||||||
this.tags.subjectless = !this.subject;
|
|
||||||
this.subject || (this.subject = new Literal('true'));
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
return Switch;
|
return Switch;
|
||||||
|
@ -1792,28 +1778,27 @@
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
Switch.prototype.compileNode = function(o) {
|
Switch.prototype.compileNode = function(o) {
|
||||||
var _i, _j, _len, _len2, _ref2, _ref3, block, code, condition, conditions, exprs, idt, pair;
|
var _i, _j, _len, _len2, _ref2, _ref3, _ref4, _ref5, block, code, condition, conditions, idt1, idt2;
|
||||||
idt = (o.indent = this.idt(2));
|
idt1 = this.idt(1);
|
||||||
|
idt2 = (o.indent = this.idt(2));
|
||||||
o.top = true;
|
o.top = true;
|
||||||
code = ("" + (this.tab) + "switch (" + (this.subject.compile(o)) + ") {");
|
code = ("" + (this.tab) + "switch (" + ((((_ref2 = this.subject) != null) ? _ref2.compile(o) : undefined) || true) + ") {");
|
||||||
for (_i = 0, _len = (_ref2 = this.cases).length; _i < _len; _i++) {
|
for (_i = 0, _len = (_ref3 = this.cases).length; _i < _len; _i++) {
|
||||||
pair = _ref2[_i];
|
_ref4 = _ref3[_i], conditions = _ref4[0], block = _ref4[1];
|
||||||
conditions = pair[0], block = pair[1];
|
for (_j = 0, _len2 = (_ref5 = flatten([conditions])).length; _j < _len2; _j++) {
|
||||||
exprs = block.expressions;
|
condition = _ref5[_j];
|
||||||
for (_j = 0, _len2 = (_ref3 = flatten([conditions])).length; _j < _len2; _j++) {
|
if (!this.subject) {
|
||||||
condition = _ref3[_j];
|
condition = condition.invert().invert();
|
||||||
if (this.tags.subjectless) {
|
|
||||||
condition = new Op('!!', new Parens(condition));
|
|
||||||
}
|
}
|
||||||
code += ("\n" + (this.idt(1)) + "case " + (condition.compile(o)) + ":");
|
code += ("\n" + idt1 + "case " + (condition.compile(o)) + ":");
|
||||||
}
|
}
|
||||||
code += ("\n" + (block.compile(o)));
|
code += ("\n" + (block.compile(o)));
|
||||||
if (!(last(exprs) instanceof Return)) {
|
if (!(last(block.expressions) instanceof Return)) {
|
||||||
code += ("\n" + idt + "break;");
|
code += ("\n" + idt2 + "break;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.otherwise) {
|
if (this.otherwise) {
|
||||||
code += ("\n" + (this.idt(1)) + "default:\n" + (this.otherwise.compile(o)));
|
code += ("\n" + idt1 + "default:\n" + (this.otherwise.compile(o)));
|
||||||
}
|
}
|
||||||
code += ("\n" + (this.tab) + "}");
|
code += ("\n" + (this.tab) + "}");
|
||||||
return code;
|
return code;
|
||||||
|
@ -1965,7 +1950,7 @@
|
||||||
TAB = ' ';
|
TAB = ' ';
|
||||||
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
||||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/;
|
IDENTIFIER = /^[$A-Za-z_][$\w]*$/;
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
NUMBER = /^0x[\da-f]+$|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
||||||
SIMPLENUM = /^[+-]?\d+$/;
|
SIMPLENUM = /^[+-]?\d+$/;
|
||||||
IS_STRING = /^['"]/;
|
IS_STRING = /^['"]/;
|
||||||
utility = function(name) {
|
utility = function(name) {
|
||||||
|
|
198
src/nodes.coffee
198
src/nodes.coffee
|
@ -52,7 +52,7 @@ exports.Base = class Base
|
||||||
# object with their parent closure, to preserve the expected lexical scope.
|
# object with their parent closure, to preserve the expected lexical scope.
|
||||||
compileClosure: (o) ->
|
compileClosure: (o) ->
|
||||||
o.sharedScope = o.scope
|
o.sharedScope = o.scope
|
||||||
throw new Error 'cannot include a pure statement in an expression.' if @containsPureStatement()
|
throw SyntaxError 'cannot include a pure statement in an expression.' if @containsPureStatement()
|
||||||
Closure.wrap(this).compile o
|
Closure.wrap(this).compile o
|
||||||
|
|
||||||
# If the code generation wishes to use the result of a complex expression
|
# If the code generation wishes to use the result of a complex expression
|
||||||
|
@ -115,6 +115,7 @@ exports.Base = class Base
|
||||||
for attr in @children when this[attr]
|
for attr in @children when this[attr]
|
||||||
for child in flatten [this[attr]]
|
for child in flatten [this[attr]]
|
||||||
return if func(child) is false
|
return if func(child) is false
|
||||||
|
this
|
||||||
|
|
||||||
collectChildren: ->
|
collectChildren: ->
|
||||||
nodes = []
|
nodes = []
|
||||||
|
@ -151,7 +152,8 @@ exports.Base = class Base
|
||||||
# `if`, `switch`, or `try`, and so on...
|
# `if`, `switch`, or `try`, and so on...
|
||||||
exports.Expressions = class Expressions extends Base
|
exports.Expressions = class Expressions extends Base
|
||||||
|
|
||||||
children: ['expressions']
|
children: ['expressions']
|
||||||
|
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (nodes) ->
|
constructor: (nodes) ->
|
||||||
|
@ -212,7 +214,7 @@ exports.Expressions = class Expressions extends Base
|
||||||
if o.scope.hasAssignments this
|
if o.scope.hasAssignments this
|
||||||
code = "#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };\n#{code}"
|
code = "#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };\n#{code}"
|
||||||
if not o.globals and o.scope.hasDeclarations this
|
if not o.globals and o.scope.hasDeclarations this
|
||||||
code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#{code}"
|
code = "#{@tab}var #{ o.scope.compiledDeclarations() };\n#{code}"
|
||||||
code
|
code
|
||||||
|
|
||||||
# Compiles a single expression within the expressions body. If we need to
|
# Compiles a single expression within the expressions body. If we need to
|
||||||
|
@ -257,9 +259,9 @@ exports.Literal = class Literal extends Base
|
||||||
assigns: (name) -> name is @value
|
assigns: (name) -> name is @value
|
||||||
|
|
||||||
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 ''
|
||||||
val = if @isReserved() then "\"#{@value}\"" else @value
|
val = if @isReserved() then "\"#{@value}\"" else @value
|
||||||
idt + val + end
|
idt + val + end
|
||||||
|
|
||||||
toString: -> ' "' + @value + '"'
|
toString: -> ' "' + @value + '"'
|
||||||
|
@ -270,9 +272,10 @@ exports.Literal = class Literal extends Base
|
||||||
# make sense.
|
# make sense.
|
||||||
exports.Return = class Return extends Base
|
exports.Return = class Return extends Base
|
||||||
|
|
||||||
isStatement: YES
|
children: ['expression']
|
||||||
isPureStatement: YES
|
|
||||||
children: ['expression']
|
isStatement : YES
|
||||||
|
isPureStatement: YES
|
||||||
|
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
super()
|
super()
|
||||||
|
@ -281,7 +284,7 @@ exports.Return = class Return extends Base
|
||||||
|
|
||||||
compile: (o) ->
|
compile: (o) ->
|
||||||
expr = @expression?.makeReturn()
|
expr = @expression?.makeReturn()
|
||||||
return expr.compile o if expr and (expr not instanceof Return)
|
return expr.compile o if expr and expr not instanceof Return
|
||||||
super o
|
super o
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
|
@ -300,9 +303,9 @@ exports.Value = class Value extends Base
|
||||||
children: ['base', 'properties']
|
children: ['base', 'properties']
|
||||||
|
|
||||||
# A **Value** has a base and a list of property accesses.
|
# A **Value** has a base and a list of property accesses.
|
||||||
constructor: (@base, @properties, tag) ->
|
constructor: (@base, props, tag) ->
|
||||||
super()
|
super()
|
||||||
@properties or= []
|
@properties = props or []
|
||||||
@tags[tag] = yes if tag
|
@tags[tag] = yes if tag
|
||||||
|
|
||||||
# Add a property access to the list.
|
# Add a property access to the list.
|
||||||
|
@ -333,7 +336,6 @@ exports.Value = class Value extends Base
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
if @properties.length then super() else @base.makeReturn()
|
if @properties.length then super() else @base.makeReturn()
|
||||||
|
|
||||||
|
|
||||||
# The value can be unwrapped as its inner node, if there are no attached
|
# The value can be unwrapped as its inner node, if there are no attached
|
||||||
# properties.
|
# properties.
|
||||||
unwrap: ->
|
unwrap: ->
|
||||||
|
@ -429,7 +431,7 @@ exports.Call = class Call extends Base
|
||||||
@isNew = false
|
@isNew = false
|
||||||
@isSuper = variable is 'super'
|
@isSuper = variable is 'super'
|
||||||
@variable = if @isSuper then null else variable
|
@variable = if @isSuper then null else variable
|
||||||
@args or= []
|
@args or= []
|
||||||
|
|
||||||
compileSplatArguments: (o) ->
|
compileSplatArguments: (o) ->
|
||||||
Splat.compileSplattedArray @args, o
|
Splat.compileSplattedArray @args, o
|
||||||
|
@ -445,9 +447,9 @@ exports.Call = class Call extends Base
|
||||||
# Grab the reference to the superclass' implementation of the current method.
|
# Grab the reference to the superclass' implementation of the current method.
|
||||||
superReference: (o) ->
|
superReference: (o) ->
|
||||||
{method} = o.scope
|
{method} = o.scope
|
||||||
throw Error "cannot call super outside of a function." unless method
|
throw SyntaxError 'cannot call super outside of a function.' unless method
|
||||||
{name} = method
|
{name} = method
|
||||||
throw Error "cannot call super on an anonymous function." unless name
|
throw SyntaxError 'cannot call super on an anonymous function.' unless name
|
||||||
if method.klass
|
if method.klass
|
||||||
"#{method.klass}.__super__.#{name}"
|
"#{method.klass}.__super__.#{name}"
|
||||||
else
|
else
|
||||||
|
@ -542,8 +544,7 @@ exports.Extends = class Extends extends Base
|
||||||
|
|
||||||
# Hooks one constructor into another's prototype chain.
|
# Hooks one constructor into another's prototype chain.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
ref = new Value new Literal utility 'extends'
|
new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o
|
||||||
(new Call ref, [@child, @parent]).compile o
|
|
||||||
|
|
||||||
#### Accessor
|
#### Accessor
|
||||||
|
|
||||||
|
@ -556,12 +557,11 @@ exports.Accessor = class Accessor extends Base
|
||||||
constructor: (@name, tag) ->
|
constructor: (@name, tag) ->
|
||||||
super()
|
super()
|
||||||
@prototype = if tag is 'prototype' then '.prototype' else ''
|
@prototype = if tag is 'prototype' then '.prototype' else ''
|
||||||
@soakNode = tag is 'soak'
|
@soakNode = tag is 'soak'
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
name = @name.compile o
|
name = @name.compile o
|
||||||
namePart = if name.match(IS_STRING) then "[#{name}]" else ".#{name}"
|
@prototype + if IS_STRING.test(name) then "[#{name}]" else ".#{name}"
|
||||||
@prototype + namePart
|
|
||||||
|
|
||||||
isComplex: NO
|
isComplex: NO
|
||||||
|
|
||||||
|
@ -576,9 +576,7 @@ exports.Index = class Index extends Base
|
||||||
super()
|
super()
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
idx = @index.compile o
|
"#{ if @proto then '.prototype' else '' }[#{ @index.compile o }]"
|
||||||
prefix = if @proto then '.prototype' else ''
|
|
||||||
"#{prefix}[#{idx}]"
|
|
||||||
|
|
||||||
isComplex: -> @index.isComplex()
|
isComplex: -> @index.isComplex()
|
||||||
|
|
||||||
|
@ -716,9 +714,9 @@ exports.ArrayLiteral = class ArrayLiteral extends Base
|
||||||
|
|
||||||
children: ['objects']
|
children: ['objects']
|
||||||
|
|
||||||
constructor: (@objects) ->
|
constructor: (objs) ->
|
||||||
super()
|
super()
|
||||||
@objects or= []
|
@objects = objs or []
|
||||||
|
|
||||||
compileSplatLiteral: (o) ->
|
compileSplatLiteral: (o) ->
|
||||||
Splat.compileSplattedArray @objects, o
|
Splat.compileSplattedArray @objects, o
|
||||||
|
@ -752,15 +750,16 @@ exports.ArrayLiteral = class ArrayLiteral extends Base
|
||||||
# The CoffeeScript class definition.
|
# The CoffeeScript class definition.
|
||||||
exports.Class = class Class extends Base
|
exports.Class = class Class extends Base
|
||||||
|
|
||||||
children: ['variable', 'parent', 'properties']
|
children: ['variable', 'parent', 'properties']
|
||||||
|
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
|
||||||
# Initialize a **Class** with its name, an optional superclass, and a
|
# Initialize a **Class** with its name, an optional superclass, and a
|
||||||
# list of prototype property assignments.
|
# list of prototype property assignments.
|
||||||
constructor: (variable, @parent, @properties) ->
|
constructor: (variable, @parent, props) ->
|
||||||
super()
|
super()
|
||||||
@variable = if variable is '__temp__' then new Literal variable else variable
|
@variable = if variable is '__temp__' then new Literal variable else variable
|
||||||
@properties or= []
|
@properties = props or []
|
||||||
@returns = false
|
@returns = false
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
|
@ -782,9 +781,9 @@ exports.Class = class Class extends Base
|
||||||
|
|
||||||
if @parent
|
if @parent
|
||||||
applied = new Value @parent, [new Accessor new Literal 'apply']
|
applied = new Value @parent, [new Accessor new Literal 'apply']
|
||||||
constructor = new Code([], new Expressions([
|
constructor = new Code [], new Expressions [
|
||||||
new Call applied, [new Literal('this'), new Literal('arguments')]
|
new Call applied, [new Literal('this'), new Literal('arguments')]
|
||||||
]))
|
]
|
||||||
else
|
else
|
||||||
constructor = new Code [], new Expressions [new Return new Literal 'this']
|
constructor = new Code [], new Expressions [new Return new Literal 'this']
|
||||||
|
|
||||||
|
@ -794,9 +793,10 @@ exports.Class = class Class extends Base
|
||||||
if func not instanceof Code
|
if func not instanceof Code
|
||||||
[func, ref] = func.compileReference o
|
[func, ref] = func.compileReference o
|
||||||
props.push func if func isnt ref
|
props.push func if func isnt ref
|
||||||
apply = new Call(new Value(ref, [new Accessor new Literal 'apply']), [new Literal('this'), new Literal('arguments')])
|
apply = new Call new Value(ref, [new Accessor new Literal 'apply']),
|
||||||
|
[new Literal('this'), new Literal('arguments')]
|
||||||
func = new Code [], new Expressions([apply])
|
func = new Code [], new Expressions([apply])
|
||||||
throw new Error "cannot define a constructor as a bound function." if func.bound
|
throw SyntaxError 'cannot define a constructor as a bound function.' if func.bound
|
||||||
func.name = className
|
func.name = className
|
||||||
func.body.push new Return new Literal 'this'
|
func.body.push new Return new Literal 'this'
|
||||||
variable = new Value variable
|
variable = new Value variable
|
||||||
|
@ -809,18 +809,18 @@ exports.Class = class Class extends Base
|
||||||
func.context = className
|
func.context = className
|
||||||
else
|
else
|
||||||
func.bound = false
|
func.bound = false
|
||||||
constScope or= new Scope(o.scope, constructor.body, constructor)
|
constScope or= new Scope o.scope, constructor.body, constructor
|
||||||
me or= constScope.freeVariable 'this'
|
me or= constScope.freeVariable 'this'
|
||||||
pname = pvar.compile(o)
|
pname = pvar.compile o
|
||||||
constructor.body.push new Return new Literal 'this' if constructor.body.empty()
|
constructor.body.push new Return new Literal 'this' if constructor.body.empty()
|
||||||
constructor.body.unshift new Literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }"
|
constructor.body.unshift new Literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }"
|
||||||
if pvar
|
if pvar
|
||||||
access = if prop.context is 'this' then pvar.base.properties[0] else new Accessor(pvar, 'prototype')
|
access = if prop.context is 'this' then pvar.base.properties[0] else new Accessor(pvar, 'prototype')
|
||||||
val = new Value variable, [access]
|
val = new Value variable, [access]
|
||||||
prop = new Assign(val, func)
|
prop = new Assign val, func
|
||||||
props.push prop
|
props.push prop
|
||||||
|
|
||||||
constructor.className = className.match /[\w\d\$_]+$/
|
constructor.className = className.match /[$\w]+$/
|
||||||
constructor.body.unshift new Literal "#{me} = this" if me
|
constructor.body.unshift new Literal "#{me} = this" if me
|
||||||
construct = @idt() + new Assign(variable, constructor).compile(merge o, sharedScope: constScope) + ';'
|
construct = @idt() + new Assign(variable, constructor).compile(merge o, sharedScope: constScope) + ';'
|
||||||
props = if !props.empty() then '\n' + props.compile(o) else ''
|
props = if !props.empty() then '\n' + props.compile(o) else ''
|
||||||
|
@ -841,11 +841,11 @@ exports.Assign = class Assign extends Base
|
||||||
|
|
||||||
children: ['variable', 'value']
|
children: ['variable', 'value']
|
||||||
|
|
||||||
|
topSensitive: YES
|
||||||
|
|
||||||
constructor: (@variable, @value, @context) ->
|
constructor: (@variable, @value, @context) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
# Compile an assignment, delegating to `compilePatternMatch` or
|
# Compile an assignment, delegating to `compilePatternMatch` or
|
||||||
# `compileSplice` if appropriate. Keep track of the name of the base object
|
# `compileSplice` if appropriate. Keep track of the name of the base object
|
||||||
# we've been assigned to, for correct internal references. If the variable
|
# we've been assigned to, for correct internal references. If the variable
|
||||||
|
@ -911,7 +911,7 @@ exports.Assign = class Assign extends Base
|
||||||
# A shorthand `{a, b, @c} = val` pattern-match.
|
# A shorthand `{a, b, @c} = val` pattern-match.
|
||||||
idx = if obj.tags.this then obj.properties[0].name else obj
|
idx = if obj.tags.this then obj.properties[0].name else obj
|
||||||
unless obj instanceof Value or obj instanceof Splat
|
unless obj instanceof Value or obj instanceof Splat
|
||||||
throw new Error 'pattern matching must use only identifiers on the left-hand side.'
|
throw SyntaxError 'pattern matching must use only identifiers on the left-hand side.'
|
||||||
accessClass = if isObject and IDENTIFIER.test(idx.value) then Accessor else Index
|
accessClass = if isObject and IDENTIFIER.test(idx.value) then Accessor else Index
|
||||||
if not splat and obj instanceof Splat
|
if not splat and obj instanceof Splat
|
||||||
val = new Literal obj.compileValue o, valVar, i, olength - i - 1
|
val = new Literal obj.compileValue o, valVar, i, olength - i - 1
|
||||||
|
@ -972,7 +972,7 @@ exports.Code = class Code extends Base
|
||||||
top = del o, 'top'
|
top = del o, 'top'
|
||||||
o.scope = sharedScope or new Scope(o.scope, @body, this)
|
o.scope = sharedScope or new Scope(o.scope, @body, this)
|
||||||
o.top = true
|
o.top = true
|
||||||
o.indent = @idt(1)
|
o.indent = @idt 1
|
||||||
empty = @body.expressions.length is 0
|
empty = @body.expressions.length is 0
|
||||||
delete o.bare
|
delete o.bare
|
||||||
delete o.globals
|
delete o.globals
|
||||||
|
@ -998,9 +998,9 @@ exports.Code = class Code extends Base
|
||||||
else
|
else
|
||||||
params.push param
|
params.push param
|
||||||
o.scope.startLevel()
|
o.scope.startLevel()
|
||||||
params = (param.compile(o) for param in params)
|
params = param.compile(o) for param in params
|
||||||
@body.makeReturn() unless empty or @noReturn
|
@body.makeReturn() unless empty or @noReturn
|
||||||
(o.scope.parameter(param)) for param in params
|
o.scope.parameter param for param in params
|
||||||
comm = if @comment then @comment.compile(o) + '\n' else ''
|
comm = if @comment then @comment.compile(o) + '\n' else ''
|
||||||
o.indent = @idt 2 if @className
|
o.indent = @idt 2 if @className
|
||||||
code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else ''
|
code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else ''
|
||||||
|
@ -1052,12 +1052,12 @@ exports.Splat = class Splat extends Base
|
||||||
assigns: (name) -> @name.assigns name
|
assigns: (name) -> @name.assigns name
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
if @index? then @compileParam(o) else @name.compile(o)
|
if @index? then @compileParam o else @name.compile o
|
||||||
|
|
||||||
# Compiling a parameter splat means recovering the parameters that succeed
|
# Compiling a parameter splat means recovering the parameters that succeed
|
||||||
# the splat in the parameter list, by slicing the arguments object.
|
# the splat in the parameter list, by slicing the arguments object.
|
||||||
compileParam: (o) ->
|
compileParam: (o) ->
|
||||||
name = @name.compile(o)
|
name = @name.compile o
|
||||||
o.scope.find name
|
o.scope.find name
|
||||||
end = ''
|
end = ''
|
||||||
if @trailings.length
|
if @trailings.length
|
||||||
|
@ -1107,8 +1107,10 @@ exports.Splat = class Splat extends Base
|
||||||
# flexibility or more speed than a comprehension can provide.
|
# flexibility or more speed than a comprehension can provide.
|
||||||
exports.While = class While extends Base
|
exports.While = class While extends Base
|
||||||
|
|
||||||
children: ['condition', 'guard', 'body']
|
children: ['condition', 'guard', 'body']
|
||||||
isStatement: YES
|
|
||||||
|
topSensitive: YES
|
||||||
|
isStatement : YES
|
||||||
|
|
||||||
constructor: (condition, opts) ->
|
constructor: (condition, opts) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1123,8 +1125,6 @@ exports.While = class While extends Base
|
||||||
@returns = true
|
@returns = true
|
||||||
this
|
this
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
# The main difference from a JavaScript *while* is that the CoffeeScript
|
# The main difference from a JavaScript *while* is that the CoffeeScript
|
||||||
# *while* can be used as a part of a larger expression -- while loops may
|
# *while* can be used as a part of a larger expression -- while loops may
|
||||||
# return an array containing the computed result of each iteration.
|
# return an array containing the computed result of each iteration.
|
||||||
|
@ -1140,9 +1140,9 @@ exports.While = class While extends Base
|
||||||
set = "#{@tab}#{rvar} = [];\n"
|
set = "#{@tab}#{rvar} = [];\n"
|
||||||
@body = Push.wrap(rvar, @body) if @body
|
@body = Push.wrap(rvar, @body) if @body
|
||||||
pre = "#{set}#{@tab}while (#{cond})"
|
pre = "#{set}#{@tab}while (#{cond})"
|
||||||
@body = Expressions.wrap([new If(@guard, @body)]) if @guard
|
@body = Expressions.wrap [new If @guard, @body] if @guard
|
||||||
if @returns
|
if @returns
|
||||||
post = '\n' + new Return(new Literal rvar).compile(merge(o, indent: @idt()))
|
post = '\n' + new Return(new Literal rvar).compile merge o, indent: @idt()
|
||||||
else
|
else
|
||||||
post = ''
|
post = ''
|
||||||
"#{pre} {\n#{ @body.compile(o) }\n#{@tab}}#{post}"
|
"#{pre} {\n#{ @body.compile(o) }\n#{@tab}}#{post}"
|
||||||
|
@ -1182,21 +1182,22 @@ exports.Op = class Op extends Base
|
||||||
first = new Parens first if first instanceof Code and first.bound
|
first = new Parens first if first instanceof Code and first.bound
|
||||||
super()
|
super()
|
||||||
@operator = @CONVERSIONS[op] or op
|
@operator = @CONVERSIONS[op] or op
|
||||||
(@first = first ).tags.operation = yes
|
(@first = first ).tags.operation = yes
|
||||||
(@second = second).tags.operation = yes if second
|
(@second = second).tags.operation = yes if second
|
||||||
@flip = !!flip
|
@flip = !!flip
|
||||||
|
|
||||||
isUnary: ->
|
isUnary: ->
|
||||||
not @second
|
not @second
|
||||||
|
|
||||||
isComplex: -> @operator isnt '!' or @first.isComplex()
|
isComplex: ->
|
||||||
|
@operator isnt '!' or @first.isComplex()
|
||||||
|
|
||||||
isChainable: ->
|
isChainable: ->
|
||||||
@operator in @CHAINABLE
|
@operator in @CHAINABLE
|
||||||
|
|
||||||
invert: ->
|
invert: ->
|
||||||
if @operator in ['===', '!==']
|
if op = @INVERSIONS[@operator]
|
||||||
@operator = @INVERSIONS[@operator]
|
@operator = op
|
||||||
this
|
this
|
||||||
else if @second
|
else if @second
|
||||||
new Parens(this).invert()
|
new Parens(this).invert()
|
||||||
|
@ -1204,7 +1205,7 @@ exports.Op = class Op extends Base
|
||||||
super()
|
super()
|
||||||
|
|
||||||
toString: (idt) ->
|
toString: (idt) ->
|
||||||
super(idt, @constructor.name + ' ' + @operator)
|
super idt, @constructor.name + ' ' + @operator
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
if @isUnary()
|
if @isUnary()
|
||||||
|
@ -1221,10 +1222,8 @@ exports.Op = class Op extends Base
|
||||||
# bin/coffee -e "puts 50 < 65 > 10"
|
# bin/coffee -e "puts 50 < 65 > 10"
|
||||||
# true
|
# true
|
||||||
compileChain: (o) ->
|
compileChain: (o) ->
|
||||||
shared = @first.unwrap().second
|
[@first.second, shared] = @first.unwrap().second.compileReference o
|
||||||
[@first.second, shared] = shared.compileReference o
|
"#{ @first.compile o } && #{ shared.compile o } #{@operator} #{ @second.compile o }"
|
||||||
[first, second, shared] = [@first.compile(o), @second.compile(o), shared.compile(o)]
|
|
||||||
"(#{first}) && (#{shared} #{@operator} #{second})"
|
|
||||||
|
|
||||||
compileExistence: (o) ->
|
compileExistence: (o) ->
|
||||||
if @first.isComplex()
|
if @first.isComplex()
|
||||||
|
@ -1253,13 +1252,13 @@ exports.In = class In extends Base
|
||||||
@array instanceof Value and @array.isArray()
|
@array instanceof Value and @array.isArray()
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
if @isArray() then @compileOrTest(o) else @compileLoopTest(o)
|
if @isArray() then @compileOrTest o else @compileLoopTest o
|
||||||
|
|
||||||
compileOrTest: (o) ->
|
compileOrTest: (o) ->
|
||||||
[obj1, obj2] = @object.compileReference o, precompile: yes
|
[obj1, obj2] = @object.compileReference o, precompile: yes
|
||||||
tests = for item, i in @array.base.objects
|
tests = for item, i in @array.base.objects
|
||||||
"#{if i then obj2 else obj1} === #{item.compile(o)}"
|
"#{ if i then obj2 else obj1 } === #{ item.compile o }"
|
||||||
"(#{tests.join(' || ')})"
|
"(#{ tests.join ' || ' })"
|
||||||
|
|
||||||
compileLoopTest: (o) ->
|
compileLoopTest: (o) ->
|
||||||
[obj1, obj2] = @object.compileReference merge(o, top: yes), precompile: yes
|
[obj1, obj2] = @object.compileReference merge(o, top: yes), precompile: yes
|
||||||
|
@ -1272,14 +1271,15 @@ exports.In = class In extends Base
|
||||||
# A classic *try/catch/finally* block.
|
# A classic *try/catch/finally* block.
|
||||||
exports.Try = class Try extends Base
|
exports.Try = class Try extends Base
|
||||||
|
|
||||||
children: ['attempt', 'recovery', 'ensure']
|
children: ['attempt', 'recovery', 'ensure']
|
||||||
|
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@attempt, @error, @recovery, @ensure) ->
|
constructor: (@attempt, @error, @recovery, @ensure) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@attempt = @attempt.makeReturn() if @attempt
|
@attempt = @attempt .makeReturn() if @attempt
|
||||||
@recovery = @recovery.makeReturn() if @recovery
|
@recovery = @recovery.makeReturn() if @recovery
|
||||||
this
|
this
|
||||||
|
|
||||||
|
@ -1289,11 +1289,11 @@ exports.Try = class Try extends Base
|
||||||
o.indent = @idt 1
|
o.indent = @idt 1
|
||||||
o.top = true
|
o.top = true
|
||||||
attemptPart = @attempt.compile(o)
|
attemptPart = @attempt.compile(o)
|
||||||
errorPart = if @error then " (#{ @error.compile(o) }) " else ' '
|
errorPart = if @error then " (#{ @error.compile o }) " else ' '
|
||||||
catchPart = if @recovery
|
catchPart = if @recovery
|
||||||
" catch#{errorPart}{\n#{ @recovery.compile(o) }\n#{@tab}}"
|
" catch#{errorPart}{\n#{ @recovery.compile o }\n#{@tab}}"
|
||||||
else unless @ensure or @recovery then ' catch (_e) {}' else ''
|
else unless @ensure or @recovery then ' catch (_e) {}' else ''
|
||||||
finallyPart = (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o)) + "\n#{@tab}}"
|
finallyPart = (@ensure or '') and ' finally {\n' + @ensure.compile(merge o) + "\n#{@tab}}"
|
||||||
"#{@tab}try {\n#{attemptPart}\n#{@tab}}#{catchPart}#{finallyPart}"
|
"#{@tab}try {\n#{attemptPart}\n#{@tab}}#{catchPart}#{finallyPart}"
|
||||||
|
|
||||||
#### Throw
|
#### Throw
|
||||||
|
@ -1301,7 +1301,8 @@ exports.Try = class Try extends Base
|
||||||
# Simple node to throw an exception.
|
# Simple node to throw an exception.
|
||||||
exports.Throw = class Throw extends Base
|
exports.Throw = class Throw extends Base
|
||||||
|
|
||||||
children: ['expression']
|
children: ['expression']
|
||||||
|
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
|
@ -1311,7 +1312,7 @@ exports.Throw = class Throw extends Base
|
||||||
makeReturn: THIS
|
makeReturn: THIS
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
"#{@tab}throw #{@expression.compile(o)};"
|
"#{@tab}throw #{ @expression.compile o };"
|
||||||
|
|
||||||
#### Existence
|
#### Existence
|
||||||
|
|
||||||
|
@ -1344,23 +1345,23 @@ exports.Parens = class Parens extends Base
|
||||||
|
|
||||||
children: ['expression']
|
children: ['expression']
|
||||||
|
|
||||||
|
topSensitive: YES
|
||||||
|
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
isStatement: (o) ->
|
isStatement: (o) ->
|
||||||
@expression.isStatement(o)
|
@expression.isStatement o
|
||||||
isComplex: ->
|
isComplex: ->
|
||||||
@expression.isComplex()
|
@expression.isComplex()
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@expression.makeReturn()
|
@expression.makeReturn()
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
top = del o, 'top'
|
top = del o, 'top'
|
||||||
@expression.parenthetical = true
|
@expression.parenthetical = true
|
||||||
code = @expression.compile(o)
|
code = @expression.compile o
|
||||||
return code if top and @expression.isPureStatement o
|
return code if top and @expression.isPureStatement o
|
||||||
if @parenthetical or @isStatement o
|
if @parenthetical or @isStatement o
|
||||||
return if top then @tab + code + ';' else code
|
return if top then @tab + code + ';' else code
|
||||||
|
@ -1377,8 +1378,10 @@ exports.Parens = class Parens extends Base
|
||||||
# you can map and filter in a single pass.
|
# you can map and filter in a single pass.
|
||||||
exports.For = class For extends Base
|
exports.For = class For extends Base
|
||||||
|
|
||||||
children: ['body', 'source', 'guard']
|
children: ['body', 'source', 'guard']
|
||||||
isStatement: YES
|
|
||||||
|
topSensitive: YES
|
||||||
|
isStatement : YES
|
||||||
|
|
||||||
constructor: (@body, source, @name, @index) ->
|
constructor: (@body, source, @name, @index) ->
|
||||||
super()
|
super()
|
||||||
|
@ -1386,18 +1389,16 @@ exports.For = class For extends Base
|
||||||
@raw = !!source.raw
|
@raw = !!source.raw
|
||||||
@object = !!source.object
|
@object = !!source.object
|
||||||
[@name, @index] = [@index, @name] if @object
|
[@name, @index] = [@index, @name] if @object
|
||||||
|
throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
|
||||||
@pattern = @name instanceof Value
|
@pattern = @name instanceof Value
|
||||||
throw new Error('index cannot be a pattern matching expression') if @index instanceof Value
|
|
||||||
@returns = false
|
@returns = false
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@returns = true
|
@returns = true
|
||||||
this
|
this
|
||||||
|
|
||||||
compileReturnValue: (val, o) ->
|
compileReturnValue: (val, o) ->
|
||||||
return '\n' + new Return(new Literal val).compile(o) if @returns
|
return '\n' + new Return(new Literal val).compile o if @returns
|
||||||
return '\n' + val if val
|
return '\n' + val if val
|
||||||
''
|
''
|
||||||
|
|
||||||
|
@ -1422,7 +1423,7 @@ exports.For = class For extends Base
|
||||||
varPart = ''
|
varPart = ''
|
||||||
guardPart = ''
|
guardPart = ''
|
||||||
unstepPart = ''
|
unstepPart = ''
|
||||||
body = Expressions.wrap([@body])
|
body = Expressions.wrap [@body]
|
||||||
idt1 = @idt 1
|
idt1 = @idt 1
|
||||||
if range
|
if range
|
||||||
forPart = source.compile merge o, {index: ivar, @step}
|
forPart = source.compile merge o, {index: ivar, @step}
|
||||||
|
@ -1442,10 +1443,10 @@ exports.For = class For extends Base
|
||||||
stepPart = if @step then "#{ivar} += #{ @step.compile(o) }" else "#{ivar}++"
|
stepPart = if @step then "#{ivar} += #{ @step.compile(o) }" else "#{ivar}++"
|
||||||
forPart = "#{ivar} = 0, #{lvar} = #{sourcePart}.length; #{ivar} < #{lvar}; #{stepPart}"
|
forPart = "#{ivar} = 0, #{lvar} = #{sourcePart}.length; #{ivar} < #{lvar}; #{stepPart}"
|
||||||
resultPart = if rvar then "#{@tab}#{rvar} = [];\n" else ''
|
resultPart = if rvar then "#{@tab}#{rvar} = [];\n" else ''
|
||||||
returnResult = @compileReturnValue(rvar, o)
|
returnResult = @compileReturnValue rvar, o
|
||||||
body = Push.wrap(rvar, body) unless topLevel
|
body = Push.wrap rvar, body unless topLevel
|
||||||
if @guard
|
if @guard
|
||||||
body = Expressions.wrap([new If(@guard, body)])
|
body = Expressions.wrap [new If @guard, body]
|
||||||
if codeInBody
|
if codeInBody
|
||||||
body.unshift new Literal "var #{name} = #{ivar}" if range
|
body.unshift new Literal "var #{name} = #{ivar}" if range
|
||||||
body.unshift new Literal "var #{namePart}" if namePart
|
body.unshift new Literal "var #{namePart}" if namePart
|
||||||
|
@ -1485,8 +1486,6 @@ exports.Switch = class Switch extends Base
|
||||||
|
|
||||||
constructor: (@subject, @cases, @otherwise) ->
|
constructor: (@subject, @cases, @otherwise) ->
|
||||||
super()
|
super()
|
||||||
@tags.subjectless = !@subject
|
|
||||||
@subject or= new Literal 'true'
|
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
pair[1].makeReturn() for pair in @cases
|
pair[1].makeReturn() for pair in @cases
|
||||||
|
@ -1494,19 +1493,18 @@ exports.Switch = class Switch extends Base
|
||||||
this
|
this
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
idt = o.indent = @idt 2
|
idt1 = @idt 1
|
||||||
|
idt2 = o.indent = @idt 2
|
||||||
o.top = yes
|
o.top = yes
|
||||||
code = "#{ @tab }switch (#{ @subject.compile o }) {"
|
code = "#{ @tab }switch (#{ @subject?.compile(o) or true }) {"
|
||||||
for pair in @cases
|
for [conditions, block] in @cases
|
||||||
[conditions, block] = pair
|
|
||||||
exprs = block.expressions
|
|
||||||
for condition in flatten [conditions]
|
for condition in flatten [conditions]
|
||||||
condition = new Op '!!', new Parens condition if @tags.subjectless
|
condition = condition.invert().invert() unless @subject
|
||||||
code += "\n#{ @idt(1) }case #{ condition.compile o }:"
|
code += "\n#{ idt1 }case #{ condition.compile o }:"
|
||||||
code += "\n#{ block.compile o }"
|
code += "\n#{ block.compile o }"
|
||||||
code += "\n#{ idt }break;" unless last(exprs) instanceof Return
|
code += "\n#{ idt2 }break;" unless last(block.expressions) instanceof Return
|
||||||
if @otherwise
|
if @otherwise
|
||||||
code += "\n#{ @idt(1) }default:\n#{ @otherwise.compile o }"
|
code += "\n#{ idt1 }default:\n#{ @otherwise.compile o }"
|
||||||
code += "\n#{ @tab }}"
|
code += "\n#{ @tab }}"
|
||||||
code
|
code
|
||||||
|
|
||||||
|
@ -1556,8 +1554,8 @@ exports.If = class If extends Base
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
if @isStatement()
|
if @isStatement()
|
||||||
@body and= @ensureExpressions(@body.makeReturn())
|
@body and= @ensureExpressions @body.makeReturn()
|
||||||
@elseBody and= @ensureExpressions(@elseBody.makeReturn())
|
@elseBody and= @ensureExpressions @elseBody.makeReturn()
|
||||||
this
|
this
|
||||||
else
|
else
|
||||||
new Return this
|
new Return this
|
||||||
|
@ -1687,7 +1685,7 @@ TAB = ' '
|
||||||
TRAILING_WHITESPACE = /[ \t]+$/gm
|
TRAILING_WHITESPACE = /[ \t]+$/gm
|
||||||
|
|
||||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
|
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i
|
NUMBER = /^0x[\da-f]+$|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i
|
||||||
SIMPLENUM = /^[+-]?\d+$/
|
SIMPLENUM = /^[+-]?\d+$/
|
||||||
|
|
||||||
# Is a literal value a string?
|
# Is a literal value a string?
|
||||||
|
|
Loading…
Reference in New Issue