Table of contents
Your own callcc
TODO:
- actually make a demo of working callcc for previous example?
const script = {
type: "BinaryExpression",
operator: "*",
left: {
type: "Literal",
value: 2,
raw: "2"
},
right: {
type: "CallExpression",
callee: { type: "Identifier", name: "callcc" },
argument: { type: "Identifier", name: "yieldValue" }
}
};
evaluate(script, console.log);
// it's the same as:
2 * callcc(yieldValue);
Implementation:
const functions = {
Literal(node, c) {
c(node.value);
},
BinaryExpression(node, c, cerr, env) {
evaluate(
node.left,
(left) =>
evaluate(
node.right,
function (right) {
switch (k) {
case "+":
c(left + right);
break;
case "*":
c(left * right);
break;
}
},
cerr,
env
),
cerr,
env
);
},
Identifier(node, c, cerr, env) {
const { name } = node;
if (name in env) {
c(env[name]);
} else {
cerr(new ReferenceError(`${name} it not defined.`));
}
},
CallExpression(node, c, cerr, env) {
evaluate(
node.argument,
(argument) =>
evaluate(
node.callee,
(calleeFunction) => {
if (calleeFunction === callcc) {
argument(null, c, cerr, env);
} else {
c(calleeFunction(arg));
}
},
cerr,
env
),
cerr,
env
);
}
};
function callcc(target, c, cerr) {
throw new Error("Can't be called directly, evaluation will be handled by interpreter");
}
let continuation;
const env = {
callcc,
yieldValue(_c, c, cerr) {
continuation = c;
}
};
evaluate(script, (value) => console.log("Evaluation result: " + value), console.error, env);
continuation(3);
continuation(4);
continuation(5);