dismantles the scaffolds
high-level sketch of a functional interpreter

The main idea is pretty straightforward - instead of having mutable environment,
we make it immutable and pass it explicitly to every method of the intepreter.
an example of how one threads state in the proposed design

Nothing too fancy - no implicits, no State monad, just good old pattern matching
and variable renaming to keep track of updates to state.
pattern match that covers all interpretable TSTs

In order to save you the time of looking into what we want to interpret,
I've thrown together a pattern match that covers all typed ASTs (aka TSTs)
that can be interpreted.

Note that some of the trees described in http://den.sh/quasiquotes.html#syntax-overview
are ignored here. That's because typechecking changes the shapes of the trees,
and the guide linked above is about ASTs in general, not just TSTs.
trees that we want to skip

Some trees should be understandable by our interpreter, but it shouldn't do
anything about them. These trees are:
  1) EmptyTree (when used in an interpretable position it means "skip me")
  2) Type ascriptions and type applications (types are irrelevant to interpretation)
  3) Type definitions (for the same reason as #2)
  4) Imports (after typechecking, imports no longer matter, because typer has already resolved them)
interprets literals

Nothing fancy here, we just introduce a special method to go
from the world of JVM values to the world of interpreter values.

Note that we throw an unsupported exception when encountering classOf[T].
In principle, we could support those later on, but it's not that important
for macro interpretation, so let's skip that for now.
interprets blocks: immutability rocks!!

This commit shows off the niceties of immutable design.

Thanks to Env being immutable, interpretation of blocks is as simple as
interpretation of every statement from that block individually. Indeed,
purely functional programs compose very well!

Here we also introduce functions that update Env. We need three of those:
  1) Introduction of new local declaration into scope
  2) Assignment of a value's field
  3) Bulk import of global effects encapsulated by an instance of Env
interprets local declarations

The previous commit demonstrated updating the heap, and this commit
shows how to update lexical scope when we interpret local declarations.

Note that this code is only about locals. Since we ignore templates
(parts of classes, traits and modules) that define members, interpretation
never reaches non-local declarations.

Please note that we don't use names here - everything is based on symbols
that are always filled in in TSTs, because typer resolves all references.
This makes sure that our implementation is robust enough to handle everything
that Scala's scoping rules might throw at us (shadowing, renaming, import prioritization, etc).
interprets assignments

This commit completes the picture of Env mutators by handling assignments.

Note that after typechecking all assignments that actually stand for calls
to `update` methods get desugared into applications, so here we only have
to deal with real assignments.

Note that typechecking normalizes all references, which means that all
qualified references become qualified, even if they were written unqualified.
For example `x` in the following code would become `this.x` in TST:

  class C {
    def x = 42
    println(x) // will be typechecked as println(this.x)
  }

This little bit of knowledge allows us to distinguish assignments to
local variables and assignments to fields.
interprets references

Sketches interpretation of references (Ident, Select and This nodes).
Implementation is going to be split between name lookups in Env and
member lookups in Value.

Please note that all lookups happen using symbols, not names.
This makes sure that our implementation is as robust as possible.
interprets new

This commit handles another fundamental tree, and in this case there's
some sort of a twist.

The thing is that at a glance New seems to be completely unrelated to
its usages in Scala code (`new C`, `new C { ... }`, etc).

Handling of object instantiation is indeed quite an obscure area of scalac.

First of all, complex `new C { ... }` constructs (those that have multiple
parent classes or an explicitly specifed {...} block) are desugared into
an anonymous class definition + its instantiation.

Secondly, simple `new C(1, 2)` constructs are parsed in an unusual way:
Apply(Select(New(Ident(C)), <init>), List(1, 2). Quite a roundabout approach
to representing instantiation, right? Well, yes.

However, for our purposes this extravagant encoding of constructor invocations
actually makes a lot of sense. We can interpret New(_) in a very simple manner,
namely as creation of a raw Value, and then the constructor will be called
for us later when execution flows into the Apply part of the instantiation expression.
completes the sketch of interpreter values

Functions, applications, and conditions complete the list of Value-related
interpreter primitives