mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-11 00:00:49 +02:00
748 lines
24 KiB
Scheme
748 lines
24 KiB
Scheme
;;; "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 ()
|
|
(map (lambda (pair) (cons (car pair) (cdr pair))) 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 ()
|
|
(map (lambda (pair) (cons (car pair) (cdr pair))) 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)))
|