1 ! Copyright (C) 2004, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel classes combinators accessors sequences arrays
4 vectors assocs namespaces words sorting layouts math hashtables
5 kernel.private sets math.order ;
10 TUPLE: anonymous-union { members read-only } ;
12 : <anonymous-union> ( members -- class )
13 [ null eq? not ] filter prune
14 dup length 1 = [ first ] [ anonymous-union boa ] if ;
16 TUPLE: anonymous-intersection { participants read-only } ;
18 : <anonymous-intersection> ( participants -- class )
19 prune dup length 1 = [ first ] [ anonymous-intersection boa ] if ;
21 TUPLE: anonymous-complement { class read-only } ;
23 C: <anonymous-complement> anonymous-complement
29 GENERIC: (classes-intersect?) ( first second -- ? )
35 GENERIC: (flatten-class) ( class -- )
37 GENERIC: normalize-class ( class -- class' )
39 M: object normalize-class ;
43 GENERIC: classoid? ( obj -- ? )
45 M: word classoid? class? ;
46 M: anonymous-union classoid? members>> [ classoid? ] all? ;
47 M: anonymous-intersection classoid? participants>> [ classoid? ] all? ;
48 M: anonymous-complement classoid? class>> classoid? ;
50 : class<= ( first second -- ? )
51 class<=-cache get [ (class<=) ] 2cache ;
53 : class< ( first second -- ? )
55 { [ 2dup class<= not ] [ 2drop f ] }
56 { [ 2dup swap class<= not ] [ 2drop t ] }
57 [ [ rank-class ] bi@ < ]
60 : class<=> ( first second -- ? )
62 { [ 2dup class<= not ] [ 2drop +gt+ ] }
63 { [ 2dup swap class<= not ] [ 2drop +lt+ ] }
64 [ [ rank-class ] bi@ <=> ]
67 : class= ( first second -- ? )
68 [ class<= ] [ swap class<= ] 2bi and ;
70 : class-not ( class -- complement )
71 class-not-cache get [ (class-not) ] cache ;
73 : classes-intersect? ( first second -- ? )
74 classes-intersect-cache get [
75 normalize-class (classes-intersect?)
78 : class-and ( first second -- class )
79 class-and-cache get [ (class-and) ] 2cache ;
81 : class-or ( first second -- class )
82 class-or-cache get [ (class-or) ] 2cache ;
86 : superclass<= ( first second -- ? )
87 swap superclass dup [ swap class<= ] [ 2drop f ] if ;
89 : left-anonymous-union<= ( first second -- ? )
90 [ members>> ] dip [ class<= ] curry all? ;
92 : right-union<= ( first second -- ? )
93 members [ class<= ] with any? ;
95 : right-anonymous-union<= ( first second -- ? )
96 members>> [ class<= ] with any? ;
98 : left-anonymous-intersection<= ( first second -- ? )
99 [ participants>> ] dip [ class<= ] curry any? ;
101 : right-anonymous-intersection<= ( first second -- ? )
102 participants>> [ class<= ] with all? ;
104 : anonymous-complement<= ( first second -- ? )
105 [ class>> ] bi@ swap class<= ;
107 : normalize-complement ( class -- class' )
108 class>> normalize-class {
109 { [ dup anonymous-union? ] [
111 [ class-not normalize-class ] map
112 <anonymous-intersection>
114 { [ dup anonymous-intersection? ] [
116 [ class-not normalize-class ] map
122 : left-anonymous-complement<= ( first second -- ? )
123 [ normalize-complement ] dip class<= ;
125 PREDICATE: nontrivial-anonymous-complement < anonymous-complement
128 [ anonymous-intersection? ]
133 PREDICATE: empty-union < anonymous-union members>> empty? ;
135 PREDICATE: empty-intersection < anonymous-intersection participants>> empty? ;
137 : (class<=) ( first second -- ? )
138 2dup eq? [ 2drop t ] [
139 [ normalize-class ] bi@
140 2dup superclass<= [ 2drop t ] [
142 { [ 2dup eq? ] [ 2drop t ] }
143 { [ dup empty-intersection? ] [ 2drop t ] }
144 { [ over empty-union? ] [ 2drop t ] }
145 { [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement<= ] }
146 { [ over anonymous-union? ] [ left-anonymous-union<= ] }
147 { [ over anonymous-intersection? ] [ left-anonymous-intersection<= ] }
148 { [ over nontrivial-anonymous-complement? ] [ left-anonymous-complement<= ] }
149 { [ dup members ] [ right-union<= ] }
150 { [ dup anonymous-union? ] [ right-anonymous-union<= ] }
151 { [ dup anonymous-intersection? ] [ right-anonymous-intersection<= ] }
152 { [ dup anonymous-complement? ] [ class>> classes-intersect? not ] }
158 M: anonymous-union (classes-intersect?)
159 members>> [ classes-intersect? ] with any? ;
161 M: anonymous-intersection (classes-intersect?)
162 participants>> [ classes-intersect? ] with all? ;
164 M: anonymous-complement (classes-intersect?)
165 class>> class<= not ;
167 : anonymous-union-and ( first second -- class )
168 members>> [ class-and ] with map <anonymous-union> ;
170 : anonymous-intersection-and ( first second -- class )
171 participants>> swap suffix <anonymous-intersection> ;
173 : (class-and) ( first second -- class )
175 { [ 2dup class<= ] [ drop ] }
176 { [ 2dup swap class<= ] [ nip ] }
177 { [ 2dup classes-intersect? not ] [ 2drop null ] }
179 [ normalize-class ] bi@ {
180 { [ dup anonymous-union? ] [ anonymous-union-and ] }
181 { [ dup anonymous-intersection? ] [ anonymous-intersection-and ] }
182 { [ over anonymous-union? ] [ swap anonymous-union-and ] }
183 { [ over anonymous-intersection? ] [ swap anonymous-intersection-and ] }
184 [ 2array <anonymous-intersection> ]
189 : anonymous-union-or ( first second -- class )
190 members>> swap suffix <anonymous-union> ;
192 : ((class-or)) ( first second -- class )
193 [ normalize-class ] bi@ {
194 { [ dup anonymous-union? ] [ anonymous-union-or ] }
195 { [ over anonymous-union? ] [ swap anonymous-union-or ] }
196 [ 2array <anonymous-union> ]
199 : anonymous-complement-or ( first second -- class )
200 2dup class>> swap class<= [ 2drop object ] [ ((class-or)) ] if ;
202 : (class-or) ( first second -- class )
204 { [ 2dup class<= ] [ nip ] }
205 { [ 2dup swap class<= ] [ drop ] }
206 { [ dup anonymous-complement? ] [ anonymous-complement-or ] }
207 { [ over anonymous-complement? ] [ swap anonymous-complement-or ] }
211 : (class-not) ( class -- complement )
213 { [ dup anonymous-complement? ] [ class>> ] }
214 { [ dup object eq? ] [ drop null ] }
215 { [ dup null eq? ] [ drop object ] }
216 [ <anonymous-complement> ]
219 M: anonymous-union (flatten-class)
220 members>> [ (flatten-class) ] each ;
224 ERROR: topological-sort-failed ;
226 : largest-class ( seq -- n elt )
227 dup [ [ class< ] with any? not ] curry find-last
228 [ topological-sort-failed ] unless* ;
230 : sort-classes ( seq -- newseq )
231 [ name>> ] sort-with >vector
233 [ dup largest-class [ swap remove-nth! ] dip ]
236 : smallest-class ( classes -- class/f )
238 natural-sort <reversed>
239 [ ] [ [ class<= ] most ] map-reduce
242 : flatten-class ( class -- assoc )
243 [ (flatten-class) ] H{ } make-assoc ;