node-check.scm 6.4 KB

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