Merge commit 'f6ddf827f8f192af7a8cd255bd8374a0d38bbb74'
authorAndy Wingo <wingo@pobox.com>
Fri, 7 Feb 2014 13:51:42 +0000 (14:51 +0100)
committerAndy Wingo <wingo@pobox.com>
Fri, 7 Feb 2014 13:51:42 +0000 (14:51 +0100)
Conflicts:
module/ice-9/boot-9.scm
module/oop/goops.scm

1  2 
doc/ref/api-macros.texi
module/ice-9/boot-9.scm
module/ice-9/poll.scm
module/oop/goops.scm
module/system/foreign.scm

@@@ -1201,180 -1193,37 +1201,205 @@@ The fix is to use @code{eval-when}
  @end example
  
  @deffn {Syntax} eval-when conditions exp...
- Evaluate @var{exp...} under the given @var{conditions}. Valid conditions include
- @code{eval}, @code{load}, and @code{compile}. If you need to use
- @code{eval-when}, use it with all three conditions, as in the above example.
- Other uses of @code{eval-when} may void your warranty or poison your cat.
+ Evaluate @var{exp...} under the given @var{conditions}.  Valid
+ conditions include:
+ @table @code
+ @item expand
+ Evaluate during macro expansion, whether compiling or not.
+ @item load
+ Evaluate during the evaluation phase of compiled code, e.g. when loading
+ a compiled module or running compiled code at the REPL.
+ @item eval
+ Evaluate during the evaluation phase of non-compiled code.
+ @item compile
+ Evaluate during macro expansion, but only when compiling.
+ @end table
+ In other words, when using the primitive evaluator, @code{eval-when}
+ expressions with @code{expand} are run during macro expansion, and those
+ with @code{eval} are run during the evaluation phase.
+ When using the compiler, @code{eval-when} expressions with either
+ @code{expand} or @code{compile} are run during macro expansion, and
+ those with @code{load} are run during the evaluation phase.
+ When in doubt, use the three conditions @code{(expand load eval)}, as in
+ the example above.  Other uses of @code{eval-when} may void your
+ warranty or poison your cat.
  @end deffn
  
 +@node Macro Expansion
 +@subsection Macro Expansion
 +
 +Usually, macros are expanded on behalf of the user as needed.  Macro
 +expansion is an integral part of @code{eval} and @code{compile}.  Users
 +can also expand macros at the REPL prompt via the @code{expand} REPL
 +command; @xref{Compile Commands}.
 +
 +Macros can also be expanded programmatically, via @code{macroexpand},
 +but the details get a bit hairy for two reasons.
 +
 +The first complication is that the result of macro-expansion isn't
 +Scheme: it's Tree-IL, Guile's high-level intermediate language.
 +@xref{Tree-IL}.  As ``hygienic macros'' can produce identifiers that are
 +distinct but have the same name, the output format needs to be able to
 +represent distinctions between variable identities and names.  Again,
 +@xref{Tree-IL}, for all the details.  The easiest thing is to just run
 +@code{tree-il->scheme} on the result of macro-expansion:
 +
 +@lisp
 +(macroexpand '(+ 1 2))
 +@result{}
 +#<tree-il (call (toplevel +) (const 1) (const 2))>
 +
 +(use-modules (language tree-il))
 +(tree-il->scheme (macroexpand '(+ 1 2)))
 +@result{}
 +(+ 1 2)
 +@end lisp
 +
 +The second complication involves @code{eval-when}.  As an example, what
 +would it mean to macro-expand the definition of a macro?
 +
 +@lisp
 +(macroexpand '(define-syntax qux (identifier-syntax 'bar)))
 +@result{}
 +?
 +@end lisp
 +
 +The answer is that it depends who is macro-expanding, and why.  Do you
 +define the macro in the current environment?  Residualize a macro
 +definition?  Both?  Neither?  The default is to expand in ``eval'' mode,
 +which means an @code{eval-when} clauses will only proceed when
 +@code{eval} (or @code{expand}) is in its condition set.  Top-level
 +macros will be @code{eval}'d in the top-level environment.
 +
 +In this way @code{(macroexpand @var{foo})} is equivalent to
 +@code{(macroexpand @var{foo} 'e '(eval))}.  The second argument is the
 +mode (@code{'e} for ``eval'') and the second is the
 +eval-syntax-expanders-when parameter (only @code{eval} in this default
 +setting).
 +
 +But if you are compiling the macro definition, probably you want to
 +reify the macro definition itself.  In that case you pass @code{'c} as
 +the second argument to @code{macroexpand}.  But probably you want the
 +macro definition to be present at compile time as well, so you pass
 +@code{'(compile load eval)} as the @var{esew} parameter.  In fact
 +@code{(compile @var{foo} #:to 'tree-il)} is entirely equivalent to
 +@code{(macroexpand @var{foo} 'c '(compile load eval))}; @xref{The Scheme
 +Compiler}.
 +
 +It's a terrible interface; we know.  The macroexpander is somewhat
 +tricksy regarding modes, so unless you are building a macro-expanding
 +tool, we suggest to avoid invoking it directly.
 +
 +
 +@node Hygiene and the Top-Level
 +@subsection Hygiene and the Top-Level
 +
 +Consider the following macro.
 +
 +@lisp
 +(define-syntax-rule (defconst name val)
 +  (begin
 +    (define t val)
 +    (define-syntax-rule (name) t)))
 +@end lisp
 +
 +If we use it to make a couple of bindings:
 +
 +@lisp
 +(defconst foo 42)
 +(defconst bar 37)
 +@end lisp
 +
 +The expansion would look something like this:
 +
 +@lisp
 +(begin
 +  (define t 42)
 +  (define-syntax-rule (foo) t))
 +(begin
 +  (define t 37)
 +  (define-syntax-rule (bar) t))
 +@end lisp
 +
 +As the two @code{t} bindings were introduced by the macro, they should
 +be introduced hygienically -- and indeed they are, inside a lexical
 +contour (a @code{let} or some other lexical scope).  The @code{t}
 +reference in @code{foo} is distinct to the reference in @code{bar}.
 +
 +At the top-level things are more complicated.  Before Guile 2.2, a use
 +of @code{defconst} at the top-level would not introduce a fresh binding
 +for @code{t}.  This was consistent with a weaselly interpretation of the
 +Scheme standard, in which all possible bindings may be assumed to exist,
 +at the top-level, and in which we merely take advantage of toplevel
 +@code{define} of an existing binding being equivalent to @code{set!}.
 +But it's not a good reason.
 +
 +The solution is to create fresh names for all bindings introduced by
 +macros -- not just bindings in lexical contours, but also bindings
 +introduced at the top-level.
 +
 +However, the obvious strategy of just giving random names to introduced
 +toplevel identifiers poses a problem for separate compilation.  Consider
 +without loss of generality a @code{defconst} of @code{foo} in module
 +@code{a} that introduces the fresh top-level name @code{t-1}.  If we
 +then compile a module @code{b} that uses @code{foo}, there is now a
 +reference to @code{t-1} in module @code{b}.  If module @code{a} is then
 +expanded again, for whatever reason, for example in a simple
 +recompilation, the introduced @code{t} gets a fresh name; say,
 +@code{t-2}.  Now module @code{b} has broken because module @code{a} no
 +longer has a binding for @code{t-1}.
 +
 +If introduced top-level identifiers ``escape'' a module, in whatever
 +way, they then form part of the binary interface (ABI) of a module.  It
 +is unacceptable from an engineering point of view to allow the ABI to
 +change randomly.  (It also poses practical problems in meeting the
 +recompilation conditions of the Lesser GPL license, for such modules.)
 +For this reason many people prefer to never use identifier-introducing
 +macros at the top-level, instead making those macros receive the names
 +for their introduced identifiers as part of their arguments, or to
 +construct them programmatically and use @code{datum->syntax}.  But this
 +approach requires omniscience as to the implementation of all macros one
 +might use, and also limits the expressive power of Scheme macros.
 +
 +There is no perfect solution to this issue.  Guile does a terrible thing
 +here.  When it goes to introduce a top-level identifier, Guile gives the
 +identifier a pseudo-fresh name: a name that depends on the hash of the
 +source expression in which the name occurs.  The result in this case is
 +that the introduced definitions expand as:
 +
 +@lisp
 +(begin
 +  (define t-1dc5e42de7c1050c 42)
 +  (define-syntax-rule (foo) t-1dc5e42de7c1050c))
 +(begin
 +  (define t-10cb8ce9fdddd6e9 37)
 +  (define-syntax-rule (bar) t-10cb8ce9fdddd6e9))
 +@end lisp
 +
 +However, note that as the hash depends solely on the expression
 +introducing the definition, we also have:
 +
 +@lisp
 +(defconst baz 42)
 +@result{} (begin
 +    (define t-1dc5e42de7c1050c 42)
 +    (define-syntax-rule (baz) t-1dc5e42de7c1050c))
 +@end lisp
 +
 +Note that the introduced binding has the same name!  This is because the
 +source expression, @code{(define t 42)}, was the same.  Probably you
 +will never see an error in this area, but it is important to understand
 +the components of the interface of a module, and that interface may
 +include macro-introduced identifiers.
 +
 +
  @node Internal Macros
  @subsection Internal Macros
  
Simple merge
Simple merge
@@@ -1,6 -1,6 +1,6 @@@
  ;;; installed-scm-file
  
- ;;;; Copyright (C) 1998,1999,2000,2001,2002, 2003, 2006, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
 -;;;; Copyright (C) 1998,1999,2000,2001,2002, 2003, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
++;;;; Copyright (C) 1998,1999,2000,2001,2002, 2003, 2006, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
  ;;;; Copyright (C) 1993-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
  ;;;;
  ;;;; This library is free software; you can redistribute it and/or
  (define *goops-module* (current-module))
  
  ;; First initialize the builtin part of GOOPS
- (eval-when (eval load compile)
+ (eval-when (expand load eval)
    (%init-goops-builtins))
  
- (eval-when (eval load compile)
+ (eval-when (expand load eval)
    (use-modules ((language tree-il primitives) :select (add-interesting-primitive!)))
 -  (add-interesting-primitive! 'class-of)
 -  (define (@slot-ref o n)
 -    (struct-ref o n))
 -  (define (@slot-set! o n v)
 -    (struct-set! o n v))
 -  (add-interesting-primitive! '@slot-ref)
 -  (add-interesting-primitive! '@slot-set!))
 +  (add-interesting-primitive! 'class-of))
  
  ;; Then load the rest of GOOPS
  (use-modules (oop goops util)
             (oop goops compile))
  
  \f
- (eval-when (eval load compile)
 +;; FIXME: deprecate.
+ (eval-when (expand load eval)
    (define min-fixnum (- (expt 2 29)))
    (define max-fixnum (- (expt 2 29) 1)))
  
Simple merge