VimUnDoVpYa7]cߏv]#.k####TE_bTbeebdd5_d)Tcef)StateMachine.prototype.pbind = function (5_d6Tcef7StateMachine.prototype.pbind = function (chan, promise)5_d9Tcff9StateMachine.prototype.pbind = function (chan, promise) {5_eTdfg}5_eTdfg}5_dTdfhdfg5_ eTdfhif 5_ eTdfhif5_ eTdfhi5_ eTdfh if (5_ eTdfh if (promise.then)5_  eTdgh if (promise.then) {5_ fTegi }5_eTdfi if (promise.then) {5_eTegj egi5_[ TZ\jS return this.task_fn.cachedJumpTable[id] = new JumpTable(id, cases, blockSizes);5_[ TZ\T return (this.task_fn.cachedJumpTable[id] = new JumpTable(id, cases, blockSizes);5_[STZ\jT return (this.task_fn.cachedJumpTable[id] = new JumpTable(id, cases, blockSizes);5_eTegk egj5_f Tegk consoe5_fTeg console.log(5_fTegk console.log()5_fTegk console.log("meow")5_fTegk console.log("meow")5_fTef console.log("meow");5_fTef 5_eTegj egi5_dTcd9StateMachine.prototype.pbind = function (chan, promise) {5_dTcd" if (promise && promise.then) {5_ dTcd 5_! dTcd }5_ "!dTcd};5_!#"dTcd5_"#fTDd&// # State machine support for task.js//A// This file contains miscellaneous state machine management codeE// that is used by the code generated by the `task` macro in task.js.#var Channel = require('./channel');var nextTick = (function () {1 return this.setImmediate || process.nextTick;}());function State() { this.id = 0; this.args = [null, null]; this.err = null; this.unwinding = []; this.waiting = 0; this.isFinished = false; this.isUnwinding = false;! this.currentErrorStep = null;! this.abort_with_error = null; return this;}function controlAPIMaker() { var state_machine = this; return Object.create({}, { abort: {# value: function (err) {6 if (state_machine.state.waiting > 0) {? state_machine.state.abort_with_error = err; } else {0 state_machine.callback(err); } } }, isWaiting: { get: function () {7 return state_machine.state.waiting > 0; } }, isFinished: { get: function () {6 return state_machine.state.isFinished; } } });}7function StateMachine(context, callback, fn, task_fn) { this.state = new State(); this.fn = fn; this.task_fn = task_fn; this.context = context;" this.finalCallback = callback;8 // The following two will be initialized if the body8 // of the state machine contains a finally {} block.$ // If not, they can remain null.Z this.captureStateVars = null; // Might be initialized to function () { return array; }i this.restoreStateVars = null; // Might be initialized to function (array) { assign state variables; }* this.boundStep = this.step.bind(this);. this.boundUnwind = this.unwind.bind(this);6 this.controlAPIMaker = controlAPIMaker.bind(this);? // Initialize the jump table structure if not done already.F this.task_fn.cachedJumpTable = this.task_fn.cachedJumpTable || {}; return this;},StateMachine.prototype.start = function () { this.goTo(1);};+StateMachine.prototype.step = function () { this.state.waiting--;& if (this.state.abort_with_error) { this.performAbort(); } else {5 this.fn.apply(this.context, this.state.args); }};9// If an abortion has been requested by the state machine(// user, then bail out on the next step.3StateMachine.prototype.performAbort = function () {* var err = this.state.abort_with_error;' this.state.abort_with_error = null;$ this.fn.call(this.context, err);};-StateMachine.prototype.goTo = function (id) { this.state.id = id;% this.state.strict_unwind = false; this.state.waiting++; nextTick(this.boundStep);};/StateMachine.prototype.thenTo = function (id) { var done = false; var self = this; this.state.waiting++; return function () { var _self = self;! var _state = _self.state; _state.waiting--; if (!done) { done = true; _state.id = id;* if (_state.abort_with_error) {% _self.performAbort(); } else {: _self.fn.apply(_self.context, arguments); } } else {9 console.error('Callback called repeatedly!'); } };};6StateMachine.prototype.thenToWithErr = function (id) { var done = false; var self = this; this.state.waiting++;# return function (err, result) { var _self = self;! var _state = _self.state; _state.waiting--; if (!done) { done = true; _state.id = id;* if (_state.abort_with_error) {% _self.performAbort();/ } else if (arguments.length <= 2) {> // Slightly more efficient in the common case.@ _self.fn.call(_self.context, null, err, result); } else {D var argv = Array.prototype.slice.call(arguments, 0);S argv.unshift(null); // Push the err argument to the explicit range.5 _self.fn.apply(_self.context, argv); } } else {9 console.error('Callback called repeatedly!'); } };};B// StateMachine supports a single global error notification point.F// You can set StateMachine.onerror to an error callback function thatD// will be called asynchronously with two arguments - the error and @// the state machine instance within which the error was raised.9// You can use this, for example, to log all such errors.//D// If this callback is to process an error and err is an instance ofB// Error, then an additional '.cspjsStack' property is added. ThisC// property is an array to which more context will get added as theE// where "task_fn_name" is the given name of the async task (so yeah,A// better name your tasks if you want this to be useful) and "id"?// gives the state id responsible for the error. In the case ofH// errors raised by "throw", this will refer to the state id immediately// before the throw.//C// To locate the specified state, look into the compiled source for>// a "case :" statement under the task named task_fn_name.B// Gathering context this way permits errors to be traced even in F// reorganized code, where source context may or may not be available,0// or JS code may not be stored in files at all.//B// The overhead of this error context accumulation occurs only at ?// error propagation time and almost no cost is added to normal// control flow.2StateMachine.prototype.callback = function (err) {< this.state.args = Array.prototype.slice.call(arguments); this.state.err = err;$ this.state.strict_unwind = true;& if (err && err instanceof Error) {. err.cspjsStack = err.cspjsStack || [];X err.cspjsStack.push((this.task_fn.name || 'unnamed') + ':' + (this.state.id-1)); }M err && StateMachine.onerror && nextTick(StateMachine.onerror, err, this); nextTick(this.boundUnwind);};1StateMachine.prototype.windTo = function (step) {# this.state.isUnwinding = false; this.goTo(step);};-StateMachine.prototype.unwind = function () {* if (this.state.unwinding.length > 0) {/ var where = this.state.unwinding.pop();& this.state.isUnwinding = true;! if (where.restoreState) {6 this.restoreStateVars(where.restoreState); this.unwind();! } else if (where.retry) {% this.windTo(where.retry); } else if (where.phi) {= if (this.state.err || this.state.strict_unwind) {\ // If we're strictly unwinding, then regular phi control flow doesn't apply.+ nextTick(this.boundUnwind); } else {# // Normal phi jump.' this.windTo(where.phi); }# } else if (where.isError) {! if (this.state.err) {4 this.state.currentErrorStep = where;& this.goTo(where.step); } else {+ nextTick(this.boundUnwind); } } else { if (where.fn) { where.fn();+ nextTick(this.boundUnwind); } else {/ this.beginCleanup(where.state);& this.goTo(where.step); } }( } else if (!this.state.isFinished) { this.state.waiting = 0;% this.state.isFinished = true;V this.finalCallback && this.finalCallback.apply(this.context, this.state.args); }};IStateMachine.prototype.pushCleanupAction = function (context, fn, args) { var self = this; self.state.unwinding.push({ cleanup: true, fn: function () {$ fn.apply(context, args); } });};AStateMachine.prototype.pushCleanupStep = function (id, afterID) {Y this.state.unwinding.push({cleanup: true, step: id, state: this.captureStateVars()}); this.goTo(afterID);};?StateMachine.prototype.pushErrorStep = function (id, retryID) {w this.state.unwinding.push({isError: true, step: id, retryStep: retryID, unwindPoint: this.state.unwinding.length}); this.goTo(retryID);};8StateMachine.prototype.beginCleanup = function (state) {G this.state.unwinding.push({restoreState: this.captureStateVars()});! this.restoreStateVars(state);};>// Retry will place the error handler again on the error stack>// and jump to the beginning of the code block that previously@// generated the error. Presumably, some corrective actions have// been taken already.,StateMachine.prototype.retry = function () {' if (!this.state.currentErrorStep) {] throw new Error('SyntaxError: retry statement can only be used within catch blocks'); }0 var errorStep = this.state.currentErrorStep;O // Finally clauses might need to run between the start of the error handlerH // and the current retry statement. So we need to unwind through theJ // finally clauses before stepping out of the catch block. To do this,F // insert a plain jump into the unwind sequence at the appropriateG // point. And of course, we also restore the error step descriptionJ // object on the unwind stack so that the surrounding catch block will7 // attempt to handle any new errors that may occur.c this.state.unwinding.splice(errorStep.unwindPoint, 0, errorStep, {retry: errorStep.retryStep}); // Enter a "no error" state.' this.state.currentErrorStep = null;< this.state.args = Array.prototype.slice.call(arguments);" this.state.args.unshift(null); this.state.err = null;$ this.state.strict_unwind = true;- // Begin unwinding through the finallies. this.phi();};D// A note on semantics. phi used to be a separate stack, which meantF// that finally blocks that occur within while loops would all executeH// at the end of the while loop only. This is, in general, not desirableC// and it is useful to have the finally code executed once for eachB// scope. For this reason, it is better to have the same unwindingC// stack also handle the phi jumps so that error handling code gets// to run as soon as possible.//F// Currently, if-then-else, while and switch blocks all delimit scopes%// for execution of finally handlers.>StateMachine.prototype.pushPhi = function (id, captureState) {a this.state.unwinding.push({phi: id, state: (captureState ? this.captureStateVars() : null)});};*StateMachine.prototype.phi = function () { nextTick(this.boundUnwind);};+function JumpTable(id, cases, blockSizes) { this.id = id; this.cases = cases;! this.blockSizes = blockSizes; this.stepIDs = []; this.beyondID = id;' var i = 0, j = 0, sum = id + 1, ci;- for (i = 0; i < blockSizes.length; ++i) { ci = cases[i];) for (j = 0; j < ci.length; ++j) {& this.stepIDs[ci[j]] = sum; }@ sum += 1 + blockSizes[i]; // +1 for the additional "phi" } this.beyondID = sum; return this;}9JumpTable.prototype.jumpToCase = function (sm, caseVal) { sm.pushPhi(this.beyondID);' var stepID = this.stepIDs[caseVal]; if (!stepID) {O throw new Error("Unhandled case '" + caseVal + "' at step " + this.id); } sm.goTo(stepID);};EStateMachine.prototype.jumpTable = function (id, cases, blockSizes) {7 // cases[i] is an array of case values that all map> // to the same block whose size is given by blockSizes[i]. if (!cases) {0 return this.task_fn.cachedJumpTable[id]; }7 console.assert(cases.length === blockSizes.length);U return (this.task_fn.cachedJumpTable[id] = new JumpTable(id, cases, blockSizes));};.StateMachine.prototype.channel = function () { return new Channel();};1StateMachine.prototype.resolve = Channel.resolve;module.exports = StateMachine;5