package interpreter // environment represents the environment in which the interpreter operates. type environment struct { values map[string]any enclosing *environment } // newEnvironment creates a new environment. // e is the enclosing environment and is nil for the global environment. func newEnvironment(e *environment) *environment { return &environment{values: make(map[string]any), enclosing: e} } // define defines a new variable in the environment. func (e *environment) define(name string, value any) { e.values[name] = value } // ancestor returns the environment at a given distance. func (e *environment) ancestor(distance int) *environment { env := e for i := 0; i < distance; i++ { env = env.enclosing } return env } // getAt gets the value of a variable at a given distance. func (e *environment) getAt(distance int, name string) any { return e.ancestor(distance).values[name] } // get gets the value of a variable in the environment. func (e *environment) get(name string) any { value, ok := e.values[name] if !ok { if e.enclosing != nil { return e.enclosing.get(name) } panic("Undefined variable '" + name + "'.") } return value } // assignAt assigns a new value to a variable at a given distance. func (e *environment) assignAt(distance int, name string, value any) { e.ancestor(distance).values[name] = value } // assign assigns a new value to a variable in the environment. func (e *environment) assign(name string, value any) { _, ok := e.values[name] if !ok { if e.enclosing != nil { e.enclosing.assign(name, value) return } panic("Undefined variable '" + name + "'.") } e.values[name] = value }