[racket] macro not getting expanded as argument to class/c
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>