To get the correct lexical reach and closures in the interpreter, all you have to do is follow these rules:
- In your interpreter, variables are always scanned in the environment table passed by the caller / saved as a variable, and not some global env-stack. That is,
eval(expression, env) => value . - When the interpreted code calls the function, the environment is NOT passed to this function.
apply(function, arguments) => value . - When an interpreted function is called, the environment in which its body is evaluated is the environment in which the definition of the function was defined, and has nothing to do with the caller. Therefore, if you have a local function, then this is a closure, that is, a data structure containing the
{function definition, env-at-definition-time} fields.
To extend this last bit in the Python-ish syntax:
x = 1 return lambda y: x + y
performed as if he
x = 1 return makeClosure(<AST for "lambda y: x + y">, {"x": x})
where the second dict argument can only be current-env, not the data structure built at this time. (On the other hand, saving all env, not just private variables, may cause a memory leak.)
Kevin reid
source share