File: transform.scm

package info (click to toggle)
scheme48 1.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 18,232 kB
  • sloc: lisp: 88,907; ansic: 87,519; sh: 3,224; makefile: 771
file content (140 lines) | stat: -rw-r--r-- 4,779 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Will Noble

; Transforms

; A transform represents a source-to-source rewrite rule: either a
; macro or an in-line procedure.

(define-record-type transform :transform
  (really-make-transform kind xformer env type aux-names source id)
  transform?
  ;; macro or inline
  (kind      transform-kind)
  (xformer   transform-procedure)
  (env	     transform-env)
  (type	     transform-type)
  (aux-names transform-aux-names) ;for reification
  (source    transform-source)    ;for reification
  (id	     transform-id))

(define (make-transform/macro thing env type source id)
  (let ((type (if (or (pair? type)
		      (symbol? type))
		  (sexp->type type #t)
		  type)))
    (call-with-values
	(lambda ()
	  (if (pair? thing)
	      (values (car thing) (cdr thing))
	      (values thing #f)))
      (lambda (transformer aux-names)
	;; The usual old-style transformers take 3 args: exp rename compare.
	;; However, syntax-rules-generated transformers need a 4th arg, name?.
	;; Distinguish between the two kinds.
	(let ((proc
	       (cond
		((explicit-renaming-transformer/4? transformer)
		 (explicit-renaming-transformer/4-proc transformer))
		(else ; standard explicit-renaming transformers take only 3 args
		 (lambda (exp name? rename compare)
		   (transformer exp rename compare))))))
	  (make-immutable!
	   (really-make-transform 'macro proc env type aux-names source id)))))))

; for backwards compatibility with the PreScheme compiler
(define make-transform make-transform/macro)

(define (make-transform/inline thing env type source id)
  (let ((type (if (or (pair? type)
		      (symbol? type))
		  (sexp->type type #t)
		  type)))
    (make-immutable!
     (really-make-transform 'inline (car thing) env type (cdr thing) source id))))

(define-record-discloser :transform
  (lambda (m) (list 'transform (transform-id m))))

; See also: Rees, "Implementing Lexically Scoped Macros",
; Lisp Pointers VI(1), January-March 1993
(define (maybe-apply-macro-transform transform exp parent-name env-of-use)
  (let* ((token (cons #f #f))
	 (new-env (bind-aliases token transform env-of-use))
	 (rename (make-name-generator (transform-env transform)
				      token
				      parent-name))
	 (compare (make-keyword-comparator new-env)))
    (values ((transform-procedure transform) exp name? rename compare)
	    new-env)))

(define (apply-inline-transform transform exp parent-name)
  (let* ((env (transform-env transform))
	 (rename (make-name-generator env (cons #f #f) parent-name)))
    ((transform-procedure transform) exp env rename)))

; Two keywords are the same if:
;  - they really are the same
;  - neither one is bound and they have the same symbol in the source
;  - they are bound to the same denotation (macro or location or ...)

(define (make-keyword-comparator environment)
  (lambda (name1 name2)
    (or (eqv? name1 name2)
	(and (name? name1)	; why might they not be names?
	     (name? name2)
	     (let ((v1 (lookup environment name1))
		   (v2 (lookup environment name2)))
	       (if v1
		   (and v2 (same-denotation? v1 v2))
		   (and (not v2)
			(equal? (name->source-name name1)
				(name->source-name name2)))))))))

; Get the name that appeared in the source.

(define (name->source-name name)
  (if (generated? name)
      (name->source-name (generated-name name))
      name))
				       
; The env-of-definition for macros defined at top-level is a package,
; and the package system will take care of looking up the generated
; names.

(define (bind-aliases token transform env-of-use)
  (let ((env-of-definition (transform-env transform)))
    (if (compiler-env? env-of-definition)
	(make-compiler-env
	 (lambda (name)
	   (if (and (generated? name)
		    (eq? (generated-token name)
			 token))
	       (lookup env-of-definition (generated-name name))
	       (lookup env-of-use name)))
	 (lambda (name type . rest)
	   (assertion-violation 'bind-aliases "no definitions allowed" name))
	 (comp-env-macro-eval env-of-use)
	 #f)
	env-of-use)))

; Generate names for bindings reached in ENV reached via PARENT-NAME.
; The names are cached to preserve identity if they are bound.  TOKEN
; is used to identify names made by this generator.

(define (make-name-generator env token parent-name)
  (let ((alist '()))			;list of (symbol . generated)
    (lambda (name)
      (if (name? name)
	  (let ((probe (assq name alist)))
	    (if probe
		(cdr probe)
		(let ((new-name (make-generated name token env parent-name)))
		  (set! alist (cons (cons name new-name)
				    alist))
		  new-name)))
	  (assertion-violation 'make-name-generator
			       "non-name argument to rename procedure"
			       name parent-name)))))