;;; Ported from Scheme 48 1.9. See file COPYING for notices and license. ;;; ;;; Port Author: Andrew Whatson ;;; ;;; Original Authors: Richard Kelsey, Jonathan Rees, Martin Gasbichler, Mike Sperber ;;; ;;; scheme48-1.9.2/scheme/bcomp/schemify.scm ;;; ;;; schemify ;;; ;;; This is only used for producing error and warning messages. ;;; ;;; Flush nodes and generated names in favor of something a little more ;;; readable. Eventually, (schemify node env) ought to produce an ;;; s-expression that has the same semantics as node, when node is fully ;;; expanded. (define-module (prescheme bcomp schemify) #:use-module (prescheme scheme48) #:use-module (prescheme bcomp cenv) #:use-module (prescheme bcomp binding) #:use-module (prescheme bcomp mtype) #:use-module (prescheme bcomp name) #:use-module (prescheme bcomp node) #:use-module (prescheme bcomp package) #:use-module (prescheme bcomp transform) #:export (schemify)) (define (schemify node . maybe-env) (if (node? node) (schemify-node node (if (null? maybe-env) #f (car maybe-env))) (schemify-sexp node))) (define schemifiers (make-operator-table (lambda (node env) (let ((form (node-form node))) (if (list? form) (let ((op (car form))) (cons (cond ((operator? op) (operator-name op)) ((node? op) (schemify-node op env)) (else (schemify-sexp op))) (schemify-nodes (cdr form) env))) form))))) ;; We cache the no-env version because that's the one used to generate the ;; sources in the debugging info (which takes up a lot of space). (define (schemify-node node env) (or (and (not env) (node-ref node 'schemify)) (let ((form ((operator-table-ref schemifiers (node-operator-id node)) node env))) (if (not env) (node-set! node 'schemify form)) form))) (define (schemify-nodes nodes env) (map (lambda (node) (schemify-node node env)) nodes)) (define (define-schemifier name type proc) (operator-define! schemifiers name type proc)) (define-schemifier 'name 'leaf (lambda (node env) (if env (name->qualified (node-form node) env) (let ((form (node-form node))) (if (or #f (node? form)) (schemify-node form env) (desyntaxify form)))))) ;; Convert an alias (generated name) to S-expression form ("qualified name"). (define (name->qualified name env) (cond ((not (generated? name)) name) ((let ((d0 (lookup env name)) (d1 (lookup env (generated-name name)))) (and d0 d1 (same-denotation? d0 d1))) (generated-name name)) ;;+++ (else (make-qualified (qualify-parent (generated-parent-name name) env) (generated-name name) (generated-uid name))))) ;; As an optimization, we elide intermediate steps in the lookup path ;; when possible. E.g. ;; #(>> #(>> #(>> define-record-type define-accessors) ;; define-accessor) ;; record-ref) ;; is replaced with ;; #(>> define-record-type record-ref) (define (qualify-parent name env) (let recur ((name name) (env env)) (if (generated? name) (let ((parent (generated-parent-name name))) (if (and (environment-stable? env) (let ((b1 (generic-lookup env name)) (b2 (generic-lookup env parent))) (and b1 b2 (or (same-denotation? b1 b2) (and (binding? b1) (binding? b2) (let ((s1 (binding-static b1)) (s2 (binding-static b2))) (and (transform? s1) (transform? s2) (eq? (transform-env s1) (transform-env s2))))))))) (recur parent env) ;;+++ (make-qualified (recur parent (generated-env name)) (generated-name name) (generated-uid name)))) name))) (define-schemifier 'quote syntax-type (lambda (node env) (let ((form (node-form node))) `(quote ,(cadr form))))) (define-schemifier 'call 'internal (lambda (node env) (map (lambda (node) (schemify-node node env)) (node-form node)))) ;; We ignore the list of free variables in flat lambdas. (define (schemify-lambda node env) (let ((form (node-form node))) `(lambda ,(schemify-formals (cadr form) env) ,(schemify-node (last form) env)))) (define-schemifier 'lambda syntax-type schemify-lambda) (define-schemifier 'flat-lambda syntax-type schemify-lambda) (define (schemify-formals formals env) (cond ((node? formals) (schemify-node formals env)) ((pair? formals) (cons (schemify-node (car formals) env) (schemify-formals (cdr formals) env))) (else (schemify-sexp formals)))) ;; anything besides '() ? ;; let-syntax, letrec-syntax... (define-schemifier 'letrec syntax-type (lambda (node env) (let ((form (node-form node))) (schemify-letrec 'letrec (cadr form) (caddr form) env)))) (define-schemifier 'letrec* syntax-type (lambda (node env) (let ((form (node-form node))) (schemify-letrec 'letrec* (cadr form) (caddr form) env)))) (define-schemifier 'pure-letrec syntax-type (lambda (node env) (let ((form (node-form node))) (schemify-letrec 'letrec (cadr form) (cadddr form) env)))) (define (schemify-letrec op specs body env) `(,op ,(map (lambda (spec) (schemify-nodes spec env)) specs) ,(schemify-node body env))) (define-schemifier 'loophole syntax-type (lambda (node env) (let ((form (node-form node))) (list 'loophole (type->sexp (cadr form) #t) (schemify-node (caddr form) env))))) (define-schemifier 'lap syntax-type (lambda (node env) (let ((form (node-form node))) `(lap ,(cadr form) ,(schemify-nodes (caddr form) env) . ,(cdddr form))))) ;;---------------- (define (schemify-sexp thing) (cond ((name? thing) (desyntaxify thing)) ((pair? thing) (let ((x (schemify-sexp (car thing))) (y (schemify-sexp (cdr thing)))) (if (and (eq? x (car thing)) (eq? y (cdr thing))) thing ;;+++ (cons x y)))) ((vector? thing) (let ((new (make-vector (vector-length thing) #f))) (let loop ((i 0) (same? #t)) (if (>= i (vector-length thing)) (if same? thing new) ;+++ (let ((x (schemify-sexp (vector-ref thing i)))) (vector-set! new i x) (loop (+ i 1) (and same? (eq? x (vector-ref thing i))))))))) (else thing)))