debug.scm 9.8 KB

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