continuation.js
Version:
A module for tail call optimization by Continuation Passing Style (CPS) transformation with trampoline technique for Node.js
934 lines • 118 kB
JavaScript
if (typeof CpsFunction === 'undefined') {
CpsFunction = function (f, k) {
this.f = f;
this.k = k;
};
}
if (typeof CpsContinuation === 'undefined') {
CpsContinuation = function (k) {
if (k) {
this.k = k;
} else {
this.k = function (r) {
return r;
};
}
};
}
if (typeof CpsResult === 'undefined') {
CpsResult = function (r) {
this.r = r;
};
}
if (typeof CpsRun === 'undefined') {
CpsRun = function (x) {
var last_k;
while (x instanceof CpsFunction) {
last_k = x.k;
x = x.f(x.k);
}
if (x instanceof CpsResult) {
return x.r;
} else {
return last_k.k(x);
}
};
}
var esprima = require('esprima');
var escodegen = require('escodegen');
var assert = require('assert');
var _ = require('underscore');
var root = {};
root.parse = function CpsEnableWrapper() {
var ff9 = function (data) {
var l1 = arguments.length - 1;
var k2 = arguments[l1];
if (k2 instanceof CpsContinuation) {
if (l1 === 1) {
} else if (l1 >= 0) {
data = undefined;
}
return new CpsFunction(function (kk7) {
return esprima.parse.CpsEnabled ? esprima.parse(data, kk7) : esprima.parse(data);
}, k2);
return;
}
return esprima.parse.CpsEnabled ? CpsRun(new CpsFunction(function (kk6) {
return esprima.parse(data, kk6);
}, new CpsContinuation())) : esprima.parse(data);
};
ff9.CpsEnabled = true;
return ff9;
}();
root.push = function CpsEnableWrapper() {
var ff18 = function (lst, itm) {
var l10 = arguments.length - 1;
var k11 = arguments[l10];
if (k11 instanceof CpsContinuation) {
if (l10 === 2) {
} else if (l10 >= 1) {
itm = undefined;
} else if (l10 >= 0) {
lst = undefined;
}
if (Array.isArray(itm)) {
for (var i = 0; i < itm.length; i++) {
lst.push(itm[i]);
}
} else {
return new CpsFunction(function (kk16) {
return lst.push.CpsEnabled ? lst.push(itm, kk16) : lst.push(itm);
}, k11);
}
return;
}
if (Array.isArray(itm)) {
for (var i = 0; i < itm.length; i++) {
lst.push(itm[i]);
}
} else {
lst.push.CpsEnabled ? CpsRun(new CpsFunction(function (kk15) {
return lst.push(itm, kk15);
}, new CpsContinuation())) : lst.push(itm);
}
};
ff18.CpsEnabled = true;
return ff18;
}();
root.unshift = function (lst, itm, force) {
if (Array.isArray(itm)) {
itm = itm.reverse();
} else {
itm = [itm];
}
if (!force) {
while (lst.length > 0 && lst[0].type === 'FunctionDeclaration') {
itm.push(lst.shift());
}
}
for (var i = 0; i < itm.length; i++) {
lst.unshift(itm[i]);
}
};
root.ast_prog_header = function () {
var ast = root.parse('if (typeof CpsFunction === \'undefined\') { CpsFunction = function(f, k) { this.f = f; this.k = k; }; } if (typeof CpsContinuation === \'undefined\') { CpsContinuation = function(k) { if (k) { this.k = k; } else { this.k = function(r) { return r; }; }}; } if (typeof CpsResult === \'undefined\') { CpsResult = function(r) { this.r = r; }; } if (typeof CpsRun === \'undefined\') { CpsRun = function(x) { var last_k; while (x instanceof CpsFunction) { last_k = x.k; x = x.f(x.k); } if (x instanceof CpsResult) { return x.r; } else { return last_k.k(x); }}; }');
assert.equal(ast.type, 'Program');
return ast.body;
};
root.new_variable_counter = 1;
root.generate_new_variable_name = function CpsEnableWrapper() {
var ff35 = function (prefix, exclude_ids) {
var l27 = arguments.length - 1;
var k28 = arguments[l27];
if (k28 instanceof CpsContinuation) {
if (l27 === 2) {
} else if (l27 >= 1) {
exclude_ids = undefined;
} else if (l27 >= 0) {
prefix = undefined;
}
var varname = prefix + root.new_variable_counter++;
if (exclude_ids.indexOf(varname) >= 0) {
return new CpsFunction(function (kk33) {
return root.generate_new_variable_name.CpsEnabled ? root.generate_new_variable_name(prefix, exclude_ids, kk33) : root.generate_new_variable_name(prefix, exclude_ids);
}, k28);
} else {
return new CpsResult(k28.k(varname));
}
return;
}
var varname = prefix + root.new_variable_counter++;
if (exclude_ids.indexOf(varname) >= 0) {
return root.generate_new_variable_name.CpsEnabled ? CpsRun(new CpsFunction(function (kk32) {
return root.generate_new_variable_name(prefix, exclude_ids, kk32);
}, new CpsContinuation())) : root.generate_new_variable_name(prefix, exclude_ids);
} else {
return varname;
}
};
ff35.CpsEnabled = true;
return ff35;
}();
root.ast_func_header = function (l_varname, t_varname, a_varname, exclude_ids) {
var i_varname = root.generate_new_variable_name('i', exclude_ids);
var code = 'var ' + l_varname + ' = arguments.length - 1;';
if (t_varname) {
code += 'var ' + t_varname + ' = this;';
}
if (a_varname) {
code += 'var ' + a_varname + ' = {}; for(var ' + i_varname + ' = 0; ' + i_varname + ' <= ' + l_varname + '; ' + i_varname + '++) { ' + a_varname + '[' + i_varname + '] = arguments[' + i_varname + ']; }' + a_varname + '.length = 1 + ' + l_varname + ';' + a_varname + '.callee = arguments.callee;';
}
var ast = root.parse(code);
assert.equal(ast.type, 'Program');
return ast.body;
};
root.ast_func_wrapper = function (k_varname, l_varname, a_varname, params) {
var code = 'var ' + k_varname + ' = arguments[' + l_varname + ']; if (' + k_varname + ' instanceof CpsContinuation) { ';
if (a_varname) {
code += 'delete ' + a_varname + '[' + l_varname + ']; ' + a_varname + '.length--;';
}
if (params.length > 0) {
code += 'if (' + l_varname + ' === ' + params.length + ') {';
for (var i = params.length - 1; i >= 0; i--) {
assert.equal(params[i].type, 'Identifier');
code += '} else if (' + l_varname + ' >= ' + i + ') {' + params[i].name + ' = undefined;';
}
code += '}';
}
code += '}';
var ast = root.parse(code);
assert.equal(ast.type, 'Program');
return ast.body;
};
root.collect_all_identifiers = function (node) {
var ids = [];
var walk = function CpsEnableWrapper() {
var ff55 = function (node) {
var l44 = arguments.length - 1;
var k45 = arguments[l44];
if (k45 instanceof CpsContinuation) {
if (l44 === 1) {
} else if (l44 >= 0) {
node = undefined;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return new CpsResult(k45.k(null));
} else if (node && node.type === 'Identifier') {
return new CpsFunction(function (kk52) {
return ids.push.CpsEnabled ? ids.push(node.name, kk52) : ids.push(node.name);
}, k45);
} else if (node instanceof Object) {
return new CpsFunction(function (kk53) {
return _.each.CpsEnabled ? _.each(node, walk, kk53) : _.each(node, walk);
}, k45);
}
return;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return;
} else if (node && node.type === 'Identifier') {
ids.push.CpsEnabled ? CpsRun(new CpsFunction(function (kk50) {
return ids.push(node.name, kk50);
}, new CpsContinuation())) : ids.push(node.name);
} else if (node instanceof Object) {
_.each.CpsEnabled ? CpsRun(new CpsFunction(function (kk51) {
return _.each(node, walk, kk51);
}, new CpsContinuation())) : _.each(node, walk);
}
};
ff55.CpsEnabled = true;
return ff55;
}();
walk(node);
return ids;
};
root.replace_this_var_with = function (body, t_varname) {
var using_this_var = false;
var walk = function CpsEnableWrapper() {
var ff68 = function (node) {
var l60 = arguments.length - 1;
var k61 = arguments[l60];
if (k61 instanceof CpsContinuation) {
if (l60 === 1) {
} else if (l60 >= 0) {
node = undefined;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return new CpsResult(k61.k(null));
} else if (node && node.type === 'ThisExpression') {
node.type = 'Identifier';
node.name = t_varname;
using_this_var = true;
} else if (node instanceof Object) {
return new CpsFunction(function (kk66) {
return _.each.CpsEnabled ? _.each(node, walk, kk66) : _.each(node, walk);
}, k61);
}
return;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return;
} else if (node && node.type === 'ThisExpression') {
node.type = 'Identifier';
node.name = t_varname;
using_this_var = true;
} else if (node instanceof Object) {
_.each.CpsEnabled ? CpsRun(new CpsFunction(function (kk65) {
return _.each(node, walk, kk65);
}, new CpsContinuation())) : _.each(node, walk);
}
};
ff68.CpsEnabled = true;
return ff68;
}();
walk(body);
return using_this_var;
};
root.replace_arguments_with = function (body, a_varname) {
var using_arguments = false;
var walk = function CpsEnableWrapper() {
var ff84 = function (node) {
var l73 = arguments.length - 1;
var k74 = arguments[l73];
if (k74 instanceof CpsContinuation) {
if (l73 === 1) {
} else if (l73 >= 0) {
node = undefined;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return new CpsResult(k74.k(null));
} else if (node && node.type === 'Property') {
return new CpsResult(k74.k(null));
} else if (node && node.type === 'MemberExpression') {
return new CpsFunction(function (kk81) {
return walk.CpsEnabled ? walk(node.object, kk81) : walk(node.object);
}, k74);
} else if (node && node.type === 'Identifier' && node.name === 'arguments') {
node.name = a_varname;
using_arguments = true;
} else if (node instanceof Object) {
return new CpsFunction(function (kk82) {
return _.each.CpsEnabled ? _.each(node, walk, kk82) : _.each(node, walk);
}, k74);
}
return;
}
if (node && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return;
} else if (node && node.type === 'Property') {
return;
} else if (node && node.type === 'MemberExpression') {
walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk79) {
return walk(node.object, kk79);
}, new CpsContinuation())) : walk(node.object);
} else if (node && node.type === 'Identifier' && node.name === 'arguments') {
node.name = a_varname;
using_arguments = true;
} else if (node instanceof Object) {
_.each.CpsEnabled ? CpsRun(new CpsFunction(function (kk80) {
return _.each(node, walk, kk80);
}, new CpsContinuation())) : _.each(node, walk);
}
};
ff84.CpsEnabled = true;
return ff84;
}();
walk(body);
return using_arguments;
};
root.deep_clone = function CpsEnableWrapper() {
var ff100 = function (node) {
var l89 = arguments.length - 1;
var k90 = arguments[l89];
if (k90 instanceof CpsContinuation) {
if (l89 === 1) {
} else if (l89 >= 0) {
node = undefined;
}
if (node instanceof Date) {
return new CpsResult(k90.k(node));
} else if (node instanceof RegExp) {
return new CpsResult(k90.k(node));
} else if (Array.isArray(node)) {
return new CpsFunction(function (kk97) {
return _.map.CpsEnabled ? _.map(node, root.deep_clone, kk97) : _.map(node, root.deep_clone);
}, k90);
} else if (node instanceof Object) {
return new CpsFunction(function (kk98) {
return _.object.CpsEnabled ? _.object(_.map(_.pairs(node), function (x) {
return [
x[0],
root.deep_clone(x[1])
];
}), kk98) : _.object(_.map(_.pairs(node), function (x) {
return [
x[0],
root.deep_clone(x[1])
];
}));
}, k90);
} else {
return new CpsResult(k90.k(node));
}
return;
}
if (node instanceof Date) {
return node;
} else if (node instanceof RegExp) {
return node;
} else if (Array.isArray(node)) {
return _.map.CpsEnabled ? CpsRun(new CpsFunction(function (kk95) {
return _.map(node, root.deep_clone, kk95);
}, new CpsContinuation())) : _.map(node, root.deep_clone);
} else if (node instanceof Object) {
return _.object.CpsEnabled ? CpsRun(new CpsFunction(function (kk96) {
return _.object(_.map(_.pairs(node), function (x) {
return [
x[0],
root.deep_clone(x[1])
];
}), kk96);
}, new CpsContinuation())) : _.object(_.map(_.pairs(node), function (x) {
return [
x[0],
root.deep_clone(x[1])
];
}));
} else {
return node;
}
};
ff100.CpsEnabled = true;
return ff100;
}();
root.transform_function_body = function (params, defaults, body, exclude_ids) {
assert.equal(body.type, 'BlockStatement');
if (body.body.length === 0) {
return false;
}
var cps_func_ids = root.walk_ast(body.body);
var l_varname = root.generate_new_variable_name('l', exclude_ids);
var k_varname = root.generate_new_variable_name('k', exclude_ids);
var t_varname = root.generate_new_variable_name('t', exclude_ids);
var a_varname = root.generate_new_variable_name('a', exclude_ids);
var tmpbody = root.deep_clone(body);
var using_this_var = false;
var using_arguments = false;
var cpsenabled = false;
if (root.convert_function_call_to_cpsrun_call(tmpbody, exclude_ids)) {
using_this_var = root.replace_this_var_with(body.body, t_varname);
using_arguments = root.replace_arguments_with(body.body, a_varname);
var newbody = root.deep_clone(body);
root.convert_function_call_to_cpsrun_call(body, exclude_ids);
cpsenabled = root.convert_normal_body_to_cps_body(k_varname, exclude_ids, newbody);
var header = root.ast_func_header(l_varname, using_this_var && t_varname, using_arguments && a_varname, exclude_ids);
if (cpsenabled) {
while (newbody.body.length > 0) {
if (newbody.body[0].type === 'FunctionDeclaration') {
newbody.body.shift();
} else {
break;
}
}
var wrapper = root.ast_func_wrapper(k_varname, l_varname, using_arguments && a_varname, params);
assert.ok(wrapper[1].consequent.body.length >= 0);
root.push(wrapper[1].consequent.body, newbody.body);
root.push(wrapper[1].consequent.body, {
type: 'ReturnStatement',
argument: null
});
root.unshift(body.body, wrapper);
root.unshift(body.body, header);
} else if (using_this_var || using_arguments) {
root.unshift(body.body, header);
}
}
_.each(_.flatten(cps_func_ids), function (cps_func_id) {
root.unshift(body.body, root.create_cpsenabled_statement(cps_func_id));
});
return cpsenabled;
};
root.is_callee_having_side_effect = function (node) {
var has_side_effect = function CpsEnableWrapper() {
var ff113 = function (node) {
var l105 = arguments.length - 1;
var k106 = arguments[l105];
if (k106 instanceof CpsContinuation) {
if (l105 === 1) {
} else if (l105 >= 0) {
node = undefined;
}
if (!node) {
return new CpsResult(k106.k(false));
} else if (node.type === 'FunctionExpression') {
return new CpsResult(k106.k(true));
} else if (node.type === 'CallExpression') {
return new CpsResult(k106.k(true));
} else if (node.type === 'UpdateExpression') {
return new CpsResult(k106.k(true));
} else if (node.type === 'AssignmentExpression') {
return new CpsResult(k106.k(true));
} else if (node.type === 'NewExpression') {
return new CpsResult(k106.k(true));
} else if (node instanceof Object) {
return new CpsFunction(function (kk111) {
return _.some.CpsEnabled ? _.some(node, has_side_effect, kk111) : _.some(node, has_side_effect);
}, k106);
} else {
return new CpsResult(k106.k(false));
}
return;
}
if (!node) {
return false;
} else if (node.type === 'FunctionExpression') {
return true;
} else if (node.type === 'CallExpression') {
return true;
} else if (node.type === 'UpdateExpression') {
return true;
} else if (node.type === 'AssignmentExpression') {
return true;
} else if (node.type === 'NewExpression') {
return true;
} else if (node instanceof Object) {
return _.some.CpsEnabled ? CpsRun(new CpsFunction(function (kk110) {
return _.some(node, has_side_effect, kk110);
}, new CpsContinuation())) : _.some(node, has_side_effect);
} else {
return false;
}
};
ff113.CpsEnabled = true;
return ff113;
}();
return node.callee && has_side_effect(node.callee);
};
root.is_callee_cpsenablewrapper = function (node) {
return node.callee && node.callee.id && node.callee.id.type === 'Identifier' && node.callee.id.name === 'CpsEnableWrapper';
};
root.convert_function_call_to_cpsrun_call = function CpsEnableWrapper() {
var ff162 = function (body, exclude_ids) {
var l154 = arguments.length - 1;
var k155 = arguments[l154];
if (k155 instanceof CpsContinuation) {
if (l154 === 2) {
} else if (l154 >= 1) {
exclude_ids = undefined;
} else if (l154 >= 0) {
body = undefined;
}
var create_cpsrun_call = function (call_expression) {
var kk_varname = root.generate_new_variable_name('kk', exclude_ids);
var call_expression1 = root.deep_clone(call_expression);
var call_expression2 = root.deep_clone(call_expression);
call_expression2.arguments.push({
type: 'Identifier',
name: kk_varname
});
return {
type: 'ConditionalExpression',
test: {
type: 'MemberExpression',
computed: false,
object: call_expression1.callee,
property: {
type: 'Identifier',
name: 'CpsEnabled'
}
},
consequent: {
type: 'CallExpression',
callee: {
type: 'Identifier',
name: 'CpsRun'
},
arguments: [{
type: 'NewExpression',
callee: {
type: 'Identifier',
name: 'CpsFunction'
},
arguments: [
{
type: 'FunctionExpression',
id: null,
params: [{
type: 'Identifier',
name: kk_varname
}],
defaults: [],
body: {
type: 'BlockStatement',
body: [{
type: 'ReturnStatement',
argument: call_expression2
}]
},
rest: null,
generator: false,
expression: false
},
{
type: 'NewExpression',
callee: {
type: 'Identifier',
name: 'CpsContinuation'
},
arguments: []
}
]
}]
},
alternate: {
type: call_expression1.type,
callee: call_expression1.callee,
arguments: call_expression1.arguments
}
};
};
var is_callee_using_apply = function (node) {
return node.callee && node.callee.type === 'MembershipExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'apply';
};
var walk = function CpsEnableWrapper() {
var ff153 = function (node, tail, wrapped) {
var l130 = arguments.length - 1;
var k131 = arguments[l130];
if (k131 instanceof CpsContinuation) {
if (l130 === 3) {
} else if (l130 >= 2) {
wrapped = undefined;
} else if (l130 >= 1) {
tail = undefined;
} else if (l130 >= 0) {
node = undefined;
}
var transformed;
var i;
if (node === undefined || node === null) {
return new CpsResult(k131.k(0));
} else if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
return new CpsResult(k131.k(0));
} else if (node.type === 'CallExpression') {
if (tail && !wrapped && !root.is_callee_cpsenablewrapper(node) && !root.is_callee_having_side_effect(node) && !is_callee_using_apply(node)) {
var newnode = create_cpsrun_call(node);
_.each(node, function (value, key) {
delete node[key];
});
_.extend(node, newnode);
return new CpsResult(k131.k(1));
} else {
return new CpsResult(k131.k(0));
}
} else if (node.type === 'ConditionalExpression') {
return new CpsResult(k131.k(walk(node.test, false, wrapped) + walk(node.consequent, tail, wrapped) + walk(node.alternate, tail, wrapped)));
} else if (node.type === 'SequenceExpression') {
transformed = 0;
for (i = 0; i < node.expressions.length; i++) {
transformed += walk(node.expressions[i], false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'AssignmentExpression' || node.type === 'BinaryExpression' || node.type === 'UpdateExpression' || node.type === 'MemberExpression' || node.type === 'LogicalExpression' || node.type === 'ArrayExpression' || node.type === 'ObjectExpression' || node.type === 'UnaryExpression' || node.type === 'NewExpression' || node.type === 'ThisExpression') {
return new CpsResult(k131.k(0));
} else if (node.type === 'BlockStatement') {
transformed = 0;
for (i = 0; i < node.body.length; i++) {
transformed += walk(node.body[i], i === node.body.length - 1 ? tail : false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'ExpressionStatement') {
return new CpsFunction(function (kk146) {
return walk.CpsEnabled ? walk(node.expression, tail, wrapped, kk146) : walk(node.expression, tail, wrapped);
}, k131);
} else if (node.type === 'DoWhileStatement' || node.type === 'WhileStatement') {
return new CpsResult(k131.k(walk(node.body, false, wrapped) + walk(node.test, false, wrapped)));
} else if (node.type === 'ForStatement') {
return new CpsResult(k131.k(walk(node.body, false, wrapped) + walk(node.init, false, wrapped) + walk(node.test, false, wrapped) + walk(node.update, false, wrapped)));
} else if (node.type === 'ForInStatement') {
return new CpsResult(k131.k(walk(node.body, false, wrapped) + walk(node.left, false, wrapped) + walk(node.right, false, wrapped)));
} else if (node.type === 'IfStatement') {
return new CpsResult(k131.k(walk(node.consequent, tail, wrapped) + walk(node.alternate, tail, wrapped)));
} else if (node.type === 'LabeledStatement') {
return new CpsFunction(function (kk147) {
return walk.CpsEnabled ? walk(node.body, tail, wrapped, kk147) : walk(node.body, tail, wrapped);
}, k131);
} else if (node.type === 'WithStatement') {
return new CpsResult(k131.k(walk(node.body, tail, wrapped) + walk(node.object, false, wrapped)));
} else if (node.type === 'ReturnStatement') {
return new CpsFunction(function (kk148) {
return walk.CpsEnabled ? walk(node.argument, !wrapped, false, kk148) : walk(node.argument, !wrapped, false);
}, k131);
} else if (node.type === 'TryStatement') {
transformed = walk(node.block, tail, true);
for (i = 0; i < node.guardedHandlers.length; i++) {
transformed += walk(node.guardedHandlers[i].body, tail, node.finalizer ? true : wrapped);
}
for (i = 0; i < node.handlers.length; i++) {
transformed += walk(node.handlers[i].body, tail, node.finalizer ? true : wrapped);
}
transformed += walk(node.finalizer, tail, wrapped);
return new CpsResult(k131.k(transformed));
} else if (node.type === 'CatchClause') {
return new CpsFunction(function (kk149) {
return walk.CpsEnabled ? walk(node.body, tail, wrapped, kk149) : walk(node.body, tail, wrapped);
}, k131);
} else if (node.type === 'ThrowStatement') {
return new CpsFunction(function (kk150) {
return walk.CpsEnabled ? walk(node.argument, false, wrapped, kk150) : walk(node.argument, false, wrapped);
}, k131);
} else if (node.type === 'SwitchStatement') {
transformed = walk(node.discriminant, false, wrapped);
for (i = 0; i < node.cases.length; i++) {
transformed += walk(node.cases[i], false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'SwitchCase') {
transformed = walk(node.test, false, wrapped);
for (i = 0; i < node.consequent.length; i++) {
transformed += walk(node.consequent[i], false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'BreakStatement' || node.type === 'ContinueStatement' || node.type === 'EmptyStatement' || node.type === 'DebuggerStatement') {
return new CpsResult(k131.k(0));
} else if (node.type === 'VariableDeclaration') {
transformed = 0;
for (i = 0; i < node.declarations.length; i++) {
transformed += walk(node.declarations[i], false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'VariableDeclarator') {
return new CpsFunction(function (kk151) {
return walk.CpsEnabled ? walk(node.init, false, wrapped, kk151) : walk(node.init, false, wrapped);
}, k131);
} else if (node.type === 'Identifier') {
return new CpsResult(k131.k(0));
} else if (node.type === 'Literal') {
return new CpsResult(k131.k(0));
} else {
console.warn('continuing with unexpected node type: ' + node.type);
return new CpsResult(k131.k(0));
}
return;
}
var transformed;
var i;
if (node === undefined || node === null) {
return 0;
} else if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
return 0;
} else if (node.type === 'CallExpression') {
if (tail && !wrapped && !root.is_callee_cpsenablewrapper(node) && !root.is_callee_having_side_effect(node) && !is_callee_using_apply(node)) {
var newnode = create_cpsrun_call(node);
_.each(node, function (value, key) {
delete node[key];
});
_.extend(node, newnode);
return 1;
} else {
return 0;
}
} else if (node.type === 'ConditionalExpression') {
return walk(node.test, false, wrapped) + walk(node.consequent, tail, wrapped) + walk(node.alternate, tail, wrapped);
} else if (node.type === 'SequenceExpression') {
transformed = 0;
for (i = 0; i < node.expressions.length; i++) {
transformed += walk(node.expressions[i], false, wrapped);
}
return transformed;
} else if (node.type === 'AssignmentExpression' || node.type === 'BinaryExpression' || node.type === 'UpdateExpression' || node.type === 'MemberExpression' || node.type === 'LogicalExpression' || node.type === 'ArrayExpression' || node.type === 'ObjectExpression' || node.type === 'UnaryExpression' || node.type === 'NewExpression' || node.type === 'ThisExpression') {
return 0;
} else if (node.type === 'BlockStatement') {
transformed = 0;
for (i = 0; i < node.body.length; i++) {
transformed += walk(node.body[i], i === node.body.length - 1 ? tail : false, wrapped);
}
return transformed;
} else if (node.type === 'ExpressionStatement') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk140) {
return walk(node.expression, tail, wrapped, kk140);
}, new CpsContinuation())) : walk(node.expression, tail, wrapped);
} else if (node.type === 'DoWhileStatement' || node.type === 'WhileStatement') {
return walk(node.body, false, wrapped) + walk(node.test, false, wrapped);
} else if (node.type === 'ForStatement') {
return walk(node.body, false, wrapped) + walk(node.init, false, wrapped) + walk(node.test, false, wrapped) + walk(node.update, false, wrapped);
} else if (node.type === 'ForInStatement') {
return walk(node.body, false, wrapped) + walk(node.left, false, wrapped) + walk(node.right, false, wrapped);
} else if (node.type === 'IfStatement') {
return walk(node.consequent, tail, wrapped) + walk(node.alternate, tail, wrapped);
} else if (node.type === 'LabeledStatement') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk141) {
return walk(node.body, tail, wrapped, kk141);
}, new CpsContinuation())) : walk(node.body, tail, wrapped);
} else if (node.type === 'WithStatement') {
return walk(node.body, tail, wrapped) + walk(node.object, false, wrapped);
} else if (node.type === 'ReturnStatement') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk142) {
return walk(node.argument, !wrapped, false, kk142);
}, new CpsContinuation())) : walk(node.argument, !wrapped, false);
} else if (node.type === 'TryStatement') {
transformed = walk(node.block, tail, true);
for (i = 0; i < node.guardedHandlers.length; i++) {
transformed += walk(node.guardedHandlers[i].body, tail, node.finalizer ? true : wrapped);
}
for (i = 0; i < node.handlers.length; i++) {
transformed += walk(node.handlers[i].body, tail, node.finalizer ? true : wrapped);
}
transformed += walk(node.finalizer, tail, wrapped);
return transformed;
} else if (node.type === 'CatchClause') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk143) {
return walk(node.body, tail, wrapped, kk143);
}, new CpsContinuation())) : walk(node.body, tail, wrapped);
} else if (node.type === 'ThrowStatement') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk144) {
return walk(node.argument, false, wrapped, kk144);
}, new CpsContinuation())) : walk(node.argument, false, wrapped);
} else if (node.type === 'SwitchStatement') {
transformed = walk(node.discriminant, false, wrapped);
for (i = 0; i < node.cases.length; i++) {
transformed += walk(node.cases[i], false, wrapped);
}
return transformed;
} else if (node.type === 'SwitchCase') {
transformed = walk(node.test, false, wrapped);
for (i = 0; i < node.consequent.length; i++) {
transformed += walk(node.consequent[i], false, wrapped);
}
return transformed;
} else if (node.type === 'BreakStatement' || node.type === 'ContinueStatement' || node.type === 'EmptyStatement' || node.type === 'DebuggerStatement') {
return 0;
} else if (node.type === 'VariableDeclaration') {
transformed = 0;
for (i = 0; i < node.declarations.length; i++) {
transformed += walk(node.declarations[i], false, wrapped);
}
return transformed;
} else if (node.type === 'VariableDeclarator') {
return walk.CpsEnabled ? CpsRun(new CpsFunction(function (kk145) {
return walk(node.init, false, wrapped, kk145);
}, new CpsContinuation())) : walk(node.init, false, wrapped);
} else if (node.type === 'Identifier') {
return 0;
} else if (node.type === 'Literal') {
return 0;
} else {
console.warn('continuing with unexpected node type: ' + node.type);
return 0;
}
};
ff153.CpsEnabled = true;
return ff153;
}();
return new CpsFunction(function (kk160) {
return walk.CpsEnabled ? walk(body, true, false, kk160) : walk(body, true, false);
}, k155);
return;
}
var create_cpsrun_call = function (call_expression) {
var kk_varname = root.generate_new_variable_name('kk', exclude_ids);
var call_expression1 = root.deep_clone(call_expression);
var call_expression2 = root.deep_clone(call_expression);
call_expression2.arguments.push({
type: 'Identifier',
name: kk_varname
});
return {
type: 'ConditionalExpression',
test: {
type: 'MemberExpression',
computed: false,
object: call_expression1.callee,
property: {
type: 'Identifier',
name: 'CpsEnabled'
}
},
consequent: {
type: 'CallExpression',
callee: {
type: 'Identifier',
name: 'CpsRun'
},
arguments: [{
type: 'NewExpression',
callee: {
type: 'Identifier',
name: 'CpsFunction'
},
arguments: [
{
type: 'FunctionExpression',
id: null,
params: [{
type: 'Identifier',
name: kk_varname
}],
defaults: [],
body: {
type: 'BlockStatement',
body: [{
type: 'ReturnStatement',
argument: call_expression2
}]
},
rest: null,
generator: false,
expression: false
},
{
type: 'NewExpression',
callee: {
type: 'Identifier',
name: 'CpsContinuation'
},
arguments: []
}
]
}]
},
alternate: {
type: call_expression1.type,
callee: call_expression1.callee,
arguments: call_expression1.arguments
}
};
};
var is_callee_using_apply = function (node) {
return node.callee && node.callee.type === 'MembershipExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'apply';
};
var walk = function CpsEnableWrapper() {
var ff153 = function (node, tail, wrapped) {
var l130 = arguments.length - 1;
var k131 = arguments[l130];
if (k131 instanceof CpsContinuation) {
if (l130 === 3) {
} else if (l130 >= 2) {
wrapped = undefined;
} else if (l130 >= 1) {
tail = undefined;
} else if (l130 >= 0) {
node = undefined;
}
var transformed;
var i;
if (node === undefined || node === null) {
return new CpsResult(k131.k(0));
} else if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
return new CpsResult(k131.k(0));
} else if (node.type === 'CallExpression') {
if (tail && !wrapped && !root.is_callee_cpsenablewrapper(node) && !root.is_callee_having_side_effect(node) && !is_callee_using_apply(node)) {
var newnode = create_cpsrun_call(node);
_.each(node, function (value, key) {
delete node[key];
});
_.extend(node, newnode);
return new CpsResult(k131.k(1));
} else {
return new CpsResult(k131.k(0));
}
} else if (node.type === 'ConditionalExpression') {
return new CpsResult(k131.k(walk(node.test, false, wrapped) + walk(node.consequent, tail, wrapped) + walk(node.alternate, tail, wrapped)));
} else if (node.type === 'SequenceExpression') {
transformed = 0;
for (i = 0; i < node.expressions.length; i++) {
transformed += walk(node.expressions[i], false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'AssignmentExpression' || node.type === 'BinaryExpression' || node.type === 'UpdateExpression' || node.type === 'MemberExpression' || node.type === 'LogicalExpression' || node.type === 'ArrayExpression' || node.type === 'ObjectExpression' || node.type === 'UnaryExpression' || node.type === 'NewExpression' || node.type === 'ThisExpression') {
return new CpsResult(k131.k(0));
} else if (node.type === 'BlockStatement') {
transformed = 0;
for (i = 0; i < node.body.length; i++) {
transformed += walk(node.body[i], i === node.body.length - 1 ? tail : false, wrapped);
}
return new CpsResult(k131.k(transformed));
} else if (node.type === 'ExpressionStatement') {
return new CpsFunction(function (kk146) {
return walk.CpsEnabled ? walk(node.expression, tail, wrapped, kk146) : walk(node.expression, tail, wrapped);
}, k131);
} else if (node.type === 'DoWhileStatement' || node.type === 'WhileStatement') {
return new CpsResult(k131.k(walk(node.body, false, wrapped) + walk(node.test, false, wrapped)));
} else if (node.type === 'ForStatement') {
return new CpsResult(k131.k(walk(node.body, false, wrapped) + walk(node.init, false, wrapped) + walk(node.test, false, wrapped) + walk(node.update, false, wrapped)));
} else if (node.type === 'ForInStatement') {
return new CpsResult(k131.k(w