mirror of
https://github.com/Baidicoot/rpncalc-v4
synced 2024-12-12 11:10:26 +00:00
refactored builtins to own file
This commit is contained in:
parent
34d43452cb
commit
0d90e7b9e1
77
builtin.mjs
Normal file
77
builtin.mjs
Normal 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 ==)");
|
60
eval.mjs
60
eval.mjs
@ -40,64 +40,18 @@ const makeEval = (sign, defnarg) => {
|
||||
}
|
||||
}
|
||||
|
||||
const add = (_, args) => {
|
||||
return [{type:"int", val:args[0] + args[1]}];
|
||||
const makeBuiltin = (sign, defnarg) => {
|
||||
return {type:"closure", args:[], func:makeEval(sign, defnarg)};
|
||||
}
|
||||
|
||||
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 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)
|
||||
}
|
||||
let builtinDefn = {};
|
||||
|
||||
export const addDefn = (name, sign, func) => {
|
||||
builtinDefn[name] = makeEval(sign, func);
|
||||
builtinDefn[name] = makeBuiltin(sign, func);
|
||||
}
|
||||
|
||||
export const addRPNASTDefn = (name, ast) => {
|
||||
builtinDefn[name] = makeLambda(ast);
|
||||
builtinDefn[name] = makeObj(ast);
|
||||
}
|
||||
|
||||
const makeLambda = (lambda) => {
|
||||
@ -137,7 +91,7 @@ const lookupScope = (name, scope) => {
|
||||
}
|
||||
n = builtinDefn[name];
|
||||
if (n) {
|
||||
return {type:"closure", args:[], func:n};
|
||||
return cloneElem(n);
|
||||
} else {
|
||||
throw "var " + n + " not in scope"
|
||||
}
|
||||
@ -189,7 +143,7 @@ const defn = (elem, name, stack) => {
|
||||
stack.scope[name] = makeObj(elem);
|
||||
}
|
||||
|
||||
export const doStep = (ins, stack) => {
|
||||
const doStep = (ins, stack) => {
|
||||
let instruction = ins.shift();
|
||||
if (instruction.type === "push") {
|
||||
pushS(makeObj(instruction.elem), stack);
|
||||
|
@ -8,7 +8,7 @@ Example Programs:
|
||||
<br>
|
||||
<code>1 + 2 (v partial -> 'v partial)</code> Evaluate a partial
|
||||
</p>
|
||||
<input type="text" id="inbox">
|
||||
<textarea type="text" id="inbox"></textarea>
|
||||
<button id="submit">execute</button>
|
||||
<p id="outbox"></p>
|
||||
<script src="./main.js" type="module"></script>
|
||||
|
22
main.js
22
main.js
@ -1,6 +1,7 @@
|
||||
import {execRPN, addRPNASTDefn} from './eval.mjs';
|
||||
import {execRPN} from './eval.mjs';
|
||||
import {parseExprs} from './parse.mjs';
|
||||
import {tokenize} from './token.mjs';
|
||||
import './builtin.mjs';
|
||||
|
||||
const inbox = document.getElementById("inbox")
|
||||
const outbox = document.getElementById("outbox")
|
||||
@ -29,25 +30,6 @@ const prettyprint = (out) => {
|
||||
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) => {
|
||||
const input = inbox.value;
|
||||
let toks = tokenize(input);
|
||||
|
Loading…
Reference in New Issue
Block a user