@@ -232,16 +232,14 @@ we now have many more runtime errors, as well as unbound variable and function b

Let's begin with expressions. Expressions can be a lot of things, and we won't review them

all here (although you can see LANGUAGE in HW3 for that!). Instead, let's consider the subset of

expressions consisting of integer literals, boolean literals, variable reference expressions, the `nil` literal, and `if` expressions. One of these is not like the others: whereas the first four expression types are composed of literals or symbols, an `if` expression takes other expressions as arguments! In other words, it is a recursive expression.

expressions consisting of integer literals, boolean literals, variable reference expressions, the `nil` literal, and `if` expressions. One of these is not like the others: whereas the first four expression types are composed of literals or symbols, an `if` expression takes other expressions as arguments! In other words, it is a *recursive* expression.

So, we need our generator to generate more expressions, some of which will be recursive expressions and some of which will be literals or symbols. You may be able to envision a problem here: stack overflow! We choose a reasonably small maximum depth for expressions to address this, after which point we guarantee that a nonrecursive expression will be generated. We can think of the four aforementioned expression types as our base cases.

In this case, we need our generator to generate more expressions, some of which will be recursive expressions and some of which will be literals or symbols. You may be able to envision a problem here: stack overflow! We choose a reasonably small maximum depth for expressions to address this, after which point we guarantee that a nonrecursive expression will be generated. We can think of the four aforementioned expression types as our base cases.

Bindings are similar to expressions, but simpler in that their arguments are nodes, symbols, or

expressions, as opposed to other (non-expression) bindings.

So, we generate bindings, which generate expressions, which eventually terminate! This results in

only valid Trefoil V2 ASTs. Last time, in Trefoil V1, this was sufficient to generate exclusively

valid programs, but that is not the case in our smarter Trefoil V2 programs. Consider what happens in the following example:

Our general approach, then, is this: we generate bindings, which generate expressions, which eventually terminate. This results in only valid Trefoil V2 ASTs! If this were Trefoil V1, we would only be generating valid programs right now; recall that this was in fact the case in the previous Trefoil fuzzer, `stackFuzz`. However, our Trefoil V2 programs are more complicated, and we cannot eliminate runtime errors even in programs with valid ASTs. Consider what happens in the following example: