]> gitweb.factorcode.org Git - factor.git/blob - basis/compiler/tree/checker/checker.factor
03249db124f5d32fc866cb4e23822cfd11b499f7
[factor.git] / basis / compiler / tree / checker / checker.factor
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
8
9 ! Check some invariants; this can help catch compiler bugs.
10
11 ERROR: check-use-error value message ;
12
13 : check-use ( value uses -- )
14     [ empty? [ "No use" check-use-error ] [ drop ] if ]
15     [ all-unique? [ drop ] [ "Uses not all unique" check-use-error ] if ] 2bi ;
16
17 : check-def-use ( -- )
18     def-use get [ uses>> check-use ] assoc-each ;
19
20 GENERIC: check-node* ( node -- )
21
22 M: #shuffle check-node*
23     [ [ mapping>> values ] [ [ in-d>> ] [ in-r>> ] bi append ] bi subset? [ "Bad mapping inputs" throw ] unless ]
24     [ [ mapping>> keys ] [ [ out-d>> ] [ out-r>> ] bi append ] bi set= [ "Bad mapping outputs" throw ] unless ]
25     bi ;
26
27 : check-lengths ( seq -- )
28     [ length ] map all-equal? [ "Bad lengths" throw ] unless ;
29
30 M: #copy check-node* inputs/outputs 2array check-lengths ;
31
32 M: #return-recursive check-node* inputs/outputs 2array check-lengths ;
33
34 M: #phi check-node*
35     [ [ phi-in-d>> <flipped> ] [ out-d>> ] bi 2array check-lengths ]
36     [ phi-in-d>> check-lengths ]
37     bi ;
38
39 M: #enter-recursive check-node*
40     [ [ label>> enter-out>> ] [ out-d>> ] bi assert= ]
41     [ [ in-d>> ] [ out-d>> ] bi 2array check-lengths ]
42     [ recursive-phi-in check-lengths ]
43     tri ;
44
45 M: #push check-node*
46     out-d>> length 1 = [ "Bad #push" throw ] unless ;
47
48 M: node check-node* drop ;
49
50 : check-values ( seq -- )
51     [ integer? ] all? [ "Bad values" throw ] unless ;
52
53 ERROR: check-node-error node error ;
54
55 : check-node ( node -- )
56     [
57         [ node-uses-values check-values ]
58         [ node-defs-values check-values ]
59         [ check-node* ]
60         tri
61     ] [ check-node-error ] recover ;
62
63 SYMBOL: datastack
64 SYMBOL: retainstack
65 SYMBOL: terminated?
66
67 GENERIC: check-stack-flow* ( node -- )
68
69 : (check-stack-flow) ( nodes -- )
70     [ check-stack-flow* terminated? get not ] all? drop ;
71
72 : init-stack-flow ( -- )
73     V{ } clone datastack set
74     V{ } clone retainstack set ;
75
76 : check-stack-flow ( nodes -- )
77     [
78         init-stack-flow
79         (check-stack-flow)
80     ] with-scope ;
81
82 : check-inputs ( seq var -- )
83     [ dup length ] dip [ swap cut* swap ] change
84     sequence= [ "Bad stack flow" throw ] unless ;
85
86 : check-in-d ( node -- )
87     in-d>> datastack check-inputs ;
88
89 : check-in-r ( node -- )
90     in-r>> retainstack check-inputs ;
91
92 : check-outputs ( node var -- )
93     get push-all ;
94
95 : check-out-d ( node -- )
96     out-d>> datastack check-outputs ;
97
98 : check-out-r ( node -- )
99     out-r>> retainstack check-outputs ;
100
101 M: #introduce check-stack-flow* check-out-d ;
102
103 M: #push check-stack-flow* check-out-d ;
104
105 M: #call check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
106
107 M: #shuffle check-stack-flow*
108     { [ check-in-d ] [ check-in-r ] [ check-out-d ] [ check-out-r ] } cleave ;
109
110 : assert-datastack-empty ( -- )
111     datastack get empty? [ "Data stack not empty" throw ] unless ;
112
113 : assert-retainstack-empty ( -- )
114     retainstack get empty? [ "Retain stack not empty" throw ] unless ;
115
116 M: #return check-stack-flow*
117     check-in-d
118     assert-datastack-empty
119     terminated? get [ assert-retainstack-empty ] unless ;
120
121 M: #enter-recursive check-stack-flow*
122     check-out-d ;
123
124 M: #return-recursive check-stack-flow*
125     [ check-in-d ] [ check-out-d ] bi ;
126
127 M: #call-recursive check-stack-flow*
128     [ check-in-d ] [ check-out-d ] bi ;
129
130 : check-terminate-in-d ( #terminate -- )
131     in-d>> datastack get over length tail* sequence=
132     [ "Bad terminate data stack" throw ] unless ;
133
134 : check-terminate-in-r ( #terminate -- )
135     in-r>> retainstack get over length tail* sequence=
136     [ "Bad terminate retain stack" throw ] unless ;
137
138 M: #terminate check-stack-flow*
139     terminated? on
140     [ check-terminate-in-d ]
141     [ check-terminate-in-r ] bi ;
142
143 SYMBOL: branch-out
144
145 : check-branch ( nodes -- stack )
146     [
147         datastack [ clone ] change
148         V{ } clone retainstack set
149         (check-stack-flow)
150         terminated? get [ assert-retainstack-empty ] unless
151         terminated? get f datastack get ?
152     ] with-scope ;
153
154 M: #branch check-stack-flow*
155     [ check-in-d ]
156     [ children>> [ check-branch ] map branch-out set ]
157     bi ;
158
159 : check-phi-in ( #phi -- )
160     phi-in-d>> branch-out get [
161         dup [
162             over length tail* sequence= [
163                 "Branch outputs don't match phi inputs"
164                 throw
165             ] unless
166         ] [
167             2drop
168         ] if
169     ] 2each ;
170
171 : set-phi-datastack ( #phi -- )
172     phi-in-d>> first length
173     branch-out get [ ] find nip swap head* >vector datastack set ;
174
175 M: #phi check-stack-flow*
176     branch-out get [ ] any? [
177         [ check-phi-in ] [ set-phi-datastack ] [ check-out-d ] tri
178     ] [ drop terminated? on ] if ;
179
180 M: #recursive check-stack-flow*
181     [ check-in-d ] [ child>> (check-stack-flow) ] bi ;
182
183 M: #copy check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
184
185 M: #alien-node check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
186
187 M: #alien-callback check-stack-flow* child>> check-stack-flow ;
188
189 M: #declare check-stack-flow* drop ;
190
191 : check-nodes ( nodes -- )
192     compute-def-use
193     check-def-use
194     [ [ check-node ] each-node ]
195     [ check-stack-flow ]
196     bi ;