sai-language
Version:
An object-oriented language designed to afford code comprehension and maintenance. Transpiles in-place to Javascript.
492 lines (485 loc) • 156 kB
JavaScript
#!/usr/bin/env node
// Javascript source for Keywords.sai transpiled by SAI
//
"use strict";
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-11T22:24:03.531Z"};
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 $7g = 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 $8g = 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/Keywords.sai","workdir":"/Users/seanmpuckett/Documents/ProjSync/Node/sai/src","mtime":"2018-04-11T16:56:16.451Z","fetched":"2018-04-11T22:24:02.529Z"};
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 = 'Keywords';
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['Keywords'] = {
version: '0.0.0-unspecified',
isa: isa,
context: __context,
type: "singleton"
};
prototype.__tobelocked = prototype.__tobelocked.concat(["manifest", "docs", "introspect", "Documentation", "isa"]);
prototype.__tobefrozen = prototype.__tobefrozen.concat(["isof"]);
prototype.isof[prototype.isa].inherit = prototype.__inherits = ['Construct'];
var t = {
boringlist: ['{', '}', ']', '%%DEDENT%%', '%%INDENT%%', ',', ')', '0x', '0o', '::', '\\\\\'', '{;', '};', '\\\\/', '\\\\;', '\\', '\\\\', '__column', '__line', '__offset', '__source', '\x5e'],
goodlist: ['assert', 'debug', 'isa', 'environment']
};
for (var i in t) {
prototype.__tobelocked.push(i);
prototype[i] = t[i];
};
var $1g = function() {
var $ = this;
return {
SAI: undefined
};
}
for (var i in $1g()) {
prototype[i] = undefined;
};
var $2g = prototype.Constructor || function() {};
prototype.Constructor = function() {
$2g.call(this);
var t = $1g();
for (var i in t)
if (t[i] !== undefined) this[i] = t[i];
};
Object.defineProperty(prototype, "manifest", {
configurable: true,
enumerable: true,
get: function(p) {
var $ = this; {
return ($.introspect);
}
},
set: undefined
});
Object.defineProperty(prototype, "docs", {
configurable: true,
enumerable: true,
get: function(p) {
var $0_this, $ = this; {
return ($.introspect);
}
},
set: undefined
});
Object.defineProperty(prototype, "introspect", {
configurable: true,
enumerable: true,
get: function(p) {
var $10_none, $11_this, $12_key, $13_list, $14_none, $15_this, $16_key, $17_list, $18_none, $1_this, $2_this, $3_this, $4_key, $5, $6, $7, $8_key, $9_list, $ = this,
$_c, $_d, _boringkeywords, _category, _covered, _extra, _matcher, _matches, _missing, _parsefun, _simple, _sure; {
_boringkeywords = $AI.sum_op($.boringlist, function(s, a) {
s[a] = true;
return s;
}, {});
_parsefun = $.SAI.mainParser.parse.toString();
_matcher = /peg\$literalExpectation.\"([^"]+)\"./g;
_matches = [];
var $2_this;
while ($2_this = (_matcher.exec(_parsefun))) {
_matches.push($2_this[1]);
}
_simple = /^[0-9a-zA-Z]$|\&\#/;
$5 = _matches;
_matches = $AI.sum_op($AI.filter_op($5, function($3_this, $4_key) {
return (!((_simple.exec($3_this) || _boringkeywords[$3_this])));
}, false), function(s, v, k) {
s[v] = {};
return s;
}, {});
_missing = $AI.overlay_op($AI.clone_op(_matches), $AI.sum_op($.goodlist, function(s, a) {
s[a] = true;
return s;
}, {}));
_covered = {};
var $9_list = $.Documentation(),
$8_key = undefined;
if (undefined === $9_list) $9_list = {};
for ($8_key in $9_list) {
_category = $9_list[$8_key];
$6 = _missing;
_missing = $AI.delete_op($6, _category, true);
$7 = _covered;
_covered = $AI.overlay_op($7, _category);;
}
_extra = $AI.delete_op($AI.delete_op(_covered, $.goodlist, true), _matches, true);
var $13_list = _missing,
$12_key = undefined;
if (undefined === $13_list) $13_list = {};
for ($12_key in $13_list) {
$11_this = $13_list[$12_key];
$AI.debug_op('missing coverage for parser literal ' + $12_key);
_sure = '\'' + $12_key + '\':' + '\n' + ' subtitle \'\'' + '\n' + ' summary \'\'\'' + '\n' + ' synref \'\'\'' + '\n' + ' detail \'\'\'' + '\n' + '';;
}
var $17_list = _extra,
$16_key = undefined;
if (undefined === $17_list) $17_list = {};
for ($16_key in $17_list) {
$15_this = $17_list[$16_key];
$AI.debug_op('excess documentation for ' + $16_key);;
}
return ($.Documentation());
}
},
set: undefined
});
var $6g = prototype['Documentation'] || function() {};
prototype['Documentation'] = function(p) {
var $19_this, $ = this['Documentation'] ? this : $bindfail('Documentation'); {
return ({
'globals': {
'assert': {
subtitle: 'run-time error checking',
summary: 'If the first expression is _falsy_, throw an exception with the second expression as a message.' + '\n' + 'Otherwise, return the expression.',
synref: 'assert [test value], [error message]' + '\n' + '' + '\n' + '.. !assert [test value], [error message]',
detail: 'For example:' + '\n' + '' + '\n' + ' assert everythingIsAwesome, \'I have some bad news...\'' + '\n' + '' + '\n' + ' > Error: SAI: failed assertion: I have some bad news...' + '\n' + '' + '\n' + 'You can use __assert__ in an expression, because it returns the value passed.' + '\n' + '' + '\n' + ' set sock !assert GetSocket, "Could not obtain socket resource"' + '\n' + '' + '\n' + '__Assert__, like __debug__, is functionality that can be redefined by passing a new handler' + '\n' + 'to SAI\'s configuration facility.' + '\n' + '' + '\n' + ''
},
'debug': {
subtitle: 'print diagnostics to the console',
summary: 'Prints the value of the expression to the console.',
synref: 'debug [expr]',
detail: 'Compiles to a call to $AI.debug_op in `sai-library`, which you can hook to provide your own' + '\n' + 'implementation.' + '\n' + '' + '\n' + 'In the default implementation, just calls `console.log` with the provided value.' + '\n' + '' + '\n' + ' debug "this is a test"' + '\n' + '' + '\n' + ' > this is a test' + '\n' + '' + '\n' + ''
},
'environment': {
subtitle: 'return SAI runtime environment information',
summary: 'Call the __environment__ function to gain information about the runtime state of your SAI module.',
synref: '.. set env to environment()',
detail: 'The __environment__ function returns different things based on whether your module is running' + '\n' + 'in static or dynamic mode.' + '\n' + '' + '\n' + 'In static mode (when you\'re running from a pre-compiled `.js` script), you get this:' + '\n' + '' + '\n' + ' fields' + '\n' + ' dynamic (false)' + '\n' + ' static (true)' + '\n' + '' + '\n' + 'In dynamic mode (when you\'re using the `sai-language` package to compile on the fly), you get this:' + '\n' + '' + '\n' + ' fields' + '\n' + ' dynamic (true)' + '\n' + ' static (false)' + '\n' + ' paths (array) // array of paths searched dring CREATE' + '\n' + '' + '\n' + ' Clean (function) // reset the compiler environment' + '\n' + ' Configure (function) // e.g. change paths, etc' + '\n' + ' GetSource (function) // return full JS source for a SAI object by name' + '\n' + ' RegisterWithNode (function) // theoretically register .sai with node\'s require' + '\n' + ' Require (function) // a version of require that uses SAI\'s paths, not node\'s' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + ''
}
},
'pronouns': {
'counter': {
subtitle: 'pronount for integer-based loops',
summary: 'A partner to **count**, **counter** is a _pronoun_, populated by the **count** iterator,' + '\n' + 'if no other variable is specified in an **as** clause.',
synref: '.. counter',
detail: 'Like all pronouns, **counter** is only visible in attached expressions or code blocks, not in' + '\n' + 'any functions that may be called within those expressions.' + '\n' + '' + '\n' + 'An example:' + '\n' + '' + '\n' + ' count friends.length' + '\n' + ' debug counter' + '\n' + '' + '\n' + 'Similar to **it** in nested contexts, you are unable to access “outer” values of **counter** within' + '\n' + 'inner contexts unless you assign them to a name other than **counter** using the **as** clause.' + '\n' + '' + '\n' + ' count 3' + '\n' + ' count 3' + '\n' + ' debug counter' + '\n' + ' // only the inner loop\'s \'counter\' is visible here.' + '\n' + '' + '\n' + ' // prints 0 1 2 0 1 2 0 1 2' + '\n' + '' + '\n' + ' count 3 as i' + '\n' + ' count 3' + '\n' + ' debug i+\',\'+counter' + '\n' + ' // outer loop\'s \'counter\' now available here as \'i\'' + '\n' + '' + '\n' + ' // prints 0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2' + '\n' + '' + '\n' + ' count 3' + '\n' + ' count 3 as j' + '\n' + ' debug counter+\',\'+j' + '\n' + ' // no, this doesn\'t work, you still can\'t access the outer \'counter\'' + '\n' + ' // \'counter\' always has the value of the innermost context' + '\n' + '' + '\n' + ' // prints 0,0 1,1 2,2 0,0 1,1 2,2 0,0 1,1 2,2' + '\n' + '' + '\n' + ''
},
'error': {
subtitle: 'catch pronoun',
summary: 'summary',
synref: '.. error',
detail: 'Valid only within the **catch** exception handler clause of a **try/catch/finally** construct. Receives the exception thrown.' + '\n' + '' + '\n' + ' try' + '\n' + ' noFunction' + '\n' + ' catch' + '\n' + ' debug error' + '\n' + '' + '\n' + ' > [TypeError: undefined is not a function]' + '\n' + '' + '\n' + 'You can override this behaviour by using an **as** clause with the **catch** statement:' + '\n' + '' + '\n' + ' try' + '\n' + ' noFunction' + '\n' + ' catch as e' + '\n' + ' debug e' + '\n' + '' + '\n' + ' > [TypeError: undefined is not a function]' + '\n' + '' + '\n' + ''
},
'it': {
subtitle: 'context-sensitive pronoun',
summary: '**It** is the most commonly used pronoun, populated by most iterators and comprehensions, as well as' + '\n' + 'the **exists** conditional and **with** contextualizer.',
synref: '.. it',
detail: '_Pronouns_ have values when provided by the system during certain code events.' + '\n' + '' + '\n' + 'The **it** variable is only available in attached expressions or code blocks -- not in any functions that' + '\n' + 'may be called within those expressions, and not in code outside those blocks.' + '\n' + '' + '\n' + 'A partial list of **it** enabled events:' + '\n' + '' + '\n' + ' exists [expr] // it: expr' + '\n' + ' with [expr] // it: expr' + '\n' + '' + '\n' + ' iterate [iterable] // it: each iterated value' + '\n' + ' each [collection] // it: each value in the collection' + '\n' + ' ply [list] // it: each element in the array' + '\n' + '' + '\n' + ' .. [collection] | thru // it: each value in the collection' + '\n' + ' .. [collection] | audit' + '\n' + ' .. [collection] | into' + '\n' + ' .. [collection] | has' + '\n' + ' .. [collection] | highest' + '\n' + ' .. [collection] | lowest' + '\n' + '' + '\n' + 'When nesting contexts that create a **it** context, you will be unable to access “outer”' + '\n' + 'values of **it** within the inner contexts unless you assign them to a name other' + '\n' + 'than **it** using the **as** clause.' + '\n' + '' + '\n' + ' ply: 1,2,3' + '\n' + ' ply: 4,5,6' + '\n' + ' debug it' + '\n' + '' + '\n' + ' // prints 4 5 6 4 5 6 4 5 6' + '\n' + '' + '\n' + ' ply: 1,2,3' + '\n' + ' ply: 4,5,6 as inner' + '\n' + ' debug it' + '\n' + '' + '\n' + ' // still prints 4 5 6 4 5 6 4 5 6' + '\n' + '' + '\n' + ' ply: 1,2,3 as outer' + '\n' + ' ply: 4,5,6' + '\n' + ' debug outer' + '\n' + '' + '\n' + ' // prints 1 1 1 2 2 2 3 3 3' + '\n' + '' + '\n' + 'When **it** is populated, you can also use the “unrooted” **attribute** ( . dot) scoping' + '\n' + 'prefix. The following are all synonymous:' + '\n' + '' + '\n' + ' set field to \'province\'' + '\n' + ' set quebeckers to friends has it.province=\'QC\'' + '\n' + ' set quebeckers to friends has it[field]=\'QC\'' + '\n' + ' set quebeckers to friends has .province=\'QC\'' + '\n' + '' + '\n' + '(There is no unrooted [] lookup available, you can\'t `[field]`.)' + '\n' + '' + '\n' + ''
},
'key': {
subtitle: 'looping pronoun',
summary: 'Often a partner to **it**, **key** is the second most commonly used _pronoun_, populated by most' + '\n' + 'iterators and comprehensions.',
synref: '.. key',
detail: 'Like all pronouns, **keys** is only visible in attached expressions or code blocks, not in any functions that may be called within those expressions.' + '\n' + '' + '\n' + 'A partial list of **keys** enabled events:' + '\n' + '' + '\n' + ' each [collection] // key: the trait name of each value in the collection' + '\n' + ' ply [list] // key: the array index of each element in the array' + '\n' + ' count [expr] // key: the number being counted' + '\n' + ' iterate [generator] // key: the row number of the value being processed' + '\n' + '' + '\n' + ' .. [collection] thru // key: each trait name/array index of the collection' + '\n' + ' .. [collection] audit' + '\n' + ' .. [collection] into' + '\n' + ' .. [collection] has' + '\n' + '' + '\n' + 'An example:' + '\n' + '' + '\n' + ' ply friends' + '\n' + ' debug key' + '\n' + '' + '\n' + ' // prints: 0 1 2 3 4 5 6 7' + '\n' + '' + '\n' + ' each friends[0]' + '\n' + ' debug key' + '\n' + '' + '\n' + ' // prints: name age cat province' + '\n' + '' + '\n' + 'Similar to **it** and **counter** in nested contexts, you are unable to access “outer”' + '\n' + 'values of **key** within inner contexts unless you assign them to a specific variable' + '\n' + 'using the **as** clause. See **counter** for an example of this issue.' + '\n' + '' + '\n' + ''
},
'self': {
subtitle: 'pronoun for set statements',
summary: 'A pronoun used only in a **set** statement that contains the original value of the variable' + '\n' + 'that is being set/modified.',
synref: 'set [var] .. self ..',
detail: 'The following lines are equivalent; one of them is easier to read than the other.' + '\n' + '' + '\n' + ' set totals\key to totals\key ? 0 + amount' + '\n' + ' set totals\key to self ? 0 + amount' + '\n' + '' + '\n' + ''
},
'sum': {
subtitle: 'reduction pronoun',
summary: 'A pronoun active only within a **into** clause or code block.',
synref: '.. sum',
detail: 'Represents the static value that accumulates changes during **into** iteration over a data set.' + '\n' + '' + '\n' + ' debug friends | into 0' + '\n' + ' set sum + .age' + '\n' + '' + '\n' + ' > 185' + '\n' + '' + '\n' + '**Sum** is initialized with the value following **into**.' + '\n' + '' + '\n' + ' debug friends | into blank' + '\n' + ' set sum[.province] to (self default 0)+1' + '\n' + '' + '\n' + ' > { ON: 5, QC: 3 }' + '\n' + '' + '\n' + ''
},
'trial': {
subtitle: 'pronoun for conditionals and switch',
summary: 'A pronoun set to the value tested in an **if/exists** or **switch** statement.',
synref: 'if [expr]' + '\n' + ' .. trial ..' + '\n' + '' + '\n' + 'switch [expr]' + '\n' + ' case [match]' + '\n' + ' .. trial ..' + '\n' + ' default' + '\n' + ' .. trial ..',
detail: 'In an **if/exists** statement, **trial** is only valid in the body of the first code block.' + '\n' + '' + '\n' + ' exists readline()' + '\n' + ' // trial is available here' + '\n' + ' else' + '\n' + ' // trial is undefined here' + '\n' + '' + '\n' + 'In a **switch** statement, **trial** is available through all **case**s and the **default**.' + '\n' + '' + '\n' + ' switch Keypress.toUpperCase()' + '\n' + ' case \'N\'' + '\n' + ' Move 0,-1' + '\n' + ' case \'S\'' + '\n' + ' Move 0,1' + '\n' + ' default' + '\n' + ' debug \'I don\'t know what \${trial} means.\'' + '\n' + ' ...' + '\n' + '' + '\n' + 'You can grant a specific name to the tested value with the **as** clause:' + '\n' + '' + '\n' + ' if Keypress as key' + '\n' + ' switch key.toUpperCase()' + '\n' + ' ...' + '\n' + '' + '\n' + 'Note that **trial** receives the tested value; the final result of the **if** or **switch** expression, not the value of any component:' + '\n' + '' + '\n' + ' if Keypress>0' + '\n' + ' debug trial' + '\n' + '' + '\n' + ' // the debug statement can only ever print \'true\'' + '\n' + '' + '\n' + 'Using the parenthetical **as** is one solution to this problem:' + '\n' + '' + '\n' + ' if ( Keypress as key) > 0' + '\n' + ' debug key' + '\n' + '' + '\n' + ' // reports the actual value of key' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + ''
}
},
'operators': {
'<>': {
subtitle: 'inequality comparison',
synref: '.. [expr] <> [expr]',
summary: 'Tests two values for value inequality.',
detail: 'Compares two values for value equality; returns **true** if the values appear to be the' + '\n' + 'same, **false** otherwise.' + '\n' + '' + '\n' + 'This is implemented with Javascript’s != operator and the behaviour is identical.' + '\n' + '' + '\n' + 'Contrast with **isnt**.' + '\n' + '' + '\n' + ''
},
'%': {
subtitle: 'modulus',
summary: 'Calculates the mathematical **modulus**; returns the remainder of the left expression divided by the right.',
synref: '.. [expr] % [expr]',
detail: 'Examples:' + '\n' + '' + '\n' + ' debug 5 % 2' + '\n' + ' debug 6.2 % 1' + '\n' + '' + '\n' + ' > 1' + '\n' + ' > 0.2' + '\n' + '' + '\n' + ''
},
'*': {
subtitle: 'multiplication',
summary: 'Multiplies two expressions.',
synref: '.. [expr] * [expr]',
detail: 'As in:' + '\n' + '' + '\n' + ' debug 2 * 3' + '\n' + '' + '\n' + ' > 6' + '\n' + '' + '\n' + ''
},
'**': {
subtitle: 'exponentiation',
summary: 'Raises one value to the power of another.',
synref: '.. [lexpr] ** [rexpr]',
detail: 'Calculates an exponent; equivalent to `Math.pow([lexpr],[rexpr])`.' + '\n' + '' + '\n' + ' debug 2 ** 3' + '\n' + '' + '\n' + ' > 8' + '\n' + '' + '\n' + ''
},
'+': {
title: '+',
subtitle: 'addition / string concatenation',
summary: 'summary',
synref: '.. [expr] + [expr]' + '\n' + '',
detail: 'Adds two numbers OR concatenates two strings. If both expressions are numbers, adds them.' + '\n' + 'Otherwise converts them both to strings and concatenates.' + '\n' + '' + '\n' + ' debug 1+2' + '\n' + ' debug \'1\'+2' + '\n' + ' debug 1+\'2\'' + '\n' + ' debug \'1\'+\'2\'' + '\n' + '' + '\n' + ' > 3' + '\n' + ' > 12' + '\n' + ' > 12' + '\n' + ' > 12' + '\n' + '' + '\n' + ''
},
'-': {
title: '-',
subtitle: 'subtraction/negation',
summary: 'summary',
synref: '.. [lexpr] - [rexpr]' + '\n' + '.. - [expr]',
detail: 'Used as a binary operator, subtracts the right expression from the left.' + '\n' + '' + '\n' + ' debug 3 - 5' + '\n' + ' > -2' + '\n' + '' + '\n' + 'Used as a unary operator, negates the expression (subtracts it from 0).' + '\n' + '' + '\n' + ' set b to 5' + '\n' + ' debug 3 + -b' + '\n' + ' > -2' + '\n' + '' + '\n' + 'SAI will not let you write the following;' + '\n' + '' + '\n' + ' set a - 3' + '\n' + '' + '\n' + 'Because that could be parsed one of two ways:' + '\n' + '' + '\n' + ' - place the value `-3` in the variable `a`' + '\n' + ' - subtract `3` from the variable `a`' + '\n' + '' + '\n' + 'If you try to write code like this, a compiler error will result. Choose one of these' + '\n' + 'formats instead:' + '\n' + '' + '\n' + ' set a to -3 // store -3 in a' + '\n' + ' set a self - 3 // subtract 3 from a' + '\n' + '' + '\n' + 'Just a little gotcha.' + '\n' + '' + '\n' + ''
},
'/': {
title: '/',
subtitle: 'mathematical division',
summary: 'Divides the expression on the left by the expression on the right.',
synref: '.. [expr1] / [expr2]',
detail: 'As in:' + '\n' + '' + '\n' + ' debug 22 / 7' + '\n' + ' debug 355 / 113' + '\n' + '' + '\n' + ' > 3.142857142857143' + '\n' + ' > 3.1415929203539825' + '\n' + '' + '\n' + ''
},
'<': {
subtitle: 'less comparison',
summary: 'Evaluates **true** if lexpr is numerically or lexically lower than rexpr, **false** otherwise.',
synref: '.. [lexpr] < [rexpr]',
detail: 'For example:' + '\n' + '' + '\n' + ' debug 1 < 1 // false' + '\n' + ' debug 1 < 2 // true' + '\n' + ' debug \'a\' < \'b\' // true' + '\n' + ' debug \'a\' < \'B\' // false, case matters' + '\n' + '' + '\n' + 'If you want a case insensitive comparison, you must ensure both expressions are of the same case.' + '\n' + '' + '\n' + ''
},
'<<': {
subtitle: 'bitwise left shift',
summary: 'Convert the expression to a 32 bit integer, then perform a binary left shift bitcount times.',
synref: '.. [expr] << [bitcount]' + '\n' + '.. [expr] lsh [bitcount] // synonym',
detail: 'See its synonym __lsh__.' + '\n' + '' + '\n' + ''
},
'<=': {
subtitle: 'less or equal comparison',
summary: 'Evaluates to **true** if lexpr is numerically or lexically lower or equal to rexpr, **false** otherwise.',
synref: '.. [lexpr] <= [rexpr]',
detail: 'You know how this works.' + '\n' + '' + '\n' + ''
},
'<=>': {
subtitle: 'comparison',
summary: 'Evaluates to **-1** if lexpr is lower than rexpr, **1** if it is greater, and **0** if they are equal.',
synref: '.. [lexpr] <=> [rexpr]',
detail: 'For example:' + '\n' + '' + '\n' + ' debug 1 <=> 0 // returns 1' + '\n' + ' debug 1 <=> 1 // returns 0' + '\n' + ' debug 1 <=> 2 // returns -1' + '\n' + ' debug \'b\' <=> \'a\' // returns 1' + '\n' + ' debug \'b\' <=> \'b\' // returns 0' + '\n' + ' debug \'b\' <=> \'c\' // returns -1' + '\n' + '' + '\n' + 'Useful in sorting operations!' + '\n' + '' + '\n' + ''
},
'=': {
subtitle: 'equality comparison',
summary: 'Evaluates to **true** if the two expressions are equivalent.',
synref: '.. [expr] = [expr]',
detail: 'This compiles directly to Javascript’s `==` operator and has the same occasionally' + '\n' + 'bizarre side effects. Basically, don’t use = except for comparing numeric, boolean or string values.' + '\n' + '' + '\n' + 'Use **is** or **isnt** to compare objects or object types, except when dealing with **NaN** in which' + '\n' + 'case the only reliable way to test for its existence is to use **isNaN**. That’s Javascript for you.' + '\n' + '' + '\n' + ''
},
'>': {
subtitle: 'greater comparison',
summary: 'Evaluates **true** if lexpr is numerically or lexically greater than rexpr, **false** otherwise.',
synref: '.. [lexpr] > [rexpr]',
detail: 'For example:' + '\n' + '' + '\n' + ' debug 1 > 1 // true' + '\n' + ' debug 1 > 2 // false' + '\n' + ' debug \'a\' > \'b\' // false' + '\n' + ' debug \'a\' > \'B\' // true, case matters' + '\n' + '' + '\n' + 'If you want a case insensitive comparison, you must ensure both expressions are of the same case.' + '\n' + '' + '\n' + ''
},
'>=': {
subtitle: 'greater or equal comparison',
summary: 'Evaluates **true** if lexpr is numerically or lexically greater than or equal to rexpr, **false** otherwise.',
synref: '.. [lexpr] >= [rexpr]',
detail: 'You know the drill.' + '\n' + '' + '\n' + ''
},
'>>': {
subtitle: 'signed bitwise right shift',
summary: 'Convert the expression to a 32 bit signed integer, then shift it right bitcount times,' + '\n' + 'maintaining the sign of the expression.',
synref: '.. [expr] rsh [bitcount]' + '\n' + '.. [expr] >> [bitcount] // synonym',
detail: 'See __rsh__.' + '\n' + '' + '\n' + ''
},
'>>>': {
subtitle: 'unsigned bitwise right shift',
summary: 'Convert the expression to a 32 bit unsigned integer, then shift it right bitcount times,' + '\n' + 'Zero bits are added on the left side (msb), which does not preserve negative sign.',
synref: '.. [expr] ursh [bitcount]' + '\n' + '.. [expr] >>> [bitcount] // synonym',
detail: 'See __ursh__.' + '\n' + '' + '\n' + ''
},
'?<': {
subtitle: 'minimum',
summary: 'Evaluates to whichever expression is numerically or lexically lower.',
synref: '.. [lexpr] ?< [rexpr]',
detail: 'Kind of like Math.min except as an operator.' + '\n' + '' + '\n' + ' debug 1 ?< 2 // returns 1' + '\n' + ' debug 2 ?< 1 // returns 1' + '\n' + '' + '\n' + 'Handy when you need it.' + '\n' + '' + '\n' + ''
},
'?>': {
subtitle: 'maximum',
summary: 'Evaluates to whichever expression is numerically or lexically higher.',
synref: '.. [lexpr] ?> [rexpr]',
detail: 'Kind of like Math.max except as an operator.' + '\n' + '' + '\n' + ' debug 1 ?> 2 // returns 2' + '\n' + ' debug 2 ?> 1 // returns 2' + '\n' + '' + '\n' + 'Of course it only operates on two values at a time. But that\'s cool.' + '\n' + '' + '\n' + ''
},
'??': {
title: '?? ::',
subtitle: 'trinary conditional',
summary: 'Evaluates to expr1 if the left expression is _truthy_, otherwise evaluates to expr2.',
synref: '.. [expr] ?? [expr1] :: [expr2]',
detail: 'I get the grar about the ?: operator, it can make for unclear logic. But I\'ve found' + '\n' + 'with this _doubled up_ version that it\'s much easier to see when it\'s used, especially' + '\n' + 'if you keep spaces on either side of the operators.' + '\n' + '' + '\n' + ' debug true ?? \'True\' :: \'False\' // prints \'True\'' + '\n' + ' debug false ?? \'True\' :: \'False\' // prints \'False\'' + '\n' + '' + '\n' + 'It\'s still kind of not great, but on the other hand there are times when five lines of code' + '\n' + 'could be reduced to one without losing much clarity. And those are the times for ??::.' + '\n' + '' + '\n' + ''
},
'and': {
subtitle: 'logical and',
summary: 'Checks two or more values; if they\'re all _truthy_, return a _truthy_ value.' + '\n' + 'Otherwise returns a _falsy_ value.',
synref: '.. [expr] and [expr]' + '\n' + '.. and [list of expressions]',
detail: 'As a binary operator, if the left expression evaluates to **falsy**, returns it,' + '\n' + 'otherwise returns the right expression.' + '\n' + '' + '\n' + 'Binay operator examples:' + '\n' + '' + '\n' + ' debug 1 and 0 // prints \'0\'' + '\n' + ' debug 1 and false // prints \'false\'' + '\n' + ' debug 0 and 1 // prints \'0\'' + '\n' + ' debug false and 1 // prints \'false\'' + '\n' + ' debug 1 and 1 // prints \'1\'' + '\n' + '' + '\n' + ' debug true and \'Fred\'' + '\n' + ' > Fred' + '\n' + '' + '\n' + 'As a unary operator given a list, returns the right-most element of the list if all the' + '\n' + 'elements in the list are _truthy_, otherwise returns the first _falsy_ element.' + '\n' + '' + '\n' + 'Unary operator examples:' + '\n' + '' + '\n' + ' debug and \'frog\', 2, true' + '\n' + ' debug and \'toad\', false, \'mario\'' + '\n' + '' + '\n' + ' > true' + '\n' + ' > false' + '\n' + '' + '\n' + 'The list can be split on more than one line, indented:' + '\n' + '' + '\n' + ' debug and:' + '\n' + ' \'hello\', true' + '\n' + ' \'this\', 4, 88' + '\n' + ' lookup(\'thing\')' + '\n' + '' + '\n' + ' > [ result of call to lookup ]' + '\n' + '' + '\n' + 'You can nest logical operators on multiple lines:' + '\n' + '' + '\n' + ' debug and:' + '\n' + ' or test1(2), test2(3)' + '\n' + ' or fallback(1), fallback(2)' + '\n' + '' + '\n' + 'It can get very clunky to try and use multi-line logical expressions with IF statements.' + '\n' + 'Instead, assign the results of your test to a clearly named variable that describes your' + '\n' + 'test and then use that in your IF statement:' + '\n' + '' + '\n' + ' set buildOk to and:' + '\n' + ' fileExists(fn)' + '\n' + ' fileDate(fn) > lastBuild\\fn' + '\n' + ' not alreadyBuilt\\fn' + '\n' + ' extensionhandler[PATH.extension(fn)]' + '\n' + '' + '\n' + ' if buildOk as hdlr' + '\n' + ' hdlr.build fn // rule about AND: last element in the list if all are true.' + '\n' + '' + '\n' + ''
},
'andb': {
subtitle: 'bitwise and',
summary: 'Bitwise and operator. Converts, if possible, both left and right expressions into 32 bit signed integers, and performs a bitwise AND operation on them.',
synref: '.. [expr] andb [expr]',
detail: 'Examples:' + '\n' + '' + '\n' + ' debug 5 andb 11' + '\n' + '' + '\n' + ' > 1' + '\n' + '' + '\n' + ' // 5 in binary: 00000000000000000000000000000101' + '\n' + ' // 11 in binary: 00000000000000000000000000001011' + '\n' + ' // 1 in binary: 00000000000000000000000000000001' + '\n' + '' + '\n' + ''
},
'bind': {
subtitle: 'function context binder',
summary: 'The __bind__ operator _binds_ a function reference to the current object context.',
synref: '.. bind [function reference]',
detail: 'This is useful when you need to pass in a member function to a callback, and need to ensure the' + '\n' + 'execution context (specifically, the _this_ object) isn\'t lost.' + '\n' + '' + '\n' + 'Why is this important?' + '\n' + '' + '\n' + ' Object car' + '\n' + ' instance: plate \'876 ACET\'' + '\n' + ' CheckPlate task' + '\n' + ' DB.lookupPlate plate, PlateResults' + '\n' + ' PlateResults task given status' + '\n' + ' debug \'Status for \${plate}: \${status}\'' + '\n' + '' + '\n' + 'In the above function definition of `CheckPlate` the `DB.lookupPlate` function is an asynchronous' + '\n' + 'call with a plate number and a callback function. As written, when the callback is invoked,' + '\n' + '`PlateResults` will have been unbound from its object; it is a function reference with no context.' + '\n' + '' + '\n' + 'The code will produce this result:' + '\n' + '' + '\n' + ' Looking up 876 ACET' + '\n' + ' Status for undefined: Valid' + '\n' + '' + '\n' + 'Although the test was successful, we have _lost context_ on the callback because `PlateResults`' + '\n' + 'is passed in as an unbound function. Referring to the member trait `plate` within an unbound context' + '\n' + 'produces an undefined result. In order to make this function reference work, we need to bind it to' + '\n' + 'the current object with the __bind__ operator, as follows:' + '\n' + '' + '\n' + ' DB.lookupPlate plate, bind PlateResults' + '\n' + '' + '\n' + 'Now when we run the asynchronous function, it works as expected, because the callback has its context;' + '\n' + 'e.g. it knows where it is going (or, more accurately, where it is returning to).' + '\n' + '' + '\n' + ' Looking up 876 ACET' + '\n' + ' Status for 876 ACET: Valid' + '\n' + '' + '\n' + 'Note that __bind__ is only necessary when passing references to object member functions.' + '\n' + 'Functions you define in-place won\'t have this issue, as they create their own context.' + '\n' + 'This version of __bind__ only binds functions to the current object. If you want to bind a' + '\n' + 'function on some other object, you\'d write code something like this, making use of the Function' + '\n' + 'object\'s bind ability:' + '\n' + '' + '\n' + ' ... !anObject.anyFunction.bind anObject' + '\n' + '' + '\n' + 'SAI compiled objects do a runtime check on any member method invocation to verify that the' + '\n' + 'current execution context is, if not correct, at least not totally absent.' + '\n' + '' + '\n' + ''
},
'copy': {
subtitle: 'shallow copy',
summary: 'Use the **copy** unary operator to create a _shallow copy_ of the expression it precedes.',
synref: '.. copy [expr]',
detail: 'You sometimes need this because ordinarily SAI and Javascript assign objects, rather than copies' + '\n' + 'of object values.' + '\n' + '' + '\n' + ' set plate to fruit // i want some fruit' + '\n' + ' plate.push \'Ice cream\' // and also dessert' + '\n' + ' debug fruit // but now fruit has changed' + '\n' + '' + '\n' + ' > [ \'Apple\', \'Banana\', \'Citron\', \'Ice Cream\' ]' + '\n' + '' + '\n' + ' fruit.pop // get rid of the ice cream' + '\n' + ' debug fruit' + '\n' + '' + '\n' + ' > [ \'Apple\', \'Banana\', \'Citron\' ]' + '\n' + '' + '\n' + ' set plate to copy fruit' + '\n' + ' plate.push \'Ice cream\'' + '\n' + ' debug fruit' + '\n' + '' + '\n' + ' > [ \'Apple\', \'Banana\', \'Citron\' ]' + '\n' + '' + '\n' + ' debug plate // there we go' + '\n' + '' + '\n' + ' > [ \'Apple\', \'Banana\', \'Citron\', \'Ice Cream\' ]' + '\n' + '' + '\n' + 'Note that **copy** only copies enumerable attributes. There\'s a rabbit hole for ya.' + '\n' + '' + '\n' + ''
},
'create': {
subtitle: 'object creation',
summary: 'Creates a SAI object by name.',
synref: '.. create [expr] [parameters]',
detail: 'If we are running in dynamic mode (that is, with source that is being dynamically compiled from' + '\n' + '.SAI files), __create__ will attempt to find the object’s source by using the `SAI.config.Loader` function,' + '\n' + 'which defaults to `SAI.GetSourceFromPaths`, which tries to find a file named `[expr].sai` i' + '\n' + 'n the provided paths.' + '\n' + '' + '\n' + 'In runtime mode (that is, when running from plain Javascript .js files that have been pre-compiled),' + '\n' + '__create__ will call `require`, but do see the source in the `sai-library` that discusses this.' + '\n' + '' + '\n' + ' reference:' + '\n' + ' Tally \'Tally \x5e1.0.0\'' + '\n' + ' ..' + '\n' + '' + '\n' + ' set inventory to create Tally' + '\n' + '' + '\n' + 'The example follows best practices of placing object names in a **reference** section, aliasing' + '\n' + 'versioned names into literals.' + '\n' + '' + '\n' + 'See also __new__, which is a direct link to Javascript\'s `new`, and __singleton__, which works' + '\n' + 'like __create__ except instantiates the object only once in the scope of the runtime library; subsequent' + '\n' + 'calls will return that same object.' + '\n' + '' + '\n' + ''
},
'default': {
subtitle: 'variable initialization',
summary: 'Examines the expression on the left; if it has a value, returns it. Otherwise returns the value on the right.',
synref: '... [lexpr] default [rexpr]' + '\n' + 'set [lexpr] default [rexpr]',
detail: '#### default in expressions' + '\n' + '' + '\n' + 'If and only if the left expression evaluates to `undefined`, returns the right expression, otherwise' + '\n' + 'returns the left expression.' + '\n' + '' + '\n' + 'Like **or** except instead of checking for _truthy_ tests to see if a value is present.' + '\n' + 'Most useful in expressions where you’re not sure if a variable is initialized.' + '\n' + '' + '\n' + ' set' + '\n' + ' magnitude to undefined' + '\n' + ' angle to 60o' + '\n' + ' debug (magnitude default 1) * ~Math.cos(angle)' + '\n' + '' + '\n' + ' > 0.5' + '\n' + '' + '\n' + '#### default in **set** statements' + '\n' + '' + '\n' + 'If the left expression is `undefined` then evaluate the right expression and assign it to the left' + '\n' + 'expression. For example:' + '\n' + '' + '\n' + ' set calculationCache[key] default ExpensiveCalculation(key)' + '\n' + '' + '\n' + 'This checks to see if the calculation cache has a value for the given key, and if not,' + '\n' + 'calculates the value and assigns it to the cache.' + '\n' + '' + '\n' + ''
},
'initialized': {
subtitle: 'default with assignment',
summary: 'Examines the variable on the left; if it has a value, returns it. Otherwise calculates the value' + '\n' + 'on the right, stores it in the variable on the left, and returns it.',
synref: '... [lexpr] initialized [rexpr]',
detail: 'The __initialized__ operator works very much like the __set/default__ combination, but allows' + '\n' + 'you to use it in the middle of an expression. You should only use variables on the left,' + '\n' + 'as trying to assign into a function or calculated expression will not work.' + '\n' + '' + '\n' + 'The only real use for this is in scenarios where you would like to cache the result of an' + '\n' + 'expression and want the code to reflect this simple idea.' + '\n' + '' + '\n' + 'Here is a trivial example:' + '\n' + '' + '\n' + ' GetCachedThing task with identifier' + '\n' + ' return thingCache\identifier initialized from thingComputation identifier' + '\n' + '' + '\n' + ''
},
'is': {
subtitle: 'equivalence test',
summary: 'Returns **true** if the two expressions are completely indistinguishable.',
synref: '.. [expr] is [expr]',
detail: 'More rigorous than **=** when objects differ in type.' + '\n' + '' + '\n' + ' debug 0 = false' + '\n' + ' debug 0 is false' + '\n' + '' + '\n' + ' > true' + '\n' + ' > false' + '\n' + '' + '\n' + '_Note: Do not use **is** or **isnt** to test values against **NaN**. You must use the' + '\n' + 'specific **isNaN** operator for this._' + '\n' + '' + '\n' + ''
},
'isNaN': {
title: 'isNaN',
subtitle: 'checks for NaN',
summary: 'Returns true if the expression is the **NaN** flag.',
synref: '.. isNaN \[expr]',
detail: 'Note there is no other way to test for NaN than by using **isNaN**.' + '\n' + '' + '\n' + 'Note also that capitalization matters.' + '\n' + '' + '\n' + ' set a !parseInt \'This is not a number.\'' + '\n' + ' debug a // NaN' + '\n' + ' debug a = 0 // false' + '\n' + ' debug a = false // false' + '\n' + ' debug a = NaN // false' + '\n' + ' debug isNaN a // true' + '\n' + '' + '\n' + 'Right? Seriously:' + '\n' + '' + '\n' + ' debug NaN = NaN // false' + '\n' + ' debug NaN is NaN // false' + '\n' + '' + '\n' + 'So that\'s why we need this keyword for this one little function.' + '\n' + '' + '\n' + ''
},
'isnt': {
subtitle: 'equivalence test',
summary: 'Returns **true** if the two expressions are in any way distinguishable.',
synref: '.. [expr] isnt [expr]',
detail: 'More rigorous than **<>** when objects are of differing types.' + '\n' + '' + '\n' + ' debug 1 <> true' + '\n' + ' debug 1 isnt true' + '\n' + '' + '\n' + ' > false' + '\n' + ' > true' + '\n' + '' + '\n' + '_Note: Do not use **is** or **isnt** to test values against **NaN**. You must use the specific **isNaN** operator for this._' + '\n' + '' + '\n' + ''
},
'isof': {
subtitle: 'object information',
summary: 'All prototyped SAI objects have an **isof** trait that is a plain object that encapsulates detailed' + '\n' + 'information about the SAI object and its heritage.',
synref: '.. [object].isof' + '\n' + ' - or -' + '\n' + ' .. [object] isof [class name expr]',
detail: 'Let\'s just see how this works:' + '\n' + '' + '\n' + ' object Fruit 1.0.0' + '\n' + ' Instantiate task' + '\n' + ' debug \'I am a \${isa}\'' + '\n' + '' + '\n' + ' set a to create \'Fruit\'' + '\n' + ' > I am a Fruit' + '\n' + '' + '\n' + ' object Pear 1.0.0' + '\n' + ' inherit: Fruit' + '\n' + '' + '\n' + ' set b to create \'Pear\'' + '\n' + ' > I am a Pear' + '\n' + '' + '\n' + ' debug a.isof' + '\n' + '' + '\n' + ' > { Fruit:' + '\n' + ' > { version: \'1.0.0\',' + '\n' + ' > isa: \'Fruit\',' + '\n' + ' > context: \'./sample/Keywords/Fruit.sai\' } }' + '\n' + '' + '\n' + ' debug b.isof' + '\n' + '' + '\n' + ' > { Fruit:' + '\n' + ' > { version: \'1.0.0\',' + '\n' + ' > isa: \'Fruit\',' + '\n' + ' > context: \'./sai/sample/Keywords/Fruit.sai\' },' + '\n' + ' > Pear:' + '\n' + ' > { version: \'1.0.0\',' + '\n' + ' > isa: \'Pear\',' + '\n' + ' > context: \'./sai/sample/Keywords/Pear.sai\',' + '\n' + ' > inherit: [ \'Fruit\' ] } }' + '\n' + '' + '\n' + ' You can trace an object’s creation in order recursively by starting at the **isof** entry for the' + '\n' + ' present object — `isof[isa]` — and stepping through the **inherit** array.' + '\n' + '' + '\n' + '#### isof operator' + '\n' + '' + '\n' + ' .. [object] isof [class name expr]' + '\n' + '' + '\n' + 'Returns true if the object is an instance of a class that is, or inherits from, the given class name.' + '\n' + '' + '\n' + ' class Parent 1.0.0' + '\n' + '' + '\n' + ' class Child 1.0.0' + '\n' + ' inherits: Parent' + '\n' + '' + '\n' + ' set a to create \'Child\'' + '\n' + ' debug a isof \'Child\' // true' + '\n' + ' debug a isof \'Parent\' // true' + '\n' + '' + '\n' + ''
},
'lsh': {
subtitle: 'unsigned bitwise left shift',
summary: 'Convert the expression to a 32 bit integer, then shift it left bitcount times.',
synref: '.. [expr] lsh [bitcount]' + '\n' + '.. [expr] << [bitcount] // synonym',
detail: 'For example:' + '\n' + '' + '\n' + ' debug 4 lsh 1 // 8' + '\n' + ' debug -8 lsh 2 // -32' + '\n' + ' debug 2.8 lsh 0 // 2' + '\n' + '' + '\n' + 'The synonym __<<__ does exactly the same thing.' + '\n' + '' + '\n' + ''
},
'nand': {
subtitle: 'not-and logical',
summary: 'Checks two or more values; returns _false_ if all of the values are _truthy_. Otherwise' + '\n' + 'returns _true_.',
synref: '.. [expr] nand [expr]' + '\n' + '.. nand [list of expressions]',
detail: 'A semantic simplification of `not ([expr] and [expr])`.' + '\n' + '' + '\n' + ' debug 0 nand 0 // prints \'true\'' + '\n' + ' debug 1 nand 0 // prints \'true\'' + '\n' + ' debug 0 nand 1 // prints \'true\'' + '\n' + ' debug 1 nand 1 // prints \'false\'' + '\n' + '' + '\n' + 'These are logically the same' + '\n' + '' + '\n' + ' debug a nand b' + '\n' + ' debug not ( a and b )' + '\n' + '' + '\n' + 'For syntax of the list-based version of __nand__ please review keyword __and__.' + '\n' + '' + '\n' + ''
},
'new': {
subtitle: 'object instantiation',
summary: 'Instantiates a new object with the given prototype.',
synref: '.. new [prototype] [parameters]',
detail: 'If parameters are supplied, passes them to the object’s constructor.' + '\n' + '' + '\n' + '**New** is used for traditional Javascript objects; objects where you have in-hand the prototype' + '\n' + 'used to fabricate an instance that object. **New** trusts that the code to create that object' + '\n' + 'has already been located and compiled.' + '\n' + '' + '\n' + '**Create** is used for SAI objects; objects where you have in-hand an object name (as a string).' + '\n' + '**Create** doesn\'t assume pre-compiled prototypes; if the prototype isn\'t cached, it will attempt' + '\n' + 'to load it via the `SAI.config.Loader` function.' + '\n' + '' + '\n' + ' reference:' + '\n' + ' express require(\'express\')' + '\n' + '' + '\n' + ' object HelloHTTP 1.0.0' + '\n' + '' + '\n' + ' Instantiate task' + '\n' + ' set @app express()' + '\n' + '' + '\n' + ' @app.get \'/\', task given req, res' + '\n' + ' res.send \'Hello HTTP!\'' + '\n' + '' + '\n' + ' set @server !@app.listen 3000, \'localhost\', task' + '\n' + ' with @server.address()' + '\n' + ' debug \'Example app listening at http://\${.address}:\${.port}\'' + '\n' + '' + '\n' + 'You ordinarily need to use the **\~** global scope prefix when creating Javascript built-in objects' + '\n' + 'however `Error` has been promoted to SAI global so you don\'t have to:' + '\n' + '' + '\n' + ' if crocodiles' + '\n' + ' throw new Error "Why do we even have that lever?"' + '\n' + '' + '\n' + 'Notice here that **new** is not expecting any parameters to be wrapped in parentheses; in this way it' + '\n' + 'works like **from**.' + '\n' + '' + '\n' + 'See also __create__ which is used to instantiate SAI objects by name, and __singleton__ which is' + '\n' + 'used to create singleton SAI objects by name.' + '\n' + '' + '\n' + '' + '\n' + '' + '\n' + ''
},
'nor': {
subtitle: 'not-or logical',
summary: 'Checks two or more values; returns true only if _all_ of them are _falsy_. Otherwise' + '\n' + 'returns true.',
synref: '.. [expr] nor [expr]' + '\n' + '.. nor [list of expressions]',
detail: 'Returns **true** only if left or right expression are both _falsy_. Otherwise returns **false**.' + '\n' + '' + '\n' + 'A semantic simplification of `not ([expr] or [expr])`.' + '\n' + '' + '\n' + ' debug 0 nor 0 // prints \'true\'' + '\n' + ' debug 1 nor 0 // prints \'false\'' + '\n' + ' debug 0 nor 1 // prints \'false\'' + '\n' + ' debug 1 nor 1 // prints \'false\'' + '\n' + '' + '\n' + 'These are the same:' + '\n' + '' + '\n' + ' if not ( a or b )' + '\n' + ' if a nor b' + '\n' + ' unless a or b' + '\n' + '' + '\n' + 'For the syntax related to the list-based version of \'nor\' review keyworcd __and__.' + '\n' + '' + '\n' + ''
},
'not': {
subtitle: 'logical not',
summary: 'Performs the logical not operation.',
synref: '.. not [expr]',
detail: 'Returns **false** if the right expression is _truthy_, otherwise returns **true**.' + '\n' + '' + '\n' + ' debug not false // prints \'true\'' + '\n' + ' debug not 0 // prints \'true\'' + '\n' + ' debug not \'Sam\' // prints \'false\'' + '\n' + ' debug not empty // prints \'false\'' + '\n' + '' + '\n' + 'These are the same:' + '\n' + '' + '\n' + ' if not a' + '\n' + ' unless a' + '\n' + '' + '\n' + ''
},
'notb': {
subtitle: 'binary not',
summ