#lang debug racket/base (require racket/match racket/string (for-syntax racket/base) "param.rkt" "quad.rkt") (provide (all-defined-out)) (define (list-of proc) (λ (x) (and (list? x) (for/and ([xi (in-list x)]) (or (proc xi) (let ([procname (object-name proc)]) (raise-argument-error (string->symbol (format "list-of ~a" procname)) (symbol->string procname) xi))))))) (struct pipeline (passes) #:guard (λ (procs name) (unless ((list-of procedure?) procs) (raise-argument-error 'bad-input-to-compiler-constructor "list of procedures" procs)) procs) #:property prop:procedure (λ args (match-define (list* pipeline pass-arg _) args) (let ([show-timing? (current-show-timing?)]) (for/fold ([pass-arg pass-arg]) ([pass (in-list (pipeline-passes pipeline))]) (define thunk (λ () (pass pass-arg))) (if show-timing? (time (displayln pass) (thunk)) (thunk)))))) (define (make-pipeline . passes) (pipeline passes)) (define (compiler-append c passes) (make-pipeline (append (pipeline-passes c) passes))) (define-syntax (define-pass stx) (syntax-case stx () [(_ (PASS-NAME ARG OTHER-ARG ...) #:pre PRECOND-PROC #:post POSTCOND-PROC EXPRS ...) #`(define PASS-NAME (make-pipeline (procedure-rename #,(syntax/loc stx (λ (ARG) (define ((make-failure-handler failure-msg) exn) (raise (make-exn:fail:contract (string-replace (exn-message exn) "contract violation" (string-append "contract violation in " failure-msg)) (exn-continuation-marks exn)))) (when (current-use-preconditions?) (define failure-msg (format "~a pass (as precondition)" 'PASS-NAME)) (with-handlers ([exn:fail:contract? (make-failure-handler failure-msg)]) (unless (PRECOND-PROC ARG) (raise-argument-error 'PASS-NAME (format "~a" 'PRECOND-PROC) ARG)))) ;; a pass can be functional or mutational. ;; if it returns void, assume mutational ;; and return the input item. (define res (match (let () EXPRS ...) [(? void?) ARG] [val val])) (begin0 res (when (current-use-postconditions?) (define failure-msg (format "~a pass (as postcondition)" 'PASS-NAME)) (with-handlers ([exn:fail:contract? (make-failure-handler failure-msg)]) (unless (POSTCOND-PROC res) (raise-argument-error 'PASS-NAME (format "~a" 'POSTCOND-PROC) ARG))))))) 'PASS-NAME)))])) (define-pass (print-pass qs) #:pre values #:post values (for-each println qs))