mirror of
https://github.com/Baidicoot/rpncalc-v4
synced 2024-12-04 15:29:54 +00:00
added definitions and lambda evaluation
This commit is contained in:
parent
32db1c77b0
commit
ea57cc4cc5
30
eval.js
30
eval.js
@ -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:"func", args:["a"], body:[{type:"ident", val:"a"},{type:"int", val:1},{type:"builtin", op:"+"}]}]
|
||||
|
||||
exported functions:
|
||||
addDefn - adds a builtin function
|
||||
doStep - consumes instruction stream, stack, outputs stack
|
||||
@ -77,16 +79,18 @@ let builtinDefn = {
|
||||
"snd": makeEval(["pair"], snd)
|
||||
}
|
||||
|
||||
export const addDefn = (name, sign, func) => {
|
||||
const addDefn = (name, sign, func) => {
|
||||
builtinDefn[name] = makeEval(sign, func);
|
||||
}
|
||||
|
||||
const makeLambda = (lambda) => (scope, args) => {
|
||||
let newscope = Object.create(scope); // I am so sorry...
|
||||
for (let i = 0; i < lambda.args.length; i++) {
|
||||
newscope[lambda.args[i]] = args[i];
|
||||
}
|
||||
return execRPN(newscope, lambda.body);
|
||||
const makeLambda = (lambda) => {
|
||||
return {nargs:lambda.args.length, defn:(scope, args) => {
|
||||
let newscope = Object.create(scope); // I am so sorry...
|
||||
for (let i = 0; i < lambda.args.length; i++) {
|
||||
newscope[lambda.args[i]] = args[i];
|
||||
}
|
||||
return execRPN(newscope, lambda.body).stack;
|
||||
}};
|
||||
}
|
||||
|
||||
const makeObj = (elem) => {
|
||||
@ -103,7 +107,7 @@ const makeObj = (elem) => {
|
||||
const giveArg = (closure, arg, scope) => {
|
||||
closure.args.push(arg);
|
||||
if (closure.args.length === closure.func.nargs) {
|
||||
return closure.func.defn(scope, closure.args)
|
||||
return closure.func.defn(scope, closure.args);
|
||||
} else {
|
||||
return [closure];
|
||||
}
|
||||
@ -114,7 +118,7 @@ const apply = (elem, stack) => {
|
||||
let out = giveArg(elem, stack.stack.pop(), stack.scope);
|
||||
applyMany(out, stack);
|
||||
} else if (elem.type === "ident") {
|
||||
let id = stack.scope[elem.name];
|
||||
let id = stack.scope[elem.val];
|
||||
apply(id, stack);
|
||||
} else {
|
||||
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();
|
||||
if (instruction.type === "push") {
|
||||
pushS(makeObj(instruction.elem), stack);
|
||||
} else if (instruction.type === "defn") {
|
||||
defn(ins.defn, ins.ident, stack);
|
||||
} else {
|
||||
apply(makeObj(instruction), stack);
|
||||
}
|
||||
|
14
parse.js
14
parse.js
@ -22,7 +22,7 @@ convert:
|
||||
]
|
||||
|
||||
(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:
|
||||
[
|
||||
@ -30,7 +30,7 @@ to:
|
||||
{type:"int", val:2},
|
||||
{type:"builtin", op:"+"},
|
||||
{type:"push", elem:
|
||||
{type:"func", name:"name", args:["args"], body:[
|
||||
{type:"func", args:["args"], body:[
|
||||
{type:"int", val:1},
|
||||
{type:"ident", val:"args"},
|
||||
{type:"builtin", op:"+"},
|
||||
@ -190,9 +190,6 @@ const parsePush = (stream) => {
|
||||
/* takes in stream, outputs parsed item or null - FAILABLE */
|
||||
const parseLambda = (stream) => {
|
||||
let name = attempt(parseName)(stream);
|
||||
if (name.parsed === null) {
|
||||
name.parsed = "";
|
||||
}
|
||||
let args = many(parseIdent)(name.stream);
|
||||
let syn = parseSyntax("->")(args.stream);
|
||||
if (syn.parsed === null) {
|
||||
@ -202,7 +199,12 @@ const parseLambda = (stream) => {
|
||||
if (body.parsed === null) {
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user