diff --git a/index.html b/index.html index 7c0e90a..7551c70 100644 --- a/index.html +++ b/index.html @@ -6,9 +6,10 @@ - + +
diff --git a/index.js b/index.js new file mode 100644 index 0000000..22e60d2 --- /dev/null +++ b/index.js @@ -0,0 +1,17 @@ +var g = new Ground(function () { + console.log('here'); + World.spawn({ + step: function () { console.log('step'); }, + boot: function () { + console.log('boot'); + World.updateRoutes([sub(__), sub(__, 1)]); + World.send({msg: 'hello outer world'}, 1); + World.send({msg: 'hello inner world'}, 0); + }, + handleEvent: function (e) { + console.log('handleEvent: ' + JSON.stringify(e)); + } + }); +}); + +g.startStepping(); diff --git a/marketplace.js b/marketplace.js index 34f74e4..660ddf7 100644 --- a/marketplace.js +++ b/marketplace.js @@ -166,14 +166,15 @@ function filterEvent(e, routes) { /*---------------------------------------------------------------------------*/ /* Configurations */ -function World(bootActions) { +function World(bootFn) { this.nextPid = 0; this.eventQueue = []; this.processTable = {}; this.downwardRoutes = []; this.processActions = []; this.activePid = null; - this.enqueueActions(-1, bootActions); + this.stepperId = null; + this.asChild(-1, bootFn); } /* Class state / methods */ @@ -192,6 +193,10 @@ World.spawn = function (behavior, initialRoutes) { World.current.enqueueAction(spawn(behavior, initialRoutes)); }; +World.wrap = function (f) { + return World.current.wrap(f); +}; + /* Instance methods */ World.prototype.enqueueAction = function (action) { @@ -214,6 +219,24 @@ World.prototype.step = function () { return this.stepChildren() || !this.isQuiescent(); }; +World.prototype.startStepping = function () { + var self = this; + if (this.stepperId) return; + if (this.step()) { + this.stepperId = setTimeout(function () { + self.stepperId = null; + self.startStepping(); + }, 0); + } +}; + +World.prototype.stopStepping = function () { + if (this.stepperId) { + clearTimeout(this.stepperId); + this.stepperId = null; + } +}; + World.prototype.asChild = function (pid, f) { var oldWorld = World.current; var result = null; @@ -229,6 +252,15 @@ World.prototype.asChild = function (pid, f) { return result; }; +World.prototype.wrap = function (f) { + var savedWorld = this; + var savedPid = this.activePid; + return function () { + var actuals = arguments; + return savedWorld.asChild(savedPid, function () { return f.apply(null, actuals) }); + }; +}; + World.prototype.kill = function (pid, exn) { console.log("Killed process " + pid + (exn ? " with reason " + exn.message : "")); delete this.processTable[pid]; @@ -240,7 +272,7 @@ World.prototype.stepChildren = function () { for (var pid in this.processTable) { var p = this.processTable[pid]; if (p.behavior.step /* exists, haven't called it yet */) { - var childBusy = this.asChild(pid, function () { p.behavior.step() }); + var childBusy = this.asChild(pid, function () { return p.behavior.step() }); someChildBusy = someChildBusy || childBusy; } } @@ -298,6 +330,7 @@ World.prototype.aggregateRoutes = function (base) { acc.push(p.routes[i]); } } + return acc; }; World.prototype.issueRoutingUpdate = function () { @@ -331,9 +364,46 @@ World.prototype.handleEvent = function (e) { /*---------------------------------------------------------------------------*/ /* Ground interface */ -function Ground(bootActions) { - this.world = new World(bootActions); - this.subscriptions = {}; +function Ground(bootFn) { + var self = this; + this.stepperId = null; + this.wrap(function () { + self.world = new World(bootFn); + })(); } -// HERE: Ground.prototype. \ No newline at end of file +Ground.prototype.wrap = function (f) { + var self = this; + return function () { + var oldWorld = World.current; + var result = null; + World.current = self; + try { + result = f(); + } catch (e) { + World.current = oldWorld; + throw e; + } + World.current = oldWorld; + return result; + }; +}; + +Ground.prototype.step = function () { + var self = this; + return this.wrap(function () { + return self.world.step(); + })(); +}; + +Ground.prototype.startStepping = World.prototype.startStepping; +Ground.prototype.stopStepping = World.prototype.stopStepping; + +Ground.prototype.enqueueAction = function (action) { + if (action.type === 'routes') { + // Ignore it. These are generated outside user control so it + // shouldn't be an error. + } else { + console.error("You have sent a message into the outer void.", action); + } +};