note: This was also posted to the comp.lang.scheme earlier today. I normally wouldn't cross-post, but after I noticed the extremely low traffic on the newsgroup, I decided to try a more active, if less specialized, forum.
As part of a larger project, I am writing a macro that defines a variable and binds it to a list of pairs, where most of the pairs map a pattern and a value. Each pattern is a list, which may have a combination of symbols and strings.
I am something of a novice with (define-syntax), and have struggled to get this to where I want it to go; while I have learned a fair amount in the process, I apparently don't have a clear enough understanding yet. The current version of the macro, which I've based partly on macro designs from The Scheme Programming Language, 3rd ed. and other sources, is built of three sub-procedures: a fender predicate, a syntax-case which recognizes the individual pattern/value pairs, and the main syntax-case for the overall macro. Given that it is not that complicated a set of patterns it recognizes, I am fairly certain it could be a lot simpler, but this is the best I have managed so far. The code is for R6RS, and I am testing it in Ypsilon 0.9.6-update3.
(define-syntax define-field-pattern
(lambda (x)
(let*
((value-fender?
(lambda (w v)
(and (integer? v)
(> (expt 2 w) v))))
(expand-pattern
(lambda (width elements)
(syntax-case elements (default =>)
((default => ?value)
(value-fender? width (syntax ?value)) ;value valid?
(cons 'default (syntax ?value)))
((?el => ?value)
(value-fender? width (syntax ?value)) ;value valid?
(cons (list (syntax ?el) (syntax ?value))))
((?el-0 ?el-1 ... => ?value)
(value-fender? width (syntax ?value)) ;value valid?
(let ((element (syntax ?el-0))
(rest (syntax (?el-1 ...)))
(value (syntax ?value)))
(list
(cons
(let iter ((curr-element element)
(next-element (car rest)))
(append (list curr-element)
(if (null? next-element)
'()
(iter (next-element (cdr rest))))))
value))))))))
(syntax-case x (width)
((_ ?name (width ?size) (?pattern-0 ?pattern-1 ...))
(syntax
(define ?name
(append (list (cons 'width ?size))
(let loop ((pattern ?pattern-0)
(later-patterns (?pattern-1 ...)))
(expand-pattern (syntax ?size) pattern)
(if (null? later-patterns)
'()
(loop (car later-patterns) (cdr later-patterns))))))))))))
The test case I am using should expand to '((width . 3) ((bar) . 2))
, where width
is the bit-width of the field it represents and (bar)
is the stored pattern. However, I cannot figure out how to get the defined list to be quoted without quoting the actual code. I expect the answer lies with some combination of quasiquoting and unquoting, but I am unclear on how to get the correct sequence.
Any advice would be appreciated.