use :node;
var Node = module.require('../Node').Node;
fn CallExpression(callee, args)
extends Node { this.type = 'CallExpression'; this.callee = callee; this.callee.parent = this; ::Object.defineProperty(this, 'arguments', { value: args, enumerable: true }); for arg in args { arg.parent = this; }
}
CallExpression.prototype.codegen = () -> {
if !super.codegen() { return; } var calleeType = this.callee.type; if !this.callee.codeGenerated { this.callee = this.callee.codegen(); } var args = this.arguments; var splatPositions = []; for arg, i in args { if args[i].type == "SplatExpression" || args[i].__splat { splatPositions.push(i); } if !args[i].codeGenerated { args[i] = arg.codegen(); } } if splatPositions.length > 0 { var argsClone = args.slice(0); args.length = 0; args.push({ "type": "Literal", "value": null }); if argsClone.length == 1 { args.push(argsClone[0].arguments[0]); } else { args.push({ "type": "CallExpression", "callee": { "type": "MemberExpression", "computed": false, "object": argsClone[0] if splatPositions[0] == 0 else { "type": "ArrayExpression", "elements": argsClone[...splatPositions[0]] }, "property": { "type": "Identifier", "name": "concat" } }, "arguments": argsClone[1 if splatPositions[0] == 0 else splatPositions[0]..] .map((arg, i) -> { if splatPositions.indexOf(i + (1 if splatPositions[0] == 0 else splatPositions[0])) != -1 { return arg; } return { "type": "ArrayExpression", "elements": [arg] }; }) }); } } // If we are null propagating (?.), then turn this // into a condition and add the null propagating condition. if this.callee.type == 'ConditionalExpression' && (calleeType == 'NullPropagatingExpression' || calleeType == 'MemberExpression') { var parent = this.parent; var consequent = { type: 'CallExpression', callee: this.callee.consequent, arguments: this.arguments }; if splatPositions.length > 0 { this.callee.consequent = { "type": "MemberExpression", "computed": false, "object": this.callee.consequent, "property": { "type": "Identifier", "name": "apply" } }; } // If we're inside a statement, then turn this into // a normal if statement. if parent.type == 'ExpressionStatement' { parent.type = 'IfStatement'; parent.test = this.callee.test; parent.consequent = { type: 'BlockStatement', body: [ { type: 'ExpressionStatement', expression: consequent } ] }; parent.alternate = null; } else { // Otherwise, it should be a conditional expression (?:). this.type = 'ConditionalExpression'; this.test = this.callee.test; this.consequent = consequent; this.alternate = this.callee.alternate; } } else if splatPositions.length > 0 { this.callee = { "type": "MemberExpression", "computed": false, "object": this.callee, "property": { "type": "Identifier", "name": "apply" } }; } return this;
};
CallExpression.prototype.hasCallExpression = () -> true;
exports.CallExpression = CallExpression;