Interpreter Project: Resolving and Binding

In this chapter the interpreter gets much smarter about scopes and the variables available in them. A Resolver class was added to analyze the code before the interpreter acually runs it.

You can find my progress here.

Semantic Analysis

The Resolver code is really a semantic analysis step. It walks through the parse tree nodes and sets aside some data as it goes. In particular it makes note of variables that are available at the start of a function or a block and which environment they are in. It then sets that up for the interpreter to use while it is running the code.

This prevents problems such as the following:

var a = "global";
{
  fun show() {
    print a;
  }

  show();

  var a = "block";

  show();
}

The problem in the above example, and with the interpreter, is that when the first show() call runs it will correctly print out "global", but when the second call to show() runs it will print "block". This happens because during the first call the local var does not yet exist in the environment, so the environement looks at enclosing environment and finds the global a. However, at the point of the second call to show() the local environment has been updated with the new variable.

This is not the behavior we want. The show() function is a closure. Its environment should be defined at the time of the function definition and not change.

There is quite a bit of code to prevent that bug. The Resolver is structured much like the Interpreter class. It implements the Visitor pattern and defines visit_* methods for all of the AST Node classes. Instead of running the code, as the Interpreter does, it makes note of variables in certain AST Nodes such as functions and blocks.

When the Resolver comes across a block like the one above it sees the function, notes that it references the a variable, determines how many steps away the variable is and then squirrels away that information in the Interpreter. Later, when the Interpreter is running the code it uses that distance information to always look up the same variable for the duration of the block.

Moving Forward

Down to the last two chapters in the first section of Crafting Interpreters. Next up is Classes. I took a quick peek at it and it seems to be fairly long. I imagine there will be quite a bit of new functionality to add. New parsing rules for the keywords. New semantics for calling methods rather than functions. New scopes for storing variables in. It should be an interesting section.