Guile
wingo just patched a pretty interesting
issue I discovered in Guile's psyntax implementation. Guile
uses a modified version of the expander that's module aware,
so that lookups and bindings are done -- and hygiene is
maintained -- with respect to module eval closures.
Top-level definition forms, for example, such as `define'
or `define-syntax', create bindings in whatever Guile
thinks the "current" module is.
This works great, but there's a wrinkle added by the fact
that the expansion process can change the current module.
`define-module', for example, does this, by way of an
`eval-when' -- after creating a new module, the modules
system makes it current, so that if you've got a
sequence of expressions like:
(define-module (foo))
(define foo 'foo)
(define bar 'bar)
(define baz 'baz)
...then `foo', `bar', and `baz' will be visible to `(foo)'
and not to whatever module was current when you called
`define-module'. The issue I found involved a slight
modification to this pattern, wrapping everything in a
`begin' form:
(begin
(define-module (foo))
(define-foo 'foo)
...)
Semantically, this should be equivalent to the first form --
at the top level, `begin' splices its contents into the
surrounding code as if it weren't even there, enabling you
to produce multi-expression, uh, expressions, even in
contexts where you're only allowed to produce one, like in
the syntax transformer I was writing. But what I was seeing
was that my definitions weren't creating bindings in the
modules I'd placed them "within" -- particularly hard to
troubleshoot when it came syntax definition, since the
expander just allowed unbound custom syntax expressions to
pass through to the evaluator, assuming they were procedure
applications.
The root cause was that Guile didn't anticipate changes to
the current module during the expansion of a single
top-level form -- so the first form I described would be
fine, since the expander would be re-initialized with the
current module for each expression; but the second form
would only check the current module once, for the `begin',
and not after any of the expressions inside it. After
Andy's patch, the part of the expander that handles
top-level `begin' forms (`chi-top-sequence') checks the
current module after each expression in the sequence to see
if it's changed and updates the expansion environment
appropriately.
R6RS
All of the above has allowed me to make a fair bit of
headway on the R6RS front. A while back I'd gotten started
on implementations of the R6RS "standard libraries" and
started merging them (along with test suites as appropriate)
into Guile's module set (see the wip-r6rs-libraries
branch), but I'd had to stop because of the difficulties
caused by the issue above (which took me a very long time to
isolate and properly articulate). Now I can start again!