[plt-scheme] Injecting syntax into load

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Thu Dec 7 13:16:58 EST 2006



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!


More information about the plt-scheme mailing list