1
0
mirror of https://github.com/Baidicoot/rpncalc-v4 synced 2024-12-12 19:20:26 +00:00

refactored builtins to own file

This commit is contained in:
Aidan K. Ewart 2020-05-30 21:20:04 +01:00
parent 34d43452cb
commit 0d90e7b9e1
5 changed files with 87 additions and 75 deletions

77
builtin.mjs Normal file
View File

@ -0,0 +1,77 @@
import {addDefn, addRPNASTDefn} from './eval.mjs';
import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs';
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'
}
addRPNASTDefn(name, ast.parsed[0]);
}
const add = (_, args) => {
return [{type:"int", val:args[0] + args[1]}];
}
const sub = (_, args) => {
return [{type:"int", val:args[1] - args[0]}];
}
const div = (_, args) => {
return [{type:"int", val:args[1] / args[0]}];
}
const mult = (_, args) => {
return [{type:"int", val:args[0] * args[1]}];
}
const pow = (_, args) => {
return [{type:"int", val:Math.pow(args[1], args[0])}];
}
const root = (_, args) => {
return [{type:"int", val:Math.sqrt(args[0])}];
}
const type = (_, args) => {
return [{type:"string", val:args[0].type}];
}
const pair = (_, args) => {
return [{type:"pair", val:{fst:args[0], snd:args[1]}}];
}
const fst = (_, args) => [args[0].fst];
const snd = (_, args) => [args[0].snd];
const eq = (_, args) => {
if (args[0].type === args[1].type && args[0].val === args[1].val) {
return [{type:"ident", val:"true"}];
} else {
return [{type:"ident", val:"false"}];
}
}
addDefn("+", ["int", "int"], add);
addDefn("-", ["int", "int"], sub);
addDefn("/", ["int", "int"], div);
addDefn("*", ["int", "int"], mult);
addDefn("^", ["int", "int"], pow);
addDefn("sqrt", ["int"], root);
addDefn("==", 2, eq);
addDefn("typeof", 1, type);
addDefn("pair", 2, pair);
addDefn("fst", ["pair"], fst);
addDefn("snd", ["pair"], snd);
addRPNDefn("true", "(a b -> a)");
addRPNDefn("false", "(a b -> b)");
addRPNDefn("stop", "(-> \"stop)");
addRPNDefn("id", "(a -> a)");
addRPNDefn("inv", "(x -> 1 x /)");
addRPNDefn("fold", "(fn acc x -> '(-> x acc fn 'fn fold) '(-> acc) 'x \"stop ==)");

View File

@ -40,64 +40,18 @@ const makeEval = (sign, defnarg) => {
} }
} }
const add = (_, args) => { const makeBuiltin = (sign, defnarg) => {
return [{type:"int", val:args[0] + args[1]}]; return {type:"closure", args:[], func:makeEval(sign, defnarg)};
} }
const sub = (_, args) => { let builtinDefn = {};
return [{type:"int", val:args[1] - args[0]}];
}
const div = (_, args) => {
return [{type:"int", val:args[1] / args[0]}];
}
const mult = (_, args) => {
return [{type:"int", val:args[0] * args[1]}];
}
const type = (_, args) => {
return [{type:"string", val:args[0].type}];
}
const pair = (_, args) => {
return [{type:"pair", val:{fst:args[0], snd:args[1]}}];
}
const fst = (_, args) => [args[0].fst];
const snd = (_, args) => [args[0].snd];
const eq = (_, args) => {
if (args[0].type === args[1].type && args[0].val === args[1].val) {
return [{type:"ident", val:"true"}];
} else {
return [{type:"ident", val:"false"}];
}
}
const stop = (a, b) => {
return [{type:"string", val:"stop"}];
}
let builtinDefn = {
"+": makeEval(["int", "int"], add),
"-": makeEval(["int", "int"], sub),
"/": makeEval(["int", "int"], div),
"*": makeEval(["int", "int"], mult),
"==": makeEval(2, eq),
"typeof": makeEval(1, type),
"pair": makeEval(2, pair),
"fst": makeEval(["pair"], fst),
"snd": makeEval(["pair"], snd)
}
export const addDefn = (name, sign, func) => { export const addDefn = (name, sign, func) => {
builtinDefn[name] = makeEval(sign, func); builtinDefn[name] = makeBuiltin(sign, func);
} }
export const addRPNASTDefn = (name, ast) => { export const addRPNASTDefn = (name, ast) => {
builtinDefn[name] = makeLambda(ast); builtinDefn[name] = makeObj(ast);
} }
const makeLambda = (lambda) => { const makeLambda = (lambda) => {
@ -137,7 +91,7 @@ const lookupScope = (name, scope) => {
} }
n = builtinDefn[name]; n = builtinDefn[name];
if (n) { if (n) {
return {type:"closure", args:[], func:n}; return cloneElem(n);
} else { } else {
throw "var " + n + " not in scope" throw "var " + n + " not in scope"
} }
@ -189,7 +143,7 @@ const defn = (elem, name, stack) => {
stack.scope[name] = makeObj(elem); stack.scope[name] = makeObj(elem);
} }
export const doStep = (ins, stack) => { const doStep = (ins, stack) => {
let instruction = ins.shift(); let instruction = ins.shift();
if (instruction.type === "push") { if (instruction.type === "push") {
pushS(makeObj(instruction.elem), stack); pushS(makeObj(instruction.elem), stack);

View File

@ -8,7 +8,7 @@ Example Programs:
<br> <br>
<code>1 + 2 (v partial -> 'v partial)</code> Evaluate a partial <code>1 + 2 (v partial -> 'v partial)</code> Evaluate a partial
</p> </p>
<input type="text" id="inbox"> <textarea type="text" id="inbox"></textarea>
<button id="submit">execute</button> <button id="submit">execute</button>
<p id="outbox"></p> <p id="outbox"></p>
<script src="./main.js" type="module"></script> <script src="./main.js" type="module"></script>

22
main.js
View File

@ -1,6 +1,7 @@
import {execRPN, addRPNASTDefn} from './eval.mjs'; import {execRPN} from './eval.mjs';
import {parseExprs} from './parse.mjs'; import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs'; import {tokenize} from './token.mjs';
import './builtin.mjs';
const inbox = document.getElementById("inbox") const inbox = document.getElementById("inbox")
const outbox = document.getElementById("outbox") const outbox = document.getElementById("outbox")
@ -29,25 +30,6 @@ const prettyprint = (out) => {
return str; return str;
} }
const addRPNBuiltin = (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'
}
console.log(ast);
addRPNASTDefn(name, ast.parsed[0]);
}
addRPNBuiltin("true", "(a b -> a)");
addRPNBuiltin("false", "(a b -> b)");
addRPNBuiltin("stop", "(-> \"stop)");
addRPNBuiltin("id", "(a -> a)");
addRPNBuiltin("fold", "(fn acc x -> '(-> x acc fn 'fn fold) '(-> acc) 'x \"stop ==)");
submit.onclick = (event) => { submit.onclick = (event) => {
const input = inbox.value; const input = inbox.value;
let toks = tokenize(input); let toks = tokenize(input);

View File

@ -48,7 +48,6 @@ const attempt = (parser) => (stream) => {
let out = parser(stream); let out = parser(stream);
return out; return out;
} catch(err) { } catch(err) {
console.log(err);
return {parsed:null,stream:streamclone}; return {parsed:null,stream:streamclone};
} }
} }