Re: syntax-locally-bound-identifiers, local-eval

2012-01-25 Thread Andy Wingo
Hi,

I'd like to clarify one point here.

On Mon 23 Jan 2012 13:52, Andy Wingo wi...@pobox.com writes:

 If we want to change the format of lexical-environment, we have two
 more compelling options.  One would be to make a compatible change,
 but that's not always possible.

An example of a compatible change would be adding a field to the record.
The embedded make-struct calls from the expansion would result in a
record with the new number of fields, but with #f for the new fields.

This is actually a quite powerful capability.  For example if we wanted
to add a field to list the names of the bound identifiers, for the
record printer, we could.  If at some point we decided that was a bad
idea, we change the record printer, and ignore those new fields.

That's the other thing: we are free to change the runtime, within the
local-eval module, to do what we like.  You won't ever get an old
runtime with a new expansion, so the problem is easier than it would
otherwise be.  The suggested approach of using an all-in-one wrapper
procedure still has the runtime compatibility problem, but it's just as
tricky (if not more) to manage, because you have to remember what free
identifiers the expanded procedures could have referenced.

 The second would be to define another lexical-environment-2 or
 something; new expansions of `the-environment' would embed references
 to this new vtable.  Record type predicates could distinguish them for
 the purposes of local-eval/local-compile.

The patches that I attached to this message use an abstraction to deal
with the env that is passed to local-eval / local-compile being a
module or a lexical-environment.  In the unlikely case that a
lexical-environment-2 is needed, it would be trivial to extend this
with a third case.  But there are a number of compatible changes to go
through before reaching this state.

In summary, I think we have the compatibility needs covered here
adequately.  I don't look expect radical changes in this area, but even
if they do make sense (quite possible), I don't see the drawbacks of
this approach.

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-locally-bound-identifiers, local-eval

2012-01-23 Thread Andy Wingo
Hi Mark!

Thanks for your review of my patches.  I would like to say, our
patches, as they are not really mine, but I understand if you don't
want to claim parentage in this case :)

I fixed the module-related scope issues by adding a new accessor for
syntax objects, `syntax-module'.  It is like Racket's
`syntax-source-module'.  I added your expanded test to eval.test, and it
works fine.

You mention versioning, but I believe that this is a non-issue.  If we
want to change the format of lexical-environment, we have two more
compelling options.  One would be to make a compatible change, but
that's not always possible.  The second would be to define another
lexical-environment-2 or something; new expansions of
`the-environment' would embed references to this new vtable.  Record
type predicates could distinguish them for the purposes of
local-eval/local-compile.

Here are the current patches.  I've manually removed the parts that
patch psyntax-pp.scm, to not hurt our eyeballs :)

From 68673f7507736f9a39d2d1eac9ef2a9ad1fd80dc Mon Sep 17 00:00:00 2001
From: Andy Wingo wi...@pobox.com
Date: Sun, 15 Jan 2012 18:39:44 +0100
Subject: [PATCH 1/3] add syntax-locally-bound-identifiers

* module/ice-9/boot-9.scm (syntax-locally-bound-identifiers): Declare
  variable.
* module/ice-9/psyntax.scm: Add locally-bound-identifiers helper, and
  define syntax-locally-bound-identifiers.
* module/ice-9/psyntax-pp.scm: Regenerated.
* doc/ref/api-macros.texi: Document the new procedure.
---
 doc/ref/api-macros.texi |   37 +-
 module/ice-9/boot-9.scm |1 +
 module/ice-9/psyntax-pp.scm |24438 +++
 module/ice-9/psyntax.scm|   59 +-
 4 files changed, 13078 insertions(+), 11457 deletions(-)

diff --git a/doc/ref/api-macros.texi b/doc/ref/api-macros.texi
index 4702d2f..02b5d5c 100644
--- a/doc/ref/api-macros.texi
+++ b/doc/ref/api-macros.texi
@@ -744,7 +744,7 @@ information with macros:
 (define-syntax-rule (with-aux aux value)
   (let ((trans value))
 (set! (aux-property trans) aux)
-trans)))
+trans))
 (define-syntax retrieve-aux
   (lambda (x)
 (syntax-case x ()
@@ -768,6 +768,41 @@ information with macros:
 a syntax transformer; to call it otherwise will signal an error.
 @end deffn
 
+@deffn {Scheme Procedure} syntax-locally-bound-identifiers id
+Return a list of identifiers that were visible lexically when the
+identifier @var{id} was created, in order from outermost to innermost.
+
+This procedure is intended to be used in specialized procedural macros,
+to provide a macro with the set of bound identifiers that the macro can
+reference.
+
+As a technical implementation detail, the identifiers returned by
+@code{syntax-locally-bound-identifiers} will be anti-marked, like the
+syntax object that is given as input to a macro.  This is to signal to
+the macro expander that these bindings were present in the original
+source, and do not need to be hygienically renamed, as would be the case
+with other introduced identifiers.  See the discussion of hygiene in
+section 12.1 of the R6RS, for more information on marks.
+
+@example
+(define (local-lexicals id)
+  (filter (lambda (x)
+(eq? (syntax-local-binding x) 'lexical))
+  (syntax-locally-bound-identifiers id)))
+(define-syntax lexicals
+  (lambda (x)
+(syntax-case x ()
+  ((lexicals) #'(lexicals lexicals))
+  ((lexicals scope)
+   (with-syntax (((id ...) (local-lexicals #'scope)))
+ #'(list (cons 'id id) ...))
+
+(let* ((x 10) (x 20)) (lexicals))
+@result{} ((x . 10) (x . 20))
+@end example
+@end deffn
+
+
 @node Defmacros
 @subsection Lisp-style Macro Definitions
 
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index 2c87d13..cd55203 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -390,6 +390,7 @@ If there is no handler at all, Guile prints an error and then exits.
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
 (define syntax-local-binding #f)
+(define syntax-locally-bound-identifiers #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 ;; expanded macros, to dispatch an input against a set of patterns.
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index fd33e98..024bb85 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -791,6 +791,55 @@
   id))
  (else (syntax-violation 'id-var-name invalid id id)
 
+;; A helper procedure for syntax-locally-bound-identifiers, which
+;; itself is a helper for transformer procedures.
+;; `locally-bound-identifiers' returns a list of all bindings
+;; visible to a syntax object with the given wrap.  They are in
+;; order from outer to inner.
+;;
+;; The purpose of this procedure is to give a transformer procedure
+;; references on bound identifiers, that the transformer can then
+;; introduce some of them in its output.  As such, the identifiers

Re: syntax-locally-bound-identifiers, local-eval

2012-01-21 Thread Ludovic Courtès
Andy Wingo wi...@pobox.com skribis:

   (define-syntax lexicals
 (lambda (x)
   (syntax-case x ()
 ((lexicals) #'(lexicals lexicals))
 ((lexicals scope)
  (with-syntax (((id ...)
 (filter (lambda (x)
   (eq? (syntax-local-binding x) 
 'lexical))
 (syntax-locally-bound-identifiers 
 #'scope
  #'(list (cons 'id id) ...))

   (let* ((x 10) (x 20)) (lexicals))
   = ((x . 10) (x . 20))

Ooooh, I’m starting to find it fun!  :-)

Ludo’.




Re: syntax-locally-bound-identifiers, local-eval

2012-01-21 Thread Mark H Weaver
Hi Andy,

 There's another thing that really should be fixed, for the sake of
 preserving our ability to change the implementation `local-eval' in the
 future.

 Since (the-environment) can be included in code compiled to disk, the
 lexical environment objects that it returns are effectively now part of
 our ABI.  As it is now, if we want to change the representation, we'll
 be in for a lot of headaches to support lexical environments produced by
 older code.

 The fix is simple: Simply change the representation of the lexical
 environment object to contain only a single field: a procedure that
 takes an expression (and optional keyword arguments) and does the
 equivalent of `local-eval' or `local-compile'.  (The keyword arguments
 should specify whether or not to compile, and the compile options).

 Then, `local-eval' and `local-compile', when applied to a lexical
 environment object, should simply call the embedded procedure.

To help facilitate this change, I've attached a small patch to change my
variant of `local-eval' to use this simple future-proof representation.
As you can see, the changes are simple and nicely localized.  I'll leave
it to you to adapt these changes to your implementation.

Also, see below for an improved the-environment within a macro test
that now checks that the proper module was stored in the lexical
environment.  Please verify that this works properly with your patch.

 Thanks!
   Mark


  (pass-if the-environment within a macro
(let ((module-a-name '(test module the-environment a))
  (module-b-name '(test module the-environment b)))
  (let ((module-a (resolve-module module-a-name))
(module-b (resolve-module module-b-name)))
(module-use! module-a (resolve-interface '(guile)))
(module-use! module-a (resolve-interface '(ice-9 local-eval)))
(eval '(begin
 (define z 3)
 (define-syntax-rule (test)
   (let ((x 1) (y 2))
 (the-environment
  module-a)
(module-use! module-b (resolve-interface '(guile)))
(let ((env (eval `(let ((x 111) (y 222))
((@@ ,module-a-name test)))
 module-b)))
  (equal? (local-eval '(list x y z) env)
  '(1 2 3))


diff --git a/module/ice-9/local-eval.scm b/module/ice-9/local-eval.scm
index ece1313..fb6752c 100644
--- a/module/ice-9/local-eval.scm
+++ b/module/ice-9/local-eval.scm
@@ -24,34 +24,20 @@
   #:export (local-eval local-compile))
 
 (define-record-type lexical-environment-type
-  (make-lexical-environment module wrapper boxes pattern-bindings
-var-names pattern-var-names unsupported-names)
+  (make-lexical-environment version evaluator)
   lexical-environment?
-  (modulelexenv-module)
-  (wrapper   lexenv-wrapper)
-  (boxes lexenv-boxes)
-  (pattern-bindings  lexenv-pattern-bindings)
-  (var-names lexenv-var-names)
-  (pattern-var-names lexenv-pattern-var-names)
-  (unsupported-names lexenv-unsupported-names))
+  (version   lexenv-version)
+  (evaluator lexenv-evaluator))
 
 (set-record-type-printer!
  lexical-environment-type
  (lambda (e port)
-   (format port #lexical-environment ~S ~S ~S ~S
-   (module-name (lexenv-module e))
-   (reverse (map (lambda (name box) (list name (box)))
- (lexenv-var-names e) (lexenv-boxes e)))
-   (reverse (lexenv-pattern-var-names e))
-   (reverse (lexenv-unsupported-names e)
+   (format port #lexical-environment)))
 
 (define (local-eval x e)
   Evaluate the expression @var{x} within the lexical environment @var{e}.
   (cond ((lexical-environment? e)
- (apply (eval ((lexenv-wrapper e) x)
-  (lexenv-module e))
-(append (lexenv-boxes e)
-(lexenv-pattern-bindings e
+ ((lexenv-evaluator e) x #f))
 ((module? e)
  ;; Here we evaluate the expression within `lambda', and then
  ;; call the resulting procedure outside of the dynamic extent
@@ -64,11 +50,7 @@
 (define* (local-compile x e #:key (opts '()))
   Compile and evaluate the expression @var{x} within the lexical environment @var{e}.
   (cond ((lexical-environment? e)
- (apply (compile ((lexenv-wrapper e) x)
- #:env (lexenv-module e)
- #:from 'scheme #:opts opts)
-(append (lexenv-boxes e)
-(lexenv-pattern-bindings e
+ ((lexenv-evaluator e) x opts))
 ((module? e)
  ;; Here we compile the expression within `lambda', and then
  ;; call the resulting procedure outside of the dynamic extent
@@ -109,18 +91,21 @@
(((nested-pvar ...)
  (map within-nested-ellipses #'(pvar ...) #'(pvar-lvl ...
  #'(make-lexical-environment
-

syntax-locally-bound-identifiers, local-eval

2012-01-20 Thread Andy Wingo
Hello,

Here are a couple of patches.  The first implements a new helper,
syntax-locally-bound-identifiers, documented thusly:

 -- Scheme Procedure: syntax-locally-bound-identifiers id
 Return a list of identifiers that were visible lexically when the
 identifier ID was created, in order from outermost to innermost.

 This procedure is intended to be used in specialized procedural
 macros, to provide a macro with the set of bound identifiers that
 the macro can reference.

 As a technical implementation detail, the identifiers returned by
 `syntax-locally-bound-identifiers' will be anti-marked, like the
 syntax object that is given as input to a macro.  This is to
 signal to the macro expander that these bindings were present in
 the original source, and do not need to be hygienically renamed,
 as would be the case with other introduced identifiers.  See the
 discussion of hygiene in section 12.1 of the R6RS, for more
 information on marks.

  (define-syntax lexicals
(lambda (x)
  (syntax-case x ()
((lexicals) #'(lexicals lexicals))
((lexicals scope)
 (with-syntax (((id ...)
(filter (lambda (x)
  (eq? (syntax-local-binding x) 
'lexical))
(syntax-locally-bound-identifiers 
#'scope
 #'(list (cons 'id id) ...))

  (let* ((x 10) (x 20)) (lexicals))
  = ((x . 10) (x . 20))

The second implements local-eval, in a separate module.

There are a couple of notable changes in this version: firstly, it
correctly preserves the scope resolution order of scopes between normal
lexicals, macros, and pattern variables.  It includes all of the
original marks of all identifiers.  It also wraps pattern variables
now, and doesn't re-box normal lexicals.

Thoughts?  I will commit them tomorrow if there are no objections to the
semantics.

Thanks very much to Mark for his great work on the patches that inspired
these ones, even though he might wish to disavow this particular
implementation strategy :-)

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-locally-bound-identifiers, local-eval

2012-01-20 Thread Andy Wingo
On Fri 20 Jan 2012 13:33, Andy Wingo wi...@pobox.com writes:

 Here are a couple of patches.

Aaaand, the patches:

From f549f273139bda9591194766157bb771a67d9563 Mon Sep 17 00:00:00 2001
From: Andy Wingo wi...@pobox.com
Date: Sun, 15 Jan 2012 18:39:44 +0100
Subject: [PATCH 1/2] add syntax-locally-bound-identifiers

* module/ice-9/boot-9.scm (syntax-locally-bound-identifiers): Declare
  variable.
* module/ice-9/psyntax.scm: Add locally-bound-identifiers helper, and
  define syntax-locally-bound-identifiers.
* doc/ref/api-macros.texi: Document the new procedure.
---
 doc/ref/api-macros.texi  |   37 ++-
 module/ice-9/boot-9.scm  |1 +
 module/ice-9/psyntax.scm |   55 ++
 3 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/doc/ref/api-macros.texi b/doc/ref/api-macros.texi
index 4702d2f..02b5d5c 100644
--- a/doc/ref/api-macros.texi
+++ b/doc/ref/api-macros.texi
@@ -744,7 +744,7 @@ information with macros:
 (define-syntax-rule (with-aux aux value)
   (let ((trans value))
 (set! (aux-property trans) aux)
-trans)))
+trans))
 (define-syntax retrieve-aux
   (lambda (x)
 (syntax-case x ()
@@ -768,6 +768,41 @@ information with macros:
 a syntax transformer; to call it otherwise will signal an error.
 @end deffn
 
+@deffn {Scheme Procedure} syntax-locally-bound-identifiers id
+Return a list of identifiers that were visible lexically when the
+identifier @var{id} was created, in order from outermost to innermost.
+
+This procedure is intended to be used in specialized procedural macros,
+to provide a macro with the set of bound identifiers that the macro can
+reference.
+
+As a technical implementation detail, the identifiers returned by
+@code{syntax-locally-bound-identifiers} will be anti-marked, like the
+syntax object that is given as input to a macro.  This is to signal to
+the macro expander that these bindings were present in the original
+source, and do not need to be hygienically renamed, as would be the case
+with other introduced identifiers.  See the discussion of hygiene in
+section 12.1 of the R6RS, for more information on marks.
+
+@example
+(define (local-lexicals id)
+  (filter (lambda (x)
+(eq? (syntax-local-binding x) 'lexical))
+  (syntax-locally-bound-identifiers id)))
+(define-syntax lexicals
+  (lambda (x)
+(syntax-case x ()
+  ((lexicals) #'(lexicals lexicals))
+  ((lexicals scope)
+   (with-syntax (((id ...) (local-lexicals #'scope)))
+ #'(list (cons 'id id) ...))
+
+(let* ((x 10) (x 20)) (lexicals))
+@result{} ((x . 10) (x . 20))
+@end example
+@end deffn
+
+
 @node Defmacros
 @subsection Lisp-style Macro Definitions
 
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index d006d47..8d28c87 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -390,6 +390,7 @@ If there is no handler at all, Guile prints an error and then exits.
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
 (define syntax-local-binding #f)
+(define syntax-locally-bound-identifiers #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 ;; expanded macros, to dispatch an input against a set of patterns.
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index fd33e98..422347d 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -791,6 +791,55 @@
   id))
  (else (syntax-violation 'id-var-name invalid id id)
 
+;; A helper procedure for syntax-locally-bound-identifiers, which
+;; itself is a helper for transformer procedures.
+;; `locally-bound-identifiers' returns a list of all bindings
+;; visible to a syntax object with the given wrap.  They are in
+;; order from outer to inner.
+;;
+;; The purpose of this procedure is to give a transformer procedure
+;; references on bound identifiers, that the transformer can then
+;; introduce some of them in its output.  As such, the identifiers
+;; are anti-marked, so that rebuild-macro-output doesn't apply new
+;; marks to them.
+;;
+(define locally-bound-identifiers
+  (lambda (w mod)
+(define scan
+  (lambda (subst results)
+(if (null? subst)
+results
+(let ((fst (car subst)))
+  (if (eq? fst 'shift)
+  (scan (cdr subst) results)
+  (let ((symnames (ribcage-symnames fst))
+(marks (ribcage-marks fst)))
+(if (vector? symnames)
+(scan-vector-rib subst symnames marks results)
+(scan-list-rib subst symnames marks results
+(define scan-list-rib
+  (lambda (subst symnames marks results)
+(let f ((symnames symnames) (marks marks) (results results))
+  (if (null? symnames

Re: syntax-locally-bound-identifiers, local-eval

2012-01-20 Thread Mark H Weaver
Hi Andy.  Thanks for following through on this.  As you probably
noticed, my motivation to work on `local-eval' has largely dissipated,
so it's great that you finished this up in time for 2.0.4.

I haven't yet had time to fully review these patches, but for now, a
quick scan reveals a few remaining problems.  See below:

Andy Wingo wi...@pobox.com writes:
 +(define-syntax the-environment
 +  (lambda (x)
 +(syntax-case x ()
 +  ((the-environment)
 +   #'(the-environment the-environment))
 +  ((the-environment scope)
 +   (call-with-values (lambda ()
 +   (analyze-identifiers
 +(syntax-locally-bound-identifiers #'scope)))
 + (lambda (capture formals wrappers patterns)
 +   (define (wrap-expression x)
 + (let lp ((x x) (wrappers wrappers))
 +   (if (null? wrappers)
 +   x
 +   (lp ((car wrappers) x) (cdr wrappers)
 +   (with-syntax ((module (datum-syntax #'here (module-name 
 (current-module

* Again, the module must be the one embedded in `scope', not the
(current-module).  I guess this is a reminder that I need to add a more
thorough set of regression tests for `local-eval'.

 +(define (local-eval x e)
 +  Evaluate the expression @var{x} within the lexical environment @var{e}.
 +  (cond ((lexical-environment? e)
 + (apply (eval (local-expand x e) (lexenv-module e))
 +(lexenv-boxes e)))
 +((module? e)
 + ;; Here we evaluate the expression within `lambda', and then
 + ;; call the resulting procedure outside of the dynamic extent
 + ;; of `eval'.  We do this because `eval' sets (current-module)
 + ;; within its dynamic extent, and we don't want that.  Also,
 + ;; doing it this way makes this a proper tail call.
 + ((eval #`(lambda () #,x) e)))

* Again, there should be an `#f' before `#,x' here, to force
expression context (my mistake).

 +(else (error local-eval: invalid lexical environment e
 +
 +(define* (local-compile x e #:key (opts '()))
 +  Compile and evaluate the expression @var{x} within the lexical 
 environment @var{e}.
 +  (cond ((lexical-environment? e)
 + (apply (compile (local-expand x e)
 + #:env (lexenv-module e)
 + #:from 'scheme #:opts opts)
 +(lexenv-boxes e)))
 +((module? e)
 + ;; Here we compile the expression within `lambda', and then
 + ;; call the resulting procedure outside of the dynamic extent
 + ;; of `compile'.  We do this because `compile' sets
 + ;; (current-module) during evaluation, and we don't want that.
 + ((compile #`(lambda () #,x)

* Ditto.

 +   #:env e #:from 'scheme #:opts opts)))
 +(else (error local-compile: invalid lexical environment e

I'll try to do a more thorough review later.

Thanks,
  Mark



Re: syntax-locally-bound-identifiers, local-eval

2012-01-20 Thread Mark H Weaver
There's another thing that really should be fixed, for the sake of
preserving our ability to change the implementation `local-eval' in the
future.

Since (the-environment) can be included in code compiled to disk, the
lexical environment objects that it returns are effectively now part of
our ABI.  As it is now, if we want to change the representation, we'll
be in for a lot of headaches to support lexical environments produced by
older code.

The fix is simple: Simply change the representation of the lexical
environment object to contain only a single field: a procedure that
takes an expression (and optional keyword arguments) and does the
equivalent of `local-eval' or `local-compile'.  (The keyword arguments
should specify whether or not to compile, and the compile options).

Then, `local-eval' and `local-compile', when applied to a lexical
environment object, should simply call the embedded procedure.

 Thanks,
   Mark



Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-19 Thread Andy Wingo
On Tue 17 Jan 2012 00:27, Andy Wingo wi...@pobox.com writes:

 TBH I think this is the best thing we can do for local-eval.  We
 preserve flexibility for local-eval, make other experiments possible,
 and the local-eval implementation is a bit more perspicacious, as the
 scoping is more lexical (in the same file, even).

Perspicuous, rather.  How embarrassing!

Andy
-- 
http://wingolog.org/



Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-17 Thread David Kastrup
Andy Wingo wi...@pobox.com writes:

 What if instead we implemented closure serialization somehow?  Then we
 would handle procedural macros too, and bound-identifiers would still be
 sufficient.

 Maybe that idea is a little too crazy.

Are we still talking about Scheme?  The language with
call-with-current-continuation?  a little too crazy is not a
criterion.  Too complex to work or or with would be.  Those are
related, but not necessarily the same.

-- 
David Kastrup




Re: bound identifiers

2012-01-17 Thread Stefan Israelsson Tampe
Yes!

see attachement!

/Stefan

On Tue, Jan 17, 2012 at 12:30 AM, Andy Wingo wi...@pobox.com wrote:

 On Mon 16 Jan 2012 22:56, Stefan Israelsson Tampe stefan.ita...@gmail.com
 writes:

  As you see, it's just wild west to get the racket code working.

 :)

 Can you give a stripped-down test case for this particular behavior?

 That code is paged into my and Mark's minds right now :)

 Andy
 --
 http://wingolog.org/

(use-modules (srfi srfi-9))
(define-record-type data
  (make-data stx)
  data?
  (stx data-stx))

(define-syntax b
  (lambda (x)
(syntax-case x ()
  ((_ s)
   (with-syntax ((d (datum-syntax #'#f (make-data #'s
 #'(c #'s #'d))

(define (c s d)
  (let ((d (data-stx (syntax-datum d
(pk s)
(pk d)
(bound-identifier=? s d)))

(eval '(let ((t 1)) (b t)) (current-module))


Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Mark H Weaver
Hi Andy!

Andy Wingo wi...@pobox.com writes:
 + (cons (wrap (car symnames)
 + (anti-mark (make-wrap (car marks) subst))

 * Why are you adding anti-marks here?

 As the changelog noted (and a comment should have noted ;), the
 identifiers are anti-marked so that syntax transformers can introduce
 them, as-is.

 The purpose of this procedure is to get a list of identifiers, and to
 capture some subset of them.  It will do so by introducing references to
 them in the expansion of some macro.  However they are not introduced
 identifiers: they come from the code itself.  They are input the macro,
 and as such need an anti-mark.

 The anti-mark will be stripped from the expansion when the transformer
 that called `bound-identifiers' returns.

Does this mean that `bound-identifiers' will not function properly when
used outside of a macro?  What about if it's used within a macro that
was generated by another macro (or things of that nature)?  Are there
cases where you might need to strip more than one anti-mark?

To use your phrase, this has a bad smell.

 More importantly: I notice that you are not stripping the psyntax wrap
 from identifiers placed within the wrapper procedure above.  There are
 certainly benefits to that, but remember that the wrapper procedure will
 in general be serialized to disk and evaluated in a different Guile
 session, where the gensym counters have been reset.

 Of course, like all macros!  The forgeable gensym issue is something we
 have in Guile, more generally, that needs a broader solution.

Ah, good point!  Macros already serialize syntax-objects to disk.
psyntax wraps are already part of our ABI, so nothing new there.

However, I fear that the gensym issue might be a serious problem for
`local-eval', even though it hasn't been a problem for macros.

The reason it has not been a problem with macros is that, within a
top-level macro (which are the only ones used across Guile sessions),
the only syntax-objects that can be meaningfully _introduced_ into the
expansion are top-level/module bindings.  But these bindings have no
associated labels or gensyms, because they're not in the wrap.

On the other hand, with `local-eval', it seems to me quite plausible
that gensym collisions might occur.  Suppose in one Guile session you
compile a procedure (foo) that uses (the-environment), and then in
another Guile session, you call (foo) and then `local-eval' with the
environment returned by (foo).  Now the wrapper procedure splices
together syntax objects from two different Guile sessions into a single
top-level form, where (unlike in the macro case) all of these syntax
objects are lexicals, and thus depend on the gensyms and the labels.

See how this is a problem now where it wasn't before?
Or am I missing something?

 +((module? e)
 + ;; Here we evaluate the expression within `lambda', and then
 + ;; call the resulting procedure outside of the dynamic extent
 + ;; of `eval'.  We do this because `eval' sets (current-module)
 + ;; within its dynamic extent, and we don't want that.  Also,
 + ;; doing it this way makes this a proper tail call.
 + ((eval #`(lambda () #,x) e)))

 * This was my mistake, but since I'm already marking up the code:
 the `lambda' wrap above needs a `#f' before `e' to force expression
 context.

 OK.  (Note though that (eval X e) does indeed evaluate X in tail
 position.)

Looks to me like `eval' is initially bound to the C function scm_eval.
Is it later rebound to a Scheme procedure?  If so, where?

 For the record, I still think it's better for `the-environment' to be
 implemented within psyntax as a core form.  It's a fundamental syntactic
 construct with clean semantics, and it belongs in psyntax with its
 brethren.  Your desire to remove it from psyntax has caused you to add
 far less elegant interfaces that have been hastily designed, and that
 may not even be sufficient for a full implementation of
 `the-environment' that captures mutually-recursive local macros.

 In pursuit of the goal of agreeing on a strategy, I would like to
 convince you that you are wrong on all of these points :)  So, in that
 spirit, I argue:

Very well, I will endeavor to be open-minded.

 `the-environment' is not fundamental: it can be implemented in terms of
 simpler primitives.

The same can be said of `lambda' or `syntax-case', but that's not the
appropriate way to choose primitives in a language.  The set of
primitives chosen in Scheme are not the ones that are simplest to
implement.  It makes more sense to choose primitives with simple, clean
semantics, which segues nicely into your next paragraph.

 `the-environment' does not have clean semantics, inasmuch as it has
 nothing worthy of the name, not yet anyway.  The lambda calculus, the
 scheme language, even the syntax-case system have well-studied semantics
 (denotational and/or operational), and lots

Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Mark H Weaver
Hi Andy!

Thanks again for working on this.

Andy Wingo wi...@pobox.com writes:
 * Why are you adding anti-marks here?

 As the changelog noted (and a comment should have noted ;), the
 identifiers are anti-marked so that syntax transformers can introduce
 them, as-is.

 The purpose of this procedure is to get a list of identifiers, and to
 capture some subset of them.  It will do so by introducing references to
 them in the expansion of some macro.  However they are not introduced
 identifiers: they come from the code itself.  They are input the macro,
 and as such need an anti-mark.

 The anti-mark will be stripped from the expansion when the transformer
 that called `bound-identifiers' returns.

 Does this mean that `bound-identifiers' will not function properly when
 used outside of a macro?  What about if it's used within a macro that
 was generated by another macro (or things of that nature)?  Are there
 cases where you might need to strip more than one anti-mark?

 Well, bound-identifiers is a procedure, so if you are using it outside
 the dynamic extent of a transformer procedure, that means that you have
 a syntax object that you squirreled away from somewhere, so already
 we're in somewhat uncharted territory.

How about something like (bound-identifiers #'here)?
or (bound-identifiers #'x) where `x' is some lexical variable?

 Macro-generating macros should be fine, here.  `expand-macro' is
 iterative, not recursive, so you don't need to strip anti-marks twice.

Ah, okay.  Good point!

 I agree that this anti-mark has a bad smell, but the idea of a
 `bound-identifiers' procedure or form sounds like a good idea, so if you
 have any suggestions for improvement here, they are most welcome.

As I've already said, I don't think `bound-identifiers' will be useful
in a full implementation of `local-eval', so once we move to that
improved implementation, `bound-identifiers' will be left around as an
orphan: a primitive of dubious value, introduced specifically to
implement something that it turned out to be insufficient for.

If you insist on this strategy, I think what we really need is a list of
ribs, where each rib also specifies whether it is recursive.  We don't
actually care about `let' vs `letrec' (though there's no harm in
providing that information in the interface, and it probably makes sense
to for consistency), but we _do_ care about the difference between
`let-syntax', `letrec-syntax', and internal bodies with
mutually-recursive `define-syntax' forms.

See how we're exposing increasingly complex internal psyntax structures
in order to achieve your dream of making `local-eval' sleep outside in
the shed?

 [W]ith `local-eval', it seems to me quite plausible that gensym
 collisions might occur.  Suppose in one Guile session you compile a
 procedure (foo) that uses (the-environment), and then in another Guile
 session, you call (foo) and then `local-eval' with the environment
 returned by (foo).  Now the wrapper procedure splices together syntax
 objects from two different Guile sessions into a single top-level
 form, where (unlike in the macro case) all of these syntax objects are
 lexicals, and thus depend on the gensyms and the labels.

 See how this is a problem now where it wasn't before?
 Or am I missing something?

 To be perfectly honest, this stuff is very confusing to me, but I think
 I can see how this can happen, yes.

 I do think that it's important to fix this bug at some point, but IMO it
 is not a blocker for local-eval, much less 2.0.4.

I strongly disagree.  Your implementation will clearly be buggy without
a proper solution to the collision of gensyms (labels and marks, at
least).  I don't know about you, but personally I prefer rock-solid code
with clearly documented limitations (that almost no one is likely to hit
anyway) to buggy code.

If you don't want to deal with the gensym problem for 2.0.4, there's an
easy solution.  Simply strip the wraps for now (as is done by my patch),
and everything will robust as long as we don't capture local syntax.

 BTW, did you see my most recent model for thinking about `local-eval'?

 (the-environment) expands to (list (lambda () expr) ...), with one
 element for every possible expression: a countably infinite list that
 could be built lazily.  `local-eval' simply chooses the appropriate
 procedure from the list and calls it.  A poor implementation strategy,
 but the semantic meaning is quite clear, no?

 It sounds clear, but does it have any explanatory power?  It sounds like
 it could apply just as well to any other computation...

I don't understand what you mean here.  It seems to me that this model
can answer any question you could possibly have about the observable
behaviors of `the-environment' and `local-eval', besides their
efficiency.  Can you provide a counter-example to this claim?

 Creating wraps is not the hack.  It's creating wraps that are scoped in
 another specific module.  With the-environment in psyntax, psyntax

Re: bound identifiers

2012-01-16 Thread Andy Wingo
On Mon 16 Jan 2012 20:46, Stefan Israelsson Tampe stefan.ita...@gmail.com 
writes:

 why are these two not equal in the sense of bound-identifier=?

 #(syntax-object x ((top) #(ribcage () () ()) #(ribcage () () ()) #(ribcage 
 #(x) #((m1104 top)) #(i1105))) (hygiene guile-user))
 #(syntax-object x ((#f top) shift #(ribcage () () ()) #(ribcage #(x) #((m1104 
 top)) #(i1105))) (hygiene guile-user)))

One has been anti-marked and the other has not?  Meaning that one was
made up by your syntax expander, and the other and the other came in as
part of the form.

But that's not the right question or answer.  Can you should where these
identifiers come from?

Andy
-- 
http://wingolog.org/



Re: bound identifiers

2012-01-16 Thread Stefan Israelsson Tampe
In syntax parse the racket code stores syntax values inside structs and
then transport them
down the macro chain as argument to macros. Then when unpacking the struct
they are compared
with arguments of syntax values. I think that this is the reason. I tried
to experiment with
psyntax macro expander to poke inside structs and that solved this issue.
But on the other hand
even worse problem appeared.

What I did now was to manually clean the syntax values e.g. remove #f and
shift from the
syntax value and this gave the best result.

As you see, it's just wild west to get the racket code working.

Mayby just writing a version from scratch would be better.

/Stefan

On Mon, Jan 16, 2012 at 10:28 PM, Andy Wingo wi...@pobox.com wrote:

 On Mon 16 Jan 2012 20:46, Stefan Israelsson Tampe stefan.ita...@gmail.com
 writes:

  why are these two not equal in the sense of bound-identifier=?
 
  #(syntax-object x ((top) #(ribcage () () ()) #(ribcage () () ())
 #(ribcage #(x) #((m1104 top)) #(i1105))) (hygiene guile-user))
  #(syntax-object x ((#f top) shift #(ribcage () () ()) #(ribcage #(x)
 #((m1104 top)) #(i1105))) (hygiene guile-user)))

 One has been anti-marked and the other has not?  Meaning that one was
 made up by your syntax expander, and the other and the other came in as
 part of the form.

 But that's not the right question or answer.  Can you should where these
 identifiers come from?

 Andy
 --
 http://wingolog.org/



Re: bound identifiers

2012-01-16 Thread Andy Wingo
On Mon 16 Jan 2012 22:28, Andy Wingo wi...@pobox.com writes:

 On Mon 16 Jan 2012 20:46, Stefan Israelsson Tampe stefan.ita...@gmail.com 
 writes:

 why are these two not equal in the sense of bound-identifier=?

 But that's not the right question or answer.  Can you should where these
 identifiers come from?

Sorry, I've been making lots of typos recently.  I meant to say, can
you show where these identifiers come from?

Andy
-- 
http://wingolog.org/



Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Andy Wingo
Hi Mark,

On Mon 16 Jan 2012 21:36, Mark H Weaver m...@netris.org writes:

 Thanks again for working on this.

And thank you again for all your work, and patience with my
pigheadedness.

 if you insist in this foolish quest to banish `the-environment' to
 sleep in the shed as a second-class citizen, I cannot stop you :)

TBH I think this is the best thing we can do for local-eval.  We
preserve flexibility for local-eval, make other experiments possible,
and the local-eval implementation is a bit more perspicacious, as the
scoping is more lexical (in the same file, even).

I know there's a smilie in your statement, but really, it's not just
local-eval:  there's loads more that should be broken out into modules
over time, somehow :)  Think of it as building a hippie commune of
functionality, instead of making everyone live in the same house :)
(OK, that's stretching it a bit, but perhaps it is partially apt?)

Now, specific commentary.

 How about something like (bound-identifiers #'here)?

scheme@(guile-user) (bound-identifiers #'here)
$5 = ()

scheme@(guile-user) (let ((x 10)) (bound-identifiers #'here))
$6 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i176))) 
(hygiene guile-user)))

What should the answer be in this case?  Would you expect `x' in the
list?  Certainly for the-environment you would.  But here:

scheme@(guile-user) (define-syntax bound-here
   (lambda (x)
 (with-syntax (((id ...)
(map (lambda (id) (datum-syntax x id))
 (bound-identifiers #'here
   #'(list 'id ...
scheme@(guile-user) bound-here
$7 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i192))) 
(hygiene guile-user)))
scheme@(guile-user) (let ((y 10)) bound-here)
$8 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i192))) 
(hygiene guile-user)))

So, it seems to be sensible.

Now, what to do with these identifiers: you if you introduce one into
another macro, the mark will indeed be stripped.  I'm not sure what else
you can do with a syntax-object, actually!  Pass it directly to eval or
compile, I guess, and in that case we do lose, as the anti-mark isn't
stripped.  But that's the case for other syntax objects captured in a
syntax transformer, as well.

Should we anti-mark only within the dynamic extent of a transformer, I
wonder?

 As I've already said, I don't think `bound-identifiers' will be useful
 in a full implementation of `local-eval', so once we move to that
 improved implementation, `bound-identifiers' will be left around as an
 orphan: a primitive of dubious value, introduced specifically to
 implement something that it turned out to be insufficient for.

Hum.  Definitely something to think about.

What if instead we implemented closure serialization somehow?  Then we
would handle procedural macros too, and bound-identifiers would still be
sufficient.

Maybe that idea is a little too crazy.

If we have to lexical contours associated with bindings, recursive is
only one bit: you probably also need letrec vs letrec*.

 To be perfectly honest, this stuff is very confusing to me, but I think
 I can see how this can happen, yes.

 I do think that it's important to fix this bug at some point, but IMO it
 is not a blocker for local-eval, much less 2.0.4.

 I strongly disagree.  Your implementation will clearly be buggy without
 a proper solution to the collision of gensyms (labels and marks, at
 least).  I don't know about you, but personally I prefer rock-solid code
 with clearly documented limitations (that almost no one is likely to hit
 anyway) to buggy code.

 If you don't want to deal with the gensym problem for 2.0.4, there's an
 easy solution.  Simply strip the wraps for now (as is done by my patch),
 and everything will robust as long as we don't capture local syntax.

Thinking about it a little more, labels are a non-issue.  All they need
to be is unique in the sense of eq?.  Labels are strings.  If they are
loaded in separate compilation units, they will be unique, no matter
what their contents.

Labels are more important than marks, also, for the correctness of the
algorithm.  A mark collision is only an issue if there is also a
symbolic collision.  Label collision could alias completely unrelated
bindings.

Anyway, I would rather serialize bad marks than no marks.  That's my
personal opinion ;-) But if you think this is a huge issue, let's fix
the marks to be more unique, no?

Note that there is a well-known optimization that you don't actually
need to generate the characters corresponding to a gensym until they are
needed.  It might serve your purposes.

OK, I'm getting very sleepy now :)  Let me know your thoughts.  It would
be great if all of this could land before Sunday.  Though the cricket
folk say pace is nothing without guile, Guile is nothing without a
good development pace ;-)

Cheers,

Andy

Re: bound identifiers

2012-01-16 Thread Andy Wingo
On Mon 16 Jan 2012 22:56, Stefan Israelsson Tampe stefan.ita...@gmail.com 
writes:

 As you see, it's just wild west to get the racket code working.

:)

Can you give a stripped-down test case for this particular behavior?

That code is paged into my and Mark's minds right now :)

Andy
-- 
http://wingolog.org/



local-eval on syntax-local-binding, bound-identifiers

2012-01-15 Thread Andy Wingo
 'displaced-lexical #f
+
 (set! generate-temporaries
   (lambda (ls)
 (arg-check list? ls 'generate-temporaries)
-- 
1.7.8.3

From 2c3da44320019453115811af386febaa7eb241c3 Mon Sep 17 00:00:00 2001
From: Andy Wingo wi...@pobox.com
Date: Sun, 15 Jan 2012 18:39:44 +0100
Subject: [PATCH 2/3] add bound-identifiers

* module/ice-9/boot-9.scm (bound-identifiers): Declare variable.
* module/ice-9/psyntax.scm: Add all-bound-identifiers helper, and define
  bound-identifiers.  The identifiers are anti-marked so that syntax
  transformers can introduce them, as-is.
---
 module/ice-9/boot-9.scm  |1 +
 module/ice-9/psyntax.scm |   49 ++
 2 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index 9cdd8d1..b8aa842 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits.
 (define generate-temporaries #f)
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
+(define bound-identifiers #f)
 (define syntax-local-binding #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index 30685bc..25543e0 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -786,6 +786,48 @@
   id))
  (else (syntax-violation 'id-var-name invalid id id)
 
+;;
+;; all-bound-identifiers returns a list of all lexically bound
+;; identifiers, as syntax objects.  They are in order from outer to
+;; inner.
+;;
+(define all-bound-identifiers
+  (lambda (w mod)
+(define scan
+  (lambda (subst results)
+(if (null? subst)
+results
+(let ((fst (car subst)))
+  (if (eq? fst 'shift)
+  (scan (cdr subst) results)
+  (let ((symnames (ribcage-symnames fst))
+(marks (ribcage-marks fst)))
+(if (vector? symnames)
+(scan-vector-rib subst symnames marks results)
+(scan-list-rib subst symnames marks results
+(define scan-list-rib
+  (lambda (subst symnames marks results)
+(let f ((symnames symnames) (marks marks) (results results))
+  (if (null? symnames)
+  (scan (cdr subst) results)
+  (f (cdr symnames) (cdr marks)
+ (cons (wrap (car symnames)
+ (anti-mark (make-wrap (car marks) subst))
+ mod)
+   results))
+(define scan-vector-rib
+  (lambda (subst symnames marks results)
+(let ((n (vector-length symnames)))
+  (let f ((i 0) (results results))
+(if (fx= i n)
+(scan (cdr subst) results)
+(f (fx+ i 1)
+   (cons (wrap (vector-ref symnames i)
+   (anti-mark (make-wrap (vector-ref marks i) subst))
+   mod)
+ results)))
+(scan (wrap-subst w) '(
+
 (define transformer-environment
   (make-fluid
(lambda (k)
@@ -2470,6 +2512,13 @@
  (else (error unpossible! b)))
(values 'displaced-lexical #f
 
+(set! bound-identifiers
+  (lambda (x)
+(arg-check nonsymbol-id? x 'bound-identifiers)
+(reverse
+ (all-bound-identifiers (syntax-object-wrap x)
+(syntax-object-module x)
+
 (set! generate-temporaries
   (lambda (ls)
 (arg-check list? ls 'generate-temporaries)
-- 
1.7.8.3

From ddea51310227155e3771c3e6acbbecf24dc74c42 Mon Sep 17 00:00:00 2001
From: Mark H Weaver m...@netris.org
Date: Tue, 3 Jan 2012 04:02:08 -0500
Subject: [PATCH 3/3] Implement `local-eval', `local-compile', and
 `the-environment'

* module/ice-9/local-eval.scm: New module (ice-9 local-eval) which
  exports `the-environment', `local-eval', and `local-compile'.

* libguile/debug.c (scm_local_eval): New C function that calls the
  Scheme implementation of `local-eval' in (ice-9 local-eval).

* libguile/debug.h (scm_local_eval): Add prototype.

* doc/ref/api-evaluation.texi (Local Evaluation): Add documentation.

* test-suite/tests/eval.test (local evaluation): Add tests.

* test-suite/standalone/test-loose-ends.c (test_scm_local_eval):
  Add test.

* module/Makefile.am: Add ice-9/local-eval.scm.
---
 doc/ref/api-evaluation.texi |   38 
 libguile/debug.c|   13 +++-
 libguile/debug.h|4 +-
 module/Makefile.am  |5

Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-15 Thread Mark H Weaver
Hi Andy,

Thanks very much for heeding my call for `local-eval' in 2.0.4, and
for putting so much time into this.

For the record, I still think it's better for `the-environment' to be
implemented within psyntax as a core form.  It's a fundamental syntactic
construct with clean semantics, and it belongs in psyntax with its
brethren.  Your desire to remove it from psyntax has caused you to add
far less elegant interfaces that have been hastily designed, and that
may not even be sufficient for a full implementation of
`the-environment' that captures mutually-recursive local macros.

That said, there's a lot to like in your implementation, and it has some
notable improvements over mine.  It also has some problems, not all of
which are trivial.

Please see below, where I have inserted specific questions and comments
into your patch.

  Thanks again,
  Mark


[... skipped the first patch, which looks very well implemented, though
 I'm still not sure that we should be exposing this in our API ...]

 From 2c3da44320019453115811af386febaa7eb241c3 Mon Sep 17 00:00:00 2001
 From: Andy Wingo wi...@pobox.com
 Date: Sun, 15 Jan 2012 18:39:44 +0100
 Subject: [PATCH 2/3] add bound-identifiers

 * module/ice-9/boot-9.scm (bound-identifiers): Declare variable.
 * module/ice-9/psyntax.scm: Add all-bound-identifiers helper, and define
   bound-identifiers.  The identifiers are anti-marked so that syntax
   transformers can introduce them, as-is.
 ---
  module/ice-9/boot-9.scm  |1 +
  module/ice-9/psyntax.scm |   49 
 ++
  2 files changed, 50 insertions(+), 0 deletions(-)

 diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
 index 9cdd8d1..b8aa842 100644
 --- a/module/ice-9/boot-9.scm
 +++ b/module/ice-9/boot-9.scm
 @@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and 
 then exits.
  (define generate-temporaries #f)
  (define bound-identifier=? #f)
  (define free-identifier=? #f)
 +(define bound-identifiers #f)
  (define syntax-local-binding #f)
  
  ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
 index 30685bc..25543e0 100644
 --- a/module/ice-9/psyntax.scm
 +++ b/module/ice-9/psyntax.scm
 @@ -786,6 +786,48 @@
id))
   (else (syntax-violation 'id-var-name invalid id id)
  
 +;;
 +;; all-bound-identifiers returns a list of all lexically bound
 +;; identifiers, as syntax objects.  They are in order from outer to
 +;; inner.
 +;;
 +(define all-bound-identifiers
 +  (lambda (w mod)
 +(define scan
 +  (lambda (subst results)
 +(if (null? subst)
 +results
 +(let ((fst (car subst)))
 +  (if (eq? fst 'shift)
 +  (scan (cdr subst) results)
 +  (let ((symnames (ribcage-symnames fst))
 +(marks (ribcage-marks fst)))
 +(if (vector? symnames)
 +(scan-vector-rib subst symnames marks results)
 +(scan-list-rib subst symnames marks 
 results
 +(define scan-list-rib
 +  (lambda (subst symnames marks results)
 +(let f ((symnames symnames) (marks marks) (results results))
 +  (if (null? symnames)
 +  (scan (cdr subst) results)
 +  (f (cdr symnames) (cdr marks)
 + (cons (wrap (car symnames)
 + (anti-mark (make-wrap (car marks) subst))

* Why are you adding anti-marks here?

 + mod)
 +   results))
 +(define scan-vector-rib
 +  (lambda (subst symnames marks results)
 +(let ((n (vector-length symnames)))
 +  (let f ((i 0) (results results))
 +(if (fx= i n)
 +(scan (cdr subst) results)
 +(f (fx+ i 1)
 +   (cons (wrap (vector-ref symnames i)
 +   (anti-mark (make-wrap (vector-ref marks 
 i) subst))

* Ditto.

 +   mod)
 + results)))
 +(scan (wrap-subst w) '(
 +
  (define transformer-environment
(make-fluid
 (lambda (k)
 @@ -2470,6 +2512,13 @@
   (else (error unpossible! b)))
 (values 'displaced-lexical #f
  
 +(set! bound-identifiers
 +  (lambda (x)
 +(arg-check nonsymbol-id? x 'bound-identifiers)
 +(reverse
 + (all-bound-identifiers (syntax-object-wrap x)
 +(syntax-object-module x)
 +
  (set! generate-temporaries
(lambda (ls)
  (arg-check list? ls 'generate-temporaries