diff --git a/builtin.mjs b/builtin.mjs
new file mode 100644
index 0000000..d9812ac
--- /dev/null
+++ b/builtin.mjs
@@ -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 ==)");
\ No newline at end of file
diff --git a/eval.mjs b/eval.mjs
index 9075094..6f6bf57 100644
--- a/eval.mjs
+++ b/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);
diff --git a/index.html b/index.html
index 71caa88..0fad777 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@ Example Programs:
1 + 2 (v partial -> 'v partial)
Evaluate a partial