Commit | Line | Data |
---|---|---|
6d2d6897 AW |
1 | ;;; Tree-IL verifier |
2 | ||
3 | ;; Copyright (C) 2011 Free Software Foundation, Inc. | |
4 | ||
5 | ;;;; This library is free software; you can redistribute it and/or | |
6 | ;;;; modify it under the terms of the GNU Lesser General Public | |
7 | ;;;; License as published by the Free Software Foundation; either | |
8 | ;;;; version 3 of the License, or (at your option) any later version. | |
9 | ;;;; | |
10 | ;;;; This library is distributed in the hope that it will be useful, | |
11 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | ;;;; Lesser General Public License for more details. | |
14 | ;;;; | |
15 | ;;;; You should have received a copy of the GNU Lesser General Public | |
16 | ;;;; License along with this library; if not, write to the Free Software | |
17 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ||
19 | (define-module (language tree-il debug) | |
20 | #:use-module (language tree-il) | |
21 | #:use-module (ice-9 match) | |
22 | #:use-module (srfi srfi-1) | |
23 | #:use-module (srfi srfi-26) | |
24 | #:export (verify-tree-il)) | |
25 | ||
26 | (define (verify-tree-il exp) | |
27 | (define seen-gensyms (make-hash-table)) | |
28 | (define (add sym env) | |
29 | (if (hashq-ref seen-gensyms sym) | |
30 | (error "duplicate gensym" sym) | |
31 | (begin | |
32 | (hashq-set! seen-gensyms sym #t) | |
33 | (cons sym env)))) | |
34 | (define (add-env new env) | |
35 | (if (null? new) | |
36 | env | |
37 | (add-env (cdr new) (add (car new) env)))) | |
38 | ||
39 | (let visit ((exp exp) | |
40 | (env '())) | |
41 | (match exp | |
42 | (($ <lambda-case> src req opt rest kw inits gensyms body alt) | |
43 | (cond | |
44 | ((not (and (list? req) (and-map symbol? req))) | |
45 | (error "bad required args (should be list of symbols)" exp)) | |
46 | ((and opt (not (and (list? opt) (and-map symbol? opt)))) | |
47 | (error "bad optionals (should be #f or list of symbols)" exp)) | |
48 | ((and rest (not (symbol? rest))) | |
49 | (error "bad required args (should be #f or symbol)" exp)) | |
50 | ((and kw (not (match kw | |
51 | ((aok . kwlist) | |
52 | (and (list? kwlist) | |
53 | (and-map | |
54 | (lambda (x) | |
55 | (match x | |
56 | (((? keyword?) (? symbol?) (? symbol? sym)) | |
57 | (memq sym gensyms)) | |
58 | (_ #f))) | |
59 | kwlist))) | |
60 | (_ #f)))) | |
61 | (error "bad keywords (should be #f or (aok (kw name sym) ...))" exp)) | |
62 | ((not (and (list? gensyms) (and-map symbol? gensyms))) | |
63 | (error "bad gensyms (should be list of symbols)" exp)) | |
64 | ((not (and (list? gensyms) (and-map symbol? gensyms))) | |
65 | (error "bad gensyms (should be list of symbols)" exp)) | |
66 | ((not (= (length gensyms) | |
67 | (+ (length req) | |
68 | (if opt (length opt) 0) | |
69 | ;; FIXME: technically possible for kw gensyms to | |
70 | ;; alias other gensyms | |
71 | (if rest 1 0) | |
72 | (if kw (1- (length kw)) 0)))) | |
73 | (error "unexpected gensyms length" exp)) | |
74 | (else | |
75 | (let lp ((env (add-env (take gensyms (length req)) env)) | |
76 | (nopt (if opt (length opt) 0)) | |
77 | (inits inits) | |
78 | (tail (drop gensyms (length req)))) | |
79 | (if (zero? nopt) | |
80 | (let lp ((env (if rest (add (car tail) env) env)) | |
81 | (inits inits) | |
82 | (tail (if rest (cdr tail) tail))) | |
83 | (if (pair? inits) | |
84 | (begin | |
85 | (visit (car inits) env) | |
86 | (lp (add (car tail) env) (cdr inits) | |
87 | (cdr tail))) | |
88 | (visit body env))) | |
89 | (begin | |
90 | (visit (car inits) env) | |
91 | (lp (add (car tail) env) | |
92 | (1- nopt) | |
93 | (cdr inits) | |
94 | (cdr tail))))) | |
95 | (if alt (visit alt env))))) | |
96 | (($ <lexical-ref> src name gensym) | |
97 | (cond | |
98 | ((not (symbol? name)) | |
99 | (error "name should be a symbol" name)) | |
100 | ((not (hashq-ref seen-gensyms gensym)) | |
101 | (error "unbound lexical" exp)) | |
102 | ((not (memq gensym env)) | |
103 | (error "displaced lexical" exp)))) | |
104 | (($ <lexical-set> src name gensym exp) | |
105 | (cond | |
106 | ((not (symbol? name)) | |
107 | (error "name should be a symbol" name)) | |
108 | ((not (hashq-ref seen-gensyms gensym)) | |
109 | (error "unbound lexical" exp)) | |
110 | ((not (memq gensym env)) | |
111 | (error "displaced lexical" exp)) | |
112 | (else | |
113 | (visit exp env)))) | |
114 | (($ <lambda> src meta body) | |
115 | (cond | |
116 | ((and meta (not (and (list? meta) (and-map pair? meta)))) | |
117 | (error "meta should be alist" meta)) | |
118 | ((not (lambda-case? body)) | |
119 | (error "lambda body should be lambda-case" exp)) | |
120 | (else | |
121 | (visit body env)))) | |
122 | (($ <let> src names gensyms vals body) | |
123 | (cond | |
124 | ((not (and (list? names) (and-map symbol? names))) | |
125 | (error "names should be list of syms" exp)) | |
126 | ((not (and (list? gensyms) (and-map symbol? gensyms))) | |
127 | (error "gensyms should be list of syms" exp)) | |
128 | ((not (list? vals)) | |
129 | (error "vals should be list" exp)) | |
130 | ((not (= (length names) (length gensyms) (length vals))) | |
131 | (error "names, syms, vals should be same length" exp)) | |
132 | (else | |
133 | (for-each (cut visit <> env) vals) | |
134 | (visit body (add-env gensyms env))))) | |
135 | (($ <letrec> src in-order? names gensyms vals body) | |
136 | (cond | |
137 | ((not (and (list? names) (and-map symbol? names))) | |
138 | (error "names should be list of syms" exp)) | |
139 | ((not (and (list? gensyms) (and-map symbol? gensyms))) | |
140 | (error "gensyms should be list of syms" exp)) | |
141 | ((not (list? vals)) | |
142 | (error "vals should be list" exp)) | |
143 | ((not (= (length names) (length gensyms) (length vals))) | |
144 | (error "names, syms, vals should be same length" exp)) | |
145 | (else | |
146 | (let ((env (add-env gensyms env))) | |
147 | (for-each (cut visit <> env) vals) | |
148 | (visit body env))))) | |
149 | (($ <fix> src names gensyms vals body) | |
150 | (cond | |
151 | ((not (and (list? names) (and-map symbol? names))) | |
152 | (error "names should be list of syms" exp)) | |
153 | ((not (and (list? gensyms) (and-map symbol? gensyms))) | |
154 | (error "gensyms should be list of syms" exp)) | |
155 | ((not (list? vals)) | |
156 | (error "vals should be list" exp)) | |
157 | ((not (= (length names) (length gensyms) (length vals))) | |
158 | (error "names, syms, vals should be same length" exp)) | |
159 | (else | |
160 | (let ((env (add-env gensyms env))) | |
161 | (for-each (cut visit <> env) vals) | |
162 | (visit body env))))) | |
163 | (($ <let-values> src exp body) | |
164 | (cond | |
165 | ((not (lambda-case? body)) | |
166 | (error "let-values body should be lambda-case" exp)) | |
167 | (else | |
168 | (visit exp env) | |
169 | (visit body env)))) | |
170 | (($ <const> src val) #t) | |
171 | (($ <void> src) #t) | |
172 | (($ <toplevel-ref> src name) | |
173 | (cond | |
174 | ((not (symbol? name)) | |
175 | (error "name should be a symbol" name)))) | |
176 | (($ <module-ref> src mod name public?) | |
177 | (cond | |
178 | ((not (and (list? mod) (and-map symbol? mod))) | |
179 | (error "module name should be list of symbols" exp)) | |
180 | ((not (symbol? name)) | |
181 | (error "name should be symbol" exp)))) | |
182 | (($ <primitive-ref> src name) | |
183 | (cond | |
184 | ((not (symbol? name)) | |
185 | (error "name should be symbol" exp)))) | |
186 | (($ <toplevel-set> src name exp) | |
187 | (cond | |
188 | ((not (symbol? name)) | |
189 | (error "name should be a symbol" name)) | |
190 | (else | |
191 | (visit exp env)))) | |
192 | (($ <toplevel-define> src name exp) | |
193 | (cond | |
194 | ((not (symbol? name)) | |
195 | (error "name should be a symbol" name)) | |
196 | (else | |
197 | (visit exp env)))) | |
198 | (($ <module-set> src mod name public? exp) | |
199 | (cond | |
200 | ((not (and (list? mod) (and-map symbol? mod))) | |
201 | (error "module name should be list of symbols" exp)) | |
202 | ((not (symbol? name)) | |
203 | (error "name should be symbol" exp)) | |
204 | (else | |
205 | (visit exp env)))) | |
206 | (($ <dynlet> src fluids vals body) | |
207 | (cond | |
208 | ((not (list? fluids)) | |
209 | (error "fluids should be list" exp)) | |
210 | ((not (list? vals)) | |
211 | (error "vals should be list" exp)) | |
212 | ((not (= (length fluids) (length vals))) | |
213 | (error "mismatch in fluids/vals" exp)) | |
214 | (else | |
215 | (for-each (cut visit <> env) fluids) | |
216 | (for-each (cut visit <> env) vals) | |
217 | (visit body env)))) | |
880e7948 | 218 | (($ <dynwind> src winder pre body post unwinder) |
6d2d6897 | 219 | (visit winder env) |
880e7948 | 220 | (visit pre env) |
6d2d6897 | 221 | (visit body env) |
880e7948 | 222 | (visit post env) |
6d2d6897 AW |
223 | (visit unwinder env)) |
224 | (($ <dynref> src fluid) | |
225 | (visit fluid env)) | |
226 | (($ <dynset> src fluid exp) | |
227 | (visit fluid env) | |
228 | (visit exp env)) | |
229 | (($ <conditional> src condition subsequent alternate) | |
230 | (visit condition env) | |
231 | (visit subsequent env) | |
232 | (visit alternate env)) | |
a215c159 | 233 | (($ <primcall> src name args) |
6d2d6897 | 234 | (cond |
a215c159 AW |
235 | ((not (symbol? name)) |
236 | (error "expected symbolic operator" exp)) | |
6d2d6897 AW |
237 | ((not (list? args)) |
238 | (error "expected list of args" args)) | |
239 | (else | |
6d2d6897 | 240 | (for-each (cut visit <> env) args)))) |
a215c159 | 241 | (($ <call> src proc args) |
6d2d6897 | 242 | (cond |
a215c159 AW |
243 | ((not (list? args)) |
244 | (error "expected list of args" args)) | |
6d2d6897 | 245 | (else |
a215c159 AW |
246 | (visit proc env) |
247 | (for-each (cut visit <> env) args)))) | |
248 | (($ <seq> src head tail) | |
249 | (visit head env) | |
250 | (visit tail env)) | |
6d2d6897 AW |
251 | (($ <prompt> src tag body handler) |
252 | (visit tag env) | |
253 | (visit body env) | |
254 | (visit handler env)) | |
255 | (($ <abort> src tag args tail) | |
256 | (visit tag env) | |
257 | (for-each (cut visit <> env) args) | |
258 | (visit tail env)) | |
259 | (_ | |
260 | (error "unexpected tree-il" exp))) | |
261 | (let ((src (tree-il-src exp))) | |
262 | (if (and src (not (and (list? src) (and-map pair? src) | |
263 | (and-map symbol? (map car src))))) | |
264 | (error "bad src")) | |
265 | ;; Return it, why not. | |
266 | exp))) |