mirror of
				https://github.com/Baidicoot/rpncalc-v4
				synced 2025-10-31 15:43:00 +00:00 
			
		
		
		
	added meta
This commit is contained in:
		| @@ -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> | ||||
							
								
								
									
										52
									
								
								new/main.js
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								new/main.js
									
									
									
									
									
								
							| @@ -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]); | ||||
| } | ||||
| @@ -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) | ||||
| } | ||||
| @@ -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 ] | ||||
| @@ -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
									
								
							
							
						
						
									
										33
									
								
								script/dom.mjs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										31
									
								
								script/index.html
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										31
									
								
								script/main.js
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
| @@ -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); | ||||
| @@ -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
									
								
							
							
						
						
									
										45
									
								
								script/test.rpn
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										68
									
								
								script/token.mjs
									
									
									
									
									
										Normal 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)); | ||||
| } | ||||
| @@ -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> | ||||
		Reference in New Issue
	
	Block a user
	 Aidan K. Ewart
					Aidan K. Ewart