Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / module / language / tree-il / debug.scm
CommitLineData
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)))