[plt-scheme] Can generated lexical (syntax) bindings work?
Hey all, I have a bit of a long problem (with a possibly shorter
answer). I'm trying to write a small module which allows you to
define a syntax definition in a separate context, so that it isn't
actually defined at the top level. Later when you want to use it, you
can declare that some syntax be run in that context, thus enabling
those syntax bindings. A quick example:
(define-syntax-in-context foo my-context
(syntax-rules () ((foo) 5)))
(foo) ; Syntax error, foo is not defined
(with-context my-context (foo)) ; Equivalent to just 5
Now, the problem I'm having is in saving the symbol foo from the
define-syntax-in-context call to actually bind to the "foo" in the
with-context call. Most of the approaches I've tried hasn't allowed
with-context to generate a new lexical binding for "foo". This is
definitely non-hygienic, but it seems like it should still be
possible. I've tried three things, all of which save information
about mappings from (context, syntax-name) -> transformer in one
fashion or another:
1. define-syntax-in-context saves the transformer syntax object in a
hash table keyed by the context symbol and the syntax name symbol,
both extracted using syntax-object->datum. With-context generates a
let-syntax form, and generates new syntax objects for the syntax-name
using datum->syntax-object. This doesn't seem to work, as (foo) is
still being interpreted as a top-level form.
The code it's generating is something like this:
(let-syntax ((foo (syntax-rules () ((foo) 5)))) (foo))
But it's still failing.
2. define-syntax-in-context effectively executes the transformer
expression, creating the actual transformer function. It also
declares a top-level macro with the same name. When that macro is
called, it looks up the current context from a global variable with
dynamic scope, and then applies the appropriate transformer. This
works, but since this requires a top-level syntax declaration and
uses dynamic scope, I find this solution unsatisfying.
3. Similar to the original, I save the transformer syntax objects in
a hash table. Instead of making let-syntax terms, I create a syntax
environment using syntax-local-make-definition-context and syntax-
local-bind-syntaxes, and apply it to the body using local-expand, and
return the result. This seems to work part of the time, as long as
the with-context is being called in the module where the syntax was
originally declared. However, it fails at weird times. For instance,
in this same macro, I made another syntax object which uses with-
context to process one set of syntax multiple times in different
contexts. That doesn't seem to work.
It seems that one of my troubles relates to the actual generated
symbol syntax-object made from datum->syntax-object, possibly related
to the context syntax object I have to pass. Am I making some sort of
silly mistake, or is there something wrong with the way I'm
approaching this problem?
Thanks in advance,
- Brian Chin