Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

1.9.7-9

Adding some more transform tests
Allowing syncs to be nested (in the case that flow.sync is used witin a function called by a flow.sync)
In cases where defer can't be used, substitute sync automatically
If a flow variable isn't defined for an asyncblock, add a default one on transform to prevent errors
  • Loading branch information...
commit 24147e84ffdaa8e05f29419a23c4cd529a94d04d 1 parent 3c3ab3a
Scriby authored
View
23 lib/flow.js
@@ -22,8 +22,6 @@ var Flow = function(fiber) {
this._parentFlow = null; //In the case of nested asyncblocks, a reference to the outer block. Used to tie together stack traces
- this._lastAddedTask = null; //Keeps track of the last added task, to support some flow.sync & flow.future syntaxes
-
this._isGenerator = false; //Tracks whether the current asyncblock was created as an enumerator or not
this.maxParallel = 0; // max number of parallel tasks. maxParallel <= 0 means no limit
@@ -128,7 +126,7 @@ var callbackHandler = function(self, task){
var addTask = function(self, task){
task._flow = self;
- self._lastAddedTask = task;
+ task.caller.__asyncblock_lastAddedTask = task;
if(task.key == null) {
if(self._parallelCount === 0){
@@ -351,8 +349,8 @@ var wait = function(self) {
delete self._finishedTasks.__defaultkey__;
- if(self._lastAddedTask != null && self._lastAddedTask.key === task.key){
- self._lastAddedTask = null;
+ if(task.caller.__asyncblock_lastAddedTask != null && task.caller.__asyncblock_lastAddedTask.key === task.key){
+ task.caller.__asyncblock_lastAddedTask = null;
}
if(task.error){
@@ -387,8 +385,8 @@ var wait = function(self) {
delete self._finishedTasks[key];
- if(self._lastAddedTask != null && self._lastAddedTask.key === task.key){
- self._lastAddedTask = null;
+ if(task.caller.__asyncblock_lastAddedTask != null && task.caller.__asyncblock_lastAddedTask.key === task.key){
+ task.caller.__asyncblock_lastAddedTask = null;
}
}
});
@@ -423,8 +421,8 @@ var waitForKey = function(self, key){
}
//Clear last added task if it refers to this task
- if(self._lastAddedTask != null && self._lastAddedTask.key === task.key){
- self._lastAddedTask = null;
+ if(task.caller.__asyncblock_lastAddedTask != null && task.caller.__asyncblock_lastAddedTask.key === task.key){
+ task.caller.__asyncblock_lastAddedTask = null;
}
return task.formattedResult;
@@ -483,17 +481,12 @@ var parseSyncArgs = function(args){
Flow.prototype.sync = function(options, toExecute/*, apply*/){
if(arguments.length === 1 && typeof arguments[0] !== 'function'){
//flow.sync(asyncFunction(..., flow.add()); usage
- var lastTask = this._lastAddedTask;
+ var lastTask = this.sync.caller.__asyncblock_lastAddedTask;
if(lastTask == null){
throw new Error('flow.sync usage not correct -- no task has been added');
}
- //If the callers don't match, they added a task inside the function call, and we're going to assume the wrong task
- if(lastTask.caller !== this.sync.caller){
- throw new Error('flow.sync usage not correct - you may not add more tasks in a nested function');
- }
-
return this.wait(lastTask.key);
} else {
//flow.sync(asyncfunction, ...); usage
View
1  lib/func.js
@@ -76,6 +76,7 @@ Flow.prototype.func = function(toExecute){
}
task.toExecute = chain._toExecute;
+ task.caller = func.queue.caller;
flow._queueTask(task);
};
View
8 lib/future.js
@@ -25,17 +25,12 @@ Future.prototype.__defineSetter__("result", function(value){
Flow.prototype.future = function(options){
if(arguments.length === 1 && Object.prototype.toString.call(options) !== '[object Object]'){
//flow.future(asyncFunction(..., flow.add()); usage
- var lastTask = this._lastAddedTask;
+ var lastTask = this.future.caller.__asyncblock_lastAddedTask;
if(lastTask == null){
throw new Error('flow.future usage not correct -- no task has been added');
}
- //If the callers don't match, they added a task inside the function call, and we're going to assume the wrong task
- if(lastTask.caller !== this.future.caller){
- throw new Error('flow.future usage not correct - you may not add more tasks in a nested function');
- }
-
return new Future(this, lastTask.key);
} else {
//var future = flow.future();
@@ -43,6 +38,7 @@ Flow.prototype.future = function(options){
var task = this._parseAddArgs(arguments);
task.key = this._getNextTaskId();
task.dontWait = true;
+ task.caller = this.future.caller;
this._addTask(task);
View
63 lib/transform.js
@@ -154,8 +154,7 @@ exports.enableTransform = function(){
}
var asyncblockVarId;
- var flowVarId;
- var flowVarName;
+ var flows = [];
var transformationMade = false;
@@ -168,6 +167,19 @@ exports.enableTransform = function(){
var variableDeclarationScopes = {};//{id: scope node}
+ var addVariableToScope = function(scopeNode, varName){
+ var existingId = scopeNode.variables[varName];
+ if(existingId != null){
+ delete scopeNode.variablesRev[existingId];
+ }
+
+ var id = nextId();
+ scopeNode.variables[varName] = id;
+ scopeNode.variablesRev[id] = varName;
+
+ variableDeclarationScopes[id] = scopeNode;
+ };
+
var processAST = (function(){
var scopes = [];
@@ -194,17 +206,7 @@ exports.enableTransform = function(){
var addVariable = function(varName){
var currScope = scopes[scopes.length - 1].node;
-
- var existingId = currScope.variables[varName];
- if(existingId != null){
- delete currScope.variablesRev[existingId];
- }
-
- var id = nextId();
- currScope.variables[varName] = id;
- currScope.variablesRev[id] = varName;
-
- variableDeclarationScopes[id] = currScope;
+ addVariableToScope(currScope, varName);
};
var containingScope;
@@ -251,7 +253,8 @@ exports.enableTransform = function(){
return processAST;
})();
- var isInAsyncBlock = 0;
+ var flowVarName;
+ var flowVarId;
walkAST(ast, function(state, node){
processAST(state);
@@ -273,18 +276,34 @@ exports.enableTransform = function(){
var parent2x = state.parent.parent.node;
if(parent2x[0] === 'call' && asyncblockVarId != null && containingScope.variables[parent2x[1][1]] === asyncblockVarId){
- flowVarName = node[2];
+ flowVarName = node[2][0];
+
+ if(flowVarName == null){ //flow variable is missing, let's add it
+ node[2][0] = flowVarName = '__asyncblock_flow';
+ processAST(state);
+ addVariableToScope(node, flowVarName);
+ }
+
flowVarId = node.containingScope.variables[flowVarName];
- isInAsyncBlock++;
+ flows.push({ flowVarName: flowVarName, flowVarId: flowVarId });
state.after = function(){
- isInAsyncBlock--;
+ flows.pop();
+
+ var prevFlow = flows[flows.length - 1];
+ if(prevFlow != null){
+ flowVarName = prevFlow.flowVarName;
+ flowVarId = prevFlow.flowVarId;
+ } else {
+ flowVarName = null;
+ flowVarId = null;
+ }
};
}
- } else if(node[0] === 'call' && node[1][0] === 'dot' && containingScope.variables[node[1][1][1]] !== flowVarId){ //Detect calls on the flow variable
+ } else if(node[0] === 'call' && node[1][0] === 'dot'){
//Make sure we're in an asyncblock
- if(isInAsyncBlock > 0){
+ if(flows.length > 0){ //We're in an async block
//If sync was called
if(node[1][2] === 'sync') {
//Remove the .sync() part
@@ -330,8 +349,8 @@ exports.enableTransform = function(){
assignedToName = parent[2][1];
} else if(parent3x[0] === 'var'){
assignedToName = parent3x[1][0][0];
- } else if(parent[0] === 'return'){
- //If returning immediately, we should use sync instead of future
+ } else {
+ //If not assiging into a variable, convert to a sync call
node[1][2] = 'sync';
}
@@ -393,6 +412,8 @@ exports.enableTransform = function(){
content = originalContent;
}
+ //console.log(content.split('\n').map(function(line, i){ return (i + 1) + ': ' + line; }).join('\n'));
+
return originalCompile.apply(this, arguments);
};
View
2  package.json
@@ -1,6 +1,6 @@
{
"name": "asyncblock",
- "version": "1.9.7-8",
+ "version": "1.9.7-9",
"description": "A simple and powerful abstraction of node-fibers",
"keywords": [
"fiber", "fibers", "coroutine", "stop", "go", "green", "red" ],
View
30 test_data/transform/defer.js
@@ -64,11 +64,39 @@ exports.test6 = function(callback){
};
exports.test7 = function(callback){
- asyncblock(function(flow){
+ asyncblock(function(){
var test = function(){
return utility.echo('test').defer();
};
callback(null, test());
});
+};
+
+exports.test8 = function(callback){
+ asyncblock(function(){
+ var test = function(callback){
+ asyncblock(function(flow){
+ var result = utility.echo('test').sync();
+ callback(null, result);
+ });
+ };
+
+ var result = test().sync();
+
+ callback(null, result);
+ });
+};
+
+exports.test8 = function(callback){
+ asyncblock(function(){
+ var test = function(callback){
+ var result = utility.echo('test').sync();
+ callback(null, result);
+ };
+
+ var result = test().sync();
+
+ callback(null, result);
+ });
};
View
8 test_data/transform/no_transform.js
@@ -0,0 +1,8 @@
+var asyncblock = require('asyncblock');
+var utility = require('./utility.js');
+
+asyncblock(function(flow){
+ var result = flow.sync(utility.echo('test', flow.add()));
+});
+
+exports.transformed = module.__asyncblock_transformed;
View
5 test_data/transform/parse.js
@@ -1,4 +1,5 @@
var asyncblock = require('asyncblock');
+var utility = require('./utility.js');
var x = function(){ return { x: function() {} } };
@@ -182,11 +183,9 @@ exports.test = function(callback){
} //test
else{ //test1
-
}
- x().defer();
- callback(null, 'test');
+ callback(null, utility.echo('test').defer());
return
});
View
2  tests/errors.js
@@ -286,7 +286,7 @@ suite.addBatch({
},
'The correct errors occurred': function(errors){
- assert.instanceOf(errors.first, Error);
+ assert.isUndefined(errors.first); //The behavior of this has changed such that sync can be used in this fashion
assert.instanceOf(errors.second, Error);
}
}
View
15 tests/transform.js
@@ -11,6 +11,7 @@ var defer = require('../test_data/transform/defer.js');
var sync = require('../test_data/transform/sync.js');
var future = require('../test_data/transform/future.js');
var parse = require('../test_data/transform/parse.js');
+var no_transform = require('../test_data/transform/no_transform.js');
var makeTests = function(file, name, count){
var tests = {};
@@ -32,7 +33,7 @@ var makeTests = function(file, name, count){
return tests;
};
-suite.addBatch(makeTests(defer, 'defer', 7));
+suite.addBatch(makeTests(defer, 'defer', 8));
suite.addBatch(makeTests(sync, 'sync', 6));
suite.addBatch(makeTests(future, 'future', 7));
@@ -49,4 +50,16 @@ suite.addBatch({
}
});
+suite.addBatch({
+ 'Transformer ignores files it does not need to change': {
+ topic: function(){
+ this.callback(null, no_transform);
+ },
+
+ 'Not transformed': function(no_transform){
+ assert.isFalse(!!no_transform.transformed);
+ }
+ }
+});
+
suite.export(module);
Please sign in to comment.
Something went wrong with that request. Please try again.