unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Taylan Kammer <taylan.kammer@gmail.com>
To: Dale Mellor <guile-qf1qmg@rdmp.org>, guile-user@gnu.org
Subject: Re: Help: equivalent syntax-case to defmacro
Date: Wed, 6 May 2020 17:49:08 +0200	[thread overview]
Message-ID: <013cb23b-65d6-b7a9-26ca-c5a0319fe87d@gmail.com> (raw)
In-Reply-To: <caa251a11a68d2196c09cbaee4094f6ca7c096ca.camel@rdmp.org>

On 05.05.2020 19:34, Dale Mellor wrote:
> Been struggling with this for a while, and nothing I try works.
> 
> In test-suite/tests/getopt-long there is
> 
>       (defmacro deferr (name-frag re)
>          (let ((name (symbol-append 'exception: name-frag)))
>             `(define ,name (cons 'quit ,re))))
> 
>       (deferr no-such-option "no such option")
>       (display exception:no-such-option)
> 
> and I would like to know how the equivalent with define-syntax... syntax-case would look.

(define-syntax deferr
   (lambda (s)
     (syntax-case s ()
       ((_ name-frag re)
        (let* ((name-frag-sym (syntax->datum #'name-frag))
               (name-sym (symbol-append 'exception: name-frag-sym))
               (name (datum->syntax #'name-frag name-sym)))
          #`(define #,name (cons 'quit re)))))))

Some notes to help understand this:

- Syntax-case deals with syntax objects rather than raw symbols.  We use 
syntax->datum to turn 'name-frag' into a symbol and datum->syntax to 
turn it back into a syntax object.

- For some reason, the pattern variables bound via syntax-case (i.e. 
'name-frag' and 're' in our case) are forbidden by syntax-case to be 
referenced outside of a #' or #` form.  They must always appear in one 
of those, period.  Hence we have to call (syntax->datum #'name-frag) 
instead of simply (syntax->datum name-frag).  Honestly I still don't 
know why they designed it this way.

- The datum->syntax form requires its first argument to be an existing 
syntax object, which will tell datum->syntax for which "syntax context" 
you're creating your new syntax object.  In this case I'm passing it 
#'name-frag because the context where that comes from is the context in 
which the resulting full name will be used.

- In the output form starting with #` the 're' pattern variable can 
appear naked, whereas the manually created 'name' syntax object must be 
inserted with the #, form.  (This is related to the same design 
weirdness I mentioned before so don't ask me why.)


Hope that helps!  Happy to answer further questions.  Syntax-case is 
very tricky but once you get it, it's amazing.

- Taylan



      reply	other threads:[~2020-05-06 15:49 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-05 17:34 Help: equivalent syntax-case to defmacro Dale Mellor
2020-05-06 15:49 ` Taylan Kammer [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=013cb23b-65d6-b7a9-26ca-c5a0319fe87d@gmail.com \
    --to=taylan.kammer@gmail.com \
    --cc=guile-qf1qmg@rdmp.org \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).