[racket] macro not getting expanded as argument to class/c

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Sat Sep 21 14:26:10 EDT 2013

Christopher,

Ordinary macros are used to extend expressions and definitions; the
arguments to class/c are neither, so they are not macro expanded.  There
are ways to extend other kinds of things with macros -- match expanders,
require transformers, provide transformers, and other things like them
provide alternate kinds of transformers for syntactic forms other than
expressions and definitions.  (Hypothetically, we could have used ordinary
transformers for them as well, but that's a design question for another
day.)

If you want class/c* to use macro expansion for its clauses, you'll need to
set it up yourself: recognize "clause transformers", invoke the macro
transformer on them, simulate some of the aspects of normal macro
transformation (e.g. applying a unique mark before and after), and so on.

I don't suggest this, though.  It doesn't seem necessary.  Just do the work
of make-button-contracts in the macro that constructs the call to class/c*,
and there won't be any nested-expansion to do.  Adding a new kind of macro
expander is probably overkill for the problem at hand.

Carl Eastlund


On Sat, Sep 21, 2013 at 2:15 PM, Christopher
<ultimatemacfanatic at gmail.com>wrote:

> Hello, all you wonderful people. I'm seeing some strange behavior from my
> macros.
>
> So I invoke my *define-sequencer-buttons-info-class* macro with a bunch
> of identifiers.
> Its job is to rename the identifiers to add a "-btn" suffix (yes, I use
> macros to save typing tedium) and then
> invoke my *make-button-contracts* macro inside of my class/c* macro. The
> job of the former is to expand
> into a literal form that starts with *init-field-accessor* with some
> extra arguments which is interpreted specially by the latter.
> When I can get make-button-contracts to be invoked, it runs correctly,
> expanding into an argument list starting with *init-field-accessor*.
>
> *class/c** (star at the end) is my macro that expands argument pairs
> starting with literal symbols *init-field-accessor* and field-accessor
> into sets of init, field, and method definitions for mutations of a given
> name---or passes regular class/c statements through unmodified.
>
> The problem is that when Racket is in the *
> define-sequencer-buttons-info-class* transformer procedure, it constructs
> a definition including
> an invocation of *make-button-contracts* nested inside my invocation of *
> class/c**. When *class/c** then gets expanded, it passes the
> invocation of *make-button-contracts* through to the standard *class/c* (without
> the star)---unmodified----and then starts expanding *class/c *
> without having first expanded *make-button-contracts*.
>
> It further seems, that *class/c* does not macro-expand any of its
> arguments, but only matches literal names, so how am I going to get my *
> make-button-contracts* to expand
> BEFORE *class/c** is expanded? How can I do this with Racket?
>
> Finally, lest anyone be confused. I use a convention where my s-expression
> lists that represent immediate procedure applications at that point in the
> source are surrounded with braces, the ones that are expanded to macros or
> core, non-procedure functionality are in parentheses, and the rest are in
> brackets. It's unconventional, but it works for me.
>
>
> Many thanks!
>
> ---Christopher
>
>
> ; module total-ca-state.rkt (main file) [ file abbreviated to relevant
> portions ]
>
> (define-syntax [make-button-contracts stx]
>   (syntax-case stx []
>     [[_ btn-name ...]
>       (let [[ret #'(init-field-accessor [btn-name {is-a?/c button-info%}]
> ...)]]
>         {print ret}
>         ret )]))
>
> (define-syntax [define-sequencer-buttons-info-class stx]
>   (syntax-case stx []
>     [[_ name button ...]
>       (let [[buttons
>              (for/list [[btn-id {in-list {syntax->list #'[button ...]}}]]
>                {datum->syntax
>                  btn-id
>                  {string->symbol
>                    {string-append
>                      {symbol->string {syntax->datum btn-id}}
>                      "-btn" }}
>                  btn-id
>                  btn-id })]]
>         (define ret
>           #`(define name
>               (class/c*
>                 (make-button-contracts #, at buttons) )))
>         {print ret}
>         ret )]))
>
>
> (provide sequencer-buttons-info%)
> (define-sequencer-buttons-info-class sequencer-buttons-info%
>   next-user
>   previous-user
>   ; ... long list of names (abbreviated) ...
>   lock-user
>   )
>
>
>
>
> ;  module class-util.rkt (required by the other file) [ truncated to
> relevant portions ]
>
> (define-syntax [class/c* stx]
>   (define [flatten lst [times 1]]
>     (if {zero? times}
>         lst
>         {flatten {apply append lst} {sub1 times}} ))
>   (syntax-case stx []
>     [[_ clause ...]
>      (let []
>        (define clause-list {syntax->list #'[clause ...]})
>        (when {zero? {length clause-list}}
>          {raise-syntax-error #f
>                              "must supply at least one clause"
>                              stx })
>        (define syntax-ret
>          {datum->syntax
>           stx
>           {append
>            {list #'class/c}
>            {flatten
>             (for/list [[clause {in-list clause-list}]]
>               (syntax-case clause [init-field-accessor field-accessor]
>                 [[init-field-accessor sub-clause ...]
>                  {init-field-accessor* clause} ]
>                 [[field-accessor sub-clause ...]
>                  {field-accessor* clause} ]
>
>                 ; THIS IS WHERE THE CALL TO make-button-contracts IS
> PASSED THRU TO REGULAR class/c
>                 [whole-thing {list {list clause}}] ))
>             2 }}
>           stx})
>        {print syntax-ret}
>        syntax-ret )]))
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130921/c0b45972/attachment.html>

Posted on the users mailing list.