[plt-scheme] Injecting syntax into load
On Thu, 7 Dec 2006, Norman Gray wrote:
> Can anyone tell me how I would inject new syntax into the syntax transformer 
> used by LOAD, in such a way that REQUIRE in the loaded file works?
Hi Norman,
Here's an example that might help:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module test mzscheme
   (parameterize ([current-namespace (make-namespace)])
     (namespace-transformer-require 'mzscheme)
     (eval
      ' (begin
          (define-syntax (double stx)
            (syntax-case stx ()
              [(_ x)
               (syntax/loc stx
                 (list x x))]))))
     (let loop ([s-expr (read)])
       (cond [(eof-object? s-expr) 'done]
             [else
              (display (eval s-expr))
              (newline)
              (loop (read))]))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Namespaces affect EVAL, so whenever we want to do something with them, we 
either need to use the namespace-specific functions, or EVAL/LOAD.
The code above injects a new macro into the newly constructed namespace, 
after which we can play around with it using the hacky repl there. 
(There's some issue with NAMESPACE-TRANSFORMER-REQUIRE that I don't quite 
understand fully, which I'll mention near the bottom.)
> but that doesn't work if the loaded file has module requirements (or 
> even if it has definitions following expressions), since these can only 
> appear at the top level.
Another example of this can be found in the code for mred's 
MAKE-NAMESPACE-WITH-MRED:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   (define make-namespace-with-mred
     (opt-lambda ([flag 'mred])
       (unless (memq flag '(initial mred empty))
 	(raise-type-error 'make-namespace-with-mred
 			  "flag symbol, one of 'mred, 'initial, or 'empty"
 			  flag))
       (let ([orig (current-namespace)]
 	    [ns (make-namespace (if (eq? flag 'empty) 'empty 'initial))])
 	(parameterize ([current-namespace ns])
 	  (namespace-attach-module orig mred-module-name)
 	  (when (eq? flag 'mred)
 	    (namespace-require mred-module-name)
 	    (namespace-require class-module-name)))
 	ns)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
So notice that they're using namespace-require.  You could probably do the 
same.  So, concretely:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module test mzscheme
   (require (lib "mred.ss" "mred"))
   (define (test1)
     (parameterize ([current-namespace (make-namespace-with-mred)])
       (eval '(new object%))))
   (define (test2)
     (parameterize ([current-namespace (make-namespace)])
       (eval '(new object%)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TEST1 succeeds, because it introduces macros for OOP stuff via the 
enriched namespace, but TEST2 fails.
There's some parts about the system that I'm still very wishy-washy about. 
For example, the documentation for make-namespace says:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
* 'initial (the default) -- the new namespace contains the module 
declarations of the initial namespace (see section 8.2), and the new 
namespace's normal top-level environment contains bindings and imports as 
in the initial namespace. However, the namespace's transformer top-level 
environment is empty.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I see that the last part, about the namespace's transformer top-level 
environment being empty, is true, since in the very first example, if I 
omit the call to NAMESPACE-TRANSFORMER-REQUIRE, the macro definition 
breaks.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
. compile: bad syntax; function application is not allowed, because no 
#%app syntax transformer is bound in: (syntax-case stx () ((_ x) 
(syntax/loc stx (list x x))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I'm just not quite sure yet why the transformer environment should be 
empty, or if there is something deeper here that I'm missing.
Best of wishes!