cleanup and docs...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2016-12-10 03:08:03 +03:00
parent 878e967d5f
commit 54c79a049c
2 changed files with 151 additions and 111 deletions

View File

@ -102,7 +102,7 @@ function stringifySlangCode(code){
} }
if(typeof(code) == typeof('str') && /\s/.test(code)){ if(typeof(code) == typeof('str') && /\s/.test(code)){
return '\''+code+'\'' return '\''+code+'\''
} else if(code.constructor.name == 'Array'){ } else if(code && code.constructor.name == 'Array'){
return '[ '+code.map(stringifySlangCode).join(' ')+' ]' return '[ '+code.map(stringifySlangCode).join(' ')+' ]'
} }
return code return code
@ -198,7 +198,7 @@ function showAvailableWords(){
.map(function(e){ .map(function(e){
var code = NAMESPACE[e] var code = NAMESPACE[e]
var type var type
if(code.constructor.name == 'Array'){ if(code && code.constructor.name == 'Array'){
type = 'word' type = 'word'
code = stringifySlangCode(code) code = stringifySlangCode(code)
} else if(typeof(code) == typeof(function(){})){ } else if(typeof(code) == typeof(function(){})){

View File

@ -33,17 +33,17 @@ function run(context){
var res = context.ns[cur](context) var res = context.ns[cur](context)
// hi-level word... // hi-level word...
} else if(typeof(word) == typeof([]) && word.constructor.name == 'Array'){ } else if(typeof(word) == typeof([]) && word && word.constructor.name == 'Array'){
// XXX add isolation with a continuation... // XXX add isolation with a continuation...
context.code.splice.apply(context.code, [0, 0].concat(word)) context.code.splice.apply(context.code, [0, 0].concat(word))
var res = null var res = undefined
// variable... // variable...
} else { } else {
res = word var res = word
} }
if(res != null){ if(res !== undefined){
context.stack.push(res) context.stack.push(res)
} }
@ -73,6 +73,9 @@ var SPLITTER = RegExp([
'\\s*"([^"]*)"\\s*', '\\s*"([^"]*)"\\s*',
"\\s*'([^']*)'\\s*", "\\s*'([^']*)'\\s*",
// quote...
'\\s*(\\\\)',
// whitespace... // whitespace...
'\\s+', '\\s+',
].join('|'), ].join('|'),
@ -151,9 +154,7 @@ var PRE_NAMESPACE = {
}, },
// a no op... // a no op...
'\n': function(){ '\n': function(){ console.log('NL') },
console.log('NL')
},
} }
@ -162,8 +163,7 @@ var NAMESPACE = {
// constants... // constants...
'true': true, 'true': true,
'false': false, 'false': false,
// this is mutable, so we'll need to create a new instance each time 'null': 'null',
'[]': function(){ return [] },
'nop': function(){}, 'nop': function(){},
@ -205,8 +205,7 @@ var NAMESPACE = {
// encapsulate stack to a block... // encapsulate stack to a block...
// ... -- [ ... ] // ... -- [ ... ]
's2b': function(context){ 's2b': function(context){
context.stack = [ context.stack ] context.stack = [ context.stack ] },
},
// expand block to stack... // expand block to stack...
// NOTE: this will append the block contents to stack, w.o. replacing // NOTE: this will append the block contents to stack, w.o. replacing
// stack contents. this is different to _s2b // stack contents. this is different to _s2b
@ -217,8 +216,7 @@ var NAMESPACE = {
context.stack.splice.apply(context.stack, [context.stack.length, 0].concat(c)) context.stack.splice.apply(context.stack, [context.stack.length, 0].concat(c))
}, },
'print': function(context){ 'print': function(context){
console.log('>>>', context.stack[context.stack.length-1]) console.log('>>>', context.stack[context.stack.length-1]) },
},
// turn a sting into a lexical list... // turn a sting into a lexical list...
// c -- b // c -- b
@ -273,7 +271,7 @@ var NAMESPACE = {
'_exec': function(context){ '_exec': function(context){
// block... // block...
var b = context.stack.pop() var b = context.stack.pop()
if(typeof(b) == typeof([]) && b.constructor.name == 'Array'){ if(typeof(b) == typeof([]) && b && b.constructor.name == 'Array'){
b = b.slice() b = b.slice()
} else { } else {
b = [ b ] b = [ b ]
@ -295,9 +293,7 @@ var NAMESPACE = {
// quote - push the next elem as-is to stack... // quote - push the next elem as-is to stack...
// -- x // -- x
'\\': function(context){ '\\': function(context){
var code = context.code return context.code.splice(0, 1)[0] },
return code.splice(0, 1)[0]
},
// comparisons and logic... // comparisons and logic...
// a b -- c // a b -- c
@ -322,74 +318,59 @@ var NAMESPACE = {
}, },
// x -- b // x -- b
'not': function(context){ 'not': function(context){
return !context.stack.pop() return !context.stack.pop() },
},
// a b -- c // a b -- c
'gt': function(context){ 'gt': function(context){
return context.stack.pop() < context.stack.pop() return context.stack.pop() < context.stack.pop() },
},
// a b -- c // a b -- c
'eq': function(context){ 'eq': function(context){
return context.stack.pop() == context.stack.pop() return context.stack.pop() == context.stack.pop() },
},
// stack operations... // stack operations...
// ... x -- x ... // ... x -- x ...
'rot': function(context){ 'rot': function(context){
context.stack.splice(0, 0, context.stack.pop()) context.stack.splice(0, 0, context.stack.pop()) },
},
// x ... -- ... x // x ... -- ... x
'tor': function(context){ 'tor': function(context){
context.stack.push(context.stack.shift()) context.stack.push(context.stack.shift()) },
},
// a b -- b a // a b -- b a
'swap': function(context){ 'swap': function(context){
return context.stack.splice(context.stack.length-2, 1)[0] return context.stack.splice(context.stack.length-2, 1)[0] },
},
// x -- x x // x -- x x
'dup': function(context){ 'dup': function(context){
return context.stack[context.stack.length-1] return context.stack[context.stack.length-1] },
},
// x -- x' // x -- x'
// NOTE: this will do a deep copy... // NOTE: this will do a deep copy...
'clone': function(context){ 'clone': function(context){
return JSON.parse(JSON.stringify(context.stack.pop())) return JSON.parse(JSON.stringify(context.stack.pop())) },
},
// x -- // x --
'drop': function(context){ 'drop': function(context){
context.stack.pop() context.stack.pop() },
},
// a -- b // a -- b
// NOTE: all names are also strings so moo string? and 'moo' string? // NOTE: all names are also strings so moo string? and 'moo' string?
// are the same... // are the same...
'string?': function(context){ 'string?': function(context){
return typeof(context.stack.pop()) == typeof('str') return typeof(context.stack.pop()) == typeof('str') },
},
// basic number operations... // basic number operations...
// a -- b // a -- b
'number?': function(context){ 'number?': function(context){
return typeof(context.stack.pop()) == typeof(123) return typeof(context.stack.pop()) == typeof(123) },
},
// a b -- c // a b -- c
'add': function(context){ 'add': function(context){
return context.stack.pop() + context.stack.pop() return context.stack.pop() + context.stack.pop() },
},
'sub': function(context){ 'sub': function(context){
return - context.stack.pop() + context.stack.pop() return - context.stack.pop() + context.stack.pop() },
},
'mul': function(context){ 'mul': function(context){
return context.stack.pop() * context.stack.pop() return context.stack.pop() * context.stack.pop() },
},
'div': function(context){ 'div': function(context){
return 1/context.stack.pop() * context.stack.pop() return 1/context.stack.pop() * context.stack.pop() },
},
// block/list operations... // block/list operations...
'block?': function(context){ 'block?': function(context){
var e = context.stack.pop() var e = context.stack.pop()
return typeof(e) == typeof([]) && e.constructor.name == 'Array' return typeof(e) == typeof([]) && e && e.constructor.name == 'Array'
}, },
// b n -- b e // b n -- b e
'at': function(context){ 'at': function(context){
@ -424,12 +405,10 @@ var NAMESPACE = {
}, },
// b -- b e // b -- b e
'pop': function(context){ 'pop': function(context){
return context.stack[context.stack.length-1].pop() return context.stack[context.stack.length-1].pop() },
},
// b -- b l // b -- b l
'len': function(context){ 'len': function(context){
return context.stack[context.stack.length-1].length return context.stack[context.stack.length-1].length },
},
// b c -- b // b c -- b
'map': function(context){ 'map': function(context){
var c = context.stack.pop() var c = context.stack.pop()
@ -437,7 +416,7 @@ var NAMESPACE = {
for(var i=0; i < b.length; i++){ for(var i=0; i < b.length; i++){
// exec block in a separate context... // exec block in a separate context...
var res = run({ var res = run({
//stack: [i, b[i], c], //stack: [b, i, b[i], c],
stack: [b[i], c], stack: [b[i], c],
code: ['exec'], code: ['exec'],
// NOTE: this can have side-effects on the context... // NOTE: this can have side-effects on the context...
@ -460,7 +439,7 @@ var NAMESPACE = {
'object?': function(context){ 'object?': function(context){
var o = context.stack[context.stack.length - 1] var o = context.stack[context.stack.length - 1]
return o.constructor === Object return o && o.constructor === Object
}, },
// set item... // set item...
@ -473,12 +452,15 @@ var NAMESPACE = {
o[k] = v o[k] = v
}, },
// test item...
// o k -- o t
'item?': function(context){
return context.stack.pop() in context.stack[context.stack.length - 1] },
// get item... // get item...
// o k -- o v // o k -- o v
'item': function(context){ 'item': function(context){
var k = context.stack.pop() return context.stack[context.stack.length - 1][context.stack.pop()] },
return context.stack[context.stack.length - 1][k]
},
// remove/pop item from object... // remove/pop item from object...
// o k -- o v // o k -- o v
@ -494,8 +476,7 @@ var NAMESPACE = {
// o -- k // o -- k
'keys': function(context){ 'keys': function(context){
return Object.keys(context.stack.pop()) return Object.keys(context.stack.pop()) },
},
// make a prototype of b... // make a prototype of b...
// a b -- b // a b -- b
@ -503,9 +484,7 @@ var NAMESPACE = {
'proto!': function(context){ 'proto!': function(context){
var b = context.stack.pop() var b = context.stack.pop()
var a = context.stack.pop() var a = context.stack.pop()
b.__proto__ = a === false ? {}.__proto__ : a b.__proto__ = a === false ? {}.__proto__ : a
return b return b
}, },
@ -513,19 +492,14 @@ var NAMESPACE = {
// XXX what should this be: // XXX what should this be:
// {} getproto // {} getproto
'proto': function(context){ 'proto': function(context){
var o = context.stack.pop() return context.stack.pop().__proto__ },
return o.__proto__
},
// -- o // -- o
'ns': function(context){ 'ns': function(context){
return context.ns return context.ns },
},
// o -- // o --
'ns!': function(context){ 'ns!': function(context){
context.ns = context.stack.pop() context.ns = context.stack.pop() },
},
} }
@ -717,6 +691,57 @@ var BOOTSTRAP = [
' [ 1 2 3 4 ] [ 2 gt ] filter', ' [ 1 2 3 4 ] [ 2 gt ] filter',
' -> [ 3 4 ]', ' -> [ 3 4 ]',
'', '',
' Reduce enables us to take a list and "reduce" it to a single value...',
'',
' [ 1 2 3 4 ] \\add reduce',
' -> 10',
'',
'',
'-------------------------------------------------------------------------------',
'',
' Objects and namespaces:',
'',
' Create a variable word o and p and set them to empty objects...',
'',
' ns',
' o {} item!',
' p {} item!',
' .',
'',
' Set attribute (key-value pair) on object...',
'',
' o x 123 item!',
' -> o',
'',
' Get attribute x value...',
'',
' o x item',
' -> 123',
'',
' Test if attribute x exists...',
'',
' o x item?',
' -> true',
'',
' Get block of attribute idents...',
'',
' o keys',
' -> [ ... ]',
'',
' Get and remove an attribute value from o...',
'',
' o x popitem',
' -> 123',
'',
' Set prototype of o to p',
'',
' o p proto!',
' -> o',
'',
' Get prototype of o',
'',
' o proto',
' -> p',
'', '',
'', '',
'-------------------------------------------------------------------------------', '-------------------------------------------------------------------------------',
@ -726,22 +751,29 @@ var BOOTSTRAP = [
'', '',
'-- prepare the basic syntax for defining words...', '-- prepare the basic syntax for defining words...',
'ns', 'ns',
' -- Some sorthands...',
' . ( x -- )',
' [ drop ] item!',
' rot2 ( .. x y -- x y .. )',
' [ rot rot ] item!',
' tor2 ( x y .. -- .. x y )',
' [ tor tor ] item!',
'',
' -- Friendly exec...',
' exec ( b -- ... )', ' exec ( b -- ... )',
' [ s2b pop _exec b2s ] item!', ' [ s2b pop _exec b2s ] item!',
' -- Create a word...', ' -- Create a word...',
' word! ( w b -- )', ' word! ( w b -- )',
' [ rot rot ns tor tor item! drop ] item!', ' [ rot2 ns tor2 item! . ] item!',
' -- Word definition...', ' -- Word definition...',
' -- syntax: :: <ident> <value>', ' -- syntax: :: <ident> <value>',
' :: ( -- )', ' :: ( -- )',
' [ \\ word! \\ exec 2 2 _swapN ] item!', ' [ \\word! \\exec 2 2 _swapN ] item!',
'drop', '.',
'', '',
'', '',
'-- misc...', '-- misc...',
'', '',
':: . ( x -- ) [ drop ]',
'',
':: true? ( a -- b ) [ not not true eq ]', ':: true? ( a -- b ) [ not not true eq ]',
':: false? ( a -- b ) [ not true? ]', ':: false? ( a -- b ) [ not true? ]',
'', '',
@ -792,13 +824,13 @@ var BOOTSTRAP = [
'-- run then block and drop \'else B\' if it exists...', '-- run then block and drop \'else B\' if it exists...',
':: _run_then ( a x | -- ... | x )', ':: _run_then ( a x | -- ... | x )',
' ( a else | b -- ... | )', ' ( a else | b -- ... | )',
' [ \\ exec swap dup \\ else eq [ (drop else) drop \\ drop _swap 6 ] and', ' [ \\exec swap dup \\else eq [ (drop else) drop \\drop _swap 6 ] and',
' [ (run as-is) 1 _push 4 ] or', ' [ (run as-is) 1 _push 4 ] or',
' b2s 0 _swapN ]', ' b2s 0 _swapN ]',
'-- if \'else B\' exists, run it, else cleanup...', '-- if \'else B\' exists, run it, else cleanup...',
':: _run_else ( a | -- | a )', ':: _run_else ( a | -- | a )',
' ( b else | b -- ... | )', ' ( b else | b -- ... | )',
' [ drop dup \\ else eq [ drop \\ exec _swap 4 ] and', ' [ drop dup \\else eq [ drop \\exec _swap 4 ] and',
' [ 1 _push 2 ] or', ' [ 1 _push 2 ] or',
' b2s 0 _swapN ]', ' b2s 0 _swapN ]',
'-- And now the main operator...', '-- And now the main operator...',
@ -834,11 +866,11 @@ var BOOTSTRAP = [
'-- NOTE: this will replace ALL patterns...', '-- NOTE: this will replace ALL patterns...',
':: replace ( l v p -- l ) [', ':: replace ( l v p -- l ) [',
' swap', ' swap',
' [ . \\ VALUE ] clone', ' [ . \\VALUE ] clone',
' swap 2 to', ' swap 2 to',
' rot', ' rot',
' -- XXX for some reason ? without else messes things up...', ' -- XXX for some reason ? without else messes things up...',
' [ dup \\ PATTERN eq ? VALUE_BLOCK else [ ] ] clone', ' [ dup \\PATTERN eq ? VALUE_BLOCK else [ ] ] clone',
' swap 2 to', ' swap 2 to',
' tor 5 to', ' tor 5 to',
' map ]', ' map ]',
@ -848,13 +880,32 @@ var BOOTSTRAP = [
'-- the condition block must have the folowing stack effect: elem -- bool', '-- the condition block must have the folowing stack effect: elem -- bool',
':: filter ( b c -- b ) [', ':: filter ( b c -- b ) [',
' -- prepare the condition...', ' -- prepare the condition...',
' [ dup \\ TEST exec ] clone', ' [ dup \\TEST exec ] clone',
' swap TEST replace', ' swap TEST replace',
' -- prepare the template...', ' -- prepare the template...',
' [ TEST ? [ ] else [ . ] ] clone', ' [ TEST ? [ ] else [ . ] ] clone',
' swap TEST replace', ' swap TEST replace',
' map ]', ' map ]',
'', '',
':: reduce ( L b -- s ) [',
' rot clone',
' -- empty list, reduction is null...',
' [ len 0 eq ] ?',
' [ . tor . null ]',
' -- reduction of list of len 1 is it\'s content, so just pop it...',
' else [ [ len 1 eq ] ?',
' [ tor . b2s ]',
' -- and now recursively reduce the elements till the list is 1 in length...',
' -- XXX ugly',
' else [',
' pop rot pop rot',
' [] tor push tor push',
' -- get and run the block...',
' tor dup clone rot _exec',
' -- process the result...',
' pop rot . tor push tor',
' reduce ]]',
'',
'-- Create a block containing a range of numbers form 0 to n-1...', '-- Create a block containing a range of numbers form 0 to n-1...',
':: range ( n -- b ) [', ':: range ( n -- b ) [',
' -- initial state...', ' -- initial state...',
@ -871,43 +922,32 @@ var BOOTSTRAP = [
' [ 1 sub 0 before range ]]', ' [ 1 sub 0 before range ]]',
'', '',
'-- Sum up the elements of a block...', '-- Sum up the elements of a block...',
':: sum ( L -- s ) [', ':: sum ( L -- s ) [ [ add ] reduce ]',
' clone',
' -- empty list, sum is 0...',
' [ len 0 eq ] ?',
' [ . 0 ]',
' -- sum of list of len 1 is it\'s content, so just pop it...',
' else [ [ len 1 eq ] ?',
' b2s',
' -- and now recursively sum up elements till the list is 1 in length...',
' else',
' [ pop rot pop tor add push sum ]]',
'',
'', '',
'', '',
'-- Meta-word examples (experimental)...', '-- Meta-word examples (experimental)...',
'', '',
'-- Here is an infix operator example...', '-- Here is an infix operator example...',
'-- :: + ( a | b -- c | ) [ \\ exec 2 0 _swapN \\ exec \\ add 2 1 _swapN ]', '-- :: + ( a | b -- c | ) [ \\exec 2 0 _swapN \\exec \\add 2 1 _swapN ]',
'-- now let\'s make a meta function to make things shorter...', '-- now let\'s make a meta function to make things shorter...',
':: infix: ( | op word -- | ) [', ':: infix: ( | op word -- | ) [',
' [', ' [',
' -- format the word definition...', ' -- format the word definition...',
' -- NAME WORD -> :: NAME WORD', ' -- NAME WORD -> :: NAME WORD',
' s2b \\ :: -2 before b2s', ' s2b \\:: -2 before b2s',
'', '',
' -- our template...', ' -- our template...',
' -- exec the left side...', ' -- exec the left side...',
' [ \\ exec 2 0 _swapN', ' [ \\exec 2 0 _swapN',
' -- exec the right side and arragne the args for WORD...', ' -- exec the right side and arragne the args for WORD...',
' \\ exec \\ WORD 2 1 _swapN ] clone', ' \\exec \\WORD 2 1 _swapN ] clone',
' -- get the WORD and insert it into the template above (opsition 8)...', ' -- get the WORD and insert it into the template above (opsition 8)...',
' swap WORD replace', ' swap WORD replace',
'', '',
' -- push to code / run', ' -- push to code / run',
' 3 0 _swapN ', ' 3 0 _swapN ',
' -- swap the arguments and the code to be executed...', ' -- swap the arguments and the code to be executed...',
' ] \\ exec 2 2 _swapN ]', ' ] \\exec 2 2 _swapN ]',
'', '',
'-- Now making a word/2 an infix operator is trivial...', '-- Now making a word/2 an infix operator is trivial...',
'-- NOTE: these are at this point stupid and do not support priorities...', '-- NOTE: these are at this point stupid and do not support priorities...',
@ -930,20 +970,20 @@ var BOOTSTRAP = [
'', '',
'-- Prefix operation definition...', '-- Prefix operation definition...',
'-- Example:', '-- Example:',
'-- :: echo: ( | txt -- | ) [ \\ _flip \\ print _flip ]', '-- :: echo: ( | txt -- | ) [ \\_flip \\print _flip ]',
'-- swap stack and code untill the block finishes and consumes it\'s arguments', '-- swap stack and code untill the block finishes and consumes it\'s arguments',
'-- then swap them back...', '-- then swap them back...',
':: prefix: ( | op word -- | ) [', ':: prefix: ( | op word -- | ) [',
' [', ' [',
' -- format the word definition...', ' -- format the word definition...',
' -- NAME WORD -> :: NAME WORD', ' -- NAME WORD -> :: NAME WORD',
' s2b \\ :: -2 before b2s', ' s2b \\:: -2 before b2s',
'', '',
' -- the code template', ' -- the code template',
' [ \\ _flip \\ exec \\ WORD _flip ] clone', ' [ \\_flip \\exec \\WORD _flip ] clone',
' swap WORD replace', ' swap WORD replace',
' 3 0 _swapN', ' 3 0 _swapN',
' ] \\ exec 2 2 _swapN ]', ' ] \\exec 2 2 _swapN ]',
'', '',
'', '',
'', '',
@ -954,13 +994,13 @@ var BOOTSTRAP = [
'', '',
'-- Create a block containg a range of numbers from f to t, inclusive...', '-- Create a block containg a range of numbers from f to t, inclusive...',
':: range/2 ( f t -- b )', ':: range/2 ( f t -- b )',
' [ dup2 swap sub swap . inc range swap [] swap push \\ + 0 before map ]', ' [ dup2 swap sub swap . inc range swap [] swap push \\+ 0 before map ]',
'', '',
'-- this will enable us to create ranges via 0 .. 4', '-- this will enable us to create ranges via 0 .. 4',
'infix: .. range/2', 'infix: .. range/2',
'', '',
//':: range/3 ( a n s -- b )', //':: range/3 ( a n s -- b )',
//' [ swap range swap [] swap push \\ * 0 before map ]', //' [ swap range swap [] swap push \\* 0 before map ]',
'', '',
'-- Execute block in a context...', '-- Execute block in a context...',
'-- synctx: context: <block>', '-- synctx: context: <block>',