Sikau

Build an interpreter · Day 9 · about 40 min

Built-ins and arrays

len, push, first, rest, print — and a run() that never crashes.

Talking to the outside world

Chiya can compute, but it can't print, and it can't work with lists. Real languages ship built-in functions: functions written in the host language (here, JavaScript) that the interpreter offers to every program. Today you'll add arrays and indexing to the evaluator, a handful of built-ins, and run(source), which turns any program into { output, value, error }.

let sum = fn(arr) {
  if (len(arr) == 0) { return 0; }
  first(arr) + sum(rest(arr))
};
print("total:", sum([1, 2, 3, 4]));

Built-ins live in an environment

Built-ins are just values stored under names, so they belong in an Env. Create a base environment holding { kind: "builtin", name, fn } objects, and make the program's global environment an inner Env of it. call() gets one more case: a builtin is called by running its JavaScript fn with the arguments. Programs can even shadow a built-in with their own let len = ….

function builtins(output) {
  const env = new Env();
  const def = (name, fn) => env.define(name, { kind: "builtin", name, fn });
  def("len", (x) => {
    if (typeof x === "string" || Array.isArray(x)) return x.length;
    throw new Error(`len() needs a string or array, not ${typeOf(x)}`);
  });
  def("print", (...values) => { output.push(values.map(display).join(" ")); return null; });
  return env;
}

push returns a new array instead of changing the old one. With no assignment in Chiya yet, immutable lists keep programs predictable.

The rest of this lesson

  • Arrays, indexing and run()explain
  • Indexing past the endpredict
  • Built-in resultsmatch
  • What run() doesorder
  • The standard librarywrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 10 lessons of Build an interpreter