;;; Copyright (c) 2006, 2007 Abdulaziz Ghuloum and Kent Dybvig ;;; ;;; Permission is hereby granted, free of charge, to any person obtaining a ;;; copy of this software and associated documentation files (the "Software"), ;;; to deal in the Software without restriction, including without limitation ;;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;;; and/or sell copies of the Software, and to permit persons to whom the ;;; Software is furnished to do so, subject to the following conditions: ;;; ;;; The above copyright notice and this permission notice shall be included in ;;; all copies or substantial portions of the Software. ;;; ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;;; DEALINGS IN THE SOFTWARE. (library (psyntax builders) (export build-lexical-assignment build-global-reference build-application build-conditional build-lexical-reference build-global-assignment build-global-definition build-lambda build-case-lambda build-let build-primref build-foreign-call build-data build-sequence build-void build-letrec build-letrec* build-global-define build-library-letrec*) (import (rnrs) (psyntax compat) (psyntax config)) (define (build-global-define x) (if-wants-global-defines `(define ,x '#f) (build-void))) (define build-application (lambda (ae fun-exp arg-exps) (if ae `(annotated-call ,ae ,fun-exp . ,arg-exps) (cons fun-exp arg-exps)))) (define-syntax build-conditional (syntax-rules () ((_ ae test-exp then-exp else-exp) `(if ,test-exp ,then-exp ,else-exp)))) (define-syntax build-lexical-reference (syntax-rules () ((_ ae var) var))) (define-syntax build-lexical-assignment (syntax-rules () ((_ ae var exp) `(set! ,var ,exp)))) (define-syntax build-global-reference (syntax-rules () ((_ ae var) var))) (define-syntax build-global-assignment (syntax-rules () ((_ ae var exp) `(set! ,var ,exp)))) (define-syntax build-global-definition (syntax-rules () ((_ ae var exp) (build-global-assignment ae var exp)))) (define build-lambda (lambda (ae vars exp) (if-wants-case-lambda (build-case-lambda ae (list vars) (list exp)) `(lambda ,vars ,exp)))) (define build-case-lambda (if-wants-case-lambda (lambda (ae vars* exp*) (if ae `(annotated-case-lambda ,ae . ,(map list vars* exp*)) `(case-lambda . ,(map list vars* exp*)))) (lambda (ae vars* exp*) (define (build-error ae) (build-application ae (build-primref ae 'error) (list (build-data ae 'apply) (build-data ae "invalid arg count")))) (define (build-pred ae n vars) (let-values (((count pred) (let f ((vars vars) (count 0)) (cond ((pair? vars) (f (cdr vars) (+ count 1))) ((null? vars) (values count '=)) (else (values count '>=)))))) (build-application ae (build-primref ae pred) (list (build-lexical-reference ae n) (build-data ae count))))) (define (build-apply ae g vars exp) (build-application ae (build-primref ae 'apply) (list (build-lambda ae vars exp) (build-lexical-reference ae g)))) (define (expand-case-lambda ae vars exp*) (let ((g (gensym)) (n (gensym))) `(lambda ,g ,(build-let ae (list n) (list (build-application ae (build-primref ae 'length) (list (build-lexical-reference ae g)))) (let f ((vars* vars*) (exp* exp*)) (if (null? vars*) (build-error ae) (build-conditional ae (build-pred ae n (car vars*)) (build-apply ae g (car vars*) (car exp*)) (f (cdr vars*) (cdr exp*))))))))) (if (= (length exp*) 1) (build-lambda ae (car vars*) (car exp*)) (expand-case-lambda ae vars* exp*))))) (define build-let (lambda (ae lhs* rhs* body) (build-application ae (build-lambda ae lhs* body) rhs*))) (define-syntax build-primref (syntax-rules () ((_ ae name) (build-primref ae 1 name)) ((_ ae level name) `(primitive ,name)))) (define-syntax build-foreign-call (syntax-rules () ((_ ae name arg*) `(foreign-call ,name . ,arg*)))) (define-syntax build-data (syntax-rules () ((_ ae exp) `',exp))) (define build-sequence (lambda (ae exps) (let loop ((exps exps)) (if (null? (cdr exps)) (car exps) (if (equal? (car exps) (build-void)) (loop (cdr exps)) `(begin ,@exps)))))) (define build-void (lambda () '((primitive void)))) (define build-letrec (lambda (ae vars val-exps body-exp) (if (null? vars) body-exp `(letrec ,(map list vars val-exps) ,body-exp)))) (define build-letrec* (lambda (ae vars val-exps body-exp) (cond ((null? vars) body-exp) (else (if-wants-letrec* `(letrec* ,(map list vars val-exps) ,body-exp) (build-let ae vars (map (lambda (x) (build-data ae #f)) vars) (build-sequence ae (append (map (lambda (lhs rhs) (build-lexical-assignment ae lhs rhs)) vars val-exps) (list body-exp))))))))) (define build-library-letrec* (lambda (ae top? vars locs val-exps body-exp) (if-wants-library-letrec* `(library-letrec* ,(map list vars locs val-exps) ,body-exp) (build-letrec* ae vars val-exps (if top? body-exp (build-sequence ae (cons body-exp (map (lambda (var loc) (build-global-assignment ae loc var)) vars locs)))))))) )