mirror of
https://github.com/Baidicoot/rpncalc-v4
synced 2024-12-12 11:10:26 +00:00
bugfixes etc
This commit is contained in:
parent
0d90e7b9e1
commit
1c6bee1947
23
builtin.mjs
23
builtin.mjs
@ -1,4 +1,4 @@
|
||||
import {addDefn, addRPNASTDefn} from './eval.mjs';
|
||||
import {addDefn, addRPNASTDefn, makeFn} from './eval.mjs';
|
||||
import {parseExprs} from './parse.mjs';
|
||||
import {tokenize} from './token.mjs';
|
||||
|
||||
@ -43,7 +43,7 @@ const type = (_, args) => {
|
||||
}
|
||||
|
||||
const pair = (_, args) => {
|
||||
return [{type:"pair", val:{fst:args[0], snd:args[1]}}];
|
||||
return [{type:"pair", val:{fst:args[1], snd:args[0]}}];
|
||||
}
|
||||
|
||||
const fst = (_, args) => [args[0].fst];
|
||||
@ -58,6 +58,18 @@ const eq = (_, args) => {
|
||||
}
|
||||
}
|
||||
|
||||
const arr = (_, args) => {
|
||||
return [makeFn(args[0], (_, args) => {return [{type:"array", val:args}]})];
|
||||
}
|
||||
|
||||
const index = (_, args) => {
|
||||
return [args[1][args[0]]];
|
||||
}
|
||||
|
||||
const len = (_, args) => {
|
||||
return [{type:"int", val:args[0].length}];
|
||||
}
|
||||
|
||||
addDefn("+", ["int", "int"], add);
|
||||
addDefn("-", ["int", "int"], sub);
|
||||
addDefn("/", ["int", "int"], div);
|
||||
@ -69,9 +81,14 @@ addDefn("typeof", 1, type);
|
||||
addDefn("pair", 2, pair);
|
||||
addDefn("fst", ["pair"], fst);
|
||||
addDefn("snd", ["pair"], snd);
|
||||
addDefn("arr", ["int"], arr);
|
||||
addDefn("!!", ["int", "array"], index);
|
||||
addDefn("len", ["array"], len);
|
||||
addRPNDefn("unit", "(-> 0 arr)");
|
||||
addRPNDefn("mono", "(-> 1 arr)");
|
||||
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 ==)");
|
||||
addRPNDefn("fold", "(x acc fn -> '(-> acc) '(-> x acc fn 'fn fold) 'x \"stop ==)");
|
8
eval.mjs
8
eval.mjs
@ -40,14 +40,14 @@ const makeEval = (sign, defnarg) => {
|
||||
}
|
||||
}
|
||||
|
||||
const makeBuiltin = (sign, defnarg) => {
|
||||
export const makeFn = (sign, defnarg) => {
|
||||
return {type:"closure", args:[], func:makeEval(sign, defnarg)};
|
||||
}
|
||||
|
||||
let builtinDefn = {};
|
||||
|
||||
export const addDefn = (name, sign, func) => {
|
||||
builtinDefn[name] = makeBuiltin(sign, func);
|
||||
builtinDefn[name] = makeFn(sign, func);
|
||||
}
|
||||
|
||||
export const addRPNASTDefn = (name, ast) => {
|
||||
@ -56,9 +56,9 @@ export const addRPNASTDefn = (name, ast) => {
|
||||
|
||||
const makeLambda = (lambda) => {
|
||||
return {nargs:lambda.args.length, defn:(scope, args) => {
|
||||
let newscope = Object.create(scope); // I am so sorry...
|
||||
let newscope = Object.create(scope);
|
||||
for (let i = 0; i < lambda.args.length; i++) {
|
||||
newscope[lambda.args[i]] = args[i];
|
||||
newscope[lambda.args[i]] = args[args.length-1-i];
|
||||
}
|
||||
return execRPN(newscope, lambda.body).stack;
|
||||
}};
|
||||
|
3
main.js
3
main.js
@ -16,6 +16,8 @@ const show = (elem) => {
|
||||
return "(args: {" + prettyprint(elem.args) + "} of " + elem.func.nargs + ")"
|
||||
} else if (elem.type === "string") {
|
||||
return elem.val
|
||||
} else if (elem.type === "array") {
|
||||
return "[" + prettyprint(elem.val) + "]"
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,5 +49,6 @@ submit.onclick = (event) => {
|
||||
outbox.innerHTML = "failed to execute";
|
||||
return;
|
||||
}
|
||||
console.log(out);
|
||||
outbox.innerHTML = prettyprint(out.stack);
|
||||
}
|
@ -36,11 +36,11 @@ export function tokenize(input) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
let splitInput = inputWithAddedSpaces.split(" ");
|
||||
let splitInput = inputWithAddedSpaces.split(" ").filter((s) => s !== "");
|
||||
let output = [];
|
||||
for(i = 0; i<splitInput.length; i++){
|
||||
if(/^\d+$/.test(splitInput[i])){ // didn't need /[0-9]/, but that would be helpful to stop numbers from being in identifiers, but the ability to call a function "function_add_1" is easier to type than "function_add_one"
|
||||
output.push({type: "int", val:parseInt(splitInput[i])}); // also, /[a-zA-Z]/ wasn't necessary as my code uses anything that isn't `;() or ->
|
||||
if(!isNaN(splitInput[i])){ // didn't need /[0-9]/, but that would be helpful to stop numbers from being in identifiers, but the ability to call a function "function_add_1" is easier to type than "function_add_one"
|
||||
output.push({type: "int", val:Number(splitInput[i])}); // also, /[a-zA-Z]/ wasn't necessary as my code uses anything that isn't `;() or ->
|
||||
} else if(syntax.test(splitInput[i]) || splitInput[i] === "->"){// needs a || as -> wasn't included in the syntax regexp. it wasn't in because -> uses two characters so i wanted to have separate code for it. (also because regexps are confusing)
|
||||
output.push({type: "syntax", val:splitInput[i]});
|
||||
} else if(splitInput[i] != '') { // if syntax is next to the end of the string or other bits of syntax the two spaces are in inputWithAddedSpaces so .split returns '' as one element. this makes sure that it is not read as an identifier
|
||||
|
Loading…
Reference in New Issue
Block a user