function interpret(ctx, node) {
if (typeof node === 'undefined') {
node = ctx;
return interpret(emptyContext, node);
} else if (node.class === 'call') {
const [ctx1, fun] = interpret(ctx, node.fun);
const [ctx2, args] = interpret(ctx1, node.args);
return [ctx2, fun.apply(args)];
} else if (node.class === 'function') {
return [ctx, node.syntax];
} else if (node.class === 'list') {
const elemResArr = [];
for (const elem of node.elems) {
const [nextCtx, elemValue] = interpret(ctx, elem);
ctx = nextCtx;
elemResArr.push(elemValue);
}
return [ctx, list(...elemResArr)];
} else if (node.class === 'value') {
return [ctx, node];
} else if (node.class === 'getter') {
const [ctx1, name] = interpret(ctx, node.name);
return [ctx1, getterFun(ctx1, name)];
} else if (node.class === 'setter') {
const [ctx1, name] = interpret(ctx, node.name);
const [ctx2, val] = interpret(ctx1, node.value);
const resCtx = setterFun(ctx2, name, val);
return [resCtx, value(null)];
} else if (node.class === 'sequence') {
let lastValue;
const [ctx0, stmts] = interpret(ctx, node.statements);
ctx = ctx0;
for (const stmt of stmts.value) {
const [nextCtx, value] = interpret(ctx, stmt);
ctx = nextCtx;
lastValue = value;
}
return [ctx, lastValue];
} else if (node.class === 'lambda') {
const [ctx1, name] = interpret(ctx, node.name);
const [ctx2, expr] = interpret(ctx1, node.expr);
const lambda = arg => {
const localCtx = setterFun(ctx2, name, arg);
return interpret(localCtx, expr.value)[1];
};
return [ctx2, {
class: 'lambda',
name,
expr,
apply: lambda,
}]
}
}