sai-language
Version:
An object-oriented language designed to afford code comprehension and maintenance. Transpiles in-place to Javascript.
226 lines (210 loc) • 19.1 kB
JavaScript
// Javascript source for StateC.sai transpiled by SAI
//
;
var prototype=new function() {
this.Constructor=function(){};
this.__tobelocked=[];
this.__tobefrozen=[];
this.__contracts=[];
this.__unverified=true;
this.isof={};
return this;
}();
var $AI=require("sai-library");
// Generated code follows
var __context={"loader":"SAI.GetSourceFromFilename","path":"/Users/seanmpuckett/Documents/ProjSync/Node/sai/src/Construct.sai","workdir":"/Users/seanmpuckett/Documents/ProjSync/Node/sai/src","mtime":"2018-04-04T23:09:42.435Z","fetched":"2018-04-11T21:09:36.383Z"};
var __path=require('path');
var __require=function(fn) {
try {
return require(fn);
} catch (e) {
try {
return require(__path.join(process.cwd(),fn));
} catch (e) {
return require(__path.join(process.cwd(),'node_modules',fn));
}
}
}
var isa = prototype.isa = 'Construct';
var $bindfail = function(m) {
throw new Error("SAI: A call to " + m + " on object " + isa + " has come unbound from any instance of that object. (If this is not in error, mark the declaration of " + m + " as unbound.)");
}
prototype.isof['Construct'] = {
version: '0.0.0-unspecified',
isa: isa,
context: __context,
type: "singleton"
};
prototype.__tobelocked = prototype.__tobelocked.concat(["OutVarHelper", "ExprsHelper", "isa"]);
prototype.__tobefrozen = prototype.__tobefrozen.concat(["isof"]);
prototype.__contracts = prototype.__contracts.concat(['manifest']);
var $5g = prototype['OutVarHelper'] || function() {};
prototype['OutVarHelper'] = function(p) {
var $0_this, $1_key, $2_list, $3_length, $4_none, $5_trial, $ = this['OutVarHelper'] ? this : $bindfail('OutVarHelper'),
$_c, $_d, _out = p,
_vars; {
_vars = [];
if ($5_trial = (_out)) {
var $2_list = _out,
$1_key;
if (undefined === $2_list) $2_list = [];
var $3_length = $2_list.length;
for ($1_key = 0; $1_key < $3_length; $1_key++) {
$0_this = $2_list[$1_key];
_vars.push($0_this[0][1]);;
}
}
return (_vars);
}
};
var $6g = prototype['ExprsHelper'] || function() {};
prototype['ExprsHelper'] = function(p) {
var $6_this, $ = this['ExprsHelper'] ? this : $bindfail('ExprsHelper'),
$_b, _exprs = p; {
return (((undefined !== ($_b = (undefined === ($_b = (_exprs)) ? undefined : ($_b[2])))) ? $_b : []));
}
};
var __context={"loader":"SAI.GetSourceFromFilename","path":"/Users/seanmpuckett/Documents/ProjSync/Node/sai/src/StateC.sai","workdir":"/Users/seanmpuckett/Documents/ProjSync/Node/sai/src","mtime":"2018-04-11T16:59:55.843Z","fetched":"2018-04-11T21:09:36.307Z"};
var __path=require('path');
var __require=function(fn) {
try {
return require(fn);
} catch (e) {
try {
return require(__path.join(process.cwd(),fn));
} catch (e) {
return require(__path.join(process.cwd(),'node_modules',fn));
}
}
}
var isa = prototype.isa = 'StateC';
var $bindfail = function(m) {
throw new Error("SAI: A call to " + m + " on object " + isa + " has come unbound from any instance of that object. (If this is not in error, mark the declaration of " + m + " as unbound.)");
}
prototype.isof['StateC'] = {
version: '0.0.0-unspecified',
isa: isa,
context: __context,
type: "singleton"
};
prototype.__tobelocked = prototype.__tobelocked.concat(["manifest", "docs", "StateConstruct", "Documents", "isa"]);
prototype.__tobefrozen = prototype.__tobefrozen.concat(["isof"]);
prototype.isof[prototype.isa].inherit = prototype.__inherits = ['Construct'];
Object.defineProperty(prototype, "manifest", {
configurable: true,
enumerable: true,
get: function(p) {
var $ = this; {
return ({
'constructs': {
state: {
repeats: true,
clauses: {
state: {
exproutblock: true,
rvalue: true
}
},
handler: function() {
return ($.StateConstruct).apply($, arguments);
}
}
}
});
}
},
set: undefined
});
Object.defineProperty(prototype, "docs", {
configurable: true,
enumerable: true,
get: function(p) {
var $0_this, $ = this,
$_c, $_d; {
return ($.Documents());
}
},
set: undefined
});
var $3g = prototype['StateConstruct'] || function() {};
prototype['StateConstruct'] = function(p) {
var $1_this, $2_trial, $3, $4_this, $5_key, $6_list, $7_none, $ = this['StateConstruct'] ? this : $bindfail('StateConstruct'),
$_c, $_d, _block, _body, _header, _name, _names, _states, _tools, _trailer;
$AI.expectsThrow(p, {
"clauses": true,
"tools": true
}, '\'StateConstruct\''); {
_tools = ['var $state$getfn=function(states,state) {' + '\n' + ' return $AI.assert(states[state],"SAI runtime: STATE "+state+" does not exist; available states are "+$AI.keys_op(states).join(\',\'));' + '\n' + '}' + '\n' + 'var $state$goto=function(states,state){' + '\n' + ' var $=this;' + '\n' + ' var fn=$state$getfn(states,state);' + '\n' + ' var l=arguments.length, args=new Array(l-2);' + '\n' + ' for (var li=2; li<l; li++) args[li-2]=arguments[li];' + '\n' + ' setImmediate(function(){fn.apply($,args)});' + '\n' + '};' + '\n' + 'var $state$then=function(states,state){' + '\n' + ' var $=this;' + '\n' + ' var fn=$state$getfn(states,state);' + '\n' + ' var l=arguments.length, args=new Array(l-2);' + '\n' + ' for (var li=2; li<l; li++) args[li-2]=arguments[li];' + '\n' + ' return function(){' + '\n' + ' var l=arguments.length;' + '\n' + ' if (l) {' + '\n' + ' var o=args.length;' + '\n' + ' args.length=l+o;' + '\n' + ' for (var li=0; li<l; li++) args[o+li]=arguments[li];' + '\n' + ' }' + '\n' + ' fn.apply($,args);' + '\n' + ' };' + '\n' + '};' + '\n' + ''];
_header = 'var ' + p.tools.addlocal() + '=function(){' + '\n' + ' var _goto,_then;' + '\n' + ' var $states={' + '\n' + '';
_trailer = '}' + '\n' + ' _goto=$state$goto.bind($,$states);' + '\n' + ' _then=$state$then.bind($,$states);' + '\n' + ' _goto(' + p.clauses[0].args.expr + ');' + '\n' + '}();' + '\n' + '';
_names = {};
_states = [];
var $6_list = p.clauses,
$5_key = undefined;
if (undefined === $6_list) $6_list = {};
for ($5_key in $6_list) {
$4_this = $6_list[$5_key];
switch ($3 = ($4_this.type)) {
case 'state.exproutblock':
_name = $4_this.args.expr;
if ($2_trial = (_names[_name])) {
return ({
error: 'SAI compile: duplicate state ' + _name + ' in STATE construct'
});
}
_names[_name] = (_names[_name] || 0) + 1;
_block = p.tools.tasker({
'as': $4_this.args.out,
block: $4_this.args.block,
kind: 'function'
});
_states.push('' + _name + ':' + _block);
break;
default:
return ({
error: 'Unhandled construct type ' + $4_this.type + ' in StateConstruct'
});
break;
};
}
p.tools.addlocal('_goto');
p.tools.addlocal('_then');
_body = '' + _header + _states.join(',') + _trailer;
return ({
body: _body,
tools: _tools
});
}
};
var $4g = prototype['Documents'] || function() {};
prototype['Documents'] = function(p) {
var $8_this, $ = this['Documents'] ? this : $bindfail('Documents'); {
return ({
'constructs': {
state: {
subtitle: 'asynchronous finite state machine',
summary: 'The __state__ construct creates an asynchronous state machine (or finite automata) that can' + '\n' + 'be used for many different kinds of processes, from making requests or managing other machines,' + '\n' + 'to controlling and responding to near-realtime events.',
detail: 'Each declared __state__ is given a name (the value), and has an associated block of code.' + '\n' + 'Each block is a function, with optional parameters. These functions are invoked with' + '\n' + 'the __goto__ verb. The first parameter of __goto__ is the name of the state; any additional' + '\n' + 'parameters are passed in to the state function.' + '\n' + '' + '\n' + ' state [value1] (given [parameter list])' + '\n' + ' ... code ...' + '\n' + ' goto [value] (, [parameters for next state])' + '\n' + ' ... code ...' + '\n' + ' state [value2] (given [parameter list])' + '\n' + ' goto etc...' + '\n' + ' ... repeats for as many states as supplied' + '\n' + '' + '\n' + 'The uppermost defined __state__ in the construct is the starting state by convention,' + '\n' + 'and it is invoked first. When you __goto__ a new state, you\'ll just be scheduling the next' + '\n' + 'state to occur next. You must `return` if you want its execution to stop immediately. If you' + '\n' + 'do not __goto__ another state, the machine ends (unless a callback into to a state happens' + '\n' + 'asynchronously). State machine context is preserved until there is no more opportunity for a callback.' + '\n' + '' + '\n' + '*Note*: The __state__ construct runs asynchronously. Synchronous code execution passes the' + '\n' + 'state machine definition instantly, and the first state executes on the next event loop' + '\n' + 'tick via node\'s `setImmediate`. Each time you __goto__ a new state, that state is also' + '\n' + 'scheduled asynchronously.' + '\n' + '' + '\n' + 'While the event loop is quite fast (perhaps 100k state transitions' + '\n' + 'per second on a laptop), you will want to avoid using the __state__ construct for applications' + '\n' + 'that require high performance and/or that do not benefit greatly from asynchronous response.' + '\n' + 'In these cases, a `while` loop around a `switch` statement is a good place to start.' + '\n' + '' + '\n' + 'Context is preserved with the state machine, including the _current_ (this) object. You have' + '\n' + 'access to all member variables/methods of the object instance that invoked the __state__ construct.' + '\n' + 'Variables you `set` within any state are available to all states. However, `local` variables are' + '\n' + 'restricted to the state they\'re defined in. (Examine the generated Javascript code for clarity.)' + '\n' + '' + '\n' + 'Here is a simple example of a state machine, a Turing machine that adds two unary (bitcount)' + '\n' + 'numbers starting at the read head, extending right and separated by a single 0 digit.' + '\n' + '' + '\n' + ' set Readout to task // display Turing tape and current head position' + '\n' + ' debug tape | into \'\' sum + ((key is head) ?? \'[$\{it}]\' :: \' $\{it} \')' + '\n' + '' + '\n' + ' state \'start\' // turing machine to add two numbers, in this case 3 & 4.' + '\n' + ' set tape list 0, 1, 1, 1, 0, 1, 1, 1, 1, 0' + '\n' + ' set head 1' + '\n' + ' goto \'a\'' + '\n' + '' + '\n' + ' state \'a\'' + '\n' + ' Readout' + '\n' + ' if tape\head // seek end of first number' + '\n' + ' set tape\head 1' + '\n' + ' inc head' + '\n' + ' goto \'a\'' + '\n' + ' else // set bit between numbers' + '\n' + ' set tape\head 1' + '\n' + ' inc head' + '\n' + ' goto \'b\'' + '\n' + '' + '\n' + ' state \'b\'' + '\n' + ' Readout' + '\n' + ' if tape\head // seek end of second number' + '\n' + ' set tape\head 1' + '\n' + ' inc head' + '\n' + ' goto \'b\'' + '\n' + ' else' + '\n' + ' set tape\head 0 // rewind to end of second number' + '\n' + ' dec head' + '\n' + ' goto \'c\'' + '\n' + '' + '\n' + ' state \'c\'' + '\n' + ' Readout' + '\n' + ' if tape\head // clear bit at end of second number' + '\n' + ' set tape\head 0' + '\n' + ' dec head' + '\n' + ' goto \'d\'' + '\n' + ' else' + '\n' + ' debug "Should not be able to get here."' + '\n' + ' goto \'halt\'' + '\n' + '' + '\n' + ' state \'d\'' + '\n' + ' Readout' + '\n' + ' if tape\head // seek back to the beginning of the result' + '\n' + ' set tape\head 1' + '\n' + ' dec head' + '\n' + ' goto \'d\'' + '\n' + ' else' + '\n' + ' set tape\head 0 // return to first set bit and halt' + '\n' + ' inc head' + '\n' + ' goto \'halt\'' + '\n' + '' + '\n' + ' state \'halt\'' + '\n' + ' Readout' + '\n' + ' debug "Run complete."' + '\n' + '' + '\n' + ' debug "State machine started." // appears first because STATE is asynchronous' + '\n' + '' + '\n' + 'The output is:' + '\n' + '' + '\n' + ' State machine started.' + '\n' + ' 0 [1] 1 1 0 1 1 1 1 0' + '\n' + ' 0 1 [1] 1 0 1 1 1 1 0' + '\n' + ' 0 1 1 [1] 0 1 1 1 1 0' + '\n' + ' 0 1 1 1 [0] 1 1 1 1 0' + '\n' + ' 0 1 1 1 1 [1] 1 1 1 0' + '\n' + ' 0 1 1 1 1 1 [1] 1 1 0' + '\n' + ' 0 1 1 1 1 1 1 [1] 1 0' + '\n' + ' 0 1 1 1 1 1 1 1 [1] 0' + '\n' + ' 0 1 1 1 1 1 1 1 1 [0]' + '\n' + ' 0 1 1 1 1 1 1 1 [1] 0' + '\n' + ' 0 1 1 1 1 1 1 [1] 0 0' + '\n' + ' 0 1 1 1 1 1 [1] 1 0 0' + '\n' + ' 0 1 1 1 1 [1] 1 1 0 0' + '\n' + ' 0 1 1 1 [1] 1 1 1 0 0' + '\n' + ' 0 1 1 [1] 1 1 1 1 0 0' + '\n' + ' 0 1 [1] 1 1 1 1 1 0 0' + '\n' + ' 0 [1] 1 1 1 1 1 1 0 0' + '\n' + ' [0] 1 1 1 1 1 1 1 0 0' + '\n' + ' 0 [1] 1 1 1 1 1 1 0 0' + '\n' + ' Run complete.' + '\n' + '' + '\n' + 'There are many easier ways of programming a Turing machine without hardcoding everything' + '\n' + 'like this. This one does show off the __state__ construct fairly nicely, however.' + '\n' + '' + '\n' + '#### goto' + '\n' + '' + '\n' + 'Within the __state__ construct, the variable `goto` is defined as a function that schedules' + '\n' + 'execution of the next state. (This trickery should be essentially invisible, but just in case you' + '\n' + 'need to know how, this is how.)' + '\n' + '' + '\n' + '##### Parameters with __goto__' + '\n' + '' + '\n' + '__goto__ will pass any provide parameters on to the state function:' + '\n' + '' + '\n' + ' state \'start\'' + '\n' + ' debug "You\'re lost in a cave!"' + '\n' + ' dountil maze\\pos is \'empty\'' + '\n' + ' set pos !Rand size' + '\n' + ' goto \'move\', pos // we\'re passing the new position here as POS' + '\n' + '' + '\n' + ' state \'move\' given newpos // and it is recevied here as NEWPOS' + '\n' + ' inc moves' + '\n' + ' set position !Valid newpos' + '\n' + ' debug " move \${moves} ... now in room \${position}"' + '\n' + ' goto maze\\position' + '\n' + '' + '\n' + '#### then' + '\n' + '' + '\n' + 'Similarly, __then__ is a function that _creates a function_ that immediately jumps to the next' + '\n' + 'state rather than rescheduling another state transition. In other words, __then__ is a callback' + '\n' + 'creator.' + '\n' + '' + '\n' + 'Use __then__ like this:' + '\n' + '' + '\n' + ' state \'empty\'' + '\n' + ' ply array position-1, position+1 as adjacent' + '\n' + ' each features as dsc, feat' + '\n' + ' if feat is maze[from Valid adjacent]' + '\n' + ' debug dsc' + '\n' + '' + '\n' + ' Timer 800, !then \'step\'' + '\n' + '' + '\n' + ' state \'step\'' + '\n' + ' goto \'move\', position + !Step' + '\n' + '' + '\n' + 'This example does some housekeeping, delays for 800ms, _then_ the timer callback jumps to the' + '\n' + 'next state.' + '\n' + '' + '\n' + '##### Parameters with __then__' + '\n' + '' + '\n' + 'Because __then__ creates a callback function, there are _two_ opportunities for arguments to be' + '\n' + 'passed to the next state.' + '\n' + '' + '\n' + '1. When __then__ is executed to create the callback.' + '\n' + '2. When the callback is executed some later time.' + '\n' + '' + '\n' + 'In the above example,' + '\n' + '' + '\n' + ' Timer 800, !then \'step\'' + '\n' + '' + '\n' + 'This is the first opportunity for parameters to be passed.' + '\n' + '' + '\n' + 'To make it clear, let\'s add one:' + '\n' + '' + '\n' + ' ...' + '\n' + ' Timer 800, !then \'step\', !Step' + '\n' + '' + '\n' + ' state \'step\' given stepValue' + '\n' + ' goto \'move\', position + stepValue' + '\n' + '' + '\n' + 'Parameters added at callback creation time are resolved immediately, even though they\'re not' + '\n' + 'used until later. These parameters are invisibly bound into the callback function that is' + '\n' + 'created. In the above example, `stepValue` is calculated 800ms before the state change to `step`' + '\n' + 'occurs; this step value waiting in the callback defined when the `Timer` function is invoked.' + '\n' + '' + '\n' + 'The second opportunity is when the callback is actually made. In our example, let\'s say the timer' + '\n' + 'wishes to pass the real time it was resolved. And we want that data. But we also want our' + '\n' + '`stepValue`, which was passed in earlier.' + '\n' + '' + '\n' + 'Fortunately, we can have both pieces of data. The callback function that __then__ creates will' + '\n' + 'append any arguments it receives _as a callback_ to the arguments bound to it _on callback' + '\n' + 'creation_. So we now have two parameters to our `step` state.' + '\n' + '' + '\n' + ' state \'step\' given stepValue, resolvedTime' + '\n' + ' debug "Timer resolved at \${resolvedTime}"' + '\n' + ' goto \'move\', position + stepValue' + '\n' + '' + '\n' + 'Just to make it clear: `stepValue` was calculated and passed into the callback generator when we' + '\n' + 'started the timer, and `resolvedTime` was calculated and passed into the callback when' + '\n' + 'the timer resolved. The callback concatentated them into one set of arguments for the call to' + '\n' + 'the `step` state.' + '\n' + '' + '\n' + 'If you unroll this, it looks something like this:' + '\n' + '' + '\n' + ' then \'step\', stepValue' + '\n' + ' .. becomes ..' + '\n' + ' callback invoking \'step\' with stepValue' + '\n' + ' .. which _later_ is invoked as ..' + '\n' + ' callback resolvedTime' + '\n' + ' .. which becomes ..' + '\n' + ' invoke \'step\' with stepValue, resolvedTime' + '\n' + '' + '\n' + 'This works with any number of arguments provided at callback creation and resolution. Just be' + '\n' + 'sure you know how many of each there are when you pick them up in the _state handler_.' + '\n' + '' + '\n' + 'I hope that\'s clear. And useful!' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + ''
}
}
});
}
};
// End of generated code
$AI.finalizePrototype(prototype);
var result=prototype;
switch (prototype.isof[prototype.isa].type) {
case 'singleton':
prototype.Constructor();
if (prototype.Instantiate) prototype.Instantiate();
break;
case 'main':
result=prototype.constructor();
break;
default:
result=prototype.constructor;
break;
}
exports=result; try { module.exports=result; } catch(e) {};
return result;