1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays definitions hashtables kernel kernel.private math
4 namespaces make sequences sequences.private strings vectors
5 words quotations memory combinators generic classes
6 classes.algebra classes.algebra.private classes.builtin
7 classes.private slots.private slots math.private accessors
11 PREDICATE: tuple-class < class
12 "metaclass" word-prop tuple-class eq? ;
14 ERROR: not-a-tuple object ;
16 : check-tuple ( object -- tuple )
17 dup tuple? [ not-a-tuple ] unless ; inline
19 : all-slots ( class -- slots )
20 superclasses [ "slots" word-prop ] map concat ;
22 PREDICATE: immutable-tuple-class < tuple-class ( class -- ? )
23 all-slots [ read-only>> ] all? ;
27 : tuple-layout ( class -- layout )
30 : layout-of ( tuple -- layout )
31 1 slot { array } declare ; inline
33 M: tuple class layout-of 2 slot { word } declare ; inline
35 : tuple-size ( tuple -- size )
36 layout-of 3 slot { fixnum } declare ; inline
38 : prepare-tuple>array ( tuple -- n tuple layout )
39 check-tuple [ tuple-size iota ] [ ] [ layout-of ] tri ;
41 : copy-tuple-slots ( n tuple -- array )
42 [ array-nth ] curry map ;
44 : check-slots ( seq class -- seq class )
47 class>> 2dup instance?
48 [ 2drop ] [ bad-slot-value ] if
50 ] if-bootstrapping ; inline
54 : initial-values ( class -- slots )
55 all-slots [ initial>> ] map ;
57 : pad-slots ( slots class -- slots' class )
58 [ initial-values over length tail append ] keep ; inline
60 : tuple>array ( tuple -- array )
62 [ copy-tuple-slots ] dip
65 : tuple-slots ( tuple -- seq )
66 prepare-tuple>array drop copy-tuple-slots ;
68 GENERIC: slots>tuple ( seq class -- tuple )
70 M: tuple-class slots>tuple ( seq class -- tuple )
72 tuple-layout <tuple> [
74 [ [ set-array-nth ] curry ]
78 : >tuple ( seq -- tuple )
81 ERROR: bad-superclass class ;
83 : tuple= ( tuple1 tuple2 -- ? )
84 2dup [ tuple? ] both? [
85 2dup [ layout-of ] bi@ eq? [
87 [ [ [ drop array-nth ] [ nip array-nth ] 3bi = ] 2curry ]
90 ] [ 2drop f ] if ; inline
94 : tuple-predicate-quot/1 ( class -- quot )
95 #! Fast path for tuples with no superclass
96 [ ] curry [ layout-of 7 slot ] [ eq? ] surround 1quotation
97 [ dup tuple? ] [ [ drop f ] if ] surround ;
99 : tuple-instance? ( object class offset -- ? )
103 [ swap slot eq? ] [ 3drop f ] if
104 ] [ 3drop f ] if ; inline
106 : layout-class-offset ( echelon -- n )
109 : tuple-predicate-quot ( class echelon -- quot )
110 layout-class-offset [ tuple-instance? ] 2curry ;
112 : echelon-of ( class -- n )
115 : define-tuple-predicate ( class -- )
117 { 1 [ tuple-predicate-quot/1 ] }
118 [ tuple-predicate-quot ]
119 } case define-predicate ;
121 : class-size ( class -- n )
122 superclasses [ "slots" word-prop length ] map-sum ;
124 : (instance-check-quot) ( class -- quot )
127 [ "predicate" word-prop % ]
128 [ [ literalize , \ bad-slot-value , ] [ ] make , ] bi
132 : (fixnum-check-quot) ( class -- quot )
133 (instance-check-quot) fixnum "coercer" word-prop prepend ;
135 : instance-check-quot ( class -- quot )
137 { [ dup object bootstrap-word eq? ] [ drop [ ] ] }
138 { [ dup "coercer" word-prop ] [ "coercer" word-prop ] }
139 { [ dup \ fixnum class<= ] [ (fixnum-check-quot) ] }
140 [ (instance-check-quot) ]
143 : boa-check-quot ( class -- quot )
144 all-slots [ class>> instance-check-quot ] map spread>quot
147 : define-boa-check ( class -- )
148 dup boa-check-quot "boa-check" set-word-prop ;
150 : tuple-prototype ( class -- prototype )
151 [ initial-values ] keep over [ ] any?
152 [ slots>tuple ] [ 2drop f ] if ;
154 : define-tuple-prototype ( class -- )
155 dup tuple-prototype "prototype" set-word-prop ;
157 : prepare-slots ( slots superclass -- slots' )
158 [ make-slots ] [ class-size 2 + ] bi* finalize-slots ;
160 : define-tuple-slots ( class -- )
161 dup "slots" word-prop over superclass prepare-slots
164 : make-tuple-layout ( class -- layout )
168 [ [ superclass class-size ] [ "slots" word-prop length ] bi + , ]
169 [ superclasses length 1 - , ]
170 [ superclasses [ [ , ] [ hashcode , ] bi ] each ]
174 : define-tuple-layout ( class -- )
175 dup make-tuple-layout "layout" set-word-prop ;
177 : compute-slot-permutation ( new-slots old-slots -- triples )
178 [ [ [ name>> ] map ] bi@ [ index ] curry map ]
179 [ drop [ class>> ] map ]
180 [ drop [ initial>> ] map ]
183 : update-slot ( old-values n class initial -- value )
185 [ [ swap nth dup ] dip instance? ] dip swap
187 ] [ [ 3drop ] dip ] if ;
189 : apply-slot-permutation ( old-values triples -- new-values )
190 [ first3 update-slot ] with map ;
192 SYMBOL: outdated-tuples
194 : permute-slots ( old-values layout -- new-values )
195 [ first all-slots ] [ outdated-tuples get at ] bi
196 compute-slot-permutation
197 apply-slot-permutation ;
199 : update-tuple ( tuple -- newtuple )
200 [ tuple-slots ] [ layout-of ] bi
201 [ permute-slots ] [ first ] bi
204 : outdated-tuple? ( tuple assoc -- ? )
205 [ [ layout-of ] dip key? ]
206 [ drop class "forgotten" word-prop not ]
209 : update-tuples ( -- )
211 dup assoc-empty? [ drop ] [
212 [ [ tuple? ] instances ] dip [ outdated-tuple? ] curry filter
213 dup [ update-tuple ] map become
216 : update-tuples-after ( class -- )
217 [ all-slots ] [ tuple-layout ] bi outdated-tuples get set-at ;
219 M: tuple-class update-class
222 [ define-tuple-layout ]
223 [ define-tuple-slots ]
224 [ define-tuple-predicate ]
225 [ define-tuple-prototype ]
228 : define-new-tuple-class ( class superclass slots -- )
229 [ drop f f tuple-class define-class ]
230 [ nip "slots" set-word-prop ]
231 [ 2drop update-classes ]
234 : subclasses ( class -- classes )
235 class-usages [ tuple-class? ] filter ;
237 : each-subclass ( class quot -- )
238 [ subclasses ] dip each ; inline
240 : redefine-tuple-class ( class superclass slots -- )
244 [ update-tuples-after ]
245 [ changed-definition ]
249 [ define-new-tuple-class ] 3bi ;
251 : tuple-class-unchanged? ( class superclass slots -- ? )
252 [ [ superclass ] [ bootstrap-word ] bi* = ]
253 [ [ "slots" word-prop ] dip = ]
256 GENERIC: valid-superclass? ( class -- ? )
258 M: tuple-class valid-superclass? drop t ;
260 M: builtin-class valid-superclass? tuple eq? ;
262 M: class valid-superclass? drop f ;
264 : check-superclass ( superclass -- )
265 dup valid-superclass? [ bad-superclass ] unless drop ;
267 GENERIC# (define-tuple-class) 2 ( class superclass slots -- )
271 : define-tuple-class ( class superclass slots -- )
272 over check-superclass
274 (define-tuple-class) ;
276 M: word (define-tuple-class)
277 define-new-tuple-class ;
279 M: tuple-class (define-tuple-class)
280 3dup tuple-class-unchanged?
281 [ 2drop ?define-symbol ] [ redefine-tuple-class ] if ;
283 : thrower-effect ( slots -- effect )
284 [ name>> ] map { "*" } <effect> ;
286 : define-error-class ( class superclass slots -- )
287 [ define-tuple-class ]
288 [ 2drop reset-generic ]
291 [ dup [ boa throw ] curry ]
292 [ all-slots thrower-effect ]
296 : boa-effect ( class -- effect )
297 [ all-slots [ name>> ] map ] [ name>> 1array ] bi <effect> ;
299 : define-boa-word ( word class -- )
300 [ [ boa ] curry ] [ boa-effect ] bi define-inline ;
302 M: tuple-class reset-class
304 dup "slots" word-prop [
306 [ reader-word method forget ]
307 [ writer-word method forget ] 2bi
311 [ { "layout" "slots" "boa-check" "prototype" } reset-props ]
315 M: tuple-class rank-class drop 0 ;
317 M: tuple-class instance?
318 dup echelon-of layout-class-offset tuple-instance? ;
320 M: tuple-class (flatten-class) dup set ;
322 M: tuple-class (classes-intersect?)
324 { [ over tuple eq? ] [ 2drop t ] }
325 { [ over builtin-class? ] [ 2drop f ] }
326 { [ over tuple-class? ] [ [ class<= ] [ swap class<= ] 2bi or ] }
327 [ swap classes-intersect? ]
330 M: tuple clone (clone) ; inline
332 M: tuple equal? over tuple? [ tuple= ] [ 2drop f ] if ;
334 GENERIC: tuple-hashcode ( n tuple -- x )
336 M: tuple tuple-hashcode
338 [ class hashcode ] [ tuple-size iota ] [ ] tri
340 swapd array-nth hashcode* sequence-hashcode-step
342 ] recursive-hashcode ;
344 M: tuple hashcode* tuple-hashcode ;
347 dup "prototype" word-prop [ (clone) ] [ tuple-layout <tuple> ] ?if ;
350 [ "boa-check" word-prop [ call ] when* ]
354 M: tuple-class initial-value* new ;