~ chicken-core (chicken-5) 806c211b443a33bee673b50a46193257c9521775


commit 806c211b443a33bee673b50a46193257c9521775
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Sun Sep 26 22:05:03 2010 +0200
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Sun Sep 26 22:05:03 2010 +0200

    ir-macro-transformer docs by sjamaan

diff --git a/manual/Macros b/manual/Macros
index 5c40447c..796e189a 100644
--- a/manual/Macros
+++ b/manual/Macros
@@ -149,7 +149,7 @@ as
                   (else `(,(rename 'if)
                           ,test
                            (,(rename 'begin) ,@(cdr first))
-                           (cond ,@rest))))))))
+                           (,(r 'cond) ,@rest))))))))
 
 In this example the identifier {{else}} is renamed before being passed
 to the comparison predicate, so the comparison will be true if and
@@ -159,6 +159,9 @@ as {{else}} denotes in the syntactic environment in which the {{cond}}
 macro was defined.  If {{else}} were not renamed before being passed to
 the comparison predicate, then it would match a local variable that
 happened to be named {{else}}, and the macro would not be hygienic.
+The final recursive call to {{cond}} also needs to be renamed because
+someone might create an alias for this macro and use it in a {{let}}
+where {{cond}} is an ordinary variable.
 
 Some macros are non-hygienic by design.  For example, the
 following defines a {{loop}} macro that implicitly binds {{exit}} to an
@@ -196,12 +199,89 @@ not hygienic.  Like {{loop}}, it must be written using procedurally:
           (,(r 'if) (,(r 'not) ,test) (exit #f))
           ,@body))))
 
+Think about it: If we ''did'' rename {{exit}}, it would refer to an
+{{exit}} procedure existing in the context of the macro's definition.
+That one [[Unit library#exit|actually exists]]; it is the procedure
+that exits the Scheme interpreter.  Definitely ''not'' the one we want :)
+So now we make it refer to an {{exit}} that's locally bound in the
+environment where the macro is expanded.
+
 Note: this implementation of explicit-renaming macros allows passing
 arbitrary expressions to the renaming and comparison procedures. When
 being renamed, a fresh copy of the expression will be produced, with all
 identifiers renamed appropriately. Comparison also supports arbitrary
 expressions as arguments.
 
+=== Implicit renaming macros
+
+Explicit renaming macros generally require the user to perform quite a
+few renames, because most identifiers that aren't taken from the input
+expression should generally be inserted hygienically.  It would make
+more sense to give the output expression as-is, and only explicitly
+convert those identifiers that you want to treat as ''unhygienic''.
+
+This can be done with implicit renaming macros.  They just swap the
+default insertion "mode" from unhygienic to hygienic, so to speak.
+Here's the {{cond}} example from the previous section as an ir-macro:
+
+
+  (ir-macro-transformer
+    (lambda (exp inject compare)
+      (let ((clauses (cdr exp)))
+        (if (null? clauses)
+            `(quote unspecified)
+            (let* ((first (car clauses))
+                   (rest (cdr clauses))
+                   (test (car first)))
+              (cond ((and (symbol? test)
+                          (compare test 'else))
+                     `(begin ,@(cdr first)))
+                    (else `(if ,test
+                               (begin ,@(cdr first))
+                               (cond ,@rest)))))))))
+
+In this example the identifier {{else}} does ''not'' need to be renamed
+before being passed to the comparison predicate because it is already
+''implicitly'' renamed.  This comparison will also be true if and
+only if the test expression is an identifier that denotes the same
+thing in the syntactic environment of the expression being transformed
+as {{else}} denotes in the syntactic environment in which the {{cond}}
+macro was defined.  If {{else}} were not renamed before being passed to
+the comparison predicate, then it would match a local variable that
+happened to be named {{else}}, and the macro would not be hygienic.
+
+As you can see, the code is a lot clearer because it isn't obscured
+by excessive renaming.
+
+Here's the {{loop}} macro so you can see how hygiene can be broken
+with implicit renaming macros:
+
+  (define-syntax loop
+    (ir-macro-transformer
+      (lambda (expr inject compare)
+        (let ((body (cdr expr)))
+          `(call-with-current-continuation
+            (lambda (,(inject 'exit))
+             (let f () ,@body (f))))))))
+
+The {{while}} macro is a little trickier: do we inject the call to
+{{exit}} or not?  Just like the explicit renaming macro version
+did ''not'' rename it, we must inject it to allow it to be captured
+by the {{loop}} macro:
+
+  (define-syntax while
+    (ir-macro-transformer
+      (lambda (expr inject compare)
+        (let ((test (cadr expr))
+              (body (cddr expr)))
+          `(loop
+            (if (not ,test) (,(inject 'exit) #f))
+            ,@body)))))
+
+Note: Just like explicit renaming macros, this implementation of
+implicit renaming macros allow passing arbitrary expressions to
+the injection and comparison procedures.  The injection procedure
+also return fresh copies of its input.
 
 ---
 Previous: [[Non-standard macros and special forms]]
diff --git a/manual/Unit expand b/manual/Unit expand
index 61fbceba..b9b6f41b 100644
--- a/manual/Unit expand	
+++ b/manual/Unit expand	
@@ -43,6 +43,31 @@ This procedure does nothing and is available for writing low-level
 macros in a more portable fashion, without hard-coding the signature
 of a transformer procedure.
 
+==== ir-macro-transformer
+
+<procedure>(ir-macro-transformer TRANSFORMER)</procedure>
+
+This procedure accepts a ''reverse'' syntax transformer, also known as
+an ''implicit renaming macro transformer''.  This is a transformer which
+works almost like er-macro-transformer, except the rename and compare
+procedures it receives work a little differently.
+
+The rename procedure is now called {{inject}} and instead of renaming
+the identifier to be resolved in the macro's definition environment,
+it will explicitly ''inject'' the identifier to be resolved in the
+expansion environment.  Any non-injected identifiers in the output
+expression produced by the transformer will be implicitly renamed to
+refer to the macro's environment instead.  All identifiers in the
+input expression are of course implicitly injected just like with
+explicit renaming macros.
+
+To compare an input identifier you can generally compare to the bare
+symbol and only free identifiers will match.  In practice, this means
+that when you would call e.g.  {{(compare (cadr expression) (rename 'x))}}
+in an ER macro, you simply call {{(compare (cadr expression) 'x)}} in the
+IR macro.  Likewise, an ''unhygienic'' ER macro's comparison
+{{(compare sym 'abc)}} should be written as {{(compare sym (inject 'abc))}}
+in an IR macro.
 
 ---
 Previous: [[Unit library]]
Trap