1 ! Copyright (C) 2004, 2008 Slava Pestov.
\r
2 ! See http://factorcode.org/license.txt for BSD license.
\r
3 USING: kernel classes classes.builtin combinators accessors
\r
4 sequences arrays vectors assocs namespaces words sorting layouts
\r
5 math hashtables kernel.private sets math.order ;
\r
8 : 2cache ( key1 key2 assoc quot -- value )
\r
9 >r >r 2array r> [ first2 ] r> compose cache ; inline
\r
13 : class<= ( first second -- ? )
\r
14 class<=-cache get [ (class<=) ] 2cache ;
\r
18 : class-not ( class -- complement )
\r
19 class-not-cache get [ (class-not) ] cache ;
\r
21 DEFER: (classes-intersect?) ( first second -- ? )
\r
23 : classes-intersect? ( first second -- ? )
\r
24 classes-intersect-cache get [ (classes-intersect?) ] 2cache ;
\r
28 : class-and ( first second -- class )
\r
29 class-and-cache get [ (class-and) ] 2cache ;
\r
33 : class-or ( first second -- class )
\r
34 class-or-cache get [ (class-or) ] 2cache ;
\r
36 TUPLE: anonymous-union members ;
\r
38 C: <anonymous-union> anonymous-union
\r
40 TUPLE: anonymous-intersection participants ;
\r
42 C: <anonymous-intersection> anonymous-intersection
\r
44 TUPLE: anonymous-complement class ;
\r
46 C: <anonymous-complement> anonymous-complement
\r
48 : superclass<= ( first second -- ? )
\r
49 >r superclass r> class<= ;
\r
51 : left-anonymous-union<= ( first second -- ? )
\r
52 >r members>> r> [ class<= ] curry all? ;
\r
54 : right-anonymous-union<= ( first second -- ? )
\r
55 members>> [ class<= ] with contains? ;
\r
57 : left-anonymous-intersection<= ( first second -- ? )
\r
58 >r participants>> r> [ class<= ] curry contains? ;
\r
60 : right-anonymous-intersection<= ( first second -- ? )
\r
61 participants>> [ class<= ] with all? ;
\r
63 : anonymous-complement<= ( first second -- ? )
\r
64 [ class>> ] bi@ swap class<= ;
\r
66 : normalize-class ( class -- class' )
\r
68 { [ dup members ] [ members <anonymous-union> ] }
\r
69 { [ dup participants ] [ participants <anonymous-intersection> ] }
\r
73 : normalize-complement ( class -- class' )
\r
74 class>> normalize-class {
\r
75 { [ dup anonymous-union? ] [
\r
77 [ class-not normalize-class ] map
\r
78 <anonymous-intersection>
\r
80 { [ dup anonymous-intersection? ] [
\r
82 [ class-not normalize-class ] map
\r
87 : left-anonymous-complement<= ( first second -- ? )
\r
88 >r normalize-complement r> class<= ;
\r
90 PREDICATE: nontrivial-anonymous-complement < anonymous-complement
\r
92 [ anonymous-union? ]
\r
93 [ anonymous-intersection? ]
\r
98 PREDICATE: empty-union < anonymous-union members>> empty? ;
\r
100 PREDICATE: empty-intersection < anonymous-intersection participants>> empty? ;
\r
102 : (class<=) ( first second -- -1/0/1 )
\r
103 2dup eq? [ 2drop t ] [
\r
104 [ normalize-class ] bi@ {
\r
105 { [ dup empty-intersection? ] [ 2drop t ] }
\r
106 { [ over empty-union? ] [ 2drop t ] }
\r
107 { [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement<= ] }
\r
108 { [ over anonymous-union? ] [ left-anonymous-union<= ] }
\r
109 { [ over anonymous-intersection? ] [ left-anonymous-intersection<= ] }
\r
110 { [ over nontrivial-anonymous-complement? ] [ left-anonymous-complement<= ] }
\r
111 { [ dup anonymous-union? ] [ right-anonymous-union<= ] }
\r
112 { [ dup anonymous-intersection? ] [ right-anonymous-intersection<= ] }
\r
113 { [ dup anonymous-complement? ] [ class>> classes-intersect? not ] }
\r
114 { [ over superclass ] [ superclass<= ] }
\r
119 : anonymous-union-intersect? ( first second -- ? )
\r
120 members>> [ classes-intersect? ] with contains? ;
\r
122 : anonymous-intersection-intersect? ( first second -- ? )
\r
123 participants>> [ classes-intersect? ] with all? ;
\r
125 : anonymous-complement-intersect? ( first second -- ? )
\r
126 class>> class<= not ;
\r
128 : tuple-class-intersect? ( first second -- ? )
\r
130 { [ over tuple eq? ] [ 2drop t ] }
\r
131 { [ over builtin-class? ] [ 2drop f ] }
\r
132 { [ over tuple-class? ] [ [ class<= ] [ swap class<= ] 2bi or ] }
\r
133 [ swap classes-intersect? ]
\r
136 : builtin-class-intersect? ( first second -- ? )
\r
138 { [ 2dup eq? ] [ 2drop t ] }
\r
139 { [ over builtin-class? ] [ 2drop f ] }
\r
140 [ swap classes-intersect? ]
\r
143 : (classes-intersect?) ( first second -- ? )
\r
145 { [ dup anonymous-union? ] [ anonymous-union-intersect? ] }
\r
146 { [ dup anonymous-intersection? ] [ anonymous-intersection-intersect? ] }
\r
147 { [ dup anonymous-complement? ] [ anonymous-complement-intersect? ] }
\r
148 { [ dup tuple-class? ] [ tuple-class-intersect? ] }
\r
149 { [ dup builtin-class? ] [ builtin-class-intersect? ] }
\r
150 { [ dup superclass ] [ superclass classes-intersect? ] }
\r
153 : anonymous-union-and ( first second -- class )
\r
154 members>> [ class-and ] with map <anonymous-union> ;
\r
156 : anonymous-intersection-and ( first second -- class )
\r
157 participants>> swap suffix <anonymous-intersection> ;
\r
159 : (class-and) ( first second -- class )
\r
161 { [ 2dup class<= ] [ drop ] }
\r
162 { [ 2dup swap class<= ] [ nip ] }
\r
163 { [ 2dup classes-intersect? not ] [ 2drop null ] }
\r
165 [ normalize-class ] bi@ {
\r
166 { [ dup anonymous-union? ] [ anonymous-union-and ] }
\r
167 { [ dup anonymous-intersection? ] [ anonymous-intersection-and ] }
\r
168 { [ over anonymous-union? ] [ swap anonymous-union-and ] }
\r
169 { [ over anonymous-intersection? ] [ swap anonymous-intersection-and ] }
\r
170 [ 2array <anonymous-intersection> ]
\r
175 : anonymous-union-or ( first second -- class )
\r
176 members>> swap suffix <anonymous-union> ;
\r
178 : ((class-or)) ( first second -- class )
\r
179 [ normalize-class ] bi@ {
\r
180 { [ dup anonymous-union? ] [ anonymous-union-or ] }
\r
181 { [ over anonymous-union? ] [ swap anonymous-union-or ] }
\r
182 [ 2array <anonymous-union> ]
\r
185 : anonymous-complement-or ( first second -- class )
\r
186 2dup class>> swap class<= [ 2drop object ] [ ((class-or)) ] if ;
\r
188 : (class-or) ( first second -- class )
\r
190 { [ 2dup class<= ] [ nip ] }
\r
191 { [ 2dup swap class<= ] [ drop ] }
\r
192 { [ dup anonymous-complement? ] [ anonymous-complement-or ] }
\r
193 { [ over anonymous-complement? ] [ swap anonymous-complement-or ] }
\r
197 : (class-not) ( class -- complement )
\r
199 { [ dup anonymous-complement? ] [ class>> ] }
\r
200 { [ dup object eq? ] [ drop null ] }
\r
201 { [ dup null eq? ] [ drop object ] }
\r
202 [ <anonymous-complement> ]
\r
205 : class< ( first second -- ? )
\r
207 { [ 2dup class<= not ] [ 2drop f ] }
\r
208 { [ 2dup swap class<= not ] [ 2drop t ] }
\r
209 [ [ rank-class ] bi@ < ]
\r
212 : largest-class ( seq -- n elt )
\r
213 dup [ [ class< ] with contains? not ] curry find-last
\r
214 [ "Topological sort failed" throw ] unless* ;
\r
216 : sort-classes ( seq -- newseq )
\r
217 [ [ name>> ] compare ] sort >vector
\r
219 [ dup largest-class >r over delete-nth r> ]
\r
222 : min-class ( class seq -- class/f )
\r
223 over [ classes-intersect? ] curry filter
\r
224 dup empty? [ 2drop f ] [
\r
225 tuck [ class<= ] with all? [ peek ] [ drop f ] if
\r
228 DEFER: (flatten-class)
\r
229 DEFER: flatten-builtin-class
\r
231 : flatten-intersection-class ( class -- )
\r
232 participants [ flatten-builtin-class ] map
\r
234 drop builtins get [ (flatten-class) ] each
\r
236 unclip [ assoc-intersect ] reduce [ swap set ] assoc-each
\r
239 : (flatten-class) ( class -- )
\r
241 { [ dup tuple-class? ] [ dup set ] }
\r
242 { [ dup builtin-class? ] [ dup set ] }
\r
243 { [ dup members ] [ members [ (flatten-class) ] each ] }
\r
244 { [ dup participants ] [ flatten-intersection-class ] }
\r
245 { [ dup superclass ] [ superclass (flatten-class) ] }
\r
249 : flatten-class ( class -- assoc )
\r
250 [ (flatten-class) ] H{ } make-assoc ;
\r
252 : flatten-builtin-class ( class -- assoc )
\r
254 dup tuple class<= [ 2drop tuple tuple ] when
\r
257 : class-types ( class -- seq )
\r
258 flatten-builtin-class keys
\r
259 [ "type" word-prop ] map natural-sort ;
\r
261 : class-tags ( class -- tag/f )
\r
263 dup num-tags get >=
\r
264 [ drop \ hi-tag tag-number ] when
\r