Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first pass on streamline integration

  • Loading branch information...
commit 2e4b01c2c822e82a97cd02387833d7ba367be8a2 1 parent 08e9779
@bjouhier bjouhier authored committed
Showing with 50 additions and 12 deletions.
  1. +8 −3 lib/spoon/block.js
  2. +32 −8 lib/spoon/cfg.js
  3. +10 −1 lib/spoon/renderer.js
View
11 lib/spoon/block.js
@@ -93,7 +93,7 @@ Block.prototype.distance = function distance(to) {
return best ? best.path : Infinity;
};
-Block.prototype.split = function split(at, root, asyncify) {
+Block.prototype.split = function split(at, root, asyncify, marker) {
var index = this.instructions.indexOf(at),
head = this.instructions.slice(0, index),
tail = this.instructions.slice(asyncify ? index + 1 : index);
@@ -114,13 +114,18 @@ Block.prototype.split = function split(at, root, asyncify) {
var fn = root.prepend('fn', [ next ]);
fn.name = '__$fn' + next.id;
- fn.params = ['__$r'];
+ fn.params = ['__$e', '__$r'];
fn.isExpression = false;
+ next.instructions = [this.add('async-test-err')].concat(next.instructions);
this.ended = false;
if (asyncify) {
- at.args.push(this.add('get', [ fn.name ]));
+ if (marker) {
+ at.args[at.args.length - marker].args[0] = fn.name;
+ } else {
+ at.args.push(this.add('get', [ fn.name ]));
+ }
this.instructions.push(at);
this.add('async-end', [ at ]);
View
40 lib/spoon/cfg.js
@@ -99,13 +99,13 @@ Cfg.prototype.translate = function translate(ast) {
}
};
-Cfg.prototype.split = function split(at, root, asyncify) {
+Cfg.prototype.split = function split(at, root, asyncify, marker) {
var block = at.block;
// Do not split same blocks twice
if (this.asyncifyState[block.id]) return this.asyncifyState[block.id];
- var info = block.split(at, root, asyncify);
+ var info = block.split(at, root, asyncify, marker);
this.asyncifyState[block.id] = info.fn;
this.roots.push(info.next);
@@ -145,6 +145,24 @@ Cfg.prototype.asyncify = function asyncify(asts, options) {
return ast.body[0].expression;
});
+ function markerIndex(instr, marker) {
+ if (!marker) return -1;
+ var args;
+ if (instr.type === 'call') {
+ args = instr.args.slice(1);
+ } else if (instr.type === 'method') {
+ args = instr.args.slice(2);
+ }
+ if (!args) return -1;
+ var found = -1;
+ args.forEach(function(arg, i) {
+ if (arg.type === 'get' && arg.args[0] === marker) {
+ found = args.length - i;
+ }
+ });
+ return found;
+ }
+
// Test whether instr matches 'fn' or not
function match(instr) {
return targets.some(function(target) {
@@ -195,6 +213,11 @@ Cfg.prototype.asyncify = function asyncify(asts, options) {
instr.uses.length > 0)) {
return false;
}
+ if (options.marker && block.fn.root.instr) {
+ var marker = block.fn.root.instr.params.indexOf(options.marker);
+ if (marker < 0) return false;
+ block.fn.root.instr.params[marker] = '__$callback';
+ }
hasDeclaration[block.id] = block;
return true;
@@ -224,10 +247,11 @@ Cfg.prototype.asyncify = function asyncify(asts, options) {
}
block.instructions.forEach(function(instr) {
- if (!match(instr)) return;
+ var marker = markerIndex(instr, options.marker);
+ if (marker < 0 && !match(instr)) return;
// Split graph at instruction
- this.split(instr, instr.block.getRoot(), true);
+ var fn = this.split(instr, instr.block.getRoot(), true, marker);
// Replace all instruction uses by __$r
instr.uses.forEach(function(use, i) {
@@ -1008,7 +1032,7 @@ Cfg.prototype.visitThis = function visitThis(ast) {
};
Cfg.prototype.visitFor = function visitFor(ast) {
- this.visit(ast.init);
+ if (ast.init) this.visit(ast.init);
return this.enterLoop(function(end, loop) {
var start = this.current,
@@ -1024,7 +1048,7 @@ Cfg.prototype.visitFor = function visitFor(ast) {
});
};
-Cfg.prototype.visitForIn = function visitFor(ast) {
+Cfg.prototype.visitForIn = function visitForIn(ast) {
var left = ast.left,
right = ast.right;
@@ -1114,7 +1138,7 @@ Cfg.prototype.visitTry = function visitTry(ast) {
return null;
};
-Cfg.prototype.visitThrow = function visitTry(ast) {
+Cfg.prototype.visitThrow = function visitThrow(ast) {
this.add('throw', ast.argument ? [ this.visit(ast.argument) ] : []);
this.current.end();
return null;
@@ -1128,7 +1152,7 @@ Cfg.prototype.visitNew = function visitNew(ast) {
}, this)));
};
-Cfg.prototype.visitSwitch = function visitTry(ast) {
+Cfg.prototype.visitSwitch = function visitSwitch(ast) {
throw new TypeError('Switch is not implemented yet');
var self = this,
disc = this.visit(ast.discriminant),
View
11 lib/spoon/renderer.js
@@ -204,6 +204,8 @@ Renderer.prototype.renderInstruction = function renderInstruction(instr) {
fn = this.renderAsyncReturn;
} else if (t === 'async-end') {
fn = this.renderAsyncEnd;
+ } else if (t === 'async-test-err') {
+ fn = this.renderAsyncTestErr;
} else if (t === 'nop') {
fn = this.renderNop;
} else {
@@ -396,7 +398,7 @@ Renderer.prototype.renderNew = function renderNew(args) {
Renderer.prototype.renderAsyncReturn = function renderAsyncReturn(args) {
return ['return', ['call',
['dot', ['name', '__$callback'], 'call'],
- [['name', 'this']].concat(args)]];
+ [['name', 'this'],['name', 'null']].concat(args)]];
};
Renderer.prototype.renderAsyncEnd = function renderAsyncEnd(args) {
@@ -407,6 +409,13 @@ Renderer.prototype.renderAsyncGoto = function renderAsyncGoto(args) {
return ['return', ['call', ['dot', args[0], 'call'], [['name', 'this']]]];
};
+Renderer.prototype.renderAsyncTestErr = function renderAsyncTestErr(args) {
+ return ['if', ['name', '__$e'], ['block',
+ [['return', ['call',
+ ['dot', ['name', '__$callback'], 'call'],
+ [['name', 'this'],['name', '__$e']]]]]]];
+};
+
Renderer.prototype.renderNop = function renderNop() {
return null;
};
Please sign in to comment.
Something went wrong with that request. Please try again.