fix codetest failure - trailing whitespace
[parrot.git] / src / pmc / packfileannotations.pmc
blob67210c333e2a7d76e5be31b8452f6271bc06074a
1 /*
2 Copyright (C) 2001-2008, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/packfileannotations.pmc - PackfileAnnotations PMC
9 =head1 DESCRIPTION
11 This class implements a PackfileAnnotations object, a segment of the .pbc data
12 file used for listing annotations.  It is a container for PackfileAnnotation
13 objects.
15 See packfile.pmc for the toplevel Packfile interface, see packfilesegment.pmc
16 for the list of common methods every packfile segment pmc must implement; see
17 PDD13 for the design spec.
19 To works properly PackfileAnnotations has to be added to PackfileDirectory with
20 PackfileConstantTable. Otherwise PackfileAnnotationKey can't be created.
22 =head2 Methods
24 =over 4
26 =cut
30 #include "pmc/pmc_packfileannotation.h"
32 pmclass PackfileAnnotations auto_attrs extends PackfileSegment {
33     /* ConstantTable used for names lookup */
34     ATTR PMC *const_table;
36     /* RPA of Annotation */
37     ATTR PMC *annotations;
41 =item C<void init()>
43 Initialize PackfileAnnotations.
45 =cut
48     VTABLE void init() {
49         Parrot_PackfileAnnotations_attributes * attrs =
50                 PMC_data_typed(SELF, Parrot_PackfileAnnotations_attributes*);
52         attrs->annotations = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
53         /*
54         Don't initialize C<const_table>. It will be set to NULL bu auto_attrs
55         handling. And should be set to proper PMC in set_directory.
56         */
58         PObj_custom_mark_SET(SELF);
59     }
63 =item C<void mark()>
65 Marks the object as live.
67 =cut
71     VTABLE void mark() {
72         Parrot_PackfileAnnotations_attributes * attrs =
73                 PARROT_PACKFILEANNOTATIONS(SELF);
75         Parrot_gc_mark_PMC_alive(interp, attrs->const_table);
76         Parrot_gc_mark_PMC_alive(interp, attrs->annotations);
78         SUPER();
79     }
84 =item C<INTVAL elements()>
86 Get the number of elements in the array.
88 =cut
91     VTABLE INTVAL elements() {
92         return VTABLE_elements(interp,
93                 PARROT_PACKFILEANNOTATIONS(SELF)->annotations);
94     }
99 =item C<PMC *get_pmc_keyed_int(INTVAL index)>
101 Fetch an annotation PMC from the array.
103 =cut
106     VTABLE PMC *get_pmc_keyed_int(INTVAL index)  {
107         return VTABLE_get_pmc_keyed_int(interp,
108                 PARROT_PACKFILEANNOTATIONS(SELF)->annotations, index);
109     }
114 =item C<void set_pmc_keyed_int(INTVAL index, PMC *annotation)>
116 Add an annotation to the array at the given offset.  An exception will be
117 thrown unless all of the following criteria are met:
119 =over 4
121 =item - The type of the PMC passed is PackfileAnnotation
123 =item - The entry at the previous index is defined
125 =item - The offset of the previous entry is less than this entry
127 =item - The offset of the next entry, if it exists, is greater than this entry
129 =item - The key ID references a valid annotation key
131 =back
133 =cut
136     VTABLE void set_pmc_keyed_int(INTVAL index, PMC *annotation)  {
137         Parrot_PackfileAnnotations_attributes * attrs =
138                 PARROT_PACKFILEANNOTATIONS(SELF);
139         Parrot_PackfileAnnotation_attributes  * entity_attrs =
140                 PARROT_PACKFILEANNOTATION(annotation);
141         INTVAL dummy;
143         /* TODO: add checks desribed above */
144         VTABLE_set_pmc_keyed_int(interp, attrs->annotations, index, annotation);
146         /* Add required constants */
147         Parrot_mmd_multi_dispatch_from_c_args(interp,
148             "get_or_create_constant", "PS->I", attrs->const_table,
149             entity_attrs->name, &dummy);
151         switch (entity_attrs->value_type) {
152             case PF_ANNOTATION_KEY_TYPE_STR:
153                 Parrot_mmd_multi_dispatch_from_c_args(interp,
154                     "get_or_create_constant", "PS->I", attrs->const_table,
155                     entity_attrs->str_value, &dummy);
156                 break;
158             case PF_ANNOTATION_KEY_TYPE_NUM:
159                 Parrot_mmd_multi_dispatch_from_c_args(interp,
160                     "get_or_create_constant", "PN->I", attrs->const_table,
161                     entity_attrs->num_value, &dummy);
162                 break;
164             default:
165                 /* Do nothing. If value_type if INT it will be stored directly */
166                 break;
167         }
168     }
172 =item C<void set_directory()>
174 Handle setting of ownership.
176 Find PackfileConstantTable in PackfileDirectory and pass it to
177 PackfileAnnotationKeys.
179 =cut
183     METHOD set_directory(PMC *directory) {
184         Parrot_PackfileAnnotations_attributes *attrs =
185                 PARROT_PACKFILEANNOTATIONS(SELF);
186         STRING *name;
187         PMC    *segment;
189         PMC *iter = VTABLE_get_iter(interp, directory);
190         while (VTABLE_get_bool(interp, iter)) {
191             name = VTABLE_shift_string(interp, iter);
192             segment = VTABLE_get_pmc_keyed_str(interp, directory, name);
193             if (VTABLE_isa(interp, segment,
194                     Parrot_str_new_constant(interp, "PackfileConstantTable"))) {
195                 attrs->const_table = segment;
196                 break;
197             }
198         }
199     }
203 =item C<void set_pointer(void *ptr)>
205 Initialize PackfileAnnotations from PackFile_Annotations*.
207 =cut
210     VTABLE void set_pointer(void *pointer) {
211         PackFile_Annotations * a = (PackFile_Annotations*)pointer;
212         Parrot_PackfileAnnotations_attributes *attrs =
213                 PARROT_PACKFILEANNOTATIONS(SELF);
214         opcode_t  i;
215         PMC      *annotation;
216         Parrot_PackfileAnnotation_attributes *annotation_attrs;
218         /* Copy annotations to own array */
219         VTABLE_set_integer_native(interp, attrs->annotations, a->num_entries);
220         for (i = 0; i < a->num_entries; ++i) {
221             PackFile_Annotations_Entry *entry = a->entries[i];
222             PackFile_Annotations_Key   *key   = a->keys[entry->key];
223             annotation = Parrot_pmc_new(interp, enum_class_PackfileAnnotation);
225             /* Poke directly to annotation attributes. */
226             annotation_attrs         = PARROT_PACKFILEANNOTATION(annotation);
227             annotation_attrs->offset = entry->bytecode_offset;
228             annotation_attrs->name   = VTABLE_get_string_keyed_int(interp,
229                     attrs->const_table, key->name);
230             switch (key->type) {
231                 case PF_ANNOTATION_KEY_TYPE_INT:
232                     VTABLE_set_integer_native(interp, annotation, entry->value);
233                     break;
234                 case PF_ANNOTATION_KEY_TYPE_STR:
235                     VTABLE_set_string_native(interp, annotation,
236                         VTABLE_get_string_keyed_int(interp, attrs->const_table, entry->value));
237                     break;
238                 case PF_ANNOTATION_KEY_TYPE_NUM:
239                     VTABLE_set_number_native(interp, annotation,
240                         VTABLE_get_number_keyed_int(interp, attrs->const_table, entry->value));
241                     break;
242                 default:
243                     Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_MALFORMED_PACKFILE,
244                             "Unknown value type %d in Packfile Annotation", key->type);
245             }
247             VTABLE_set_pmc_keyed_int(interp, attrs->annotations, i, annotation);
248         }
249     }
253 =item C<void *get_pointer()>
255 Create PackFile_Annotations* from self.
257 =cut
260     VTABLE void *get_pointer() {
261         Parrot_PackfileAnnotations_attributes *attrs =
262                 PARROT_PACKFILEANNOTATIONS(SELF);
263         PackFile_Annotations *res = mem_gc_allocate_zeroed_typed(INTERP,
264                 PackFile_Annotations);
265         INTVAL                i, num;
266         INTVAL                key_type;
267         PMC                  *keys;             /* Temporary representation of Keys */
268         PMC                  *names;            /* Constants for Key's names */
269         PMC                  *types;            /* Types of Keys */
270         INTVAL                key_id;
271         INTVAL                last_key_id;
272         INTVAL                name_id;
274         res->base.type = PF_ANNOTATIONS_SEG;
276         /*
277             Create keys. Hash will be created in next structure:
278             keys => {
279                 name => [
280                     $int_key_id,
281                     $str_key_id,
282                     $num_key_id,
283                 ]
284             }
286             Each key has name from ConstantTable. We store them in names Array.
287             names => [
288                 $constant_id_1,
289                 $contsant_id_2,
290                 ...
291             ]
292         */
293         keys        = Parrot_pmc_new(interp, enum_class_Hash);
294         names       = Parrot_pmc_new(interp, enum_class_ResizableIntegerArray);
295         types       = Parrot_pmc_new(interp, enum_class_ResizableIntegerArray);
296         last_key_id = -1;
298         /* Iterate over stored annotations and create Key if required. */
299         num = VTABLE_elements(interp, attrs->annotations);
300         res->num_entries = num;
301         res->entries = mem_gc_allocate_n_typed(INTERP, num, PackFile_Annotations_Entry*);
302         for (i = 0; i < num; ++i) {
303             PMC  *entity = VTABLE_get_pmc_keyed_int(interp, attrs->annotations, i);
304             Parrot_PackfileAnnotation_attributes *entity_attrs = PARROT_PACKFILEANNOTATION(entity);
306             /* Handle creating of Key */
307             PMC * key_array = VTABLE_get_pmc_keyed_str(interp, keys, entity_attrs->name);
308             if (PMC_IS_NULL(key_array)) {
309                 /* Never see this name before. Create new FIA and add to keys. */
310                 key_array = Parrot_pmc_new(interp, enum_class_FixedIntegerArray);
311                 VTABLE_set_integer_native(interp, key_array, 3);
312                 VTABLE_set_integer_keyed_int(interp, key_array, 0, -1);
313                 VTABLE_set_integer_keyed_int(interp, key_array, 1, -1);
314                 VTABLE_set_integer_keyed_int(interp, key_array, 2, -1);
316                 VTABLE_set_pmc_keyed_str(interp, keys, entity_attrs->name, key_array);
317             }
319             /* PackfileAnnotation.value_type exactly the same as key.type */
320             key_id = VTABLE_get_integer_keyed_int(interp, key_array, entity_attrs->value_type);
322             /* If key_id is -1 it means we have to create new key. */
323             if (key_id == -1) {
324                 key_id = ++last_key_id;
325                 VTABLE_set_integer_keyed_int(interp, key_array, entity_attrs->value_type, key_id);
327                 /* Store type */
328                 VTABLE_set_integer_keyed_int(interp, types, key_id, entity_attrs->value_type);
331                 /* Store constant for name. */
332                 Parrot_mmd_multi_dispatch_from_c_args(interp, "get_or_create_constant",
333                             "PS->I", attrs->const_table, entity_attrs->name, &name_id);
335                 VTABLE_set_integer_keyed_int(interp, names, key_id, name_id);
336             }
338             /* At this point we have create (if nesassary) key and name constant. */
339             /* Start storing real entity */
340             res->entries[i] = mem_gc_allocate_zeroed_typed(INTERP,
341                     PackFile_Annotations_Entry);
343             res->entries[i]->bytecode_offset = entity_attrs->offset;
344             res->entries[i]->key             = key_id;
346             /* Handle value */
347             switch (entity_attrs->value_type) {
348                 case PF_ANNOTATION_KEY_TYPE_INT:
349                     res->entries[i]->value = entity_attrs->int_value;
350                     break;
351                 case PF_ANNOTATION_KEY_TYPE_STR:
352                     Parrot_mmd_multi_dispatch_from_c_args(interp, "get_or_create_constant",
353                             "PS->I", attrs->const_table, entity_attrs->str_value,
354                             &res->entries[i]->value);
355                     break;
356                 case PF_ANNOTATION_KEY_TYPE_NUM:
357                     Parrot_mmd_multi_dispatch_from_c_args(interp, "get_or_create_constant",
358                             "PN->I", attrs->const_table, entity_attrs->num_value,
359                             &res->entries[i]->value);
360                     break;
361                 default:
362                     Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_MALFORMED_PACKFILE,
363                             "Unknown value type in PackfileAnnotation");
364             }
365         }
367         /* Time to pack keys */
368         num = VTABLE_elements(interp, types);
369         res->num_keys = num;
370         res->keys = mem_gc_allocate_n_zeroed_typed(INTERP, num,
371                 PackFile_Annotations_Key*);
372         for (i = 0; i < num; ++i) {
373             res->keys[i] = mem_gc_allocate_typed(INTERP, PackFile_Annotations_Key);
374             res->keys[i]->name = VTABLE_get_integer_keyed_int(interp, names, i);
375             res->keys[i]->type = VTABLE_get_integer_keyed_int(interp, types, i);
376         }
378         return res;
379     }
383 =item C<METHOD type()>
385 Get segment type.
387 =cut
391     METHOD type() {
392         RETURN(INTVAL PF_ANNOTATIONS_SEG);
393     }
399 =back
401 =cut
406  * Local variables:
407  *   c-file-style: "parrot"
408  * End:
409  * vim: expandtab shiftwidth=4:
410  */