From 1c6bee19471f0f5ca1af632765eda0b39cce959b Mon Sep 17 00:00:00 2001 From: "Aidan K. Ewart" Date: Sat, 30 May 2020 22:39:45 +0100 Subject: [PATCH] bugfixes etc --- builtin.mjs | 23 ++++++++++++++++++++--- eval.mjs | 8 ++++---- main.js | 3 +++ token.mjs | 6 +++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/builtin.mjs b/builtin.mjs index d9812ac..3004340 100644 --- a/builtin.mjs +++ b/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 ==)"); \ No newline at end of file +addRPNDefn("fold", "(x acc fn -> '(-> acc) '(-> x acc fn 'fn fold) 'x \"stop ==)"); \ No newline at end of file diff --git a/eval.mjs b/eval.mjs index 6f6bf57..4a26678 100644 --- a/eval.mjs +++ b/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; }}; diff --git a/main.js b/main.js index 9c00d5e..597df28 100644 --- a/main.js +++ b/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); } \ No newline at end of file diff --git a/token.mjs b/token.mjs index 7072776..3e0a341 100644 --- a/token.mjs +++ b/token.mjs @@ -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 + 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