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

From: Christopher (ultimatemacfanatic at gmail.com)
Date: Sat Sep 21 14:15:02 EDT 2013

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 )]))

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130921/539d576a/attachment-0001.html>

Posted on the users mailing list.