;"mwdenote.scm" Syntactic Environments ; Copyright 1992 William Clinger ; ; Permission to copy this software, in whole or in part, to use this ; software for any lawful purpose, and to redistribute this software ; is granted subject to the restriction that all copies made of this ; software must include this copyright notice in full. ; ; I also request that you send me a copy of any improvements that you ; make to this software so that they may be incorporated within it to ; the benefit of the Scheme community. ;;;; Syntactic environments. ; A syntactic environment maps identifiers to denotations, ; where a denotation is one of ; ; (special ) ; (macro ) ; (identifier ) ; ; and where is one of ; ; quote ; lambda ; if ; set! ; begin ; define ; define-syntax ; let-syntax ; letrec-syntax ; syntax-rules ; ; and where is a compiled (see R4RS), ; is a syntactic environment, and is an identifier. (define mw:standard-syntax-environment '((quote . (special quote)) (lambda . (special lambda)) (if . (special if)) (set! . (special set!)) (begin . (special begin)) (define . (special define)) (let . (special let)) ;; @@ added KAD (let* . (special let*)) ;; @@ " (letrec . (special letrec)) ;; @@ " (quasiquote . (special quasiquote)) ;; @@ " (unquote . (special unquote)) ;; @@ " (unquote-splicing . (special unquote-splicing)) ; @@ " (do . (special do)) ;; @@ " (define-syntax . (special define-syntax)) (let-syntax . (special let-syntax)) (letrec-syntax . (special letrec-syntax)) (syntax-rules . (special syntax-rules)) (... . (identifier ...)) (::: . (identifier :::)))) ; An unforgeable synonym for lambda, used to expand definitions. (define mw:lambda0 (string->symbol " lambda ")) ; The mw:global-syntax-environment will always be a nonempty ; association list since there is no way to remove the entry ; for mw:lambda0. That entry is used as a header by destructive ; operations. (define mw:global-syntax-environment (cons (cons mw:lambda0 (cdr (assq 'lambda mw:standard-syntax-environment))) (mw:syntax-copy mw:standard-syntax-environment))) (define (mw:global-syntax-environment-set! env) (set-cdr! mw:global-syntax-environment env)) (define (mw:syntax-bind-globally! id denotation) (if (and (mw:identifier? denotation) (eq? id (mw:identifier-name denotation))) (letrec ((remove-bindings-for-id (lambda (bindings) (cond ((null? bindings) '()) ((eq? (caar bindings) id) (remove-bindings-for-id (cdr bindings))) (else (cons (car bindings) (remove-bindings-for-id (cdr bindings)))))))) (mw:global-syntax-environment-set! (remove-bindings-for-id (cdr mw:global-syntax-environment)))) (let ((x (assq id mw:global-syntax-environment))) (if x (set-cdr! x denotation) (mw:global-syntax-environment-set! (cons (cons id denotation) (cdr mw:global-syntax-environment))))))) (define (mw:syntax-divert env1 env2) (append env2 env1)) (define (mw:syntax-extend env ids denotations) (mw:syntax-divert env (map cons ids denotations))) (define (mw:syntax-lookup-raw env id) (let ((entry (assq id env))) (if entry (cdr entry) #f))) (define (mw:syntax-lookup env id) (or (mw:syntax-lookup-raw env id) (mw:make-identifier-denotation id))) (define (mw:syntax-assign! env id denotation) (let ((entry (assq id env))) (if entry (set-cdr! entry denotation) (mw:bug "Bug detected in mw:syntax-assign!" env id denotation)))) (define mw:denote-of-quote (mw:syntax-lookup mw:standard-syntax-environment 'quote)) (define mw:denote-of-lambda (mw:syntax-lookup mw:standard-syntax-environment 'lambda)) (define mw:denote-of-if (mw:syntax-lookup mw:standard-syntax-environment 'if)) (define mw:denote-of-set! (mw:syntax-lookup mw:standard-syntax-environment 'set!)) (define mw:denote-of-begin (mw:syntax-lookup mw:standard-syntax-environment 'begin)) (define mw:denote-of-define (mw:syntax-lookup mw:standard-syntax-environment 'define)) (define mw:denote-of-define-syntax (mw:syntax-lookup mw:standard-syntax-environment 'define-syntax)) (define mw:denote-of-let-syntax (mw:syntax-lookup mw:standard-syntax-environment 'let-syntax)) (define mw:denote-of-letrec-syntax (mw:syntax-lookup mw:standard-syntax-environment 'letrec-syntax)) (define mw:denote-of-syntax-rules (mw:syntax-lookup mw:standard-syntax-environment 'syntax-rules)) (define mw:denote-of-... (mw:syntax-lookup mw:standard-syntax-environment '...)) (define mw:denote-of-::: (mw:syntax-lookup mw:standard-syntax-environment ':::)) (define mw:denote-of-let (mw:syntax-lookup mw:standard-syntax-environment 'let)) ;; @@ KenD (define mw:denote-of-let* (mw:syntax-lookup mw:standard-syntax-environment 'let*)) ;; @@ KenD (define mw:denote-of-letrec (mw:syntax-lookup mw:standard-syntax-environment 'letrec)) ;; @@ KenD (define mw:denote-of-quasiquote (mw:syntax-lookup mw:standard-syntax-environment 'quasiquote)) ;; @@ KenD (define mw:denote-of-unquote (mw:syntax-lookup mw:standard-syntax-environment 'unquote)) ;; @@ KenD (define mw:denote-of-unquote-splicing (mw:syntax-lookup mw:standard-syntax-environment 'unquote-splicing)) ;@@ KenD (define mw:denote-of-do (mw:syntax-lookup mw:standard-syntax-environment 'do)) ;; @@ KenD (define mw:denote-class car) ;(define (mw:special? denotation) ; (eq? (mw:denote-class denotation) 'special)) ;(define (mw:macro? denotation) ; (eq? (mw:denote-class denotation) 'macro)) (define (mw:identifier? denotation) (eq? (mw:denote-class denotation) 'identifier)) (define (mw:make-identifier-denotation id) (list 'identifier id)) (define macwork:rules cadr) (define macwork:env caddr) (define mw:identifier-name cadr) (define (mw:same-denotation? d1 d2) (or (eq? d1 d2) (and (mw:identifier? d1) (mw:identifier? d2) (eq? (mw:identifier-name d1) (mw:identifier-name d2))))) ; Renaming of variables. ; Given a datum, strips the suffixes from any symbols that appear within ; the datum, trying not to copy any more of the datum than necessary. ; Well, right now I'm just copying the datum, but I need to fix that! (define (mw:strip x) (cond ((symbol? x) (let ((chars (memv mw:suffix-character (reverse (string->list (symbol->string x)))))) (if chars (string->symbol (list->string (reverse (cdr chars)))) x))) ((pair? x) (cons (mw:strip (car x)) (mw:strip (cdr x)))) ((vector? x) (list->vector (map mw:strip (vector->list x)))) (else x))) ; Given a list of identifiers, returns an alist that associates each ; identifier with a fresh identifier. (define (mw:rename-vars vars) (set! mw:renaming-counter (+ mw:renaming-counter 1)) (let ((suffix (string-append (string mw:suffix-character) (number->string mw:renaming-counter)))) (map (lambda (var) (if (symbol? var) (cons var (string->symbol (string-append (symbol->string var) suffix))) (slib:error "Illegal variable" var))) vars))) ; Given a syntactic environment env to be extended, an alist returned ; by mw:rename-vars, and a syntactic environment env2, extends env by ; binding the fresh identifiers to the denotations of the original ; identifiers in env2. (define (mw:syntax-alias env alist env2) (mw:syntax-divert env (map (lambda (name-pair) (let ((old-name (car name-pair)) (new-name (cdr name-pair))) (cons new-name (mw:syntax-lookup env2 old-name)))) alist))) ; Given a syntactic environment and an alist returned by mw:rename-vars, ; extends the environment by binding the old identifiers to the fresh ; identifiers. (define (mw:syntax-rename env alist) (mw:syntax-divert env (map (lambda (old new) (cons old (mw:make-identifier-denotation new))) (map car alist) (map cdr alist)))) ; Given a and an alist returned by mw:rename-vars that contains ; a new name for each formal identifier in , renames the ; formal identifiers. (define (mw:rename-formals formals alist) (cond ((null? formals) '()) ((pair? formals) (cons (cdr (assq (car formals) alist)) (mw:rename-formals (cdr formals) alist))) (else (cdr (assq formals alist))))) (define mw:renaming-counter 0)