CoffeeScript-in-CoffeeScript is compiling function calls

This commit is contained in:
Jeremy Ashkenas
2010-02-08 22:55:56 -05:00
parent 0b5b6113ee
commit 210d673ef0
4 changed files with 164 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
(function(){
var CommentNode, Expressions, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, compact, del, dup, flatten, inherit, merge, statement;
var CallNode, CommentNode, Expressions, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement;
var __hasProp = Object.prototype.hasOwnProperty;
process.mixin(require('./scope'));
// The abstract base class for all CoffeeScript nodes.
@@ -270,6 +270,21 @@
}).call(this);
return dest;
};
// Do any of the elements in the list pass a truth test?
any = function any(list, test) {
var __a, __b, __c, item, result;
result = (function() {
__a = []; __b = list;
for (__c = 0; __c < __b.length; __c++) {
item = __b[__c];
if (test(item)) {
__a.push(true);
}
}
return __a;
}).call(this);
return !!result.length;
};
// Delete a key from an object, returning the value.
del = function del(obj, key) {
var val;
@@ -612,4 +627,79 @@
}
}));
statement(CommentNode);
// Node for a function invocation. Takes care of converting super() calls into
// calls against the prototype's function of the same name.
CallNode = (exports.CallNode = inherit(Node, {
constructor: function constructor(variable, args) {
this.variable = variable;
this.args = args || [];
this.children = flatten([this.variable, this.args]);
this.prefix = '';
return this;
},
new_instance: function new_instance() {
this.prefix = 'new ';
return this;
},
push: function push(arg) {
this.args.push(arg);
return this.children.push(arg);
},
// Compile a vanilla function call.
compile_node: function compile_node(o) {
var __a, __b, __c, arg, args;
if (any(this.args, function(a) {
return a instanceof SplatNode;
})) {
return this.compile_splat(o);
}
args = ((function() {
__a = []; __b = this.args;
for (__c = 0; __c < __b.length; __c++) {
arg = __b[__c];
__a.push(arg.compile(o));
}
return __a;
}).call(this)).join(', ');
if (this.variable === 'super') {
return this.compile_super(args, o);
}
return this.prefix + this.variable.compile(o) + '(' + args + ')';
},
// Compile a call against the superclass's implementation of the current function.
compile_super: function compile_super(args, o) {
var arg_part, meth, methname;
methname = o.scope.method.name;
arg_part = args.length ? ', ' + args : '';
meth = o.scope.method.proto ? o.scope.method.proto + '.__superClass__.' + methname : methname + '.__superClass__.constructor';
return meth + '.call(this' + arg_part + ')';
},
// Compile a function call being passed variable arguments.
compile_splat: function compile_splat(o) {
var __a, __b, arg, args, code, i, meth, obj;
meth = this.variable.compile(o);
obj = this.variable.source || 'this';
args = (function() {
__a = []; __b = this.args;
for (i = 0; i < __b.length; i++) {
arg = __b[i];
__a.push((function() {
code = arg.compile(o);
code = arg instanceof SplatNode ? code : '[' + code + ']';
return i === 0 ? code : '.concat(' + code + ')';
}).call(this));
}
return __a;
}).call(this);
return this.prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')';
},
// If the code generation wished to use the result of a function call
// in multiple places, ensure that the function is only ever called once.
compile_reference: function compile_reference(o) {
var call, reference;
reference = o.scope.free_variable();
call = new ParentheticalNode(new AssignNode(reference, this));
return [call, reference];
}
}));
})();