fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / packfileannotations.pmc
blob5718bfcd22f7ae41d4302a5d2da231f48d4441e1
1 /*
2 Copyright (C) 2001-2010, 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 /* HEADERIZER HFILE: none */
33 /* HEADERIZER BEGIN: static */
34 /* HEADERIZER END: static */
36 pmclass PackfileAnnotations auto_attrs extends PackfileSegment {
37     /* ConstantTable used for names lookup */
38     ATTR PMC *const_table;
40     /* Annotations group: two RIA for a now */
41     ATTR PMC *gr_byte;
42     ATTR PMC *gr_entries;
43     /* RPA of Annotation */
44     ATTR PMC *annotations;
48 =item C<void init()>
50 Initialize PackfileAnnotations.
52 =cut
55     VTABLE void init() {
56         Parrot_PackfileAnnotations_attributes * attrs =
57                 PMC_data_typed(SELF, Parrot_PackfileAnnotations_attributes*);
59         attrs->annotations = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
60         /*
61         Don't initialize C<const_table>. It will be set to NULL bu auto_attrs
62         handling. And should be set to proper PMC in set_directory.
63         */
65         PObj_custom_mark_SET(SELF);
66     }
70 =item C<void mark()>
72 Marks the object as live.
74 =cut
78     VTABLE void mark() {
79         Parrot_PackfileAnnotations_attributes * attrs =
80                 PARROT_PACKFILEANNOTATIONS(SELF);
82         Parrot_gc_mark_PMC_alive(INTERP, attrs->const_table);
83         Parrot_gc_mark_PMC_alive(INTERP, attrs->gr_byte);
84         Parrot_gc_mark_PMC_alive(INTERP, attrs->gr_entries);
85         Parrot_gc_mark_PMC_alive(INTERP, attrs->annotations);
87         SUPER();
88     }
93 =item C<INTVAL elements()>
95 Get the number of elements in the array.
97 =cut
100     VTABLE INTVAL elements() {
101         return VTABLE_elements(INTERP,
102                 PARROT_PACKFILEANNOTATIONS(SELF)->annotations);
103     }
108 =item C<PMC *get_pmc_keyed_int(INTVAL index)>
110 Fetch an annotation PMC from the array.
112 =cut
115     VTABLE PMC *get_pmc_keyed_int(INTVAL index)  {
116         return VTABLE_get_pmc_keyed_int(INTERP,
117                 PARROT_PACKFILEANNOTATIONS(SELF)->annotations, index);
118     }
123 =item C<void set_pmc_keyed_int(INTVAL index, PMC *annotation)>
125 Add an annotation to the array at the given offset.  An exception will be
126 thrown unless all of the following criteria are met:
128 =over 4
130 =item - The type of the PMC passed is PackfileAnnotation
132 =item - The entry at the previous index is defined
134 =item - The offset of the previous entry is less than this entry
136 =item - The offset of the next entry, if it exists, is greater than this entry
138 =item - The key ID references a valid annotation key
140 =back
142 =cut
145     VTABLE void set_pmc_keyed_int(INTVAL index, PMC *annotation)  {
146         Parrot_PackfileAnnotations_attributes * attrs =
147                 PARROT_PACKFILEANNOTATIONS(SELF);
148         Parrot_PackfileAnnotation_attributes  * entity_attrs =
149                 PARROT_PACKFILEANNOTATION(annotation);
150         INTVAL dummy;
152         /* TODO: add checks desribed above */
153         VTABLE_set_pmc_keyed_int(INTERP, attrs->annotations, index, annotation);
155         /* Add required constants */
156         Parrot_mmd_multi_dispatch_from_c_args(INTERP,
157             "get_or_create_constant", "PS->I", attrs->const_table,
158             entity_attrs->name, &dummy);
160         switch (entity_attrs->value_type) {
161             case PF_ANNOTATION_KEY_TYPE_STR:
162                 Parrot_mmd_multi_dispatch_from_c_args(INTERP,
163                     "get_or_create_constant", "PS->I", attrs->const_table,
164                     entity_attrs->str_value, &dummy);
165                 break;
167             case PF_ANNOTATION_KEY_TYPE_NUM:
168                 Parrot_mmd_multi_dispatch_from_c_args(INTERP,
169                     "get_or_create_constant", "PN->I", attrs->const_table,
170                     entity_attrs->num_value, &dummy);
171                 break;
173             default:
174                 /* Do nothing. If value_type if INT it will be stored directly */
175                 break;
176         }
177     }
181 =item C<void set_directory()>
183 Handle setting of ownership.
185 Find PackfileConstantTable in PackfileDirectory and pass it to
186 PackfileAnnotationKeys.
188 =cut
192     METHOD set_directory(PMC *directory) {
193         Parrot_PackfileAnnotations_attributes *attrs =
194                 PARROT_PACKFILEANNOTATIONS(SELF);
195         STRING *name;
196         PMC    *segment;
198         PMC *iter = VTABLE_get_iter(INTERP, directory);
199         while (VTABLE_get_bool(INTERP, iter)) {
200             name = VTABLE_shift_string(INTERP, iter);
201             segment = VTABLE_get_pmc_keyed_str(INTERP, directory, name);
202             if (VTABLE_isa(INTERP, segment,
203                     Parrot_str_new_constant(INTERP, "PackfileConstantTable"))) {
204                 attrs->const_table = segment;
205                 break;
206             }
207         }
208     }
212 =item C<void set_pointer(void *ptr)>
214 Initialize PackfileAnnotations from PackFile_Annotations*.
216 =cut
219     VTABLE void set_pointer(void *pointer) {
220         PackFile_Annotations * a = (PackFile_Annotations*)pointer;
221         Parrot_PackfileAnnotations_attributes *attrs =
222                 PARROT_PACKFILEANNOTATIONS(SELF);
223         opcode_t  i;
224         PMC      *annotation;
225         Parrot_PackfileAnnotation_attributes *annotation_attrs;
227         /* Copy annotations groups */
228         if (a->num_groups > 0) {
229             attrs->gr_byte  = Parrot_pmc_new_init_int(INTERP,
230                     enum_class_ResizableIntegerArray, a->num_groups);
231             attrs->gr_entries = Parrot_pmc_new_init_int(INTERP,
232                     enum_class_ResizableIntegerArray, a->num_groups);
233             for (i = 0; i < a->num_groups; ++i) {
234                 VTABLE_set_integer_keyed_int(INTERP, attrs->gr_byte, i,
235                         a->groups[i].bytecode_offset);
236                 VTABLE_set_integer_keyed_int(INTERP, attrs->gr_entries, i,
237                         a->groups[i].entries_offset);
238             }
239         }
241         /* Copy annotations to own array */
242         VTABLE_set_integer_native(INTERP, attrs->annotations, a->num_entries);
243         for (i = 0; i < a->num_entries; ++i) {
244             PackFile_Annotations_Entry *entry = a->entries + i;
245             PackFile_Annotations_Key   *key   = a->keys + entry->key;
246             annotation = Parrot_pmc_new(INTERP, enum_class_PackfileAnnotation);
248             /* Poke directly to annotation attributes. */
249             annotation_attrs         = PARROT_PACKFILEANNOTATION(annotation);
250             annotation_attrs->offset = entry->bytecode_offset;
251             if (! attrs->const_table)
252                 Parrot_ex_throw_from_c_args(INTERP, NULL,
253                         EXCEPTION_MALFORMED_PACKFILE, "No constant table");
255             annotation_attrs->name   = VTABLE_get_string_keyed_int(INTERP,
256                     attrs->const_table, key->name);
257             switch (key->type) {
258                 case PF_ANNOTATION_KEY_TYPE_INT:
259                     VTABLE_set_integer_native(INTERP, annotation, entry->value);
260                     break;
261                 case PF_ANNOTATION_KEY_TYPE_STR:
262                     VTABLE_set_string_native(INTERP, annotation,
263                         VTABLE_get_string_keyed_int(INTERP, attrs->const_table, entry->value));
264                     break;
265                 case PF_ANNOTATION_KEY_TYPE_NUM:
266                     VTABLE_set_number_native(INTERP, annotation,
267                         VTABLE_get_number_keyed_int(INTERP, attrs->const_table, entry->value));
268                     break;
269                 default:
270                     Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_MALFORMED_PACKFILE,
271                             "Unknown value type %d in Packfile Annotation", key->type);
272             }
274             VTABLE_set_pmc_keyed_int(INTERP, attrs->annotations, i, annotation);
275         }
276     }
280 =item C<void *get_pointer()>
282 Create PackFile_Annotations* from self.
284 =cut
287     VTABLE void *get_pointer() {
288         Parrot_PackfileAnnotations_attributes *attrs =
289                 PARROT_PACKFILEANNOTATIONS(SELF);
290         PackFile_Annotations *res = mem_gc_allocate_zeroed_typed(INTERP,
291                 PackFile_Annotations);
292         INTVAL                i, num;
293         PMC                  *keys;             /* Temporary representation of Keys */
294         PMC                  *names;            /* Constants for Key's names */
295         PMC                  *types;            /* Types of Keys */
296         INTVAL                key_id;
297         INTVAL                last_key_id;
298         INTVAL                name_id;
300         res->base.type = PF_ANNOTATIONS_SEG;
302         /* Create annotations groups */
303         num = PMC_IS_NULL(attrs->gr_byte) ?
304             (INTVAL)0 : VTABLE_elements(INTERP, attrs->gr_byte);
305         res->num_groups = num;
306         if (num > 0) {
307             res->groups = mem_gc_allocate_n_zeroed_typed(interp,
308                     num, PackFile_Annotations_Group);
309             for (i = 0; i < num; ++i) {
310                 res->groups[i].bytecode_offset =
311                         VTABLE_get_integer_keyed_int(INTERP, attrs->gr_byte, i);
312                 res->groups[i].entries_offset =
313                         VTABLE_get_integer_keyed_int(INTERP, attrs->gr_entries, i);
314             }
315         }
317         /*
318             Create keys. Hash will be created in next structure:
319             keys => {
320                 name => [
321                     $int_key_id,
322                     $str_key_id,
323                     $num_key_id,
324                 ]
325             }
327             Each key has name from ConstantTable. We store them in names Array.
328             names => [
329                 $constant_id_1,
330                 $contsant_id_2,
331                 ...
332             ]
333         */
334         keys        = Parrot_pmc_new(INTERP, enum_class_Hash);
335         names       = Parrot_pmc_new(INTERP, enum_class_ResizableIntegerArray);
336         types       = Parrot_pmc_new(INTERP, enum_class_ResizableIntegerArray);
337         last_key_id = -1;
339         /* Iterate over stored annotations and create Key if required. */
340         num = VTABLE_elements(INTERP, attrs->annotations);
341         res->num_entries = num;
342         res->entries = mem_gc_allocate_n_typed(INTERP, num, PackFile_Annotations_Entry);
343         for (i = 0; i < num; ++i) {
344             PMC  * const entity = VTABLE_get_pmc_keyed_int(INTERP, attrs->annotations, i);
345             const Parrot_PackfileAnnotation_attributes * const entity_attrs =
346                 PARROT_PACKFILEANNOTATION(entity);
348             /* Handle creating of Key */
349             PMC * key_array = VTABLE_get_pmc_keyed_str(INTERP, keys, entity_attrs->name);
350             if (PMC_IS_NULL(key_array)) {
351                 /* Never see this name before. Create new FIA and add to keys. */
352                 key_array = Parrot_pmc_new_init_int(INTERP, enum_class_FixedIntegerArray, 3);
353                 VTABLE_set_integer_keyed_int(INTERP, key_array, 0, -1);
354                 VTABLE_set_integer_keyed_int(INTERP, key_array, 1, -1);
355                 VTABLE_set_integer_keyed_int(INTERP, key_array, 2, -1);
357                 VTABLE_set_pmc_keyed_str(INTERP, keys, entity_attrs->name, key_array);
358             }
360             /* PackfileAnnotation.value_type exactly the same as key.type */
361             key_id = VTABLE_get_integer_keyed_int(INTERP, key_array, entity_attrs->value_type);
363             /* If key_id is -1 it means we have to create new key. */
364             if (key_id == -1) {
365                 key_id = ++last_key_id;
366                 VTABLE_set_integer_keyed_int(INTERP, key_array, entity_attrs->value_type, key_id);
368                 /* Store type */
369                 VTABLE_set_integer_keyed_int(INTERP, types, key_id, entity_attrs->value_type);
372                 /* Store constant for name. */
373                 Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
374                             "PS->I", attrs->const_table, entity_attrs->name, &name_id);
376                 VTABLE_set_integer_keyed_int(INTERP, names, key_id, name_id);
377             }
379             /* At this point we have create (if nesassary) key and name constant. */
380             /* Start storing real entity */
382             res->entries[i].bytecode_offset = entity_attrs->offset;
383             res->entries[i].key             = key_id;
385             /* Handle value */
386             switch (entity_attrs->value_type) {
387                 case PF_ANNOTATION_KEY_TYPE_INT:
388                     res->entries[i].value = entity_attrs->int_value;
389                     break;
390                 case PF_ANNOTATION_KEY_TYPE_STR:
391                     Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
392                             "PS->I", attrs->const_table, entity_attrs->str_value,
393                             &res->entries[i].value);
394                     break;
395                 case PF_ANNOTATION_KEY_TYPE_NUM:
396                     Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
397                             "PN->I", attrs->const_table, entity_attrs->num_value,
398                             &res->entries[i].value);
399                     break;
400                 default:
401                     Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_MALFORMED_PACKFILE,
402                             "Unknown value type in PackfileAnnotation");
403             }
404         }
406         /* Time to pack keys */
407         num = VTABLE_elements(INTERP, types);
408         res->num_keys = num;
409         res->keys = mem_gc_allocate_n_zeroed_typed(INTERP, num,
410                 PackFile_Annotations_Key);
411         for (i = 0; i < num; ++i) {
412             res->keys[i].name = VTABLE_get_integer_keyed_int(INTERP, names, i);
413             res->keys[i].type = VTABLE_get_integer_keyed_int(INTERP, types, i);
414         }
416         return res;
417     }
421 =item C<METHOD type()>
423 Get segment type.
425 =cut
429     METHOD type() {
430         RETURN(INTVAL PF_ANNOTATIONS_SEG);
431     }
437 =back
439 =cut
444  * Local variables:
445  *   c-file-style: "parrot"
446  * End:
447  * vim: expandtab shiftwidth=4:
448  */