On Mon, 2009-08-24 at 13:48 -0500, Eduardo Cavazos wrote:
> Hello,
>
> Infix in Scheme is all the rage these days. ;-) Awhile back I mentioned
> an 'alg' procedure which converts a string containing an infix
> expression to an sexp. So for example:
>
> > (import (numero symbolic alg))
> > (alg "x+y")
> (+ x y)
> > (alg "f(x,y)+z")
> (+ (f x y) z)
> >
>
> I'd like to have a macro version of alg which expands to the sexp at at
> "expansion time" (what's the right terminology here?).
"Expand time" or "compile time" are both commonly used.
> Here's a version which seems to work in simple cases. I wanted to run it
> by y'all though; does it look correct? Any advice?
>
> (define-syntax algm
>
> (lambda (stx)
>
> (syntax-case stx ()
>
> ( (algm expr)
>
> (with-syntax ((new-expr (datum->syntax
> (syntax algm)
> (alg (syntax->datum (syntax expr))))))
>
> (syntax new-expr)) ))))
The with-syntax is not needed. Just return the result of the
datum->syntax.
If alg might raise an exception, you probably should handle it by
re-raising it as a syntax violation. Something like:
(with-exception-handler
(lambda (ex)
(syntax-violation #F (condition-message ex) stx (syntax expr)))
(lambda ()
(alg (syntax->datum (syntax expr)))))
You may want to use a syntax-case fender to check
(string? (syntax->datum (syntax expr)))
You should be aware that because you give the output syntax the lexical
context of (syntax algm), macros built on top of algm would need to deal
with this. E.g., this is broken:
(define-syntax foo
(syntax-rules ()
((_ e0 e1)
(list (algm e0) (algm e1)))))
because the transformed infix expressions are given the lexical context
of the algm identifiers, which is the context where those identifiers
lexically are there in the macro definition, which is incorrect.
Because the infix expressions are not identifiers, you cannot use their
lexical context, which would be ideal but datum->syntax requires an
identifier and it's unspecified whether non-identifier syntax objects
are wrapped with lexical context info. You might think of doing
something like:
(with-syntax ((algm (datum->syntax (syntax foo) (quote algm))))
(syntax (list (algm e0) (algm e1))))
but that requires the correct algm to be bound in the lexical context of
the use of foo, which you cannot rely on, and it would have the same
problem of macros built on top of foo.
So, if you want to support being able to make macros built on top of
algm, you'll need:
(define-syntax algm/lexical-context
(lambda (stx)
(syntax-case stx ()
((_ ctxt expr)
(datum->syntax (syntax ctxt)
(alg (syntax->datum (syntax expr))))))))
(define-syntax algm
(lambda (stx)
(syntax-case stx ()
((kw expr)
(syntax (algm/lexical-context kw expr))))))
And now other macros can be built on top of algm/lexical-context, and
they can control what lexical context the transformed infix expressions
get, and the desired lexical context can be passed-through as many
layers of macros as necessary (as long as those macros have
a /lexical-context version).
--
: Derick
----------------------------------------------------------------