Pairs, boxes, and strings are hashed by values; vectors and structures
are "hashed" by reference. Takes into account the possibility of cycles.
This is a prelude to implementing hash-tables.
* Remap all instance variables in one pass, to avoid an insidious bug [1].
* Fix another bug by merging promote-shared-variables and narrow-binds [2].
* Don't assume different variable means different value in propogate-set!.
* Add support for (apply), (value-list) and (call-with-values) forms.
* Add support for including files (as if directly substituted) in reader.
* Use scheme/match library to simplify form pattern-matching.
* Refactor (map-form) and (search-form) using a more basic (traverse-form),
which just recurses over the form and returns void by default, and a
new utility function (curry-keywords) to provide default keyword arguments.
[1] Was renaming e.g. %f0 to %i0, then %i0 to %i1, which eliminates the
distinction between %f0 and %i0. Solution is to construct a map from old
names to new names, then traverse the form and change every old variable
to its new equivalent in the map exactly once.
[2] Some variables were not being promoted to boxes, as promotions only occur
at the top-level, when constructing each lambda, and narrow-binds could push
the unpromoted variables down into a subordinate lambda form first. Solution
was to promote variables immediately after narrowing bindings, including the
recursive calls which exist after pushing variables into nested scopes.
Module consists of mixed (declare ...) forms and expressions.
Groups of (declare ...) forms become (letrec ...)s surrounding
later expressions and (declare ...) groups.
The (declare (fn-name . arglist) forms...) syntax is supported.
Created one module one per pass, plus utilities functions, primitives, and output.
Changed extension to ".scm" for compatibility with hg syntax highlighting backend.
Was moving (set!) into the (%bind) form, and thus setting the wrong variable.
Now, if set! var is bound, will create a temporary for result of %bind first,
and set! original variable to temporary in the proper scope.
Also, normalize rules for nested (%bind)s:
* The (%bind) inside a (%lambda) is always flat.
- This is a responsiblity of simplify-lambda, and any function which
may change structure after simplification (e.g. promote-to-box).
* Any other (%bind) may be nested, unless otherwise noted.
Also:
- assume top-level free variables are constants, not boxes;
- bind variable 'argv' to top-level argument list, rather than assuming no arguments;
- make %values a first-class form, just like %apply and %call/cc (was: pseudo-primitive);
- fix case where 'rest' argument is sole item in argument list: (lambda argv ...); and
- perform misc. cleanup in output code.
Also performed misc. cleanup, corrected use of temp variables in (let ...),
changed make-bindings-unique to preserve original names as prefixes, improved
detection of unused %set! forms in reduce-set!, and fixed map-variables to
extract the real value from (quote ...) literal forms.
With this change, any (%bind) returned from (simplify-let) or (simplify-form)
can be assumed to be flat, with unique bound symbols. Before, this was only
true of (%lambda) forms and the output of (compile).
Exception is (%tail-call ...) form, which is permitted simply because
(%tail-call ...) transfers control unidirectionally; the enclosing
(%set! ...) form wouldn't be run anyway.
Maps lexical variables, decodes argument lists, and flattens procedures
to simple lists of primitive operations, but does not yet convert to
CPS or perform register (gN, iN, fN) allocation, much less optimization.
Should simplify error-handling and sequences of primitive tests.
Also, automatically instantiate templates used in the tail-call lambda & cont'n fields.
This is to separate the three 'call' parameters (target, argv, ctx) from
the 'return to' parameter (k). The old order made it look as if the dynamic
context was in some way related to the continuation, which is not the case.