The final pass before code-generation has, as its only job, to deal with variables and lambdas.
It converts each variable reference into a ``free reference'' or a ``bound reference'', depending on whether the variable is found in the immediately-enclosing lambda or not. This reference includes the index into either the formals list of the immediately-enclosing lambda, or into the free variables list.
It converts lambda expressions into ``build-closure'' expressions:
These expressions can be viewed much like calls to the primitive(build-closure (lambda formals body) free-reference ...)
vector (so ``build-closure'' could be considered to be an
inlined primitive). build-closure takes as its first
``argument'' an old-style lambda expression, and as its second and
further arguments it takes ``references'' to the free variables of
that lambda expression.
(define list-index
(lambda (v ls)
(let loop ([ls ls] [acc 0])
(cond
[(null? ls) #f]
[(eq? (car ls) v) acc]
[else (loop (cdr ls) (add1 acc))]))))
> (code-generation-form '(cons '1 '2))
(cons '1 '2)
> (code-generation-form '(lambda (x) '(free) x))
(build-closure (lambda (x) (bound 0 x)))
> (code-generation-form '
(lambda (x) '(free) (lambda (y) '(free x) x)))
(build-closure
(lambda (x)
(build-closure (lambda (y) (free 0 x)) (bound 0 x))))
> (code-generation-form
'(lambda (x)
'(free)
(lambda (y z)
'(free x)
(lambda (w) '(free x y z) (w x y z)))))
(build-closure
(lambda (x)
(build-closure
(lambda (y z)
(build-closure
(lambda (w) ((bound 0 w) (free 0 x) (free 1 y) (free 2 z)))
(free 0 x)
(bound 0 y)
(bound 1 z)))
(bound 0 x))))