node-check.scm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Mike Sperber
  3. ; Check that a node is well-formed
  4. (define (check-node node)
  5. (cond
  6. ((lambda-node? node)
  7. (check-lambda node))
  8. ((call-node? node)
  9. (check-call node))
  10. ((literal-node? node)
  11. (check-literal node))
  12. ((reference-node? node)
  13. (check-reference node))
  14. (else
  15. (assertion-violation 'check-node "unknown node type" node))))
  16. (define (check-lambda node)
  17. (if (not (memq (lambda-type node) '(cont proc jump)))
  18. (assertion-violation 'check-node "invalid lambda type" node))
  19. (if (and (eq? 'jump (lambda-type node))
  20. (not (memq (call-primop-id (node-parent node)) '(let letrec2))))
  21. (assertion-violation 'check-node "jump lambda must be bound by let or letrec2" node))
  22. (for-each (lambda (var)
  23. (set-variable-flag! var #t))
  24. (lambda-variables node))
  25. (let ((body (lambda-body node)))
  26. (if (not (call-node? body))
  27. (assertion-violation 'check-node "lambda body is not a call" node))
  28. (if (trivial-primop-call? body)
  29. (assertion-violation 'check-node "body call of a lambda must have non-trivial primop" node))
  30. (check-nontrivial-primop-call body))
  31. (for-each (lambda (var)
  32. (set-variable-flag! var #f))
  33. (lambda-variables node)))
  34. (define (trivial-primop-call? node)
  35. (primop-trivial? (call-primop node)))
  36. (define (check-call node)
  37. (if (> (call-exits node) (call-arg-count node))
  38. (assertion-violation 'check-node "call node has more exits than arguments"))
  39. (if (trivial-primop-call? node)
  40. (check-trivial-primop-call node)
  41. (check-nontrivial-primop-call node)))
  42. (define (check-trivial-primop-call node)
  43. (walk-vector (lambda (arg)
  44. (if (not (yields-value? node))
  45. (assertion-violation 'check-node "argument to trivial-primop call must yield value" arg))
  46. (check-node arg))
  47. (call-args node)))
  48. (define (cont-lambda? node)
  49. (and (lambda-node? node)
  50. (eq? 'cont (lambda-type node))))
  51. (define (call-primop-id node)
  52. (primop-id (call-primop node)))
  53. (define (call-primop-name node)
  54. (symbol->string (primop-id (call-primop node))))
  55. ; check that first argument is a continuation variable
  56. (define (check-cont-var node)
  57. (if (positive? (call-exits node))
  58. (assertion-violation 'check-node
  59. (string-append (call-primop-name node)
  60. " node has non-zero exit count")
  61. node))
  62. (if (not (and (positive? (call-arg-count node))
  63. (reference-node? (call-arg node 0))))
  64. (assertion-violation 'check-node
  65. (string-append (call-primop-name node)
  66. " node must have cont var as first argument"
  67. (call-arg node 0)))))
  68. ; check that the call has single continuation
  69. (define (check-cont node)
  70. (if (not (= 1 (call-exits node)))
  71. (assertion-violation 'check-node
  72. (string-append (call-primop-name node)
  73. " node must have single continuation")
  74. node))
  75. (if (not (and (positive? (call-arg-count node))
  76. (cont-lambda? (call-arg node 0))))
  77. (assertion-violation 'check-node
  78. (string-append (symbol->string primop-id)
  79. " node must have cont lambda as first argument" (call-arg node 0)))))
  80. (define (check-nontrivial-primop-call node)
  81. (let ((exit-count (call-exits node))
  82. (arg-count (call-arg-count node))
  83. (primop-id (call-primop-id node)))
  84. (do ((i 0 (+ 1 i)))
  85. ((= i arg-count))
  86. (let ((arg (call-arg node i)))
  87. (cond
  88. ((< i exit-count)
  89. (if (not (cont-lambda? arg))
  90. (assertion-violation 'check-node "exit argument must be cont lambda" arg)))
  91. ((not (yields-value? arg))
  92. (assertion-violation 'check-node "regular call argument must yield value" arg)))
  93. (check-node arg)))
  94. (let ((check-proc-arg
  95. (lambda ()
  96. (if (< arg-count 2)
  97. (assertion-violation 'check-node "call node must have >=2 arguments" node)))))
  98. (case primop-id
  99. ((let)
  100. (check-cont node)
  101. (if (not (= (length (lambda-variables (call-arg node 0)))
  102. (- arg-count 1)))
  103. (assertion-violation 'check-node
  104. "variable and value count don't match up in let node" node)))
  105. ((letrec1)
  106. (check-cont node)
  107. (if (not (= 1 arg-count))
  108. (assertion-violation 'check-node
  109. "letrec1 node must have exactly 1 arg" node))
  110. (let* ((cont (call-arg node 0))
  111. (cont-args (lambda-variables cont))
  112. (cont-arg-count (length cont-args))
  113. (next (lambda-body cont)))
  114. (check-cont next)
  115. (if (not (eq? 'letrec2 (call-primop-id next)))
  116. (assertion-violation 'check-node
  117. "letrec1 node must be followed by letrec2 node" node))
  118. (if (zero? cont-arg-count)
  119. (assertion-violation 'check-node
  120. "letrec1 cont lambda must have at least one variable" node))
  121. (if (not (= cont-arg-count
  122. (- (call-arg-count next) 1)))
  123. (assertion-violation 'check-node
  124. "letrec1 and letrec2 nodes must have matching arity" node))
  125. (let ((var (car cont-args)))
  126. (if (not (= 1 (length (variable-refs var))))
  127. (assertion-violation 'check-node
  128. "letrec id variable must have exactly one reference" node))
  129. (if (or (not (eq? next (node-parent (car (variable-refs var)))))
  130. (not (= 1 (node-index (car (variable-refs var))))))
  131. (assertion-violation 'check-node
  132. "letrec id binding invalid" node)))))
  133. ((call unknown-call)
  134. (check-proc-arg)
  135. (check-cont node))
  136. ((tail-call unknown-tail-call)
  137. (check-proc-arg)
  138. (check-cont-var node))
  139. ((return unknown-return)
  140. (check-cont-var node))
  141. ((jump)
  142. (check-cont-var node) ; sort of
  143. (let ((jump-target (get-lambda-value (call-arg node 0))))
  144. (if (not (eq? 'jump (lambda-type jump-target)))
  145. (assertion-violation 'check-node
  146. "jump must go to jump lambda"
  147. node jump-target))))))))
  148. (define (check-reference ref)
  149. (let ((var (reference-variable ref)))
  150. (if (and (variable-binder var)
  151. (not (variable-flag var)))
  152. (assertion-violation 'check-node
  153. "unbound variable reference" ref))))
  154. (define (check-literal node)
  155. (values)) ; nothing to check
  156. (define (yields-value? node)
  157. (or (lambda-node? node)
  158. (and (call-node? node)
  159. (trivial-primop-call? node))
  160. (literal-node? node)
  161. (reference-node? node)))