added meta

This commit is contained in:
Aidan K. Ewart 2020-06-03 17:54:59 +01:00
parent 2ec9cf6a0c
commit c3c39b1fff
13 changed files with 279 additions and 277 deletions

View File

@ -1,33 +0,0 @@
<html>
<style>
textarea {
width: 100%;
height: 30%;
}
code {
background-color:rgb(230, 230, 230);
padding: 0 0.125rem;
}
</style>
<textarea id="inbox"></textarea>
<button id="submit">execute</button>
<pre id="outbox"></pre>
<script src="./main.js" type="module"></script>
<h3>Documentation</h3>
<p>use <code>(name; value)</code> to define something. the definition can be recursive. <code>value</code> is executed and <code>name</code> is set to the final state of the stack, i.e. <code>(name; 1 3)</code> is possible</p>
<p>use <code>'</code> to push instead of apply to the stack, e.g. <code>'(a -> a)</code>. This is useful for lazyness, i.e. <code>'(->lazy evaluated thing)</code></p>
<ul>
<li><code>+, -, *, /, ^, sqrt</code>: mathematical operations</li>
<li><code>==</code>: equality (automatically derived for all types); returns <code>a b -> a</code> if true, <code>a b -> b</code> if false</li>
<li><code>typeof</code>: returns the type of the object</li>
<li><code>pair, fst, snd</code>: pairs two objects, gets first or second item of pair</li>
<li><code>tuple</code>: used like <code>... 3 tuple</code>; creates an n tuple of n items on the stack</li>
<li><code>!!</code>: index into a tuple</li>
<li><code>len</code>: length of a tuple</li>
<li><code>unsafeCoerce</code>: unsafely transforms one type into another. useage: <code>1 "type unsafeCoerce</code></li>
<li><code>true, false</code>: true/false used in <code>==</code></li>
<li><code>stop</code>: equivalent to <code>"stop</code></li>
<li><code>inv</code>: equivalent to <code>1 x /</code></li>
<li><code>fold</code>: equivalent to <code>x acc fn -> acc '(-> x acc fn 'fn fold) 'x \"stop ==</code></li>
</ul>
</html>

View File

@ -1,52 +0,0 @@
import {execRPN} from './shiny.mjs';
import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs';
import {scope, customHandler} from './builtin.mjs';
const inbox = document.getElementById("inbox")
const outbox = document.getElementById("outbox")
const submit = document.getElementById("submit")
const show = (elem) => {
if (elem.type === "pair") {
return "{" + show(elem.val.fst) + ", " + show(elem.val.snd) + "}"
} else if (elem.type === "closure") {
return "(needs: " + elem.val.args.join(", ") + ")"
} else if (elem.type === "array") {
return "[" + prettyprint(elem.val) + "]"
} else {
return "(" + elem.val + ": " + elem.type + ")"
}
}
const prettyprint = (out) => {
let str = "";
for (let i = 0; i < out.length; i++) {
str += show(out[i]);
if (i < out.length - 1) {
str += " ";
}
}
return str;
}
submit.onclick = (event) => {
const input = inbox.value;
let toks = tokenize(input);
if (!toks) {
outbox.innerHTML = "could not parse input: " + input;
return;
}
let ast = parseExprs(toks);
if (ast.stream.length !== 0) {
outbox.innerHTML = "unexpected token: " + ((e)=>{if(e.type==="ident"){return e.name}else{return e.val}})(ast.stream[0]);
return;
}
let out = execRPN(scope, ast.parsed, customHandler);
if (!out) {
outbox.innerHTML = "failed to execute";
return;
}
console.log(out);
outbox.innerHTML = prettyprint(out.stacks[0]);
}

View File

@ -1,40 +0,0 @@
export function tokenize(input) {
let i;
let inputWithAddedSpaces = "";
const syntax = /['";()]/;
for(i = 0; i<input.length; i++){
if(syntax.test(input.charAt(i))){
if(input.charAt(i-1) != " "){
inputWithAddedSpaces += " ";
}
if(input.charAt(i+1) != " "){
inputWithAddedSpaces += input.charAt(i) + " ";
} else {
inputWithAddedSpaces += input.charAt(i);
}
} else if(input.charAt(i) === "-" && input.charAt(i+1) === ">"){
if(input.charAt(i-1) != " "){
inputWithAddedSpaces += " ";
}
if(input.charAt(i+2) != " "){
inputWithAddedSpaces += "->" + " ";
} else {
inputWithAddedSpaces += "->";
}
} else if(input.charAt(i) != ">") {
inputWithAddedSpaces += input.charAt(i);
}
}
let splitInput = inputWithAddedSpaces.split(" ").filter((s) => s !== "");
let output = [];
for(i = 0; i<splitInput.length; i++){
if(!isNaN(splitInput[i])){
output.push({type: "num", val:Number(splitInput[i])});
} else if(syntax.test(splitInput[i]) || splitInput[i] === "->"){
output.push({type: "syntax", val:splitInput[i]});
} else if(splitInput[i] != '') {
output.push({type: "ident", name:splitInput[i]});
}
}
return(output)
}

View File

@ -1,96 +0,0 @@
0 info it worked if it ends with ok
1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'i', 'rationals' ]
2 info using npm@3.5.2
3 info using node@v8.10.0
4 verbose config Skipping project config: /home/aidan/.npmrc. (matches userconfig)
5 silly loadCurrentTree Starting
6 silly install loadCurrentTree
7 silly install readLocalPackageData
8 silly fetchPackageMetaData rationals
9 silly fetchNamedPackageData rationals
10 silly mapToRegistry name rationals
11 silly mapToRegistry using default registry
12 silly mapToRegistry registry https://registry.npmjs.org/
13 silly mapToRegistry uri https://registry.npmjs.org/rationals
14 verbose request uri https://registry.npmjs.org/rationals
15 verbose request no auth needed
16 info attempt registry request try #1 at 19:23:48
17 verbose request id 1f9e752341fc452f
18 verbose etag W/"e0fb616d3d75eb1a38936789fa99e693"
19 verbose lastModified Sat, 12 Oct 2019 22:31:44 GMT
20 http request GET https://registry.npmjs.org/rationals
21 http 304 https://registry.npmjs.org/rationals
22 verbose headers { date: 'Mon, 01 Jun 2020 18:23:48 GMT',
22 verbose headers connection: 'keep-alive',
22 verbose headers 'set-cookie':
22 verbose headers [ '__cfduid=da1ea1de35cfdbd41bc4da4edd15edf091591035828; expires=Wed, 01-Jul-20 18:23:48 GMT; path=/; domain=.npmjs.org; HttpOnly; SameSite=Lax' ],
22 verbose headers 'cf-ray': '59caf7cabb5ad210-MAN',
22 verbose headers age: '10',
22 verbose headers 'cache-control': 'public, max-age=300',
22 verbose headers etag: '"e0fb616d3d75eb1a38936789fa99e693"',
22 verbose headers 'last-modified': 'Sat, 12 Oct 2019 22:31:44 GMT',
22 verbose headers vary: 'Accept-Encoding',
22 verbose headers 'cf-cache-status': 'HIT',
22 verbose headers 'cf-request-id': '0312b932ae0000d2108792b200000001',
22 verbose headers 'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
22 verbose headers server: 'cloudflare' }
23 silly get cb [ 304,
23 silly get { date: 'Mon, 01 Jun 2020 18:23:48 GMT',
23 silly get connection: 'keep-alive',
23 silly get 'set-cookie':
23 silly get [ '__cfduid=da1ea1de35cfdbd41bc4da4edd15edf091591035828; expires=Wed, 01-Jul-20 18:23:48 GMT; path=/; domain=.npmjs.org; HttpOnly; SameSite=Lax' ],
23 silly get 'cf-ray': '59caf7cabb5ad210-MAN',
23 silly get age: '10',
23 silly get 'cache-control': 'public, max-age=300',
23 silly get etag: '"e0fb616d3d75eb1a38936789fa99e693"',
23 silly get 'last-modified': 'Sat, 12 Oct 2019 22:31:44 GMT',
23 silly get vary: 'Accept-Encoding',
23 silly get 'cf-cache-status': 'HIT',
23 silly get 'cf-request-id': '0312b932ae0000d2108792b200000001',
23 silly get 'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
23 silly get server: 'cloudflare' } ]
24 verbose etag https://registry.npmjs.org/rationals from cache
25 verbose get saving rationals to /home/aidan/.npm/registry.npmjs.org/rationals/.cache.json
26 silly install normalizeTree
27 silly loadCurrentTree Finishing
28 silly loadIdealTree Starting
29 silly install loadIdealTree
30 silly cloneCurrentTree Starting
31 silly install cloneCurrentTreeToIdealTree
32 silly cloneCurrentTree Finishing
33 silly loadShrinkwrap Starting
34 silly install loadShrinkwrap
35 silly loadShrinkwrap Finishing
36 silly loadAllDepsIntoIdealTree Starting
37 silly install loadAllDepsIntoIdealTree
38 verbose stack Error: Missing required argument #1
38 verbose stack at andLogAndFinish (/usr/share/npm/lib/fetch-package-metadata.js:31:3)
38 verbose stack at fetchPackageMetadata (/usr/share/npm/lib/fetch-package-metadata.js:51:22)
38 verbose stack at resolveWithNewModule (/usr/share/npm/lib/install/deps.js:456:12)
38 verbose stack at /usr/share/npm/lib/install/deps.js:190:5
38 verbose stack at /usr/share/npm/node_modules/slide/lib/async-map.js:52:35
38 verbose stack at Array.forEach (<anonymous>)
38 verbose stack at /usr/share/npm/node_modules/slide/lib/async-map.js:52:11
38 verbose stack at Array.forEach (<anonymous>)
38 verbose stack at asyncMap (/usr/share/npm/node_modules/slide/lib/async-map.js:51:8)
38 verbose stack at exports.loadRequestedDeps (/usr/share/npm/lib/install/deps.js:188:3)
39 verbose cwd /home/aidan/Desktop/js-projects/rpncalc-v4
40 error Linux 5.3.0-53-generic
41 error argv "/usr/bin/node" "/usr/bin/npm" "i" "rationals"
42 error node v8.10.0
43 error npm v3.5.2
44 error code EMISSINGARG
45 error typeerror Error: Missing required argument #1
45 error typeerror at andLogAndFinish (/usr/share/npm/lib/fetch-package-metadata.js:31:3)
45 error typeerror at fetchPackageMetadata (/usr/share/npm/lib/fetch-package-metadata.js:51:22)
45 error typeerror at resolveWithNewModule (/usr/share/npm/lib/install/deps.js:456:12)
45 error typeerror at /usr/share/npm/lib/install/deps.js:190:5
45 error typeerror at /usr/share/npm/node_modules/slide/lib/async-map.js:52:35
45 error typeerror at Array.forEach (<anonymous>)
45 error typeerror at /usr/share/npm/node_modules/slide/lib/async-map.js:52:11
45 error typeerror at Array.forEach (<anonymous>)
45 error typeerror at asyncMap (/usr/share/npm/node_modules/slide/lib/async-map.js:51:8)
45 error typeerror at exports.loadRequestedDeps (/usr/share/npm/lib/install/deps.js:188:3)
46 error typeerror This is an error with npm itself. Please report this error at:
46 error typeerror <http://github.com/npm/npm/issues>
47 verbose exit [ 1, true ]

View File

@ -1,6 +1,4 @@
import {defnOp, makeOp, defn} from './shiny.mjs';
import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs';
import {defnOp, makeOp} from './shiny.mjs';
const objEq = (a, b) => {
if (typeof a !== 'object' && typeof b !== 'object') {
@ -27,29 +25,13 @@ const objEq = (a, b) => {
export let scope = {};
export const customHandler = (ins) => {
return [ins];
}
const addRPNDefn = (name, def) => {
let toks = tokenize(def);
if (!toks) {
throw 'could not load builtin'
}
let ast = parseExprs(toks);
if (!ast.parsed) {
throw 'could not load builtin'
}
scope = defn(name, ast.parsed, scope);
}
const assertType = (type) => (elem) => {
export const assertType = (type) => (elem) => {
if (elem.type !== type) {
throw 'typeerror'
}
}
const addDefn = (name, args, fn) => {
export const addDefn = (name, args, fn) => {
if (Array.isArray(args)) {
const nargs = [...Array(args.length).keys()];
const liftFn = (scope) => {
@ -83,12 +65,25 @@ const mult = (args) => [{type:"num", val:args[0] * args[1]}];
const pow = (args) => [{type:"num", val:Math.pow(args[0], args[1])}];
const root = (args) => [{type:"num", val:Math.sqrt(args[0])}];
const type = (args) => [{type:"type", val:args[0].type}];
const pair = (args) => [{type:"pair", val:{fst:args[0], snd:args[1]}}];
const fst = (args) => [args[0].fst];
const snd = (args) => [args[0].snd];
const tuple = (args) => makeOp([...Array(args[0]).keys()], (args) => {return [{type:"tuple", val:args}]});
const index = (args) => args[0][args[1]];
const index = (args) => [args[0][args[1]]];
const len = (args) => [{type:"num", val:args[0].length}];
const untuple = (args) => args[0];
const coerce = (args) => {
if (args[1].type === "type") {
return [{type:args[1].val, val:args[0].val}];
} else {
throw 'typeerror'
}
}
const tuple = (args) => makeOp([...Array(args[0]).keys()], (iargs) => {
let arr = [];
for (let i = 0; i < args[0]; i++) {
arr.push(iargs[i][0]);
}
return [{type:"tuple", val:arr}]
});
const eq = (args) => {
console.log(args[2], args[3])
@ -106,19 +101,9 @@ addDefn("*", ["num", "num"], mult);
addDefn("^", ["num", "num"], pow);
addDefn("sqrt", ["num"], root);
addDefn("==", 4, eq);
addDefn("pair", 2, pair);
addDefn("fst", ["pair"], fst);
addDefn("snd", ["pair"], snd);
addDefn("tuple", ["num"], tuple);
addDefn("!!", ["tuple", "num"], index);
addDefn("len", ["tuple"], len);
addDefn("untuple", ["tuple"], untuple);
addDefn("typeof", 1, type);
addRPNDefn("stop", "\"stop");
addRPNDefn("inv", "(x -> 1 x /)");
addRPNDefn("fold", "(x acc fn -> acc '(-> x acc fn 'fn fold) 'x stop ==)");
addRPNDefn("range", "(x y -> x '(->x x 1 + y range) 'x y ==)");
addRPNDefn("listthen", "(fn -> (internal; x acc -> '(->acc fn) '(->x acc pair internal) x stop ==) 0 tuple internal)");
addRPNDefn("list", "'(a -> a) listthen");
addRPNDefn("lmap", "(list fn -> list '(->list fst fn list snd 'fn lmap pair) list 0 tuple ==)");
addRPNDefn("unlist", "(l -> (internal; list -> '(->) '(->list fst list snd internal) list 0 tuple ==) stop l internal)");
addRPNDefn("map", "fn -> '(l->l 'fn lmap unlist) listthen");
addDefn("coerce", 2, coerce);

33
script/dom.mjs Normal file
View File

@ -0,0 +1,33 @@
import {assertType, addDefn} from './builtin.mjs';
import {execFn} from './shiny.mjs';
const getElem = (args) => [{type:"domNode", val:document.getElementById(args[0])}];
const setHTML = (args) => args[0].innerHTML = args[1];
const mutref = (args) => [{type:"&mut", val:args[0]}];
const readmut = (args) => [args[0]];
const log = (args) => {
console.log(args);
return [];
}
const writemut = (args) => {
assertType("&mut", args[1]);
args[1].val = args[0];
return [];
}
const onclick = (args) => {
args[0].onclick = (_) => {
execFn(args[1]);
}
return [];
}
addDefn("log", 1, log);
addDefn("getId", ["string"], getElem);
addDefn("setHTML", ["domNode", "string"], setHTML);
addDefn("mutref", 1, mutref);
addDefn("readmut", ["&mut"], readmut);
addDefn("writemut", 2, writemut);
addDefn("onclick", ["domNode", "closure"], onclick);

31
script/index.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meta Calculator</title>
</head>
<body>
<p id="out"></p>
<button id="1">1</button>
<button id="2">2</button>
<button id="3">3</button>
<button id="4">4</button>
<button id="5">5</button>
<button id="6">6</button>
<button id="7">7</button>
<button id="8">8</button>
<button id="9">9</button>
<button id="0">0</button>
<button id="push">push</button>
<button id="pop">pop</button>
<button id="zero">zero</button>
<br>
<button id="add">+</button>
<button id="sub">-</button>
<button id="mul">*</button>
<button id="div">/</button>
</body>
<script src="./test.rpn" type="text/rpncalc"></script>
<script src="./main.js" type="module"></script>
</html>

31
script/main.js Normal file
View File

@ -0,0 +1,31 @@
import {execRPN} from './shiny.mjs';
import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs';
import {scope} from './builtin.mjs';
import './dom.mjs';
const tags = document.getElementsByTagName("script");
let scripts = []
for (let i = 0; i < tags.length; i++) {
scripts.push(tags.item(i));
}
scripts = scripts.filter(script => script.type === "text/rpncalc");
const dispatch = (src) => {
setTimeout(() => {
let http = new XMLHttpRequest();
http.onreadystatechange = async(e) => {
if (http.readyState == 4 && http.status == 200) {
execRPN(scope, parseExprs(tokenize(http.responseText)).parsed);
}
};
http.open("get", src);
http.responseType = "text";
http.send();
}, 0);
}
for (let i = 0; i < scripts.length; i++) {
dispatch(scripts[i].src);
}

View File

@ -115,6 +115,19 @@ const parseType = (stream) => {
//return {parsed:null, stream:stream};
}
const parseString = (stream) => {
let e = stream[0];
if (e === undefined) {
return {parsed:null, stream:stream};
}
if (e.type !== "string") {
return {parsed:null, stream:stream};
} else {
stream.shift();
return {parsed:{type:e.type, val:e.val}, stream:stream};
}
}
/* takes in stream, outputs parsed item or null - FAILABLE */
const parsePush = (stream) => {
let syn = attempt(parseSyntax("'"))(stream);
@ -161,9 +174,10 @@ const parseExpr = or(
attempt(parseLambda), or(
parseType, or(
parseIdent, or(
parseNum,
parseNum, or(
parseString,
parsePush
))))));
)))))));
/* takes in stream, outputs parsed items */
export const parseExprs = many(parseExpr);

View File

@ -99,7 +99,7 @@ const applyMany = (elems, state) => {
}
}
const makeStackElems = (ins, state, handler) => {
const makeStackElems = (ins, state) => {
if (ins.type === "push") {
throw 'nested push error'
} else if (ins.type === "ident") {
@ -107,21 +107,21 @@ const makeStackElems = (ins, state, handler) => {
} else if (ins.type === "func") {
return [{type:"closure", val:{scope:state.scopes[state.scopes.length-1], args:ins.args, defn:{type:"ins", ins:ins.body}}}];
} else {
return handler(ins);
return [ins];
}
}
const doIns = (ins, state, handler) => {
const doIns = (ins, state) => {
if (ins.type === "push") {
state.stacks[state.stacks.length-1] = state.stacks[state.stacks.length-1].concat(makeStackElems(ins.elem, state, handler));
state.stacks[state.stacks.length-1] = state.stacks[state.stacks.length-1].concat(makeStackElems(ins.elem, state));
} else if (ins.type === "defn") {
state.scopes[state.scopes.length-1] = defn(ins.ident, ins.defn, state.scopes[state.scopes.length-1]);
} else {
applyMany(makeStackElems(ins, state, handler), state);
applyMany(makeStackElems(ins, state), state);
}
}
const step = (state, handler) => {
const step = (state) => {
if (state.calls[state.calls.length-1].length === 0) {
if (state.calls.length === 1) {
throw 'finished execution'
@ -136,17 +136,26 @@ const step = (state, handler) => {
} else {
let ins = state.calls[state.calls.length-1][0];
state.calls[state.calls.length-1] = state.calls[state.calls.length-1].slice(1);
doIns(ins, state, handler);
doIns(ins, state);
}
}
export const execRPN = (scope, ins, handler=(x)=>[x]) => {
let state = {scopes:[scope], stacks:[[]], calls:[ins]};
export const exec = (state) => {
while (state.calls[0].length > 0 || state.calls.length > 1) {
step(state, handler);
step(state);
if (state.stacks.length > 4096) {
throw 'max recursion depth exceeded'
}
}
return state;
}
export const execFn = (fn) => {
let state = {stacks:[[]], scopes:[fn.scope], calls:[fn.defn.ins]};
return exec(state);
}
export const execRPN = (scope, ins) => {
let state = {scopes:[scope], stacks:[[]], calls:[ins]};
return exec(state);
}

45
script/test.rpn Normal file
View File

@ -0,0 +1,45 @@
(output; `out` getId)
(acc; 0 mutref)
(stack; 0 tuple mutref)
(show; '(->
output acc readmut "string coerce setHTML))
(writeDigit; x ->
acc readmut 10 * x + acc writemut show)
(spush; stack val ->
stack untuple val stack len 1 + tuple)
(push; '(->
stack readmut acc readmut spush stack writemut))
(spop; stack ->
stack untuple (a ->) stack len 1 - tuple)
(last; stack ->
stack stack len 1 - !!)
(pop; '(->
stack readmut last stack readmut spop stack writemut))
(b1; `1` getId) b1 '(->1 writeDigit) onclick
(b2; `2` getId) b2 '(->2 writeDigit) onclick
(b3; `3` getId) b3 '(->3 writeDigit) onclick
(b4; `4` getId) b4 '(->4 writeDigit) onclick
(b5; `5` getId) b5 '(->5 writeDigit) onclick
(b6; `6` getId) b6 '(->6 writeDigit) onclick
(b7; `7` getId) b7 '(->7 writeDigit) onclick
(b8; `8` getId) b8 '(->8 writeDigit) onclick
(b9; `9` getId) b9 '(->9 writeDigit) onclick
(b0; `0` getId) b0 '(->0 writeDigit) onclick
(bpush; `push` getId) bpush '(->push 0 acc writemut show) onclick
(bpop; `pop` getId) bpop '(->pop acc writemut show) onclick
(bzero; `zero` getId) bzero '(->0 acc writemut show) onclick
(badd; `add` getId) badd '(->pop pop + acc writemut show) onclick
(bsub; `sub` getId) bsub '(->pop pop (a b -> b a) - acc writemut show) onclick
(bmul; `mul` getId) bmul '(->pop pop * acc writemut show) onclick
(bdiv; `div` getId) bdiv '(->pop pop (a b -> b a) / acc writemut show) onclick

68
script/token.mjs Normal file
View File

@ -0,0 +1,68 @@
const tokens = (stream) => {
let toks = [];
let currTok = {val:"", type:"str"};
let stringmode = false;
for (let i = 0; i < stream.length; i++) {
if (stringmode) {
if (stream[i] === '`') {
toks.push(currTok);
stringmode = false;
currTok = {val:"", type:"str"};
} else {
currTok.val += stream[i];
}
} else if (stream[i] === '`') {
if (currTok.val !== "") {
toks.push(currTok);
}
stringmode = true;
currTok = {val:"", type:"string"};
} else if ("()';\"".includes(stream[i])) {
if (currTok.val !== "") {
toks.push(currTok);
}
toks.push({val:stream[i], type:"syntax"});
currTok = {val:"", type:"str"};
} else if (stream[i] === "-") {
if (stream[i+1] === ">") {
if (currTok.val !== "") {
toks.push(currTok);
}
toks.push({val:"->", type:"syntax"});
i++;
currTok = {val:"", type:"str"};
} else {
currTok.val += "-";
}
} else if (/\s/.test(stream[i])) {
if (currTok.val !== "") {
toks.push(currTok);
}
currTok = {val:"", type:"str"};
} else {
currTok.val += stream[i];
}
}
if (currTok.val !== "") {
toks.push(currTok);
}
return toks;
}
const classify = (tokens) => {
return tokens.map(tok => {
if (tok.type === "str") {
if (!isNaN(tok.val)) {
return {val:Number(tok.val), type:"num"};
} else {
return {name:tok.val, type:"ident"};
}
} else {
return tok;
}
});
}
export const tokenize = (stream) => {
return classify(tokens(stream));
}

View File

@ -18,7 +18,7 @@ code {
<pre id="insbox"></pre>
<pre id="outbox"></pre>
<script src="./main.js" type="module"></script>
<h3>Documentation</h3>
<h3>documentation</h3>
<p>use <code>(name; value)</code> to define something. the definition can be recursive. <code>value</code> is executed and <code>name</code> is set to the final state of the stack, i.e. <code>(name; 1 3)</code> is possible</p>
<p>use <code>'</code> to push instead of apply to the stack, e.g. <code>'(a -> a)</code>. This is useful for lazyness, i.e. <code>'(->lazy evaluated thing)</code></p>
<ul>
@ -29,10 +29,17 @@ code {
<li><code>tuple</code>: used like <code>... 3 tuple</code>; creates an n tuple of n items on the stack</li>
<li><code>!!</code>: index into a tuple</li>
<li><code>len</code>: length of a tuple</li>
<li><code>unsafeCoerce</code>: unsafely transforms one type into another. useage: <code>1 "type unsafeCoerce</code></li>
<li><code>true, false</code>: true/false used in <code>==</code></li>
<li><code>stop</code>: equivalent to <code>"stop</code></li>
<li><code>inv</code>: equivalent to <code>1 x /</code></li>
<li><code>fold</code>: equivalent to <code>x acc fn -> acc '(-> x acc fn 'fn fold) 'x \"stop ==</code></li>
</ul>
<h3>stdlib</h3>
<ul>
<li><code>stop; "stop</code></li>
<li><code>inv; x -> 1 x /</code></li>
<li><code>fold; x acc fn -> acc '(-> x acc fn 'fn fold) 'x \"stop ==</code></li>
<li><code>range; x y -> x '(->x x 1 + y range) 'x y ==</code></li>
<li><code>listthen; fn -> (internal; x acc -> '(->acc fn) '(->x acc pair internal) x stop ==) 0 tuple internal</code></li>
<li><code>list; (a -> a) listthen</code></li>
<li><code>lmap; list fn -> list '(->list fst fn list snd 'fn lmap pair) list 0 tuple ==</code></li>
<li><code>unlist; l -> (internal; list -> '(->) '(->list fst list snd internal) list 0 tuple ==) stop l internal</code></li>
<li><code>map; fn -> '(l->l 'fn lmap unlist) listthen</code></li>
</ul>
</html>