Sikau

Build an interpreter · Day 7 · about 40 min

Names and environments

let, variable lookup, if/else, blocks and return.

Remembering things

Every language you use has environments under the hood. When JavaScript says a variable is not defined, it has walked a chain just like this one.

let x = 5; has to store 5 somewhere, and a later x has to find it. That storage is an environment: a map from names to values. Environments link to an outer environment, which is how a function body can see names defined outside it — the basis of scope. Today evaluate gains a second argument: the environment to use.

let price = 180;
let tax = price * 13 / 100;
if (tax > 20) { price + tax } else { price }

The Env class

An Env holds a Map and a reference to its outer Env (or null at the top). define(name, value) always writes into this env. get(name) looks here first, then asks the outer env, and so on up the chain; if nobody has the name, it's an error. Tomorrow each function call will make a new Env whose outer is where the function was created.

class Env {
  constructor(outer = null) { this.vars = new Map(); this.outer = outer; }
  get(name) {
    if (this.vars.has(name)) return this.vars.get(name);
    if (this.outer) return this.outer.get(name);
    throw new Error(`Unknown name: ${name}`);
  }
  define(name, value) { this.vars.set(name, value); }
}

Use vars.has(name), not vars.get(name) !== undefined, so a variable holding null still counts as defined.

The rest of this lesson

  • Return needs to escapeexplain
  • Which value comes out?predict
  • Node to actionmatch
  • Looking up a namefill
  • Variables and returnwrite 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