Carl. 

You were right. I just needed to do the work of make-button-contracts in my 
define-sequencer-buttons-info-class syntax transformer and that saved me having 
to "recognize 'clause transformers', invoke the macro transformer on them, 
[and] simulate some of the aspects of normal macro transformation".

In case you or anyone following this is curious, the fixed code (with some 
previously omitted lines from the last email put back in) follows below.

Thanks to you Carl and to all participants on this list that make it such a 
great place to get help.

--Christopher

; make-button-contracts and its previously unlisted companion have been 
removed, as their function is subsumed in the macro below

(define-syntax [define-sequencer-buttons-info-class stx]
  (syntax-case stx []
    [[_ cls-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 })]]
        (when {null? buttons}
          {raise-syntax-error 
           'no-buttons
           "must supply at least one button name after class name" })
        (with-syntax [[[btn-name ...] buttons]]
          #'(define/contract cls-name
              (class/c*
                [init-field-accessor 
                 [btn-name {is-a?/c button-info%}] ... ] )
              (class object%
                (init-field-accessor btn-name ...)
                (super-new) ))))]))

On Sep 21, 2013, at 12:26 PM, Carl Eastlund <c...@ccs.neu.edu> wrote:

> 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 <ultimatemacfana...@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 #,@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
> 
> 

____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to