home *** CD-ROM | disk | FTP | other *** search
- ;;; "synclo.scm" Syntactic Closures -*-Scheme-*-
- ;;; Copyright (c) 1989-91 Massachusetts Institute of Technology
- ;;;
- ;;; This material was developed by the Scheme project at the
- ;;; Massachusetts Institute of Technology, Department of Electrical
- ;;; Engineering and Computer Science. Permission to copy this
- ;;; software, to redistribute it, and to use it for any purpose is
- ;;; granted, subject to the following restrictions and understandings.
- ;;;
- ;;; 1. Any copy made of this software must include this copyright
- ;;; notice in full.
- ;;;
- ;;; 2. Users of this software agree to make their best efforts (a) to
- ;;; return to the MIT Scheme project any improvements or extensions
- ;;; that they make, so that these may be included in future releases;
- ;;; and (b) to inform MIT of noteworthy uses of this software.
- ;;;
- ;;; 3. All materials developed as a consequence of the use of this
- ;;; software shall duly acknowledge such use, in accordance with the
- ;;; usual standards of acknowledging credit in academic research.
- ;;;
- ;;; 4. MIT has made no warrantee or representation that the operation
- ;;; of this software will be error-free, and MIT is under no
- ;;; obligation to provide any services, by way of maintenance, update,
- ;;; or otherwise.
- ;;;
- ;;; 5. In conjunction with products arising from the use of this
- ;;; material, there shall be no use of the name of the Massachusetts
- ;;; Institute of Technology nor of any adaptation thereof in any
- ;;; advertising, promotional, or sales literature without prior
- ;;; written consent from MIT in each case.
-
- ;;;; Syntactic Closures
- ;;; written by Alan Bawden
- ;;; extensively modified by Chris Hanson
-
- ;;; See "Syntactic Closures", by Alan Bawden and Jonathan Rees, in
- ;;; Proceedings of the 1988 ACM Conference on Lisp and Functional
- ;;; Programming, page 86.
-
- ;;;; Classifier
- ;;; The classifier maps forms into items. In addition to locating
- ;;; definitions so that they can be properly processed, it also
- ;;; identifies keywords and variables, which allows a powerful form
- ;;; of syntactic binding to be implemented.
-
- (define (classify/form form environment definition-environment)
- (cond ((identifier? form)
- (syntactic-environment/lookup environment form))
- ((syntactic-closure? form)
- (let ((form (syntactic-closure/form form))
- (environment
- (filter-syntactic-environment
- (syntactic-closure/free-names form)
- environment
- (syntactic-closure/environment form))))
- (classify/form form
- environment
- definition-environment)))
- ((pair? form)
- (let ((item
- (classify/subexpression (car form) environment)))
- (cond ((keyword-item? item)
- ((keyword-item/classifier item) form
- environment
- definition-environment))
- ((list? (cdr form))
- (let ((items
- (classify/subexpressions (cdr form)
- environment)))
- (make-expression-item
- (lambda ()
- (output/combination
- (compile-item/expression item)
- (map compile-item/expression items)))
- form)))
- (else
- (syntax-error "combination must be a proper list"
- form)))))
- (else
- (make-expression-item ;don't quote literals evaluating to themselves
- (if (or (boolean? form) (char? form) (number? form) (string? form))
- (lambda () (output/literal-unquoted form))
- (lambda () (output/literal-quoted form))) form))))
-
- (define (classify/subform form environment definition-environment)
- (classify/form form
- environment
- definition-environment))
-
- (define (classify/subforms forms environment definition-environment)
- (map (lambda (form)
- (classify/subform form environment definition-environment))
- forms))
-
- (define (classify/subexpression expression environment)
- (classify/subform expression environment environment))
-
- (define (classify/subexpressions expressions environment)
- (classify/subforms expressions environment environment))
-
- ;;;; Compiler
- ;;; The compiler maps items into the output language.
-
- (define (compile-item/expression item)
- (let ((illegal
- (lambda (item name)
- (let ((decompiled (decompile-item item))) (newline)
- (slib:error (string-append name
- " may not be used as an expression")
- decompiled)))))
- (cond ((variable-item? item)
- (output/variable (variable-item/name item)))
- ((expression-item? item)
- ((expression-item/compiler item)))
- ((body-item? item)
- (let ((items (flatten-body-items (body-item/components item))))
- (if (null? items)
- (illegal item "empty sequence")
- (output/sequence (map compile-item/expression items)))))
- ((definition-item? item)
- (let ((binding ;allows later scheme errors, but allows top-level
- (bind-definition-item! ;(if (not (defined? x)) define it)
- scheme-syntactic-environment item))) ;as in Init.scm
- (output/top-level-definition
- (car binding)
- (compile-item/expression (cdr binding)))))
- ((keyword-item? item)
- (illegal item "keyword"))
- (else
- (impl-error "unknown item" item)))))
-
- (define (compile/subexpression expression environment)
- (compile-item/expression
- (classify/subexpression expression environment)))
-
- (define (compile/top-level forms environment)
- ;; Top-level syntactic definitions affect all forms that appear
- ;; after them.
- (output/top-level-sequence
- (let forms-loop ((forms forms))
- (if (null? forms)
- '()
- (let items-loop
- ((items
- (item->list
- (classify/subform (car forms)
- environment
- environment))))
- (cond ((null? items)
- (forms-loop (cdr forms)))
- ((definition-item? (car items))
- (let ((binding
- (bind-definition-item! environment (car items))))
- (if binding
- (cons (output/top-level-definition
- (car binding)
- (compile-item/expression (cdr binding)))
- (items-loop (cdr items)))
- (items-loop (cdr items)))))
- (else
- (cons (compile-item/expression (car items))
- (items-loop (cdr items))))))))))
-
- ;;;; De-Compiler
- ;;; The de-compiler maps partly-compiled things back to the input language,
- ;;; as far as possible. Used to display more meaningful macro error messages.
-
- (define (decompile-item item)
- (display " ")
- (cond ((variable-item? item) (variable-item/name item))
- ((expression-item? item)
- (decompile-item (expression-item/annotation item)))
- ((body-item? item)
- (let ((items (flatten-body-items (body-item/components item))))
- (display "sequence")
- (if (null? items)
- "empty sequence"
- "non-empty sequence")))
- ((definition-item? item) "definition")
- ((keyword-item? item)
- (decompile-item (keyword-item/name item)));in case expression
- ((syntactic-closure? item); (display "syntactic-closure;")
- (decompile-item (syntactic-closure/form item)))
- ((list? item) (display "(")
- (map decompile-item item) (display ")") "see list above")
- ((string? item) item);explicit name-string for keyword-item
- ((symbol? item) (display item) item) ;symbol for syntactic-closures
- ((boolean? item) (display item) item) ;symbol for syntactic-closures
- (else (write item) (impl-error "unknown item" item))))
-
- ;;;; Syntactic Closures
-
- (define syntactic-closure-type
- (make-record-type "syntactic-closure" '(ENVIRONMENT FREE-NAMES FORM)))
-
- (define make-syntactic-closure
- (record-constructor syntactic-closure-type '(ENVIRONMENT FREE-NAMES FORM)))
-
- (define syntactic-closure?
- (record-predicate syntactic-closure-type))
-
- (define syntactic-closure/environment
- (record-accessor syntactic-closure-type 'ENVIRONMENT))
-
- (define syntactic-closure/free-names
- (record-accessor syntactic-closure-type 'FREE-NAMES))
-
- (define syntactic-closure/form
- (record-accessor syntactic-closure-type 'FORM))
-
- (define (make-syntactic-closure-list environment free-names forms)
- (map (lambda (form) (make-syntactic-closure environment free-names form))
- forms))
-
- (define (strip-syntactic-closures object)
- (cond ((syntactic-closure? object)
- (strip-syntactic-closures (syntactic-closure/form object)))
- ((pair? object)
- (cons (strip-syntactic-closures (car object))
- (strip-syntactic-closures (cdr object))))
- ((vector? object)
- (let ((length (vector-length object)))
- (let ((result (make-vector length)))
- (do ((i 0 (+ i 1)))
- ((= i length))
- (vector-set! result i
- (strip-syntactic-closures (vector-ref object i))))
- result)))
- (else
- object)))
-
- (define (identifier? object)
- (or (symbol? object)
- (synthetic-identifier? object)))
-
- (define (synthetic-identifier? object)
- (and (syntactic-closure? object)
- (identifier? (syntactic-closure/form object))))
-
- (define (identifier->symbol identifier)
- (cond ((symbol? identifier)
- identifier)
- ((synthetic-identifier? identifier)
- (identifier->symbol (syntactic-closure/form identifier)))
- (else
- (impl-error "not an identifier" identifier))))
-
- (define (identifier=? environment-1 identifier-1 environment-2 identifier-2)
- (let ((item-1 (syntactic-environment/lookup environment-1 identifier-1))
- (item-2 (syntactic-environment/lookup environment-2 identifier-2)))
- (or (eq? item-1 item-2)
- ;; This is necessary because an identifier that is not
- ;; explicitly bound by an environment is mapped to a variable
- ;; item, and the variable items are not cached. Therefore
- ;; two references to the same variable result in two
- ;; different variable items.
- (and (variable-item? item-1)
- (variable-item? item-2)
- (eq? (variable-item/name item-1)
- (variable-item/name item-2))))))
-
- ;;;; Syntactic Environments
-
- (define syntactic-environment-type
- (make-record-type
- "syntactic-environment"
- '(PARENT
- LOOKUP-OPERATION
- RENAME-OPERATION
- DEFINE-OPERATION
- BINDINGS-OPERATION)))
-
- (define make-syntactic-environment
- (record-constructor syntactic-environment-type
- '(PARENT
- LOOKUP-OPERATION
- RENAME-OPERATION
- DEFINE-OPERATION
- BINDINGS-OPERATION)))
-
- (define syntactic-environment?
- (record-predicate syntactic-environment-type))
-
- (define syntactic-environment/parent
- (record-accessor syntactic-environment-type 'PARENT))
-
- (define syntactic-environment/lookup-operation
- (record-accessor syntactic-environment-type 'LOOKUP-OPERATION))
-
- (define (syntactic-environment/assign! environment name item)
- (let ((binding
- ((syntactic-environment/lookup-operation environment) name)))
- (if binding
- (set-cdr! binding item)
- (impl-error "can't assign unbound identifier" name))))
-
- (define syntactic-environment/rename-operation
- (record-accessor syntactic-environment-type 'RENAME-OPERATION))
-
- (define (syntactic-environment/rename environment name)
- ((syntactic-environment/rename-operation environment) name))
-
- (define syntactic-environment/define!
- (let ((accessor
- (record-accessor syntactic-environment-type 'DEFINE-OPERATION)))
- (lambda (environment name item)
- ((accessor environment) name item))))
-
- (define syntactic-environment/bindings
- (let ((accessor
- (record-accessor syntactic-environment-type 'BINDINGS-OPERATION)))
- (lambda (environment)
- ((accessor environment)))))
-
- (define (syntactic-environment/lookup environment name)
- (let ((binding
- ((syntactic-environment/lookup-operation environment) name)))
- (cond (binding
- (let ((item (cdr binding)))
- (if (reserved-name-item? item)
- (syntax-error "premature reference to reserved name"
- name)
- item)))
- ((symbol? name)
- (make-variable-item name))
- ((synthetic-identifier? name)
- (syntactic-environment/lookup (syntactic-closure/environment name)
- (syntactic-closure/form name)))
- (else
- (impl-error "not an identifier" name)))))
-
- (define root-syntactic-environment
- (make-syntactic-environment
- #f
- (lambda (name)
- name
- #f)
- (lambda (name)
- name)
- (lambda (name item)
- (impl-error "can't bind name in root syntactic environment" name item))
- (lambda ()
- '())))
-
- (define null-syntactic-environment
- (make-syntactic-environment
- #f
- (lambda (name)
- (impl-error "can't lookup name in null syntactic environment" name))
- (lambda (name)
- (impl-error "can't rename name in null syntactic environment" name))
- (lambda (name item)
- (impl-error "can't bind name in null syntactic environment" name item))
- (lambda ()
- '())))
-
- (define (top-level-syntactic-environment parent)
- (let ((bound '()))
- (make-syntactic-environment
- parent
- (let ((parent-lookup (syntactic-environment/lookup-operation parent)))
- (lambda (name)
- (or (assq name bound)
- (parent-lookup name))))
- (lambda (name)
- name)
- (lambda (name item)
- (let ((binding (assq name bound)))
- (if binding
- (set-cdr! binding item)
- (set! bound (cons (cons name item) bound)))))
- (lambda ()
- (alist-copy bound)))))
-
- (define (internal-syntactic-environment parent)
- (let ((bound '())
- (free '()))
- (make-syntactic-environment
- parent
- (let ((parent-lookup (syntactic-environment/lookup-operation parent)))
- (lambda (name)
- (or (assq name bound)
- (assq name free)
- (let ((binding (parent-lookup name)))
- (if binding (set! free (cons binding free)))
- binding))))
- (make-name-generator)
- (lambda (name item)
- (cond ((assq name bound)
- =>
- (lambda (association)
- (if (and (reserved-name-item? (cdr association))
- (not (reserved-name-item? item)))
- (set-cdr! association item)
- (impl-error "can't redefine name; already bound" name))))
- ((assq name free)
- (if (reserved-name-item? item)
- (syntax-error "premature reference to reserved name"
- name)
- (impl-error "can't define name; already free" name)))
- (else
- (set! bound (cons (cons name item) bound)))))
- (lambda ()
- (alist-copy bound)))))
-
- (define (filter-syntactic-environment names names-env else-env)
- (if (or (null? names)
- (eq? names-env else-env))
- else-env
- (let ((make-operation
- (lambda (get-operation)
- (let ((names-operation (get-operation names-env))
- (else-operation (get-operation else-env)))
- (lambda (name)
- ((if (memq name names) names-operation else-operation)
- name))))))
- (make-syntactic-environment
- else-env
- (make-operation syntactic-environment/lookup-operation)
- (make-operation syntactic-environment/rename-operation)
- (lambda (name item)
- (impl-error "can't bind name in filtered syntactic environment"
- name item))
- (lambda ()
- (map (lambda (name)
- (cons name
- (syntactic-environment/lookup names-env name)))
- names))))))
-
- ;;;; Items
-
- ;;; Reserved name items do not represent any form, but instead are
- ;;; used to reserve a particular name in a syntactic environment. If
- ;;; the classifier refers to a reserved name, a syntax error is
- ;;; signalled. This is used in the implementation of LETREC-SYNTAX
- ;;; to signal a meaningful error when one of the <init>s refers to
- ;;; one of the names being bound.
-
- (define reserved-name-item-type
- (make-record-type "reserved-name-item" '()))
-
- (define make-reserved-name-item
- (record-constructor reserved-name-item-type '()))
-
- (define reserved-name-item?
- (record-predicate reserved-name-item-type))
-
- ;;; Keyword items represent macro keywords.
-
- (define keyword-item-type
- (make-record-type "keyword-item" '(CLASSIFIER NAME)))
- ; (make-record-type "keyword-item" '(CLASSIFIER)))
-
- (define make-keyword-item
- ; (lambda (cl) (display "make-keyword-item:") (write cl) (newline)
- ; ((record-constructor keyword-item-type '(CLASSIFIER)) cl)))
- (record-constructor keyword-item-type '(CLASSIFIER NAME)))
- ; (record-constructor keyword-item-type '(CLASSIFIER)))
-
- (define keyword-item?
- (record-predicate keyword-item-type))
-
- (define keyword-item/classifier
- (record-accessor keyword-item-type 'CLASSIFIER))
-
- (define keyword-item/name
- (record-accessor keyword-item-type 'NAME))
-
- ;;; Variable items represent run-time variables.
-
- (define variable-item-type
- (make-record-type "variable-item" '(NAME)))
-
- (define make-variable-item
- (record-constructor variable-item-type '(NAME)))
-
- (define variable-item?
- (record-predicate variable-item-type))
-
- (define variable-item/name
- (record-accessor variable-item-type 'NAME))
-
- ;;; Expression items represent any kind of expression other than a
- ;;; run-time variable or a sequence. The ANNOTATION field is used to
- ;;; make expression items that can appear in non-expression contexts
- ;;; (for example, this could be used in the implementation of SETF).
-
- (define expression-item-type
- (make-record-type "expression-item" '(COMPILER ANNOTATION)))
-
- (define make-expression-item
- (record-constructor expression-item-type '(COMPILER ANNOTATION)))
-
- (define expression-item?
- (record-predicate expression-item-type))
-
- (define expression-item/compiler
- (record-accessor expression-item-type 'COMPILER))
-
- (define expression-item/annotation
- (record-accessor expression-item-type 'ANNOTATION))
-
- ;;; Body items represent sequences (e.g. BEGIN).
-
- (define body-item-type
- (make-record-type "body-item" '(COMPONENTS)))
-
- (define make-body-item
- (record-constructor body-item-type '(COMPONENTS)))
-
- (define body-item?
- (record-predicate body-item-type))
-
- (define body-item/components
- (record-accessor body-item-type 'COMPONENTS))
-
- ;;; Definition items represent definitions, whether top-level or
- ;;; internal, keyword or variable.
-
- (define definition-item-type
- (make-record-type "definition-item" '(BINDING-THEORY NAME VALUE)))
-
- (define make-definition-item
- (record-constructor definition-item-type '(BINDING-THEORY NAME VALUE)))
-
- (define definition-item?
- (record-predicate definition-item-type))
-
- (define definition-item/binding-theory
- (record-accessor definition-item-type 'BINDING-THEORY))
-
- (define definition-item/name
- (record-accessor definition-item-type 'NAME))
-
- (define definition-item/value
- (record-accessor definition-item-type 'VALUE))
-
- (define (bind-definition-item! environment item)
- ((definition-item/binding-theory item)
- environment
- (definition-item/name item)
- (promise:force (definition-item/value item))))
-
- (define (syntactic-binding-theory environment name item)
- (if (or (keyword-item? item)
- (variable-item? item))
- (begin
- (syntactic-environment/define! environment name item)
- #f)
- (syntax-error "syntactic binding value must be a keyword or a variable"
- item)))
-
- (define (variable-binding-theory environment name item)
- ;; If ITEM isn't a valid expression, an error will be signalled by
- ;; COMPILE-ITEM/EXPRESSION later.
- (cons (bind-variable! environment name) item))
-
- (define (overloaded-binding-theory environment name item)
- (if (keyword-item? item)
- (begin
- (syntactic-environment/define! environment name item)
- #f)
- (cons (bind-variable! environment name) item)))
-
- ;;;; Classifiers, Compilers, Expanders
-
- (define (sc-expander->classifier expander keyword-environment)
- (lambda (form environment definition-environment)
- (classify/form (expander form environment)
- keyword-environment
- definition-environment)))
-
- (define (er-expander->classifier expander keyword-environment)
- (sc-expander->classifier (er->sc-expander expander) keyword-environment))
-
- (define (er->sc-expander expander)
- (lambda (form environment)
- (capture-syntactic-environment
- (lambda (keyword-environment)
- (make-syntactic-closure
- environment '()
- (expander form
- (let ((renames '()))
- (lambda (identifier)
- (let ((association (assq identifier renames)))
- (if association
- (cdr association)
- (let ((rename
- (make-syntactic-closure
- keyword-environment
- '()
- identifier)))
- (set! renames
- (cons (cons identifier rename)
- renames))
- rename)))))
- (lambda (x y)
- (identifier=? environment x
- environment y))))))))
-
- (define (classifier->keyword classifier)
- (make-syntactic-closure
- (let ((environment
- (internal-syntactic-environment null-syntactic-environment)))
- (syntactic-environment/define! environment
- 'KEYWORD
- (make-keyword-item classifier "c->k"))
- environment)
- '()
- 'KEYWORD))
-
- (define (compiler->keyword compiler)
- (classifier->keyword (compiler->classifier compiler)))
-
- (define (classifier->form classifier)
- `(,(classifier->keyword classifier)))
-
- (define (compiler->form compiler)
- (classifier->form (compiler->classifier compiler)))
-
- (define (compiler->classifier compiler)
- (lambda (form environment definition-environment)
- definition-environment ;ignore
- (make-expression-item
- (lambda () (compiler form environment)) form)))
-
- ;;;; Macrologies
- ;;; A macrology is a procedure that accepts a syntactic environment
- ;;; as an argument, producing a new syntactic environment that is an
- ;;; extension of the argument.
-
- (define (make-primitive-macrology generate-definitions)
- (lambda (base-environment)
- (let ((environment (top-level-syntactic-environment base-environment)))
- (let ((define-classifier
- (lambda (keyword classifier)
- (syntactic-environment/define!
- environment
- keyword
- (make-keyword-item classifier keyword)))))
- (generate-definitions
- define-classifier
- (lambda (keyword compiler)
- (define-classifier keyword (compiler->classifier compiler)))))
- environment)))
-
- (define (make-expander-macrology object->classifier generate-definitions)
- (lambda (base-environment)
- (let ((environment (top-level-syntactic-environment base-environment)))
- (generate-definitions
- (lambda (keyword object)
- (syntactic-environment/define!
- environment
- keyword
- (make-keyword-item (object->classifier object environment) keyword)))
- base-environment)
- environment)))
-
- (define (make-sc-expander-macrology generate-definitions)
- (make-expander-macrology sc-expander->classifier generate-definitions))
-
- (define (make-er-expander-macrology generate-definitions)
- (make-expander-macrology er-expander->classifier generate-definitions))
-
- (define (compose-macrologies . macrologies)
- (lambda (environment)
- (do ((macrologies macrologies (cdr macrologies))
- (environment environment ((car macrologies) environment)))
- ((null? macrologies) environment))))
-
- ;;;; Utilities
-
- (define (bind-variable! environment name)
- (let ((rename (syntactic-environment/rename environment name)))
- (syntactic-environment/define! environment
- name
- (make-variable-item rename))
- rename))
-
- (define (reserve-names! names environment)
- (let ((item (make-reserved-name-item)))
- (for-each (lambda (name)
- (syntactic-environment/define! environment name item))
- names)))
-
- (define (capture-syntactic-environment expander)
- (classifier->form
- (lambda (form environment definition-environment)
- form ;ignore
- (classify/form (expander environment)
- environment
- definition-environment))))
-
- (define (unspecific-expression)
- (compiler->form
- (lambda (form environment)
- form environment ;ignore
- (output/unspecific))))
-
- (define (unassigned-expression)
- (compiler->form
- (lambda (form environment)
- form environment ;ignore
- (output/unassigned))))
-
- (define (syntax-quote expression)
- `(,(compiler->keyword
- (lambda (form environment)
- environment ;ignore
- (syntax-check '(KEYWORD DATUM) form)
- (output/literal-quoted (cadr form))))
- ,expression))
-
- (define (flatten-body-items items)
- (append-map item->list items))
-
- (define (item->list item)
- (if (body-item? item)
- (flatten-body-items (body-item/components item))
- (list item)))
-
- (define (output/let names values body)
- (if (null? names)
- body
- (output/combination (output/lambda names body) values)))
-
- (define (output/letrec names values body)
- (if (null? names)
- body
- (output/let
- names
- (map (lambda (name) name (output/unassigned)) names)
- (output/sequence
- (list (if (null? (cdr names))
- (output/assignment (car names) (car values))
- (let ((temps (map (make-name-generator) names)))
- (output/let
- temps
- values
- (output/sequence
- (map output/assignment names temps)))))
- body)))))
-
- (define (output/top-level-sequence expressions)
- (if (null? expressions)
- (output/unspecific)
- (output/sequence expressions)))
-