(module term mzscheme (require "matcher.ss") (provide term term-let term-let-fn term-define-fn) (require-for-syntax "term-fn.ss") (define (with-syntax* stx) (syntax-case stx () [(_ () e) (syntax e)] [(_ (a b ...) e) (syntax (with-syntax (a) (with-syntax* (b ...) e)))])) (define-syntax (term orig-stx) (define outer-bindings '()) (define (rewrite stx) (let loop ([stx stx] [depth 0]) (syntax-case stx (unquote unquote-splicing in-hole hole) [(f arg) (and (identifier? (syntax f)) (term-fn? (syntax-local-value (syntax f) (λ () #f)))) (let ([term-fn (syntax-local-value (syntax f))]) (with-syntax ([f (term-fn-get term-fn 0)] [(f-results) (generate-temporaries '(f-results))]) (let d-loop ([arg-dots (loop (syntax arg) depth)] [fres (syntax f-results)] [func (syntax (lambda (x) (f (syntax-object->datum x))))] [depth depth]) (cond [(zero? depth) (let ([res (with-syntax ([fres fres] [func func] [arg-dots arg-dots]) (set! outer-bindings (cons (syntax [fres (func (quasisyntax arg-dots))]) outer-bindings)) (syntax f-results))]) res)] [else (with-syntax ([dots (quote-syntax ...)] [arg-dots arg-dots] [fres fres]) (d-loop (syntax (arg-dots dots)) (syntax (fres dots)) (with-syntax ([f func]) (syntax (lambda (l) (map f (syntax->list l))))) (- depth 1)))]))))] [f (and (identifier? (syntax f)) (term-fn? (syntax-local-value (syntax f) (λ () #f)))) (raise-syntax-error 'term "metafunction must be in an application" orig-stx stx)] [(f) (and (identifier? (syntax f)) (term-fn? (syntax-local-value (syntax f) (λ () #f)))) (raise-syntax-error 'term "metafunction called with no arguments (expected only a single argument)" orig-stx stx)] [(f x y z ...) (and (identifier? (syntax f)) (term-fn? (syntax-local-value (syntax f) (λ () #f)))) (raise-syntax-error 'term "metafunction called with too many arguments (expected only a single argument)" orig-stx stx)] [(unquote x) (syntax (unsyntax x))] [(unquote . x) (raise-syntax-error 'term "malformed unquote" orig-stx stx)] [(unquote-splicing x) (syntax (unsyntax-splicing x))] [(unquote-splicing . x) (raise-syntax-error 'term "malformed unquote splicing" orig-stx stx)] [(in-hole id body) (syntax (unsyntax (plug (term id) (term body))))] [(in-hole . x) (raise-syntax-error 'term "malformed in-hole" orig-stx stx)] [hole (syntax (unsyntax (make-hole #f)))] [(hole stuff) (syntax (unsyntax (make-hole 'stuff)))] [(x ...) (with-syntax ([(x-rewrite ...) (let i-loop ([xs (syntax->list (syntax (x ...)))]) (cond [(null? xs) null] [(null? (cdr xs)) (list (loop (car xs) depth))] [(and (identifier? (cadr xs)) (module-identifier=? (quote-syntax ...) (cadr xs))) (cons (loop (car xs) (+ depth 1)) (i-loop (cdr xs)))] [else (cons (loop (car xs) depth) (i-loop (cdr xs)))]))]) (syntax (x-rewrite ...)))] [_ stx]))) (syntax-case orig-stx () [(_ arg) (with-syntax ([rewritten (rewrite (syntax arg))]) (let loop ([bs (reverse outer-bindings)]) (cond [(null? bs) (syntax (syntax-object->datum (quasisyntax rewritten)))] [else (with-syntax ([rec (loop (cdr bs))] [fst (car bs)]) (syntax (with-syntax (fst) rec)))])))])) (define-syntax (term-let-fn stx) (syntax-case stx () [(_ ([f rhs] ...) body1 body2 ...) (with-syntax ([(g ...) (generate-temporaries (syntax (f ...)))]) (syntax (let ([g rhs] ...) (let-syntax ([f (make-term-fn #'g)] ...) body1 body2 ...))))])) (define-syntax (term-define-fn stx) (syntax-case stx () [(_ id exp) (with-syntax ([(id2) (generate-temporaries (syntax (id)))]) (syntax (begin (define id2 exp) (define-syntax id (make-term-fn ((syntax-local-certifier) #'id2))))))])) (define-syntax (term-let stx) (syntax-case stx () [(_ ([x rhs] ...) body1 body2 ...) (syntax (with-syntax ([x rhs] ...) (begin body1 body2 ...)))] [(_ x) (raise-syntax-error 'term-let "expected at least one body" stx)])))