build-a-programming-language / lesson-31.md
Lesson 31 · Evaluation

Bindings and the environment

Variables need somewhere to live. Today you build the environment - a name-to-value store - so a let binding can save a value and an identifier can look it up.

The goal

Evaluate let bindings into an environment and resolve identifiers by looking them up.

Start here - the target
TO DO
Scenario: Binding and resolving a variable
Giventhe source let a = 5; let b = a; b
Whenthe evaluator evaluates the program
Thenthe result is 5
Andevaluating let a = 5 * 5; a yields 25
Background

A let statement needs somewhere to put its value, and an identifier needs somewhere to find it: that shared store is the environment, a map from names to objects. Evaluating let a = 5 computes 5 and stores it under "a"; evaluating the identifier a looks it up and returns the value.

This is the biggest structural change since Eval began, because the environment has to travel with evaluation - every Eval call now takes an environment argument and passes it down. Do that plumbing carefully; it is the same environment you will extend per function call in the closures chapter, which is the whole mechanism behind local variables and closures. Looking up a name that was never bound is an error - you will report it cleanly in the next lesson.

Make it work
type Environment struct { store map[string]Object }
func (e *Environment) Get(name string) (Object, bool) { o, ok := e.store[name]; return o, ok }
func (e *Environment) Set(name string, val Object) Object { e.store[name] = val; return val }
// Eval now threads an *Environment; let -> Set, Identifier -> Get
CheckpointDONE
Variables can be bound with let and read back by name. Commit.