Skip to content

Commit

Permalink
Place runtimes ($asyncbind and $asyncspawn) in a separate file
Browse files Browse the repository at this point in the history
('lib/runtime.js') so the dedicated Babler or other tool builder can
extract them without having to include the entire compiler
  • Loading branch information
matAtWork committed Apr 21, 2016
1 parent 337ea94 commit 3ba1eb0
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 86 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,10 @@ The test is a simple set of nested loops calling async functions that don't do m

Changelog
==========
21-Apr-16 v2.5.1

- Place runtimes ($asyncbind and $asyncspawn) in a separate file ('lib/runtime.js') so the dedicated Babler or other tool builder can extract them without having to include the entire compiler.

01-Apr-16 v2.5.0

- Implement `nodent.EagerThenable()` to provide Promise-like (but unchainable) execution semantics (eager evaluation, asynchronous resolution)
Expand Down
68 changes: 68 additions & 0 deletions lib/runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
var $asyncbind = eval(("(function $asyncbind(self,catcher){ \n"+
" var resolver = this; \n"+
" if (catcher===true) { \n"+
" if (!Function.prototype.$asyncbind.EagerThenable) \n"+
" Function.prototype.$asyncbind.EagerThenable = "+require('./eager.js').toString()+"(); \n"+
" return new (Function.prototype.$asyncbind.EagerThenable)(boundThen); \n"+
" } \n"+
" if (catcher) { \n"+
" if (Function.prototype.$asyncbind.wrapAsyncStack) \n"+
" catcher = Function.prototype.$asyncbind.wrapAsyncStack(catcher); \n"+
" return then; \n"+
" } \n"+
" function then(result,error){ \n"+
" try { \n"+
" return result && (result instanceof Object) && typeof result.then==='function' \n"+
" ? result.then(then,catcher) : resolver.call(self,result,error||catcher); \n"+
" } catch (ex) { \n"+
" return (error||catcher)(ex); \n"+
" } \n"+
" } \n"+
" function boundThen(result,error) { \n"+
" return resolver.call(self,result,error); \n"+
" } \n"+
" boundThen.then = boundThen; \n"+
" return boundThen; \n"+
"})").replace(/\s+/g,' ')) ;

function $asyncspawn(promiseProvider,self) {
var genF = this ;
return new promiseProvider(function enough(resolve, reject) {
var gen = genF.call(self, resolve, reject);
function step(fn,arg) {
var next;
try {
next = fn.call(gen,arg);
if(next.done) {
if (next.value !== resolve) {
if (next.value && next.value===next.value.then)
return next.value(resolve,reject) ;
resolve && resolve(next.value);
resolve = null ;
}
return;
}

if (next.value.then) {
next.value.then(function(v) {
step(gen.next,v);
}, function(e) {
step(gen.throw,e);
});
} else {
step(gen.next,next.value);
}
} catch(e) {
reject && reject(e);
reject = null ;
return;
}
}
step(gen.next);
});
}

module.exports = {
$asyncbind:$asyncbind,
$asyncspawn:$asyncspawn
};
112 changes: 27 additions & 85 deletions nodent.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,98 +367,40 @@ The paths are:
$asyncbind(obj,true) // Call this function, bound to obj, returning a (possibly resolved) Thenable for its completion
$asyncbind(obj,function(exception){}) // Return a Thenable bound to obj, passing exceptions to the specified handler when (if) it throws
*/
var $asyncbind = eval(("(function $asyncbind(self,catcher){ \n"+
" var resolver = this; \n"+
" if (catcher===true) { \n"+
" if (!Function.prototype.$asyncbind.EagerThenable) \n"+
" Function.prototype.$asyncbind.EagerThenable = "+require('./lib/eager.js').toString()+"(); \n"+
" return new (Function.prototype.$asyncbind.EagerThenable)(boundThen); \n"+
" } \n"+
" if (catcher) { \n"+
" if (Function.prototype.$asyncbind.wrapAsyncStack) \n"+
" catcher = Function.prototype.$asyncbind.wrapAsyncStack(catcher); \n"+
" return then; \n"+
" } \n"+
" function then(result,error){ \n"+
" try { \n"+
" return result && (result instanceof Object) && typeof result.then==='function' \n"+
" ? result.then(then,catcher) : resolver.call(self,result,error||catcher); \n"+
" } catch (ex) { \n"+
" return (error||catcher)(ex); \n"+
" } \n"+
" } \n"+
" function boundThen(result,error) { \n"+
" return resolver.call(self,result,error); \n"+
" } \n"+
" boundThen.then = boundThen; \n"+
" return boundThen; \n"+
"})").replace(/\s+/g,' ')) ;

function wrapAsyncStack(catcher) {
var context = {} ;
Error.captureStackTrace(context,$asyncbind) ;
return function wrappedCatch(ex){
if (ex instanceof Error && context) {
try {
ex.stack = //+= "\n\t...\n"+
ex.stack.split("\n").slice(0,3)
.filter(function(s){
return !s.match(/^\s*at.*nodent\.js/) ;
}).join("\n")+
ex.stack.split("\n").slice(3).map(function(s){return "\n "+s}).join("")+
context.stack.split("\n").slice(2)
.filter(function(s){
return !s.match(/^\s*at.*nodent\.js/) ;
})
.map(function(s,idx){
return idx?"\n"+s:s.replace(/^(\s*)at /g,"\n$1await ")
}).join("") ;
} catch (stackError) {
// Just fall through and don't modify the stack
}
context = null ;
}
return catcher.call(this,ex) ;
} ;
}
var runtimes = require('./lib/runtime') ;
var $asyncbind = runtimes.$asyncbind ;
var $asyncspawn = runtimes.$asyncspawn ;

function $asyncspawn(promiseProvider,self) {
var genF = this ;
return new promiseProvider(function enough(resolve, reject) {
var gen = genF.call(self, resolve, reject);
function step(fn,arg) {
var next;
function wrapAsyncStack(catcher) {
var context = {} ;
Error.captureStackTrace(context,$asyncbind) ;
return function wrappedCatch(ex){
if (ex instanceof Error && context) {
try {
next = fn.call(gen,arg);
if(next.done) {
if (next.value !== resolve) {
if (next.value && next.value===next.value.then)
return next.value(resolve,reject) ;
resolve && resolve(next.value);
resolve = null ;
}
return;
}

if (next.value.then) {
next.value.then(function(v) {
step(gen.next,v);
}, function(e) {
step(gen.throw,e);
});
} else {
step(gen.next,next.value);
}
} catch(e) {
reject && reject(e);
reject = null ;
return;
ex.stack = //+= "\n\t...\n"+
ex.stack.split("\n").slice(0,3)
.filter(function(s){
return !s.match(/^\s*at.*nodent\.js/) ;
}).join("\n")+
ex.stack.split("\n").slice(3).map(function(s){return "\n "+s}).join("")+
context.stack.split("\n").slice(2)
.filter(function(s){
return !s.match(/^\s*at.*nodent\.js/) ;
})
.map(function(s,idx){
return idx?"\n"+s:s.replace(/^(\s*)at /g,"\n$1await ")
}).join("") ;
} catch (stackError) {
// Just fall through and don't modify the stack
}
context = null ;
}
step(gen.next);
});
return catcher.call(this,ex) ;
} ;
}


var Thenable = require('./lib/thenable') ;

/* NodentCompiler prototypes, that refer to 'this' */
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nodent",
"version": "2.5.0",
"version": "2.5.1",
"description": "NoDent - Asynchronous Javascript language extensions",
"main": "nodent.js",
"scripts": {
Expand Down

0 comments on commit 3ba1eb0

Please sign in to comment.