datum->syntax
, which I faced before (if I knew this paper at that moment!).In 'Implementation' section, the SRFI mentions that this is implemented on 'Rapid Scheme', Guile and Racket. Unfortunately there's no portable implementation. In my very prejudiced perspective, Guile isn't so fascinated by macro, so the syntax parameters is probably implemented on top of existing macro expander (I haven't check since Guile is released under GPL, and if I see the code it may violates the license). If so, it might be able to be implemented on
syntax-case
.Without any deep thinking, I've written the very sloppy implementation like this:
#!r6rs (library (srfi :139 syntax-parameters) (export define-syntax-parameter syntax-parameterize) (import (rnrs)) (define-syntax define-syntax-parameter (syntax-rules () ((_ keyword transformer) (define-syntax keyword transformer)))) (define-syntax syntax-parameterize (lambda (x) (define (rewrite k body keys) (syntax-case body () (() '()) ((a . d) #`(#,(rewrite k #'a keys). #,(rewrite k #'d keys))) (#(e ...) #`#(#,@(rewrite k #'(e ...) keys))) (e (and (identifier? #'e) (exists (lambda (o) (free-identifier=? #'e o)) keys)) (datum->syntax k (syntax->datum #'e))) (e #'e))) (syntax-case x () ((k ((keyword spec) ...) body1 body* ...) (with-syntax (((n* ...) (map (lambda (n) (datum->syntax #'k (syntax->datum n))) #'(keyword ...))) ((nb1 nb* ...) (rewrite #'k #'(body1 body* ...) #'(keyword ...)))) #'(letrec-syntax ((n* spec) ...) nb1 nb* ...)))))) )And this can be used like this (taken from example of the SRFI):
#!r6rs (import (rnrs) (srfi :139 syntax-parameters)) (define-syntax-parameter abort (syntax-rules () ((_ . _) (syntax-error "abort used outside of a loop")))) (define-syntax forever (syntax-rules () ((forever body1 body2 ...) (call-with-current-continuation (lambda (escape) (syntax-parameterize ((abort (syntax-rules () ((abort value (... ...)) (escape value (... ...)))))) (let loop () body1 body2 ... (loop)))))))) (define i 0) (forever (display i) (newline) (set! i (+ 1 i)) (when (= i 10) (abort))) (define-syntax-parameter return (syntax-rules () ((_ . _) (syntax-error "return used outside of a lambda^")))) (define-syntax lambda^ (syntax-rules () ((lambda^ formals body1 body2 ...) (lambda formals (call-with-current-continuation (lambda (escape) (syntax-parameterize ((return (syntax-rules () ((return value (... ...)) (escape value (... ...)))))) body1 body2 ...))))))) (define product (lambda^ (list) (fold-left (lambda (n o) (if (zero? n) (return 0) (* n o))) 1 list))) (display (product '(1 2 3 4 5))) (newline)I've tested on Chez, Larceny, Mosh and Sagittarius.
This implementation violates some of 'MUST' specified in the SRFI.
- keyword bound on
syntax-parameterize
doesn't have to be syntax parameter. (on the SRFI it MUST be) - keyword on
syntax-parameterize
doesn't have to have binding.
define-syntax-parameter
does nothingsyntax-parameterize
traverses the given expression.
No comments:
Post a Comment