home *** CD-ROM | disk | FTP | other *** search
- ; "mwsynrul.scm" Compiler for a <transformer spec>.
- ; 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.
-
- ;;;; Compiler for a <transformer spec>.
-
- ;;; The input is a <transformer spec> and a syntactic environment.
- ;;; Syntactic environments are described in another file.
-
- ;;; Transormer specs are in slib.texi.
-
- (define mw:pattern-variable-flag (list 'v))
- (define mw:ellipsis-pattern-flag (list 'e))
- (define mw:ellipsis-template-flag mw:ellipsis-pattern-flag)
-
- (define (mw:make-patternvar v rank)
- (vector mw:pattern-variable-flag v rank))
- (define (mw:make-ellipsis-pattern P vars)
- (vector mw:ellipsis-pattern-flag P vars))
- (define (mw:make-ellipsis-template T vars)
- (vector mw:ellipsis-template-flag T vars))
-
- (define (mw:patternvar? x)
- (and (vector? x)
- (= (vector-length x) 3)
- (eq? (vector-ref x 0) mw:pattern-variable-flag)))
-
- (define (mw:ellipsis-pattern? x)
- (and (vector? x)
- (= (vector-length x) 3)
- (eq? (vector-ref x 0) mw:ellipsis-pattern-flag)))
-
- (define (mw:ellipsis-template? x)
- (and (vector? x)
- (= (vector-length x) 3)
- (eq? (vector-ref x 0) mw:ellipsis-template-flag)))
-
- (define (mw:patternvar-name V) (vector-ref V 1))
- (define (mw:patternvar-rank V) (vector-ref V 2))
- (define (mw:ellipsis-pattern P) (vector-ref P 1))
- (define (mw:ellipsis-pattern-vars P) (vector-ref P 2))
- (define (mw:ellipsis-template T) (vector-ref T 1))
- (define (mw:ellipsis-template-vars T) (vector-ref T 2))
-
- (define (mw:pattern-variable v vars)
- (cond ((null? vars) #f)
- ((eq? v (mw:patternvar-name (car vars)))
- (car vars))
- (else (mw:pattern-variable v (cdr vars)))))
-
- ; Given a <transformer spec> and a syntactic environment,
- ; returns a macro denotation.
- ;
- ; A macro denotation is of the form
- ;
- ; (macro (<rule> ...) env)
- ;
- ; where each <rule> has been compiled as described above.
-
- (define (mw:compile-transformer-spec spec env)
- (if (and (> (mw:safe-length spec) 1)
- (eq? (mw:syntax-lookup env (car spec))
- mw:denote-of-syntax-rules))
- (let ((literals (cadr spec))
- (rules (cddr spec)))
- (if (or (not (list? literals))
- (not (comlist:every (lambda (rule)
- (and (= (mw:safe-length rule) 2)
- (pair? (car rule))))
- rules)))
- (mw:error "Malformed syntax-rules" spec))
- (list 'macro
- (map (lambda (rule)
- (mw:compile-rule rule literals env))
- rules)
- env))
- (mw:error "Malformed syntax-rules" spec)))
-
- (define (mw:compile-rule rule literals env)
- (mw:compile-pattern (cdr (car rule))
- literals
- env
- (lambda (compiled-rule patternvars)
- ; should check uniqueness of pattern variables here!!!!!
- (cons compiled-rule
- (mw:compile-template
- (cadr rule)
- patternvars
- env)))))
-
- (define (mw:compile-pattern P literals env k)
- (define (loop P vars rank k)
- (cond ((symbol? P)
- (if (memq P literals)
- (k P vars)
- (let ((var (mw:make-patternvar P rank)))
- (k var (cons var vars)))))
- ((null? P) (k '() vars))
- ((pair? P)
- (if (and (pair? (cdr P))
- (symbol? (cadr P))
- (eq? (mw:syntax-lookup env (cadr P))
- mw:denote-of-...))
- (if (null? (cddr P))
- (loop (car P)
- '()
- (+ rank 1)
- (lambda (P vars1)
- (k (mw:make-ellipsis-pattern P vars1)
- (comlist:union vars1 vars))))
- (mw:error "Malformed pattern" P))
- (loop (car P)
- vars
- rank
- (lambda (P1 vars)
- (loop (cdr P)
- vars
- rank
- (lambda (P2 vars)
- (k (cons P1 P2) vars)))))))
- ((vector? P)
- (loop (vector->list P)
- vars
- rank
- (lambda (P vars)
- (k (vector P) vars))))
- (else (k P vars))))
- (loop P '() 0 k))
-
- (define (mw:compile-template T vars env)
-
- (define (loop T inserted referenced rank escaped? k)
- (cond ((symbol? T)
- (let ((x (mw:pattern-variable T vars)))
- (if x
- (if (>= rank (mw:patternvar-rank x))
- (k x inserted (cons x referenced))
- (mw:error
- "Too few ellipses follow pattern variable in template"
- (mw:patternvar-name x)))
- (k T (cons T inserted) referenced))))
- ((null? T) (k '() inserted referenced))
- ((pair? T)
- (cond ((and (not escaped?)
- (symbol? (car T))
- (eq? (mw:syntax-lookup env (car T))
- mw:denote-of-:::)
- (pair? (cdr T))
- (null? (cddr T)))
- (loop (cadr T) inserted referenced rank #t k))
- ((and (not escaped?)
- (pair? (cdr T))
- (symbol? (cadr T))
- (eq? (mw:syntax-lookup env (cadr T))
- mw:denote-of-...))
- (loop1 T inserted referenced rank escaped? k))
- (else
- (loop (car T)
- inserted
- referenced
- rank
- escaped?
- (lambda (T1 inserted referenced)
- (loop (cdr T)
- inserted
- referenced
- rank
- escaped?
- (lambda (T2 inserted referenced)
- (k (cons T1 T2) inserted referenced))))))))
- ((vector? T)
- (loop (vector->list T)
- inserted
- referenced
- rank
- escaped?
- (lambda (T inserted referenced)
- (k (vector T) inserted referenced))))
- (else (k T inserted referenced))))
-
- (define (loop1 T inserted referenced rank escaped? k)
- (loop (car T)
- inserted
- '()
- (+ rank 1)
- escaped?
- (lambda (T1 inserted referenced1)
- (loop (cddr T)
- inserted
- (append referenced1 referenced)
- rank
- escaped?
- (lambda (T2 inserted referenced)
- (k (cons (mw:make-ellipsis-template
- T1
- (comlist:remove-if-not
- (lambda (var) (> (mw:patternvar-rank var)
- rank))
- referenced1))
- T2)
- inserted
- referenced))))))
-
- (loop T
- '()
- '()
- 0
- #f
- (lambda (T inserted referenced)
- (list T inserted))))
-
- ; The pattern matcher.
- ;
- ; Given an input, a pattern, and two syntactic environments,
- ; returns a pattern variable environment (represented as an alist)
- ; if the input matches the pattern, otherwise returns #f.
-
- (define mw:empty-pattern-variable-environment
- (list (mw:make-patternvar (string->symbol "") 0)))
-
- (define (mw:match F P env-def env-use)
-
- (define (match F P answer rank)
- (cond ((null? P)
- (and (null? F) answer))
- ((pair? P)
- (and (pair? F)
- (let ((answer (match (car F) (car P) answer rank)))
- (and answer (match (cdr F) (cdr P) answer rank)))))
- ((symbol? P)
- (and (symbol? F)
- (mw:same-denotation? (mw:syntax-lookup env-def P)
- (mw:syntax-lookup env-use F))
- answer))
- ((mw:patternvar? P)
- (cons (cons P F) answer))
- ((mw:ellipsis-pattern? P)
- (match1 F P answer (+ rank 1)))
- ((vector? P)
- (and (vector? F)
- (match (vector->list F) (vector-ref P 0) answer rank)))
- (else (and (equal? F P) answer))))
-
- (define (match1 F P answer rank)
- (cond ((not (list? F)) #f)
- ((null? F)
- (append (map (lambda (var) (cons var '()))
- (mw:ellipsis-pattern-vars P))
- answer))
- (else
- (let* ((P1 (mw:ellipsis-pattern P))
- (answers (map (lambda (F) (match F P1 answer rank))
- F)))
- (if (comlist:every identity answers)
- (append (map (lambda (var)
- (cons var
- (map (lambda (answer)
- (cdr (assq var answer)))
- answers)))
- (mw:ellipsis-pattern-vars P))
- answer)
- #f)))))
-
- (match F P mw:empty-pattern-variable-environment 0))
-
- (define (mw:rewrite T alist)
-
- (define (rewrite T alist rank)
- (cond ((null? T) '())
- ((pair? T)
- ((if (mw:ellipsis-pattern? (car T))
- append
- cons)
- (rewrite (car T) alist rank)
- (rewrite (cdr T) alist rank)))
- ((symbol? T) (cdr (assq T alist)))
- ((mw:patternvar? T) (cdr (assq T alist)))
- ((mw:ellipsis-template? T)
- (rewrite1 T alist (+ rank 1)))
- ((vector? T)
- (list->vector (rewrite (vector-ref T 0) alist rank)))
- (else T)))
-
- (define (rewrite1 T alist rank)
- (let* ((T1 (mw:ellipsis-template T))
- (vars (mw:ellipsis-template-vars T))
- (rows (map (lambda (var) (cdr (assq var alist)))
- vars)))
- (map (lambda (alist) (rewrite T1 alist rank))
- (make-columns vars rows alist))))
-
- (define (make-columns vars rows alist)
- (define (loop rows)
- (if (null? (car rows))
- '()
- (cons (append (map (lambda (var row)
- (cons var (car row)))
- vars
- rows)
- alist)
- (loop (map cdr rows)))))
- (if (or (null? (cdr rows))
- (apply = (map length rows)))
- (loop rows)
- (mw:error "Use of macro is not consistent with definition"
- vars
- rows)))
-
- (rewrite T alist 0))
-
- ; Given a use of a macro, the syntactic environment of the use,
- ; and a continuation that expects a transcribed expression and
- ; a new environment in which to continue expansion,
- ; does the right thing.
-
- (define (mw:transcribe exp env-use k)
- (let* ((m (mw:syntax-lookup env-use (car exp)))
- (rules (macwork:rules m))
- (env-def (macwork:env m))
- (F (cdr exp)))
- (define (loop rules)
- (if (null? rules)
- (mw:error "Use of macro does not match definition" exp)
- (let* ((rule (car rules))
- (pattern (car rule))
- (alist (mw:match F pattern env-def env-use)))
- (if alist
- (let* ((template (cadr rule))
- (inserted (caddr rule))
- (alist2 (mw:rename-vars inserted))
- (newexp (mw:rewrite template (append alist2 alist))))
- (k newexp
- (mw:syntax-alias env-use alist2 env-def)))
- (loop (cdr rules))))))
- (loop rules)))
-