]> gitweb.factorcode.org Git - factor.git/blob - basis/classes/struct/struct.factor
dc7fa965db490b56598e0eba39cb84965dba7442
[factor.git] / basis / classes / struct / struct.factor
1 ! (c)Joe Groff bsd license
2 USING: accessors alien alien.c-types alien.structs
3 alien.structs.fields arrays byte-arrays classes classes.parser
4 classes.tuple classes.tuple.parser classes.tuple.private
5 combinators combinators.short-circuit combinators.smart
6 definitions functors.backend fry generalizations generic.parser
7 kernel kernel.private lexer libc locals macros make math math.order
8 parser quotations sequences slots slots.private struct-arrays vectors
9 words compiler.tree.propagation.transforms specialized-arrays.uchar ;
10 FROM: slots => reader-word writer-word ;
11 IN: classes.struct
12
13 ! struct class
14
15 ERROR: struct-must-have-slots ;
16
17 TUPLE: struct
18     { (underlying) c-ptr read-only } ;
19
20 TUPLE: struct-slot-spec < slot-spec
21     c-type ;
22
23 PREDICATE: struct-class < tuple-class \ struct subclass-of? ;
24
25 : struct-slots ( struct-class -- slots )
26     "struct-slots" word-prop ;
27
28 ! struct allocation
29
30 M: struct >c-ptr
31     2 slot { c-ptr } declare ; inline
32
33 M: struct equal?
34     {
35         [ [ class ] bi@ = ]
36         [ [ >c-ptr ] [ [ >c-ptr ] [ byte-length ] bi ] bi* memory= ]
37     } 2&& ; inline
38
39 M: struct hashcode*
40     [ >c-ptr ] [ byte-length ] bi <direct-uchar-array> hashcode* ; inline    
41
42 : struct-prototype ( class -- prototype ) "prototype" word-prop ; foldable
43
44 : memory>struct ( ptr class -- struct )
45     ! This is sub-optimal if the class is not literal, but gets
46     ! optimized down to efficient code if it is.
47     '[ _ boa ] call( ptr -- struct ) ; inline
48
49 <PRIVATE
50 : (init-struct) ( class with-prototype: ( prototype -- alien ) sans-prototype: ( class -- alien ) -- alien )
51     '[ dup struct-prototype _ _ ?if ] keep memory>struct ; inline
52 PRIVATE>
53
54 : (malloc-struct) ( class -- struct )
55     [ heap-size malloc ] keep memory>struct ; inline
56
57 : malloc-struct ( class -- struct )
58     [ >c-ptr malloc-byte-array ] [ 1 swap heap-size calloc ] (init-struct) ; inline
59
60 : (struct) ( class -- struct )
61     [ heap-size (byte-array) ] keep memory>struct ; inline
62
63 : <struct> ( class -- struct )
64     [ >c-ptr clone ] [ heap-size <byte-array> ] (init-struct) ; inline
65
66 MACRO: <struct-boa> ( class -- quot: ( ... -- struct ) )
67     [
68         [ <wrapper> \ (struct) [ ] 2sequence ]
69         [
70             struct-slots
71             [ length \ ndip ]
72             [ [ name>> setter-word 1quotation ] map \ spread ] bi
73         ] bi
74     ] [ ] output>sequence ;
75
76 <PRIVATE
77 : pad-struct-slots ( values class -- values' class )
78     [ struct-slots [ initial>> ] map over length tail append ] keep ;
79
80 : (reader-quot) ( slot -- quot )
81     [ c-type>> c-type-getter-boxer ]
82     [ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
83
84 : (writer-quot) ( slot -- quot )
85     [ c-type>> c-setter ]
86     [ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
87
88 : (boxer-quot) ( class -- quot )
89     '[ _ memory>struct ] ;
90
91 : (unboxer-quot) ( class -- quot )
92     drop [ >c-ptr ] ;
93 PRIVATE>
94
95 M: struct-class boa>object
96     swap pad-struct-slots
97     [ <struct> ] [ struct-slots ] bi 
98     [ [ (writer-quot) call( value struct -- ) ] with 2each ] curry keep ;
99
100 ! Struct slot accessors
101
102 GENERIC: struct-slot-values ( struct -- sequence )
103
104 M: struct-class reader-quot
105     nip (reader-quot) ;
106
107 M: struct-class writer-quot
108     nip (writer-quot) ;
109
110 ! c-types
111
112 <PRIVATE
113 : struct-slot-values-quot ( class -- quot )
114     struct-slots
115     [ name>> reader-word 1quotation ] map
116     \ cleave [ ] 2sequence
117     \ output>array [ ] 2sequence ;
118
119 : define-inline-method ( class generic quot -- )
120     [ create-method-in ] dip [ define ] [ drop make-inline ] 2bi ;
121
122 : (define-struct-slot-values-method) ( class -- )
123     [ \ struct-slot-values ] [ struct-slot-values-quot ] bi
124     define-inline-method ;
125
126 : clone-underlying ( struct -- byte-array )
127     [ >c-ptr ] [ byte-length ] bi memory>byte-array ; inline
128
129 : (define-clone-method) ( class -- )
130     [ \ clone ]
131     [ \ clone-underlying swap literalize \ memory>struct [ ] 3sequence ] bi
132     define-inline-method ;
133
134 : slot>field ( slot -- field )
135     field-spec new swap {
136         [ name>> >>name ]
137         [ offset>> >>offset ]
138         [ c-type>> >>type ]
139         [ name>> reader-word >>reader ]
140         [ name>> writer-word >>writer ]
141     } cleave ;
142
143 : define-struct-for-class ( class -- )
144     [
145         {
146             [ name>> ]
147             [ "struct-size" word-prop ]
148             [ "struct-align" word-prop ]
149             [ struct-slots [ slot>field ] map ]
150         } cleave
151         struct-type (define-struct)
152     ] [
153         {
154             [ name>> c-type ]
155             [ (unboxer-quot) >>unboxer-quot ]
156             [ (boxer-quot) >>boxer-quot ]
157             [ >>boxed-class ]
158         } cleave drop
159     ] bi ;
160
161 : align-offset ( offset class -- offset' )
162     c-type-align align ;
163
164 : struct-offsets ( slots -- size )
165     0 [
166         [ c-type>> align-offset ] keep
167         [ (>>offset) ] [ c-type>> heap-size + ] 2bi
168     ] reduce ;
169
170 : union-struct-offsets ( slots -- size )
171     [ 0 >>offset c-type>> heap-size ] [ max ] map-reduce ;
172
173 : struct-align ( slots -- align )
174     [ c-type>> c-type-align ] [ max ] map-reduce ;
175 PRIVATE>
176
177 M: struct-class c-type
178     name>> c-type ;
179
180 M: struct-class c-type-align
181     "struct-align" word-prop ;
182
183 M: struct-class c-type-getter
184     drop [ swap <displaced-alien> ] ;
185
186 M: struct-class c-type-setter
187     [ c-type-getter ] [ c-type-unboxer-quot ] [ heap-size ] tri
188     '[ @ swap @ _ memcpy ] ;
189
190 M: struct-class c-type-boxer-quot
191     (boxer-quot) ;
192
193 M: struct-class c-type-unboxer-quot
194     (unboxer-quot) ;
195
196 M: struct-class heap-size
197     "struct-size" word-prop ;
198
199 M: struct byte-length
200     class "struct-size" word-prop ; foldable
201
202 ! class definition
203
204 <PRIVATE
205 : make-struct-prototype ( class -- prototype )
206     [ heap-size <byte-array> ]
207     [ memory>struct ]
208     [ struct-slots ] tri
209     [
210         [ initial>> ]
211         [ (writer-quot) ] bi
212         over [ swapd [ call( value struct -- ) ] curry keep ] [ 2drop ] if
213     ] each ;
214
215 : (struct-methods) ( class -- )
216     [ (define-struct-slot-values-method) ]
217     [ (define-clone-method) ]
218     bi ;
219
220 : (struct-word-props) ( class slots size align -- )
221     [
222         [ "struct-slots" set-word-prop ]
223         [ define-accessors ] 2bi
224     ]
225     [ "struct-size" set-word-prop ]
226     [ "struct-align" set-word-prop ] tri-curry*
227     [ tri ] 3curry
228     [ dup make-struct-prototype "prototype" set-word-prop ]
229     [ (struct-methods) ] tri ;
230
231 : check-struct-slots ( slots -- )
232     [ c-type>> c-type drop ] each ;
233
234 : redefine-struct-tuple-class ( class -- )
235     [ dup class? [ forget-class ] [ drop ] if ] [ struct f define-tuple-class ] bi ;
236
237 : (define-struct-class) ( class slots offsets-quot -- )
238     [ 
239         [ struct-must-have-slots ]
240         [ drop redefine-struct-tuple-class ] if-empty
241     ]
242     swap '[
243         make-slots dup
244         [ check-struct-slots ] _ [ struct-align [ align ] keep ] tri
245         (struct-word-props)
246     ]
247     [ drop define-struct-for-class ] 2tri ; inline
248 PRIVATE>
249
250 : define-struct-class ( class slots -- )
251     [ struct-offsets ] (define-struct-class) ;
252
253 : define-union-struct-class ( class slots -- )
254     [ union-struct-offsets ] (define-struct-class) ;
255
256 ERROR: invalid-struct-slot token ;
257
258 : struct-slot-class ( c-type -- class' )
259     c-type c-type-boxed-class
260     dup \ byte-array = [ drop \ c-ptr ] when ;
261
262 : <struct-slot-spec> ( name c-type attributes -- slot-spec )
263     [ struct-slot-spec new ] 3dip
264     [ >>name ]
265     [ [ >>c-type ] [ struct-slot-class >>class ] bi ]
266     [ [ dup empty? ] [ peel-off-attributes ] until drop ] tri* ;
267
268 <PRIVATE
269 : scan-c-type ( -- c-type )
270     scan dup "{" = [ drop \ } parse-until >array ] when ;
271
272 : parse-struct-slot ( -- slot )
273     scan scan-c-type \ } parse-until <struct-slot-spec> ;
274     
275 : parse-struct-slots ( slots -- slots' more? )
276     scan {
277         { ";" [ f ] }
278         { "{" [ parse-struct-slot over push t ] }
279         [ invalid-struct-slot ]
280     } case ;
281
282 : parse-struct-definition ( -- class slots )
283     CREATE-CLASS 8 <vector> [ parse-struct-slots ] [ ] while >array ;
284 PRIVATE>
285
286 SYNTAX: STRUCT:
287     parse-struct-definition define-struct-class ;
288 SYNTAX: UNION-STRUCT:
289     parse-struct-definition define-union-struct-class ;
290
291 SYNTAX: S{
292     scan-word dup struct-slots parse-tuple-literal-slots parsed ;
293
294 SYNTAX: S@
295     scan-word scan-object swap memory>struct parsed ;
296
297 ! functor support
298
299 <PRIVATE
300 : scan-c-type` ( -- c-type/param )
301     scan dup "{" = [ drop \ } parse-until >array ] [ >string-param ] if ;
302
303 : parse-struct-slot` ( accum -- accum )
304     scan-string-param scan-c-type` \ } parse-until
305     [ <struct-slot-spec> over push ] 3curry over push-all ;
306
307 : parse-struct-slots` ( accum -- accum more? )
308     scan {
309         { ";" [ f ] }
310         { "{" [ parse-struct-slot` t ] }
311         [ invalid-struct-slot ]
312     } case ;
313 PRIVATE>
314
315 FUNCTOR-SYNTAX: STRUCT:
316     scan-param parsed
317     [ 8 <vector> ] over push-all
318     [ parse-struct-slots` ] [ ] while
319     [ >array define-struct-class ] over push-all ;
320
321 USING: vocabs vocabs.loader ;
322
323 "prettyprint" vocab [ "classes.struct.prettyprint" require ] when