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);