1
0
mirror of https://github.com/Baidicoot/rpncalc-v4 synced 2024-06-14 09:16:51 +00:00

added definitions and lambda evaluation

This commit is contained in:
Aidan K. Ewart 2020-05-21 16:31:45 +01:00
parent 32db1c77b0
commit ea57cc4cc5
2 changed files with 28 additions and 16 deletions

30
eval.js
View File

@ -13,6 +13,8 @@ types of object on list:
[{type:"int", val:1},{type:"int", val:1},{type:"builtin", op:"+"}] [{type:"int", val:1},{type:"int", val:1},{type:"builtin", op:"+"}]
[{type:"int", val:1},{type:"int", val:1},{type:"func", args:["a"], body:[{type:"ident", val:"a"},{type:"int", val:1},{type:"builtin", op:"+"}]}]
exported functions: exported functions:
addDefn - adds a builtin function addDefn - adds a builtin function
doStep - consumes instruction stream, stack, outputs stack doStep - consumes instruction stream, stack, outputs stack
@ -77,16 +79,18 @@ let builtinDefn = {
"snd": makeEval(["pair"], snd) "snd": makeEval(["pair"], snd)
} }
export const addDefn = (name, sign, func) => { const addDefn = (name, sign, func) => {
builtinDefn[name] = makeEval(sign, func); builtinDefn[name] = makeEval(sign, func);
} }
const makeLambda = (lambda) => (scope, args) => { const makeLambda = (lambda) => {
let newscope = Object.create(scope); // I am so sorry... return {nargs:lambda.args.length, defn:(scope, args) => {
for (let i = 0; i < lambda.args.length; i++) { let newscope = Object.create(scope); // I am so sorry...
newscope[lambda.args[i]] = args[i]; for (let i = 0; i < lambda.args.length; i++) {
} newscope[lambda.args[i]] = args[i];
return execRPN(newscope, lambda.body); }
return execRPN(newscope, lambda.body).stack;
}};
} }
const makeObj = (elem) => { const makeObj = (elem) => {
@ -103,7 +107,7 @@ const makeObj = (elem) => {
const giveArg = (closure, arg, scope) => { const giveArg = (closure, arg, scope) => {
closure.args.push(arg); closure.args.push(arg);
if (closure.args.length === closure.func.nargs) { if (closure.args.length === closure.func.nargs) {
return closure.func.defn(scope, closure.args) return closure.func.defn(scope, closure.args);
} else { } else {
return [closure]; return [closure];
} }
@ -114,7 +118,7 @@ const apply = (elem, stack) => {
let out = giveArg(elem, stack.stack.pop(), stack.scope); let out = giveArg(elem, stack.stack.pop(), stack.scope);
applyMany(out, stack); applyMany(out, stack);
} else if (elem.type === "ident") { } else if (elem.type === "ident") {
let id = stack.scope[elem.name]; let id = stack.scope[elem.val];
apply(id, stack); apply(id, stack);
} else { } else {
stack.stack.push(elem); stack.stack.push(elem);
@ -136,10 +140,16 @@ const pushS = (elem, stack) => {
} }
} }
export const doStep = (ins, stack) => { const defn = (elem, name, stack) => {
stack.scope[name] = makeObj(elem);
}
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);
} else if (instruction.type === "defn") {
defn(ins.defn, ins.ident, stack);
} else { } else {
apply(makeObj(instruction), stack); apply(makeObj(instruction), stack);
} }

View File

@ -22,7 +22,7 @@ convert:
] ]
(for c+p) (for c+p)
[{type:"int",val:1},{type:"int",val:2},{type:"ident",name:"+"},{type:"syntax",val:"'"},{type:"syntax",val:"("},{type:"ident",name:"name"},{type:"syntax",val:";"},{type:"ident",name:"args"},{type:"syntax",val:"->"},{type:"int",val:2},{type:"ident",name:"args"},{type:"ident",name:"+"},{type:"syntax",val:")"}] [{type:"int",val:1},{type:"int",val:2},{type:"ident",name:"+"},{type:"syntax",val:"'"},{type:"syntax",val:"("},{type:"ident",name:"name"},{type:"ident",name:"args"},{type:"syntax",val:"->"},{type:"int",val:2},{type:"ident",name:"args"},{type:"ident",name:"+"},{type:"syntax",val:")"}]
to: to:
[ [
@ -30,7 +30,7 @@ to:
{type:"int", val:2}, {type:"int", val:2},
{type:"builtin", op:"+"}, {type:"builtin", op:"+"},
{type:"push", elem: {type:"push", elem:
{type:"func", name:"name", args:["args"], body:[ {type:"func", args:["args"], body:[
{type:"int", val:1}, {type:"int", val:1},
{type:"ident", val:"args"}, {type:"ident", val:"args"},
{type:"builtin", op:"+"}, {type:"builtin", op:"+"},
@ -190,9 +190,6 @@ const parsePush = (stream) => {
/* takes in stream, outputs parsed item or null - FAILABLE */ /* takes in stream, outputs parsed item or null - FAILABLE */
const parseLambda = (stream) => { const parseLambda = (stream) => {
let name = attempt(parseName)(stream); let name = attempt(parseName)(stream);
if (name.parsed === null) {
name.parsed = "";
}
let args = many(parseIdent)(name.stream); let args = many(parseIdent)(name.stream);
let syn = parseSyntax("->")(args.stream); let syn = parseSyntax("->")(args.stream);
if (syn.parsed === null) { if (syn.parsed === null) {
@ -202,7 +199,12 @@ const parseLambda = (stream) => {
if (body.parsed === null) { if (body.parsed === null) {
throw 'no lambda body found!'; throw 'no lambda body found!';
} }
return {parsed:{type:"func", name:name.parsed, args:args.parsed.map(x => x.val), body:body.parsed}, stream:body.stream}; let func = {type:"func", args:args.parsed.map(x => x.val), body:body.parsed};
if (name.parsed === null) {
return {parsed:func, stream:body.stream};
} else {
return {type:"defn", ident:name.parsed, defn:func};
}
} }
/* takes in stream, outputs parsed item or null */ /* takes in stream, outputs parsed item or null */