racket/collects/swindle/patterns.rkt
2010-04-27 16:50:15 -06:00

266 lines
11 KiB
Racket

#lang mzscheme
(provide (all-from-except mzscheme
define-values
define
let-values
let*-values
letrec-values
let
let*
letrec
set!
set!-values
lambda))
(provide (rename define-values~ define-values)
(rename define~ define)
(rename let-values~ let-values)
(rename let*-values~ let*-values)
(rename letrec-values~ letrec-values)
(rename let~ let)
(rename let*~ let*)
(rename letrec~ letrec)
(rename set!~ set!)
(rename set!-values~ set!-values)
(rename lambda~ lambda))
(define-syntaxes (define-values~
define~
let-values~
let*-values~
letrec-values~
let~
let*~
letrec~
set!~
set!-values~
lambda~)
(let ()
(define (id->handlers id)
(and (identifier? id)
(syntax-local-value
(datum->syntax-object id
(string->symbol
(string-append "extended-arg-keyword:"
(symbol->string
(syntax-e id))))
id)
(lambda () #f))))
(define (flatten-extended-bindings/values stxs expr)
(define temps (generate-temporaries stxs))
(define (remove-false-2nd l)
(let loop ([l l] [r '()])
(if (null? l)
(reverse r)
(loop (cdr l) (if (cadar l) (cons (car l) r) r)))))
(let loop (;; tail: listof (cons extended-id, assigned-temp)
[tail (map cons (syntax->list stxs) temps)]
;; r: listof (list extended-ids new-temps convert-expr)
;; or (list extended-id same-temp #f)
[r '()]
;; #f if non-id scanned, otherwise #t or 'first on first pass
[simple? 'first]
;; vbinds: listof listof listof (vars expr)
[vbinds (list (list (list temps expr)))])
(if (null? tail)
(let ([r (reverse r)])
(if simple?
(if (eq? simple? 'first)
(values stxs expr)
(values (datum->syntax-object stxs (map car r) stxs)
(let loop ([vbs (reverse vbinds)])
(if (null? vbs)
(if (and (pair? r) (null? (cdr r)))
(quasisyntax/loc stxs #,(cadar r))
(quasisyntax/loc stxs (values #,@(map cadr r))))
(quasisyntax/loc stxs
(let-values #,(remove-false-2nd (car vbs))
#,(loop (cdr vbs))))))))
;; saw non-identifiers, so start another iteration
(loop (apply append (map (lambda (x)
(if (caddr x)
(map cons (car x) (cadr x))
(list (cons (car x) (cadr x)))))
r))
'() #t (cons (map cdr r) vbinds))))
(syntax-case (caar tail) ()
[var (identifier? #'var)
(loop (cdr tail) (cons (list (caar tail) (cdar tail) #f) r)
simple? vbinds)]
[(id . xs) (identifier? #'id)
(cond
[(id->handlers #'id) =>
(lambda (handlers)
(let ([bindings (syntax->list ((car handlers) #'xs))]
[new-expr ((cadr handlers) (cdar tail) #'xs)])
(unless (list? bindings)
(error 'extended-binding
"`~s->bindings' returned a non-list value: ~s"
(syntax-e #'id) bindings))
(loop (cdr tail)
(cons (list bindings (generate-temporaries bindings)
new-expr)
r)
#f vbinds)))]
[else (raise-syntax-error
'extended-binding
"got a form which is not an extended binding"
(caar tail) #'id)])]
[_ (raise-syntax-error
'extended-binding "bad binding" (caar tail))]))))
(define (_define-values stx)
(syntax-case stx ()
[(_ (var ...) expr)
(let-values ([(bindings expr)
(flatten-extended-bindings/values #'(var ...) #'expr)])
(quasisyntax/loc stx (define-values #,bindings #,expr)))]))
(define (_define stx)
(syntax-case stx (values)
[(_ (values x ...) expr)
(syntax/loc stx (define-values~ (x ...) expr))]
[(_ (id . xs) expr) (id->handlers #'id)
(syntax/loc stx (define-values~ ((id . xs)) expr))]
[(_ (id . xs) body0 body ...)
(syntax/loc stx (define-values~ (id) (lambda~ xs body0 body ...)))]
[(_ x expr)
(syntax/loc stx (define-values~ (x) expr))]))
(define (make-let-values let-form)
(lambda (stx)
(syntax-case stx ()
[(_ (binding ...) body0 body ...)
(quasisyntax/loc stx
(#,let-form
#,(map (lambda (binding)
(syntax-case binding ()
[((var ...) expr)
(let-values ([(bindings expr)
(flatten-extended-bindings/values
#'(var ...) #'expr)])
(quasisyntax/loc binding
(#,bindings #,expr)))]))
(syntax->list #'(binding ...)))
body0 body ...))])))
(define _let-values (make-let-values #'let-values))
(define _let*-values (make-let-values #'let*-values))
(define _letrec-values (make-let-values #'letrec-values))
(define (make-let let-form label?)
(lambda (stx)
(syntax-case stx ()
[(_ label ((var val) ...) body0 body ...)
(and label? (identifier? #'label))
(quasisyntax/loc stx
((letrec~ ([label (lambda~ (var ...) body0 body ...)]) label)
val ...))]
[(_ (binding ...) body0 body ...)
(quasisyntax/loc stx
(#,let-form #,(map (lambda (binding)
(syntax-case binding (values)
[((values x ...) expr) #'((x ...) expr)]
[(x expr) #'((x) expr)]))
(syntax->list #'(binding ...)))
body0 body ...))])))
(define _let (make-let #'let-values~ #t))
(define _let* (make-let #'let*-values~ #f))
(define _letrec (make-let #'letrec-values~ #f))
(define (_set! stx)
(syntax-case stx (values)
[(_ (values x ...) expr) (syntax/loc stx (set!-values~ (x ...) expr))]
[(_ x expr) (syntax/loc stx (set!-values~ (x) expr))]))
(define (_set!-values stx)
(syntax-case stx ()
[(_ (var ...) expr)
(let-values ([(bindings expr)
(flatten-extended-bindings/values #'(var ...) #'expr)])
(quasisyntax/loc stx
(set!-values #,bindings #,expr)))]))
(define (_lambda stx)
(syntax-case stx ()
[(_ vars body0 body ...)
(let loop ([vs #'vars] [newvars '()] [specials '()] [restarg '()])
(syntax-case vs ()
[((id xs ...) . rest) (identifier? #'id)
(let ([newvar (car (generate-temporaries #'(id)))])
(loop #'rest (cons newvar newvars)
(cons (list #'(id xs ...) newvar) specials)
restarg))]
[(id . rest) (identifier? #'id)
(loop #'rest (cons #'id newvars) specials restarg)]
[id (identifier? #'id)
(loop #'() newvars specials #'id)]
[() (let ([args (datum->syntax-object
#'vars (append (reverse newvars) restarg)
#'vars)])
(if (null? specials)
(quasisyntax/loc stx (lambda #,args body0 body ...))
(quasisyntax/loc stx
(lambda #,args
(let~ #,(reverse specials)
body0 body ...)))))]))]))
(values _define-values
_define
_let-values
_let*-values
_letrec-values
_let
_let*
_letrec
_set!
_set!-values
_lambda)))
;; These are used as procedures for the syntax level
(provide extended-arg-keyword:list extended-arg-keyword:vector)
(define-syntax extended-arg-keyword:list
(list (lambda (vars) vars)
(lambda (expr vars)
(quasisyntax/loc expr (apply values #,expr)))))
(define-syntax extended-arg-keyword:vector
(list (lambda (vars) vars)
(lambda (expr vars)
(quasisyntax/loc expr (apply values (vector->list #,expr))))))
;; quote turns implicit lists and vectors to explicit ones
(provide extended-arg-keyword:quote)
(define-syntax extended-arg-keyword:quote
(list (lambda (vars)
(define (do-vars vs)
(datum->syntax-object
vs (map (lambda (v)
(if (identifier? v) v (quasisyntax/loc v '#,v)))
(syntax->list vs))
vs))
(do-vars (syntax-case vars ()
[((v ...)) #'(v ...)] [(#(v ...)) #'(v ...)])))
(lambda (expr vars)
(syntax-case vars ()
[((v ...))
(quasisyntax/loc expr (apply values #,expr))]
[(#(v ...))
(quasisyntax/loc expr (apply values (vector->list #,expr)))]))))
;; (define (values a (list (vector b c) (vector d) (list)) e)
;; (values 1 (list (vector 2 3) (vector 4) (list)) 5))
;; (list a b c d e)
;; (let ([(values a (list (vector b c) (vector d) (list)) e)
;; (values 1 (list (vector 2 3) (vector 4) (list)) 5)])
;; (list a b c d e))
;; (let* ([(list x y) (list 1 2)] [(list x y) (list y x)]) (list x y))
;; (let ([(values a '(#(b c) #(d) ()) e)
;; (values 1 '(#(2 3) #(4) ()) 5)])
;; (list a b c d e))
;; (map (lambda ((list x y)) (list y x)) '((1 2) (3 4)))
;; (let loop ([(list str n) (list "foo" 10)])
;; (if (zero? n) str (loop (list (string-append str "!") (sub1 n)))))
;;
;; (module foo mzscheme
;; (provide (struct point (x y)) extended-arg-keyword:make-point)
;; (define-struct point (x y))
;; (define-syntax extended-arg-keyword:make-point
;; (list (lambda (vars) (syntax-case vars () ((x y) vars)))
;; (lambda (expr vars)
;; (quasisyntax/loc expr
;; (values (point-x #,expr) (point-y #,expr)))))))
;; (require foo)
;; (define a (make-point 1 2))
;; (let ([(make-point x y) a]) (+ x y))