On Fri, Aug 12, 2011 at 9:22 AM, Neil Van Dyke <n...@neilvandyke.org> wrote: > 1. Without trying it, I'm pretty sure this particular syntax transformation > can be done in "syntax-rules", but I'm not certain it can be done using only > the power of "..." in "syntax-rules", without a helper macro. Your life > might be easier if you do this particular transformation in "syntax-case" > rather than "syntax-rules". >
Below is an example of how to do it without the syntax-rules acrobatics. Besides abandoning syntax-rules, I made two other changes: 1. The `transition-function' macro takes the `curr-state' variable as an input. The macro could make up a variable with the same name, but it wouldn't be bound by the letrec generated by the `automaton' macro -- it's out of scope. The original `process-state' macro had this problem. 2. The `END' transition is defined at the top. It would again be possible to pass the letrec-bound variable into `transition-function' macro, but lifting is easier. ;;;; (define-for-syntax (make-transition-case curr-state-stx transition-spec) (with-syntax ([curr-state curr-state-stx]) (syntax-case transition-spec (-> END) [(label -> END) #'[(label) (set! curr-state END) 'endstate]] [(label -> new-state) #'[(label) (set! curr-state new-state) 'ok]]))) (define-syntax (transition-function stx) (syntax-case stx () [(_ curr-state transition-spec ...) (with-syntax ([(transition-case ...) (for/list ([spec (syntax->list #'(transition-spec ...))]) (make-transition-case #'curr-state spec))]) #'(λ (symbol) (case symbol transition-case ...)))])) (define-syntax automaton (syntax-rules (: -> END) [(_ init-state (state : transition ...) ...) (letrec ([curr-state empty] [state (transition-function curr-state transition ...)] ...) (set! curr-state init-state) (lambda (c) (curr-state c)))])) (define (END symbol) 'reading-past-end-error) (define (make-selector-automaton) (automaton init (init : (c -> more)) (more : (a -> more) (d -> more) (r -> END)))) (require rackunit) (let ([a (make-selector-automaton)]) (check-equal? (a 'c) 'ok) (check-equal? (a 'a) 'ok) (check-equal? (a 'd) 'ok) (check-equal? (a 'r) 'endstate) (check-equal? (a 'q) (END 'whatever))) (let ([a (make-selector-automaton)]) (check-equal? (a 'c) 'ok) ; falls off end of the `case' (check-true (void? (a 'c)))) _________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users