1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs columns combinators compiler.tree
4 compiler.tree.combinators compiler.tree.def-use
5 compiler.tree.recursive continuations grouping kernel math
6 namespaces sequences sets vectors ;
7 IN: compiler.tree.checker
9 ! Check some invariants; this can help catch compiler bugs.
11 ERROR: check-use-error value message ;
13 : check-use ( value uses -- )
14 [ empty? [ "No use" throw-check-use-error ] [ drop ] if ]
18 [ "Uses not all unique" throw-check-use-error ] if
21 : check-def-use ( -- )
22 def-use get [ uses>> check-use ] assoc-each ;
24 GENERIC: check-node* ( node -- )
26 M: #shuffle check-node*
27 [ [ mapping>> values ] [ [ in-d>> ] [ in-r>> ] bi append ] bi subset? [ "Bad mapping inputs" throw ] unless ]
28 [ [ mapping>> keys ] [ [ out-d>> ] [ out-r>> ] bi append ] bi set= [ "Bad mapping outputs" throw ] unless ]
31 : check-lengths ( seq -- )
32 [ length ] map all-equal? [ "Bad lengths" throw ] unless ;
34 M: #copy check-node* inputs/outputs 2array check-lengths ;
36 M: #return-recursive check-node* inputs/outputs 2array check-lengths ;
39 [ [ phi-in-d>> <flipped> ] [ out-d>> ] bi 2array check-lengths ]
40 [ phi-in-d>> check-lengths ]
43 M: #enter-recursive check-node*
44 [ [ label>> enter-out>> ] [ out-d>> ] bi assert= ]
45 [ [ in-d>> ] [ out-d>> ] bi 2array check-lengths ]
46 [ recursive-phi-in check-lengths ]
50 out-d>> length 1 = [ "Bad #push" throw ] unless ;
52 M: node check-node* drop ;
54 : check-values ( seq -- )
55 [ integer? ] all? [ "Bad values" throw ] unless ;
57 ERROR: check-node-error node error ;
59 : check-node ( node -- )
61 [ node-uses-values check-values ]
62 [ node-defs-values check-values ]
65 ] [ throw-check-node-error ] recover ;
71 GENERIC: check-stack-flow* ( node -- )
73 : (check-stack-flow) ( nodes -- )
74 [ check-stack-flow* terminated? get not ] all? drop ;
76 : init-stack-flow ( -- )
77 V{ } clone datastack set
78 V{ } clone retainstack set ;
80 : check-stack-flow ( nodes -- )
86 : check-inputs ( seq var -- )
87 [ dup length ] dip [ swap cut* swap ] change
88 sequence= [ "Bad stack flow" throw ] unless ;
90 : check-in-d ( node -- )
91 in-d>> datastack check-inputs ;
93 : check-in-r ( node -- )
94 in-r>> retainstack check-inputs ;
96 : check-outputs ( node var -- )
99 : check-out-d ( node -- )
100 out-d>> datastack check-outputs ;
102 : check-out-r ( node -- )
103 out-r>> retainstack check-outputs ;
105 M: #introduce check-stack-flow* check-out-d ;
107 M: #push check-stack-flow* check-out-d ;
109 M: #call check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
111 M: #shuffle check-stack-flow*
112 { [ check-in-d ] [ check-in-r ] [ check-out-d ] [ check-out-r ] } cleave ;
114 : assert-datastack-empty ( -- )
115 datastack get empty? [ "Data stack not empty" throw ] unless ;
117 : assert-retainstack-empty ( -- )
118 retainstack get empty? [ "Retain stack not empty" throw ] unless ;
120 M: #return check-stack-flow*
122 assert-datastack-empty
123 terminated? get [ assert-retainstack-empty ] unless ;
125 M: #enter-recursive check-stack-flow*
128 M: #return-recursive check-stack-flow*
129 [ check-in-d ] [ check-out-d ] bi ;
131 M: #call-recursive check-stack-flow*
132 [ check-in-d ] [ check-out-d ] bi ;
134 : check-terminate-in-d ( #terminate -- )
135 in-d>> datastack get over length tail* sequence=
136 [ "Bad terminate data stack" throw ] unless ;
138 : check-terminate-in-r ( #terminate -- )
139 in-r>> retainstack get over length tail* sequence=
140 [ "Bad terminate retain stack" throw ] unless ;
142 M: #terminate check-stack-flow*
144 [ check-terminate-in-d ]
145 [ check-terminate-in-r ] bi ;
149 : check-branch ( nodes -- stack )
151 datastack [ clone ] change
152 V{ } clone retainstack set
154 terminated? get [ assert-retainstack-empty ] unless
155 terminated? get f datastack get ?
158 M: #branch check-stack-flow*
160 [ children>> [ check-branch ] map branch-out set ]
163 : check-phi-in ( #phi -- )
164 phi-in-d>> branch-out get [
166 over length tail* sequence= [
167 "Branch outputs don't match phi inputs"
175 : set-phi-datastack ( #phi -- )
176 phi-in-d>> first length
177 branch-out get [ ] find nip swap head* >vector datastack set ;
179 M: #phi check-stack-flow*
180 branch-out get [ ] any? [
181 [ check-phi-in ] [ set-phi-datastack ] [ check-out-d ] tri
182 ] [ drop terminated? on ] if ;
184 M: #recursive check-stack-flow*
185 [ check-in-d ] [ child>> (check-stack-flow) ] bi ;
187 M: #copy check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
189 M: #alien-node check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
191 M: #alien-callback check-stack-flow* child>> check-stack-flow ;
193 M: #declare check-stack-flow* drop ;
195 : check-nodes ( nodes -- )
198 [ [ check-node ] each-node ]