> Let's
assume we are writing a macro that reimplements syntax (or
some
> variation thereof) and which has to check whether
identifiers are
> ellipses. For example, the following could be given:
>
> (with-ellipsis e
> (my-syntax a e)
>
> Now, this could be a result of a macro expansion and e
could carry
> different marks than with-syntax or my-syntax. This is
why I have been
> thinking that one also needs the lexical context of
my-syntax and not
> only the context of e.
I don't see what problem would be caused by 'e' carrying
different marks
than 'my-syntax'.
As far as I can tell, in the end, the two instances of 'e'
above will
effectively be compared to one another using
'bound-identifier=?'. They
must have the same name and the same marks to match. The
marks on
'my-syntax' are irrelevant here.
I have been thinking of the scope in which $sc-ellipsis is
bound by `with-syntax'. If `my-syntax' is within the scope of
`with-ellipsis', the binding of $sc-ellipsis introduced by
this `with-syntax' will be relevant; if `my-syntax' is not in
the lexical scope of `with-ellipsis', the binding should be
irrelevant; thus my thought that we need the lexical
information of my-syntax as well.
Operationally,
when (with-ellipsis e (my-syntax a e)) is expanded, 'e'
will be added to the macro expansion environment as the
innermost
binding of the ellipsis identifier, and then (my-syntax a e)
will be
expanded within that new expansion environment. That is the
expansion
environment that will be consulted by the
'ellipsis-identifier?'
predicate to find the current ellipsis identifier, which is
compared
with its argument (after stripping its anti-mark) using
'bound-identifier=?'.
Aha, so maybe I have misunderstood the scope of
`with-syntax'. Please consider the following example:
(define-syntax foo
(lambda (stx)
(with-ellipsis e
(syntax-case stx ()
((_ x e) (bar #'(x e)))))))
(eval-when (expand)
(define (bar x*)
(syntax-case x* ()
((x ...) ---))))
I would have thought that the `...' identifier in `bar' is
recognized as an ellipsis, but from what you are saying it
seems that the binding `with-syntax' is dynamic with respect
to macro expansion (like syntax parameters). Is this really
what we want? This way, as soon we use `with-ellipsis', we can
never call third-party macro transformer helpers (like `bar')
because they may rely on the fact that the ellipsis `...'
still has its usual meaning. And circumventing the problem
with (with-ellipsis e --- (with-ellipsis ... ---)) would also
not work because the inner `...' is not `bound-identifier=?'
to the the global ellipsis `...'.
Therefore I think, we want `with-ellipsis' to be lexically
scoped (in the macro transformer code).
> Thanks
for the explanation. I have been toying with my own
> implementation of the syntax-case system. In my
implementation the
> (shared) lexical environments are part of the wraps (so
the
> identifiers are in some way self-contained).
Interesting. Are locally-bound macro transformers included in
those
lexical environments? If so, how do you implement
'letrec-syntax'?
My environments are lists of ribs where each rib
corresponds to a lexical frame. Given the form
(letrec-syntax ((var init)) body ...)
I create a new rib that contains the binding of var to init
and add a wrap around each expression in body ... that
contains the new rib but no new marks. When the body is
examined by the expander, the wraps are gradually pushed down
(like in the original description of `syntax-case' by Dybvig
and Hieb) so that eventually the environments stored with the
identifiers in body gain another rib.
> Will
ellipsis? also work outside of macros? Say, what would be the
> result of the following (run-time) code?
>
> (with-syntax e
> (ellipsis? #'e)
No, this is an error. Like 'syntax-local-binding', the
'ellipsis-identifier?' predicate must be called within the
dynamic
extent of a macro transformer call by the macro expander.
Is this related to the question above of whether
`with-syntax' has lexical or dynamic scope? In the former case
I don't see a theoretical reason why it has to be restricted
to the dynamic extent of a macro transformer call.
> P.S.:
By the way, the module (system syntax) and in particular the
> procedure syntax-local-binding has already helped me a
lot because I
> needed to attach extra information to symbols and Guile
doesn't (yet)
> support Chez's define-property (well, this would be
another feature
> request).
Hmm. Can you tell me more specifically how you are using
'syntax-local-binding' to accomplish this? As the Guile
manual warns,
those interfaces are subject to change in future versions of
Guile, and
therefore it is best to avoid them where possible.
What I have been implementing is a pattern matcher and
rewriter as a macro in Guile that works much like
syntax-case/syntax. Let's call it my-syntax-case/my-syntax. When
`my-syntax' is given a template, it has to check whether an
identifier appearing in the template is a "my-"pattern variable
or not. For that, `my-syntax-case' introduces (via `let-syntax')
lexical bindings of the identifiers that are used as pattern
variables. The associated syntax transformer just outputs an
error (namely that the pattern variable is used outside of
`my-syntax'). However, I also attach a custom property (with
`make-object-property`) to this syntax transformer that holds
information about the match and the nesting depth of the pattern
variable. In order to retrieve this information in `my-syntax',
I use `syntax-local-binding' to get hold of the associated
syntax transformer.
In Chez Scheme, I would have used `define-property' to define
my custom property directly on the identifier standing for the
pattern variable. I haven't found an equivalent feature in
Guile. I don't know how to nicely code my-syntax-case/my-syntax
in standard R6RS.