1 ! Copyright (C) 2005, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays byte-arrays kernel kernel.private math namespaces
4 make sequences strings words effects generic generic.standard
5 classes classes.algebra slots.private combinators accessors
6 words sequences.private assocs alien quotations hashtables ;
9 TUPLE: slot-spec name offset class initial read-only ;
11 PREDICATE: reader < word "reader" word-prop ;
13 PREDICATE: writer < word "writer" word-prop ;
15 : <slot-spec> ( -- slot-spec )
17 object bootstrap-word >>class ;
19 : define-typecheck ( class generic quot props -- )
20 [ dup define-simple-generic create-method ] 2dip
21 [ [ props>> ] [ drop ] [ ] tri* update ]
25 : reader-quot ( slot-spec -- quot )
29 dup class>> object bootstrap-word eq?
30 [ drop ] [ class>> 1array , \ declare , ] if
33 : reader-word ( name -- word )
34 ">>" append "accessors" create
35 dup (( object -- value )) "declared-effect" set-word-prop
36 dup t "reader" set-word-prop ;
38 : reader-props ( slot-spec -- assoc )
41 [ read-only>> [ t "foldable" set ] when ] bi
45 : define-reader ( class slot-spec -- )
46 [ name>> reader-word ] [ reader-quot ] [ reader-props ] tri
49 : writer-word ( name -- word )
50 "(>>" ")" surround "accessors" create
51 dup (( value object -- )) "declared-effect" set-word-prop
52 dup t "writer" set-word-prop ;
54 ERROR: bad-slot-value value class ;
56 : writer-quot/object ( slot-spec -- )
57 offset>> , \ set-slot , ;
59 : writer-quot/coerce ( slot-spec -- )
60 [ class>> "coercer" word-prop [ dip ] curry % ]
61 [ offset>> , \ set-slot , ]
64 : writer-quot/check ( slot-spec -- )
68 dup class>> "predicate" word-prop %
70 class>> [ 2nip bad-slot-value ] curry [ ] like ,
75 : writer-quot/fixnum ( slot-spec -- )
76 [ [ >fixnum ] dip ] % writer-quot/check ;
78 : writer-quot ( slot-spec -- quot )
81 { [ dup class>> object bootstrap-word eq? ] [ writer-quot/object ] }
82 { [ dup class>> "coercer" word-prop ] [ writer-quot/coerce ] }
83 { [ dup class>> fixnum bootstrap-word class<= ] [ writer-quot/fixnum ] }
88 : writer-props ( slot-spec -- assoc )
91 : define-writer ( class slot-spec -- )
92 [ name>> writer-word ] [ writer-quot ] [ writer-props ] tri
95 : setter-word ( name -- word )
96 ">>" prepend "accessors" create ;
98 : define-setter ( name -- )
99 dup setter-word dup deferred? [
100 [ \ over , swap writer-word , ] [ ] make
101 (( object value -- object )) define-inline
104 : changer-word ( name -- word )
105 "change-" prepend "accessors" create ;
107 : define-changer ( name -- )
108 dup changer-word dup deferred? [
111 over reader-word 1quotation
112 [ dip call ] curry [ dip swap ] curry %
114 ] [ ] make (( object quot -- object )) define-inline
117 : define-slot-methods ( class slot-spec -- )
120 dup read-only>> [ 2drop ] [
121 [ name>> define-setter drop ]
122 [ name>> define-changer drop ]
128 : define-accessors ( class specs -- )
129 [ define-slot-methods ] with each ;
131 : define-protocol-slot ( name -- )
133 [ reader-word define-simple-generic ]
134 [ writer-word define-simple-generic ]
139 ERROR: no-initial-value class ;
141 GENERIC: initial-value* ( class -- object )
143 M: class initial-value* no-initial-value ;
145 : initial-value ( class -- object )
147 { [ \ f bootstrap-word over class<= ] [ f ] }
148 { [ \ array-capacity bootstrap-word over class<= ] [ 0 ] }
149 { [ float bootstrap-word over class<= ] [ 0.0 ] }
150 { [ string bootstrap-word over class<= ] [ "" ] }
151 { [ array bootstrap-word over class<= ] [ { } ] }
152 { [ byte-array bootstrap-word over class<= ] [ B{ } ] }
153 { [ simple-alien bootstrap-word over class<= ] [ <bad-alien> ] }
154 [ dup initial-value* ]
157 GENERIC: make-slot ( desc -- slot-spec )
163 : peel-off-name ( slot-spec array -- slot-spec array )
164 [ first >>name ] [ rest ] bi ; inline
166 : peel-off-class ( slot-spec array -- slot-spec array )
169 [ first >>class ] [ rest ] bi
173 ERROR: bad-slot-attribute key ;
175 : peel-off-attributes ( slot-spec array -- slot-spec array )
178 { initial: [ [ first >>initial ] [ rest ] bi ] }
179 { read-only [ [ t >>read-only ] dip ] }
180 [ bad-slot-attribute ]
184 ERROR: bad-initial-value name ;
186 : check-initial-value ( slot-spec -- slot-spec )
189 dup [ initial>> ] [ class>> ] bi instance?
190 [ name>> bad-initial-value ] unless
193 dup class>> initial-value >>initial
201 [ dup empty? ] [ peel-off-attributes ] [ ] until drop
202 check-initial-value ;
204 M: slot-spec make-slot
205 check-initial-value ;
207 : make-slots ( slots -- specs )
210 : finalize-slots ( specs base -- specs )
211 over length [ + ] with map [ >>offset ] 2map ;
213 : slot-named ( name specs -- spec/f )
214 [ name>> = ] with find nip ;