Hi Andy, thanks for the quick feedback. I'll respond to the rest of your email later, but just a few quick notes for now:
> What are the meanings of these expressions: > > ;; Toplevel > (local-eval '(define foo 42) (the-environment)) > > ;; Lexical, tail context > (local-eval '(define foo 42) (let ((x 100)) (the-environment))) > > ;; Lexical, tail context -- but with a definition > (local-eval '(begin (define foo 42) foo) (let ((x 100)) (the-environment))) > > ;; Lexical, tail context -- but with a definition, and nested reference > (local-eval '(begin (define foo 42) (bar)) > (let ((x 100)) (define (bar) foo) (the-environment))) > > ;; Lexical, not a definition context > (local-eval '(define foo 42) (let ((x 100)) not-a-definition > (the-environment))) All of these will raise errors, because my current implementation of `local-eval' (I just posted a new version of the evaluator-only patch) uses `expand' instead of `expand-top-sequence' to expand the local expression, therefore definitions are not allowed. > What about this one: > > ;; Keeping in mind that `or' expands to (let ((t ...)) (if t t ...)), > ;; hygienically > (local-eval 't '(let ((t 42)) (or #f (the-environment)))) Yes, even my first patch handles this properly (though you must use `primitive-eval', since the compiler currently barfs if it encounters `the-environment'): scheme@(guile-user)> (local-eval 't (primitive-eval '(let ((t 42)) (or #f (the-environment))))) $1 = 42 > Can you pass syntax objects into `local-eval'? I believe so, but I haven't verified that this works as it should. I don't have much experience using syntax-case. The expression passed to `local-eval' simply gets passed along to `expand' within psyntax.scm, using the saved "expander environment": i.e. the values of the `r', `w', and `mod' in psyntax, at the point where (the-environment) was expanded. This "expander environment" is stored in the tree-il representation of (the-environment). Here's what I currently see: scheme@(guile-user)> (local-eval #'t (primitive-eval '(let ((t 42)) (or #f (the-environment))))) ERROR: In procedure memoize-variable-access!: ERROR: Unbound variable: t This is the correct behavior, no? > Are let-syntax / letrec-syntax / nested define-syntax forms present in a > local environment? Yes: scheme@(guile-user)> (define env1 (primitive-eval '(let-syntax ((foo (syntax-rules () ((foo x) (quote x))))) (let ((x 1) (y 2)) (the-environment))))) scheme@(guile-user)> (local-eval '(foo (1 2)) env1) $3 = (1 2) scheme@(guile-user)> (define env2 (local-eval '(let-syntax ((bar (syntax-rules () ((bar x) (foo x))))) (let ((x 1) (z 3)) (the-environment))) env1)) scheme@(guile-user)> (local-eval '(bar (1 2)) env2) $5 = (1 2) scheme@(guile-user)> (local-eval '(foo (1 2)) env2) $6 = (1 2) > Currently these things never leave the expander. I suppose as long as > they are understood to be opaque, it would be OK. Agreed. However, it should be noted that if we compile a form containing (the-environment) into a .go file, the "expander environment" will have to be stored within the .go file as an embedded constant. This means that if the representations of r, w, or mod within psyntax changes, any .go files containing uses of (the-environment) will have to be recompiled, or else `local-eval' could fail ungracefully. This is indeed an unpleasant complication. Automatic recompilation could be achieved using a versioning scheme, using a separate expander-environment-version number. With some care, we could perhaps avoid needless recompilation of .go files that do not use (the-environment) when the expander environment version changes, though it might be a bit of a pain to do the necessary bookkeeping to determine whether a .go file contains any expander environments. I'll have to think more about this. Mark