1 /****************************************************************************
2 * Copyright (C) 2012 by Matteo Franchin *
3 * *
4 * This file is part of Box. *
5 * *
6 * Box is free software: you can redistribute it and/or modify it *
7 * under the terms of the GNU Lesser General Public License as published *
8 * by the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * Box is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU Lesser General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with Box. If not, see <http://www.gnu.org/licenses/>. *
18 ****************************************************************************/
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stddef.h>
24
25 #include <box/types.h>
26 #include <box/messages.h>
27 #include <box/mem.h>
28 #include <box/obj.h>
29 #include <box/callable.h>
30
31 #include <box/types_priv.h>
32 #include <box/core_priv.h>
33 #include <box/callable_priv.h>
34
35
36 /* Generic allocation function for BoxType objects. This function allocates a
37 * type header plus the type data, whose size and composition depend on the
38 * particular type class.
39 */
BoxType_Alloc(BoxType ** t,BoxTypeClass tc)40 void *BoxType_Alloc(BoxType **t, BoxTypeClass tc) {
41 size_t additional = 0, total;
42 size_t data_offset = offsetof(BoxTypeBundle, data);
43 BoxType *tt, *td;
44
45 switch (tc) {
46 case BOXTYPECLASS_STRUCTURE_NODE:
47 additional = sizeof(BoxTypeStructureNode); break;
48 case BOXTYPECLASS_SPECIES_NODE:
49 additional = sizeof(BoxTypeSpeciesNode); break;
50 case BOXTYPECLASS_COMB_NODE:
51 additional = sizeof(BoxTypeCombNode); break;
52 case BOXTYPECLASS_SUBTYPE_NODE:
53 additional = sizeof(BoxTypeSubtypeNode); break;
54 case BOXTYPECLASS_PRIMARY: additional = sizeof(BoxTypePrimary); break;
55 case BOXTYPECLASS_INTRINSIC: additional = sizeof(BoxTypeIntrinsic); break;
56 case BOXTYPECLASS_IDENT: additional = sizeof(BoxTypeIdent); break;
57 case BOXTYPECLASS_RAISED: additional = sizeof(BoxTypeRaised); break;
58 case BOXTYPECLASS_STRUCTURE: additional = sizeof(BoxTypeStructure); break;
59 case BOXTYPECLASS_SPECIES: additional = sizeof(BoxTypeSpecies); break;
60 case BOXTYPECLASS_FUNCTION: additional = sizeof(BoxTypeFunction); break;
61 case BOXTYPECLASS_POINTER: additional = sizeof(BoxTypePointer); break;
62 case BOXTYPECLASS_ANY: additional = sizeof(BoxTypeAny); break;
63 default:
64 MSG_FATAL("Unknown type class in BoxType_Alloc");
65 return NULL;
66 }
67
68 total = data_offset + additional;
69 tt = Box_Get_Core_Type(BOXTYPEID_TYPE);
70 td = BoxSPtr_Raw_Alloc(tt, total);
71 if (!td)
72 MSG_FATAL("Cannot allocate memory for type object.");
73
74 td->type_class = tc;
75 *t = td;
76 return & ((BoxTypeBundle *) td)->data;
77 }
78
79 /* Get the type class of a given type. The type class is effectively the
80 * type of type (the answer to whether the type is a struct, a species, etc.)
81 */
BoxType_Get_Class(BoxType * type)82 BoxTypeClass BoxType_Get_Class(BoxType *type) {
83 return type->type_class;
84 }
85
86 /* Get the data part of a type. The size and composition of the data type of
87 * a given type changes depending on the type class.
88 */
BoxType_Get_Data(BoxType * t)89 void *BoxType_Get_Data(BoxType *t) {
90 return & ((BoxTypeBundle *) t)->data;
91 }
92
93 /**
94 * Return the BoxTypeNode object associated to a node type or NULL, if the
95 * given type is not a node type.
96 */
My_Type_Get_Node(BoxType * t)97 BoxTypeNode *My_Type_Get_Node(BoxType *t) {
98 void *td = BoxType_Get_Data(t);
99 switch (t->type_class) {
100 case BOXTYPECLASS_SPECIES_NODE:
101 return & ((BoxTypeSpeciesNode *) td)->node;
102 case BOXTYPECLASS_STRUCTURE_NODE:
103 return & ((BoxTypeStructureNode *) td)->node;
104 case BOXTYPECLASS_COMB_NODE: return & ((BoxTypeCombNode *) td)->node;
105 case BOXTYPECLASS_SUBTYPE_NODE: return & ((BoxTypeSubtypeNode *) td)->node;
106 case BOXTYPECLASS_STRUCTURE: return & ((BoxTypeStructure *) td)->node;
107 case BOXTYPECLASS_SPECIES: return & ((BoxTypeSpecies *) td)->node;
108 default: return NULL;
109 }
110 }
111
112 /**
113 * @brief Get the allocated objects a given type refers to.
114 *
115 * This function returns the number of types (in *num_refs) and the number of
116 * allocations (in *num_mems) associated to the given type. The function does
117 * also write the actual references and pointers to the allocated regions
118 * in the two provided arrays. This function is internal and allows to
119 * traverse the type tree easily. It is used, for example, to deallocate all
120 * the resources associated to a given type in BoxType_Unlink.
121 * @param t The type.
122 * @param num_refs Pointer where the number of references made by the provided
123 * type makes be written (the number of references never exceeds the constant
124 * #BOX_MAX_NUM_REFS_IN_TYPE.
125 * @param refs Location where to write the references. This is an array of
126 * #BoxSPtr objects which should be able to contain at least
127 * #BOX_MAX_NUM_REFS_IN_TYPE elements.
128 * @param num_mems Pointer where the number of allocations made by the provided
129 * type should be written (the number of references never exceeds
130 * the constant #BOX_MAX_NUM_MEMS_IN_TYPE.
131 * @param mems Location where to write the pointers to the allocated blocks.
132 * This is an array of pointers which should be able to contain at least
133 * #BOX_MAX_NUM_MEMS_IN_TYPE elements.
134 *
135 * Example:
136 * @code
137 * void *mems[BOX_MAX_NUM_MEMS_IN_TYPE];
138 * BoxType *refs[BOX_MAX_NUM_REFS_IN_TYPE];
139 * int num_refs, num_mems;
140 * My_Type_Get_Refs(type, & num_refs, refs, & num_mems, mems);
141 * @endcode
142 */
My_Type_Get_Refs(BoxType * t,int * num_refs,BoxSPtr * refs,int * num_mems,void ** mems)143 static void My_Type_Get_Refs(BoxType *t, int *num_refs, BoxSPtr *refs,
144 int *num_mems, void **mems) {
145 void *tdata = BoxType_Get_Data(t);
146
147 *num_refs = 0;
148 *num_mems = 0;
149
150 switch (t->type_class) {
151 case BOXTYPECLASS_NONE:
152 break;
153 case BOXTYPECLASS_STRUCTURE_NODE:
154 refs[0] = ((BoxTypeStructureNode *) tdata)->node.next;
155 refs[1] = ((BoxTypeStructureNode *) tdata)->type;
156 *num_refs = 2;
157 /* NOTE: we do not own the reference to `previous'. */
158 mems[0] = ((BoxTypeStructureNode *) tdata)->name;
159 *num_mems = 1;
160 return;
161 case BOXTYPECLASS_SPECIES_NODE:
162 refs[0] = ((BoxTypeSpeciesNode *) tdata)->node.next;
163 refs[1] = ((BoxTypeSpeciesNode *) tdata)->type;
164 *num_refs = 2;
165 return;
166 case BOXTYPECLASS_COMB_NODE:
167 refs[0] = ((BoxTypeCombNode *) tdata)->node.next;
168 refs[1] = ((BoxTypeCombNode *) tdata)->child;
169 refs[2] = ((BoxTypeCombNode *) tdata)->callable;
170 *num_refs = 3;
171 return;
172 case BOXTYPECLASS_SUBTYPE_NODE:
173 refs[0] = ((BoxTypeSubtypeNode *) tdata)->node.next;
174 refs[1] = ((BoxTypeSubtypeNode *) tdata)->type;
175 *num_refs = 2;
176 mems[0] = ((BoxTypeSubtypeNode *) tdata)->name;
177 *num_mems = 1;
178 return;
179 case BOXTYPECLASS_PRIMARY:
180 case BOXTYPECLASS_INTRINSIC:
181 return;
182 case BOXTYPECLASS_IDENT:
183 refs[0] = ((BoxTypeIdent *) tdata)->source;
184 refs[1] = ((BoxTypeIdent *) tdata)->combs.node.next;
185 refs[2] = ((BoxTypeIdent *) tdata)->subtypes.node.next;
186 *num_refs = 3;
187 mems[0] = ((BoxTypeIdent *) tdata)->name;
188 *num_mems = 1;
189 return;
190 case BOXTYPECLASS_RAISED:
191 refs[0] = ((BoxTypeRaised *) tdata)->source;
192 *num_refs = 1;
193 return;
194 case BOXTYPECLASS_STRUCTURE:
195 refs[0] = ((BoxTypeStructure *) tdata)->node.next;
196 *num_refs = 1;
197 /* NOTE: we do not own the reference to `previous'. */
198 return;
199 case BOXTYPECLASS_SPECIES:
200 refs[0] = ((BoxTypeSpecies *) tdata)->node.next;
201 *num_refs = 1;
202 /* NOTE: we do not own the reference to `previous'. */
203 return;
204 case BOXTYPECLASS_FUNCTION:
205 refs[0] = ((BoxTypeFunction *) tdata)->child;
206 refs[1] = ((BoxTypeFunction *) tdata)->parent;
207 *num_refs = 2;
208 return;
209 case BOXTYPECLASS_POINTER:
210 refs[0] = ((BoxTypePointer *) tdata)->source;
211 *num_refs = 1;
212 return;
213 case BOXTYPECLASS_ANY:
214 *num_refs = 0;
215 return;
216 default:
217 abort();
218 }
219 }
220
221 /* Finalization function for type objects. */
My_Type_Finish(BoxPtr * parent)222 static BoxException *My_Type_Finish(BoxPtr *parent) {
223 void *mems[BOX_MAX_NUM_MEMS_IN_TYPE];
224 BoxSPtr refs[BOX_MAX_NUM_REFS_IN_TYPE];
225 int num_refs, num_mems, i;
226
227 BoxType *t = BoxPtr_Get_Target(parent);
228 My_Type_Get_Refs(t, & num_refs, refs, & num_mems, mems);
229
230 for (i = 0; i < num_mems; i++)
231 Box_Mem_Free(mems[i]);
232
233 for (i = 0; i < num_refs; i++)
234 BoxSPtr_Unlink(refs[i]);
235
236 return NULL;
237 }
238
239 /* Register initialization and finalization for types. */
Box_Register_Type_Combs(BoxCoreTypes * ct)240 BoxBool Box_Register_Type_Combs(BoxCoreTypes *ct) {
241 BoxType
242 *type_type = BoxCoreTypes_Get_Type(ct, BOXTYPEID_TYPE),
243 *finish_type = BoxCoreTypes_Get_Type(ct, BOXTYPEID_FINISH);
244
245 BoxCallable *callable =
246 BoxCallable_Create_Undefined(type_type, finish_type);
247 callable = BoxCallable_Define_From_CCall1(callable, My_Type_Finish);
248 if (!callable)
249 return BOXBOOL_FALSE;
250
251 if (BoxType_Define_Combination(type_type, BOXCOMBTYPE_AT,
252 finish_type, callable))
253 return BOXBOOL_TRUE;
254
255 BoxSPtr_Unlink(callable);
256 return BOXBOOL_FALSE;
257 }
258
259 /* Append one BoxTypeNode item to a top BoxTypeNode item. This is used in
260 * structures, enums, etc. to add members.
261 */
BoxTypeNode_Append_Node(BoxTypeNode * top_node,BoxType * item)262 void BoxTypeNode_Append_Node(BoxTypeNode *top_node, BoxType *item) {
263 BoxTypeNode *item_node = My_Type_Get_Node(item);
264 assert(top_node && item_node);
265
266 /* Adjust the links. */
267 item_node->previous = top_node->previous;
268 item_node->next = NULL;
269
270 /* Adjust the tail. */
271 if (top_node->previous != NULL) {
272 BoxTypeNode *previous_node = My_Type_Get_Node(top_node->previous);
273 assert(previous_node);
274 previous_node->next = item;
275 }
276
277 /* Adjust the top node. */
278 if (top_node->next == NULL)
279 top_node->next = item;
280 top_node->previous = item;
281 }
282
283 /* Prepend one BoxTypeNode item to a top BoxTypeNode item. This is similar
284 * to BoxTypeNode_Append_Node, but the item is inserted at the other end of
285 * the linked list.
286 */
BoxTypeNode_Prepend_Node(BoxTypeNode * top_node,BoxType * item)287 void BoxTypeNode_Prepend_Node(BoxTypeNode *top_node, BoxType *item) {
288 BoxTypeNode *item_node = My_Type_Get_Node(item);
289 assert(top_node && item_node);
290
291 /* Adjust the links. */
292 item_node->previous = NULL;
293 item_node->next = top_node->next;
294
295 /* Adjust the head. */
296 if (top_node->next != NULL) {
297 BoxTypeNode *next_node = My_Type_Get_Node(top_node->next);
298 assert(next_node);
299 next_node->previous = item;
300 }
301
302 /* Adjust the top node. */
303 if (top_node->previous == NULL)
304 top_node->previous = item;
305 top_node->next = item;
306 }
307
308 /* Remove a BoxTypeNode from a top BoxTypeNode item. This is kind-of the
309 * inverse of BoxTypeNode_Prepend_Node().
310 */
311 BoxTypeNode *
BoxTypeNode_Remove_Node(BoxTypeNode * top_node,BoxType * this)312 BoxTypeNode_Remove_Node(BoxTypeNode *top_node, BoxType *this) {
313 BoxTypeNode *this_node = My_Type_Get_Node(this);
314 assert(top_node && this_node);
315
316 if (this_node->next) {
317 /* This node is not the last: it has a next node. */
318 BoxTypeNode *next_node = My_Type_Get_Node(this_node->next);
319 assert(next_node);
320 next_node->previous = this_node->previous;
321
322 } else {
323 /* This node is the last of the chain: update the top node. */
324 assert(top_node->previous == this);
325 top_node->previous = this_node->previous;
326 }
327
328 if (this_node->previous) {
329 /* This node is not the first: it has a previous node. */
330 BoxTypeNode *previous_node = My_Type_Get_Node(this_node->previous);
331 assert(previous_node);
332 previous_node->next = this_node->next;
333
334 } else {
335 /* This node is the first in the chain: update the top node. */
336 assert(top_node->next == this);
337 top_node->next = this_node->next;
338 }
339
340 this_node->previous = this_node->next = NULL;
341 return this_node;
342 }
343
344 /* Create a new primary type with the given id, size and alignment. */
BoxType_Create_Primary(BoxTypeId id,size_t size,size_t alignment)345 BoxType *BoxType_Create_Primary(BoxTypeId id, size_t size, size_t alignment) {
346 BoxType *t;
347 BoxTypePrimary *td = BoxType_Alloc(& t, BOXTYPECLASS_PRIMARY);
348 td->id = id;
349 td->size = size;
350 td->alignment = alignment;
351 return t;
352 }
353
354 /* Create a new intrinsic type with the given size and alignment. */
BoxType_Create_Intrinsic(size_t size,size_t alignment)355 BoxType *BoxType_Create_Intrinsic(size_t size, size_t alignment) {
356 BoxType *t;
357 BoxTypeIntrinsic *ti = BoxType_Alloc(& t, BOXTYPECLASS_INTRINSIC);
358 ti->size = size;
359 ti->alignment = alignment;
360 return t;
361 }
362
363 /* Create a new identifier type. */
364 BOXOUT BoxType *
BoxType_Create_Ident(BOXIN BoxType * source,const char * name)365 BoxType_Create_Ident(BOXIN BoxType *source, const char *name) {
366 BoxType *t;
367 BoxTypeIdent *ta = BoxType_Alloc(& t, BOXTYPECLASS_IDENT);
368 ta->name = Box_Mem_Strdup(name);
369 ta->source = source;
370 ta->subtypes.node.next = NULL;
371 ta->subtypes.node.previous = NULL;
372 BoxCombs_Init(& ta->combs);
373 return t;
374 }
375
376 /* Add a child type to the namespace of a parent type. */
BoxType_Add_Type(BoxType * parent,BoxType * child)377 void BoxType_Add_Type(BoxType *parent, BoxType *child) {
378 }
379
380 /* Create a new raised type. */
BoxType_Create_Raised(BOXIN BoxType * source)381 BoxType *BoxType_Create_Raised(BOXIN BoxType *source) {
382 BoxType *t;
383 BoxTypeRaised *td = BoxType_Alloc(& t, BOXTYPECLASS_RAISED);
384 td->source = source;
385 return t;
386 }
387
388 /* Get the target type of a raised type. */
BoxType_Unraise(BoxType * raised)389 BoxType *BoxType_Unraise(BoxType *raised) {
390 if (raised->type_class == BOXTYPECLASS_RAISED) {
391 BoxTypeRaised *td = BoxType_Get_Data(raised);
392 return td->source;
393 }
394 return NULL;
395 }
396
397 /* Create a new structure type. */
BoxType_Create_Structure(void)398 BoxType *BoxType_Create_Structure(void) {
399 BoxType *t;
400 BoxTypeStructure *td = BoxType_Alloc(& t, BOXTYPECLASS_STRUCTURE);
401 td->size = 0;
402 td->alignment = 0;
403 td->num_items = 0;
404 td->node.next = NULL;
405 td->node.previous = NULL;
406 return t;
407 }
408
409 /* Add a member to a structure type defined with BoxType_Create_Structure. */
BoxType_Add_Member_To_Structure(BoxType * structure,BoxType * member,const char * member_name)410 void BoxType_Add_Member_To_Structure(BoxType *structure, BoxType *member,
411 const char *member_name) {
412 BoxType *t;
413 size_t msize, malgn, ssize;
414 BoxTypeStructureNode *td;
415 BoxTypeStructure *std = BoxType_Get_Data(structure);
416 char *dup_member_name = (member_name ? Box_Mem_Strdup(member_name) : NULL);
417
418 if (structure->type_class != BOXTYPECLASS_STRUCTURE)
419 MSG_FATAL("Attempted to add a member to a non structure");
420
421 /* Box_Mem_Strdup failed. */
422 if (member_name && !dup_member_name)
423 MSG_FATAL("Cannot allocate memory for structure member type object.");
424
425 /* Let's get the size and alignment of the member type. */
426 if (!BoxType_Get_Size_And_Alignment(member, & msize, & malgn))
427 MSG_FATAL("Cannot get size and alignment of structure member type");
428
429 /* Need to do this small computation to retrieve the structure size without
430 * padding (as std->size is the actual structure size, with padding).
431 */
432 ssize = 0;
433 if (std->node.previous != NULL) {
434 BoxTypeStructureNode *ptd = BoxType_Get_Data(std->node.previous);
435 ssize = ptd->offset + ptd->size;
436 }
437
438 /* Now create the member. */
439 td = BoxType_Alloc(& t, BOXTYPECLASS_STRUCTURE_NODE);
440 td->name = dup_member_name;
441 td->size = msize;
442 td->offset = Box_Mem_Align_Offset(ssize, malgn);
443 td->type = BoxType_Link(member);
444
445 /* Add the member to the structure. */
446 std->num_items++;
447
448 /* Alignment is the maximum of the alignments of the members. */
449 if (malgn > std->alignment)
450 std->alignment = malgn;
451
452 std->size = Box_Mem_Get_Multiple_Size(td->offset + msize, std->alignment);
453 BoxTypeNode_Append_Node(& std->node, t);
454 }
455
456 /* Get information on a structure member as obtained from
457 * BoxTypeIter_Get_Next.
458 */
459 BoxBool
BoxType_Get_Structure_Member(BoxType * node,char ** name,size_t * offset,size_t * size,BoxType ** type)460 BoxType_Get_Structure_Member(BoxType *node, char **name, size_t *offset,
461 size_t *size, BoxType **type) {
462 if (node->type_class == BOXTYPECLASS_STRUCTURE_NODE) {
463 BoxTypeStructureNode *sn = BoxType_Get_Data(node);
464
465 if (name)
466 *name = sn->name;
467 if (offset)
468 *offset = sn->offset;
469 if (size)
470 *size = sn->size;
471 if (type)
472 *type = sn->type;
473
474 return BOXBOOL_TRUE;
475
476 } else
477 return BOXBOOL_FALSE;
478 }
479
480 /* Get the type of a structure member obtained from BoxTypeIter_Get_Next. */
BoxType_Get_Structure_Member_Type(BoxType * node)481 BoxType *BoxType_Get_Structure_Member_Type(BoxType *node) {
482 BoxType *t;
483
484 if (BoxType_Get_Structure_Member(node, NULL, NULL, NULL, & t))
485 return t;
486
487 return NULL;
488 }
489
490 /* Get the type of a species member as obtained from BoxTypeIter_Get_Next. */
BoxType_Find_Structure_Member(BoxType * s,const char * name)491 BoxType *BoxType_Find_Structure_Member(BoxType *s, const char *name) {
492 BoxTypeIter ti;
493 BoxType *t;
494 char *member_name = NULL;
495
496 for (BoxTypeIter_Init(& ti, s); BoxTypeIter_Get_Next(& ti, & t);) {
497 BoxType_Get_Structure_Member(t, & member_name, NULL, NULL, NULL);
498 if (strcmp(name, member_name) == 0) {
499 BoxTypeIter_Finish(& ti);
500 return t;
501 }
502 }
503
504 BoxTypeIter_Finish(& ti);
505 return NULL;
506 }
507
508 /* Get the number of members of a structure. */
BoxType_Get_Structure_Num_Members(BoxType * t)509 size_t BoxType_Get_Structure_Num_Members(BoxType *t) {
510 if (t->type_class == BOXTYPECLASS_STRUCTURE) {
511 BoxTypeStructure *s = BoxType_Get_Data(t);
512 return s->num_items;
513
514 } else
515 return 0;
516 }
517
518 /* Create a new species type. */
BoxType_Create_Species(void)519 BOXOUT BoxType *BoxType_Create_Species(void) {
520 BoxType *t;
521 BoxTypeSpecies *td = BoxType_Alloc(& t, BOXTYPECLASS_SPECIES);
522 td->num_items = 0;
523 td->node.next = NULL;
524 td->node.previous = NULL;
525 return t;
526 }
527
528 /* Add a member to a species type defined with BoxType_Create_Species. */
BoxType_Add_Member_To_Species(BoxType * species,BoxType * member)529 void BoxType_Add_Member_To_Species(BoxType *species, BoxType *member) {
530 BoxType *t;
531 BoxTypeSpecies *std = BoxType_Get_Data(species);
532 BoxTypeSpeciesNode *td;
533
534 /* Now create the member. */
535 td = BoxType_Alloc(& t, BOXTYPECLASS_SPECIES_NODE);
536 td->type = BoxType_Link(member);
537
538 /* Add the member to the structure. */
539 std->num_items++;
540
541 BoxTypeNode_Append_Node(My_Type_Get_Node(species), t);
542 }
543
544 /* Get information on a species member as obtained from BoxTypeIter_Get_Next.
545 */
BoxType_Get_Species_Member_Type(BoxType * node)546 BoxType *BoxType_Get_Species_Member_Type(BoxType *node) {
547 if (node->type_class == BOXTYPECLASS_SPECIES_NODE) {
548 BoxTypeSpeciesNode *sn = BoxType_Get_Data(node);
549 return sn->type;
550 }
551
552 return NULL;
553 }
554
555 /* Get the target type of a species. */
BoxType_Get_Species_Target(BoxType * species)556 BoxType *BoxType_Get_Species_Target(BoxType *species) {
557 return BoxType_Resolve(species, BOXTYPERESOLVE_SPECIES, 1);
558 }
559
560 /* Create a new function type. */
561 BOXOUT BoxType *
BoxType_Create_Callable(BoxType * parent,BoxType * child)562 BoxType_Create_Callable(BoxType *parent, BoxType *child) {
563 BoxType *t;
564 BoxTypeFunction *td = BoxType_Alloc(& t, BOXTYPECLASS_FUNCTION);
565 /* A function ``Fn = In -> Out'' does only weak-reference ``In'' and ``Out''.
566 * This is fine as - in order to use the function - one object of type ``In''
567 * and one object of type ``Out'' must exist already. The only case where
568 * we may have problems is the case where the user extracts the types from
569 * ``Fn''. We then do not provide any function to allow the user to do this.
570 * Later, when a proper GC will have been implemented, we can change this is
571 * necessary.
572 */
573 td->child = BoxType_Link(child);
574 td->parent = BoxType_Link(parent);
575 return t;
576 }
577
578 /* Get the parent of a callable type. */
579 BoxType *
BoxType_Get_Callable_Parent(BoxType * callable)580 BoxType_Get_Callable_Parent(BoxType *callable) {
581 if (callable && callable->type_class == BOXTYPECLASS_FUNCTION) {
582 BoxTypeFunction *td = BoxType_Get_Data(callable);
583 return td->parent;
584 }
585 return NULL;
586 }
587
588 /* Get the child of a callable type. */
589 BoxType *
BoxType_Get_Callable_Child(BoxType * callable)590 BoxType_Get_Callable_Child(BoxType *callable) {
591 if (callable && callable->type_class == BOXTYPECLASS_FUNCTION) {
592 BoxTypeFunction *td = BoxType_Get_Data(callable);
593 return td->child;
594 }
595 return NULL;
596 }
597
598 /* Create a new pointer type. */
BoxType_Create_Pointer(BoxType * source)599 BoxType *BoxType_Create_Pointer(BoxType *source) {
600 BoxType *t;
601 BoxTypePointer *td = BoxType_Alloc(& t, BOXTYPECLASS_POINTER);
602 td->source = source;
603 return t;
604 }
605
606 /* For now we use a CCallOld. We will soon remove the code below (and the
607 * #include) and replace it with a CCall2 version...
608 */
609 #include "vm_priv.h"
610
611 /**
612 * @brief Implementation of <tt>Any@Any</tt>.
613 */
My_Any_At_Any(BoxVMX * vmx)614 static BoxTask My_Any_At_Any(BoxVMX *vmx) {
615 BoxAny *dst = BoxVMX_Get_Parent_Target(vmx),
616 *src = BoxVMX_Get_Child_Target(vmx);
617 BoxAny_Finish(dst);
618 BoxAny_Copy(dst, src);
619 return BOXTASK_OK;
620 }
621
622 /* Create a new pointer type. */
BoxType_Create_Any(void)623 BoxType *BoxType_Create_Any(void) {
624 BoxCallable *callable;
625 BoxType *comb;
626 BoxType *t;
627 BoxTypeAny *td = BoxType_Alloc(& t, BOXTYPECLASS_ANY);
628 BoxCombs_Init(& td->combs);
629
630 /* Define Any@Any. */
631 callable = BoxCallable_Create_Undefined(t, t);
632 callable = BoxCallable_Define_From_CCallOld(callable, My_Any_At_Any);
633 BoxCallable_Set_Uid(callable, "Any@Any");
634 comb = BoxType_Define_Combination(t, BOXCOMBTYPE_AT, t, callable);
635 assert(comb);
636
637 return t;
638 }
639
640 /**
641 * Get the iterator over the subtypes of the given identifier type.
642 * @param type An identifier type or a subtype node.
643 * @param iter A pointer where to store the iterator.
644 * @return BOXBOOL_TRUE for success, BOXBOOL_FALSE for failure.
645 */
BoxType_Get_Subtypes(BoxType * type,BoxTypeIter * iter)646 BoxBool BoxType_Get_Subtypes(BoxType *type, BoxTypeIter *iter) {
647 if (type->type_class == BOXTYPECLASS_IDENT) {
648 BoxTypeIdent *td = BoxType_Get_Data(type);
649 iter->current_node = td->subtypes.node.next;
650 return BOXBOOL_TRUE;
651
652 } else if (type->type_class == BOXTYPECLASS_SUBTYPE_NODE) {
653 BoxTypeSubtypeNode *td = BoxType_Get_Data(type);
654 iter->current_node = td->subtypes.node.next;
655 return BOXBOOL_TRUE;
656
657 } else
658 return BOXBOOL_FALSE;
659 }
660
661 /* Add a subtype type for a given type. */
BoxType_Create_Subtype(BoxType * parent,const char * name,BoxType * type)662 BoxType *BoxType_Create_Subtype(BoxType *parent, const char *name,
663 BoxType *type) {
664 BoxType *sn;
665 BoxTypeSubtypeNode *sd;
666 BoxTypeNode *node;
667
668 if (parent->type_class == BOXTYPECLASS_IDENT) {
669 BoxTypeIdent *td = BoxType_Get_Data(parent);
670 node = & td->subtypes.node;
671
672 } else if (parent->type_class == BOXTYPECLASS_SUBTYPE_NODE) {
673 BoxTypeSubtypeNode *td = BoxType_Get_Data(parent);
674 node = & td->subtypes.node;
675
676 } else
677 return NULL;
678
679 sd = BoxType_Alloc(& sn, BOXTYPECLASS_SUBTYPE_NODE);
680 sd->name = Box_Mem_Strdup(name);
681 sd->type = type ? BoxType_Link(type) : NULL;
682 sd->parent = parent;
683 sd->subtypes.node.next = NULL;
684 sd->subtypes.node.previous = NULL;
685 BoxCombs_Init(& sd->combs);
686 BoxTypeNode_Append_Node(node, sn);
687 return sn;
688 }
689
690 /* Find a subtype of the given type. */
BoxType_Find_Own_Subtype(BoxType * parent,const char * name)691 BoxType *BoxType_Find_Own_Subtype(BoxType *parent, const char *name) {
692 BoxTypeIter ti;
693 if (BoxType_Get_Subtypes(parent, & ti)) {
694 BoxType *t;
695 for (; BoxTypeIter_Get_Next(& ti, & t);) {
696 BoxTypeSubtypeNode *node = BoxType_Get_Data(t);
697 assert(t->type_class == BOXTYPECLASS_SUBTYPE_NODE);
698 if (strcmp(name, node->name) == 0)
699 return t;
700 }
701 }
702
703 return NULL;
704 }
705
BoxType_Find_Subtype(BoxType * parent,const char * name)706 BoxType *BoxType_Find_Subtype(BoxType *parent, const char *name) {
707 BoxType *found_subtype, *former_parent;
708
709 do {
710 /* Find a combination for the parent type, if found return. */
711 found_subtype = BoxType_Find_Own_Subtype(parent, name);
712
713 if (found_subtype)
714 return found_subtype;
715
716 /* Remember the parent. */
717 former_parent = parent;
718
719 /* If not found, resolve the parent and try again. */
720 parent = BoxType_Resolve(parent,
721 (BOXTYPERESOLVE_IDENT | BOXTYPERESOLVE_SPECIES
722 | BOXTYPERESOLVE_RAISED),
723 1);
724
725 } while (parent != former_parent);
726
727 return NULL;
728 }
729
730 /* Get details about a combination found with BoxType_Find_Combination. */
BoxType_Get_Subtype_Info(BoxType * subtype,char ** name,BoxType ** parent,BoxType ** type)731 BoxBool BoxType_Get_Subtype_Info(BoxType *subtype, char **name,
732 BoxType **parent, BoxType **type) {
733 if (subtype->type_class == BOXTYPECLASS_SUBTYPE_NODE) {
734 BoxTypeSubtypeNode *td = BoxType_Get_Data(subtype);
735 if (name)
736 *name = td->name;
737 if (parent)
738 *parent = td->parent;
739 if (type)
740 *type = td->type;
741 return BOXBOOL_TRUE;
742 }
743 return BOXBOOL_FALSE;
744 }
745
746 /* Return whether the subtype was registered (it has a definite type). */
BoxType_Is_Registered_Subtype(BoxType * subtype)747 BoxBool BoxType_Is_Registered_Subtype(BoxType *subtype) {
748 if (subtype->type_class == BOXTYPECLASS_SUBTYPE_NODE) {
749 BoxTypeSubtypeNode *td = BoxType_Get_Data(subtype);
750 return (td->type) ? BOXBOOL_TRUE : BOXBOOL_FALSE;
751 }
752 return BOXBOOL_FALSE;
753 }
754
755 /* Register the type for a given subtype, if not given during creation. */
BoxType_Register_Subtype(BoxType * subtype,BoxType * type)756 BoxBool BoxType_Register_Subtype(BoxType *subtype, BoxType *type) {
757 if (subtype->type_class == BOXTYPECLASS_SUBTYPE_NODE) {
758 BoxTypeSubtypeNode *td = BoxType_Get_Data(subtype);
759 if (td->type)
760 return BOXBOOL_FALSE;
761 td->type = type ? BoxType_Link(type) : NULL;
762 return BOXBOOL_TRUE;
763 }
764 return BOXBOOL_FALSE;
765 }
766
767 /* Get the size of the type 't'. */
BoxType_Get_Size(BoxType * t)768 size_t BoxType_Get_Size(BoxType *t) {
769 size_t size;
770 if (BoxType_Get_Size_And_Alignment(t, & size, NULL))
771 return size;
772 else
773 return 0;
774 }
775
776 /* Get the size and the aligment of a given type. */
777 BoxBool
BoxType_Get_Size_And_Alignment(BoxType * t,size_t * size,size_t * algn)778 BoxType_Get_Size_And_Alignment(BoxType *t, size_t *size, size_t *algn) {
779 size_t dummy;
780
781 if (!size)
782 size = & dummy;
783
784 if (!algn)
785 algn = & dummy;
786
787 /* We do a while loop rather than opting for recursive calls.
788 * The loop is uglier, but more efficient...
789 */
790 while (t) {
791 void *td = BoxType_Get_Data(t);
792
793 switch (t->type_class) {
794 case BOXTYPECLASS_NONE:
795 case BOXTYPECLASS_STRUCTURE_NODE:
796 case BOXTYPECLASS_SPECIES_NODE:
797 case BOXTYPECLASS_ENUM_NODE:
798 case BOXTYPECLASS_COMB_NODE:
799 return BOXBOOL_FALSE;
800
801 case BOXTYPECLASS_SUBTYPE_NODE:
802 *size = sizeof(BoxSubtype);
803 *algn = __alignof__(BoxSubtype);
804 return BOXBOOL_TRUE;
805
806 case BOXTYPECLASS_PRIMARY:
807 *size = ((BoxTypePrimary *) td)->size;
808 *algn = ((BoxTypePrimary *) td)->alignment;
809 return BOXBOOL_TRUE;
810
811 case BOXTYPECLASS_INTRINSIC:
812 *size = ((BoxTypeIntrinsic *) td)->size;
813 *algn = ((BoxTypeIntrinsic *) td)->alignment;
814 return BOXBOOL_TRUE;
815
816 case BOXTYPECLASS_IDENT:
817 t = ((BoxTypeIdent *) td)->source;
818 break; /* resolve and retry... */
819
820 case BOXTYPECLASS_RAISED:
821 t = ((BoxTypeRaised *) td)->source;
822 break; /* resolve and retry... */
823
824 case BOXTYPECLASS_STRUCTURE:
825 *size = ((BoxTypeStructure *) td)->size;
826 *algn = ((BoxTypeStructure *) td)->alignment;
827 return BOXBOOL_TRUE;
828
829 case BOXTYPECLASS_SPECIES:
830 /* Get species' node for the target. */
831 t = ((BoxTypeSpecies *) td)->node.previous;
832
833 if (!t)
834 return BOXBOOL_FALSE;
835
836 /* Get the node's type. */
837 t = ((BoxTypeSpeciesNode *) BoxType_Get_Data(t))->type;
838 break; /* resolve and retry... */
839
840 #if 0
841 case BOXTYPECLASS_ENUM:
842 #endif
843
844 case BOXTYPECLASS_FUNCTION:
845 *size = sizeof(BoxCallable);
846 *algn = __alignof__(BoxCallable);
847 return BOXBOOL_TRUE;
848
849 case BOXTYPECLASS_POINTER:
850 *size = sizeof(BoxPtr);
851 *algn = __alignof__(BoxPtr);
852 return BOXBOOL_TRUE;
853
854 case BOXTYPECLASS_ANY:
855 *size = sizeof(BoxAny);
856 *algn = __alignof__(BoxAny);
857 return BOXBOOL_TRUE;
858
859 default:
860 return BOXBOOL_FALSE;
861 }
862 }
863
864 return BOXBOOL_FALSE;
865 }
866
867 /* Resolve the given type. */
BoxType_Resolve(BoxType * t,BoxTypeResolve resolve,int num)868 BoxType *BoxType_Resolve(BoxType *t, BoxTypeResolve resolve, int num) {
869 if (!t)
870 return t;
871
872 do { /* forever */
873 switch (t->type_class) {
874 case BOXTYPECLASS_NONE:
875 case BOXTYPECLASS_STRUCTURE_NODE:
876 case BOXTYPECLASS_SPECIES_NODE:
877 case BOXTYPECLASS_ENUM_NODE:
878 case BOXTYPECLASS_COMB_NODE:
879 return NULL;
880
881 case BOXTYPECLASS_SUBTYPE_NODE:
882 if ((resolve & BOXTYPERESOLVE_SUBTYPE) == 0)
883 return t;
884 else
885 t = ((BoxTypeSubtypeNode *) BoxType_Get_Data(t))->type;
886 return NULL;
887
888 case BOXTYPECLASS_IDENT:
889 if ((resolve & BOXTYPERESOLVE_IDENT) == 0)
890 return t;
891 else
892 t = ((BoxTypeIdent *) BoxType_Get_Data(t))->source;
893 break;
894
895 case BOXTYPECLASS_RAISED:
896 if ((resolve & BOXTYPERESOLVE_RAISED) == 0)
897 return t;
898 else
899 t = ((BoxTypeRaised *) BoxType_Get_Data(t))->source;
900 break;
901
902 case BOXTYPECLASS_SPECIES:
903 if ((resolve & BOXTYPERESOLVE_SPECIES) == 0)
904 return t;
905 else {
906 BoxType *tg = ((BoxTypeSpecies *) BoxType_Get_Data(t))->node.previous;
907 if (!tg)
908 return t;
909 t = ((BoxTypeSpeciesNode *) BoxType_Get_Data(tg))->type;
910 }
911 break;
912
913 case BOXTYPECLASS_PRIMARY:
914 case BOXTYPECLASS_INTRINSIC:
915 case BOXTYPECLASS_STRUCTURE:
916 case BOXTYPECLASS_ENUM:
917 case BOXTYPECLASS_FUNCTION:
918 case BOXTYPECLASS_ANY:
919 return t;
920
921 case BOXTYPECLASS_POINTER:
922 if ((resolve & BOXTYPERESOLVE_POINTER) == 0)
923 return t;
924 else
925 t = ((BoxTypePointer *) BoxType_Get_Data(t))->source;
926 break;
927
928 default:
929 MSG_FATAL("BoxType_Resolve: unknown type class %d",
930 t->type_class);
931 }
932
933 if (num == 1)
934 return t;
935
936 else if (num > 1)
937 num--;
938
939 } while (1);
940 }
941
942 /* Initialize an iterator for iteration over the members of the given type. */
BoxTypeIter_Init(BoxTypeIter * ti,BoxType * t)943 void BoxTypeIter_Init(BoxTypeIter *ti, BoxType *t) {
944 if (t) {
945 BoxTypeNode *node = My_Type_Get_Node(t);
946 if (node) {
947 ti->current_node = node->next;
948 return;
949 }
950 }
951
952 ti->current_node = NULL;
953 }
954
955 /* Iterate over the next member of the provided iterator. If the iterator has
956 * a next member, then ``*next`` is set to it and BOXBOOL_TRUE is returned.
957 * BOXBOOL_FALSE is returned otherwise.
958 */
BoxTypeIter_Get_Next(BoxTypeIter * ti,BoxType ** next)959 BoxBool BoxTypeIter_Get_Next(BoxTypeIter *ti, BoxType **next) {
960 if (ti && ti->current_node) {
961 BoxTypeNode *node = My_Type_Get_Node(ti->current_node);
962 *next = ti->current_node;
963 ti->current_node = node->next;
964 return BOXBOOL_TRUE;
965
966 } else {
967 *next = NULL;
968 return BOXBOOL_FALSE;
969 }
970 }
971
972 /* Whether the iterator has more items. */
BoxTypeIter_Has_Items(BoxTypeIter * ti)973 BoxBool BoxTypeIter_Has_Items(BoxTypeIter *ti) {
974 return (ti && ti->current_node);
975 }
976
977 /* Type comparison function. */
BoxType_Compare(BoxType * left,BoxType * right)978 BoxTypeCmp BoxType_Compare(BoxType *left, BoxType *right) {
979 if (left == right)
980 return BOXTYPECMP_SAME;
981
982 left = BoxType_Resolve(left, BOXTYPERESOLVE_IDENT, 0);
983 right = BoxType_Resolve(right,
984 BOXTYPERESOLVE_IDENT | BOXTYPERESOLVE_SPECIES, 0);
985 if (left == right)
986 return BOXTYPECMP_EQUAL;
987
988 switch (left->type_class) {
989 case BOXTYPECLASS_STRUCTURE_NODE:
990 case BOXTYPECLASS_SPECIES_NODE:
991 case BOXTYPECLASS_ENUM_NODE:
992 case BOXTYPECLASS_COMB_NODE:
993 case BOXTYPECLASS_IDENT:
994 MSG_FATAL("BoxType_Compare: Invalid type objects.");
995 return BOXTYPECMP_DIFFERENT;
996
997 case BOXTYPECLASS_PRIMARY:
998 if (right->type_class == BOXTYPECLASS_PRIMARY) {
999 BoxTypePrimary *ltd = BoxType_Get_Data(left),
1000 *rtd = BoxType_Get_Data(right);
1001 return (ltd->id == rtd->id) ? BOXTYPECMP_EQUAL : BOXTYPECMP_DIFFERENT;
1002 }
1003
1004 return BOXTYPECMP_DIFFERENT;
1005
1006 case BOXTYPECLASS_INTRINSIC:
1007 /* If we got here, we have left != right, which is enough to say the two
1008 * types are not the same (two intrinsic types are different iff they are
1009 * not the same type).
1010 */
1011 return BOXTYPECMP_DIFFERENT;
1012
1013 case BOXTYPECLASS_RAISED:
1014 /* Same as BOXTYPECLASS_INTRINSIC. */
1015 return BOXTYPECMP_DIFFERENT;
1016
1017 case BOXTYPECLASS_SPECIES:
1018 {
1019 BoxTypeIter iter;
1020 BoxType *node;
1021 for (BoxTypeIter_Init(& iter, left);
1022 BoxTypeIter_Get_Next(& iter, & node);) {
1023 BoxType *memb = BoxType_Get_Species_Member_Type(node);
1024
1025 if (BoxType_Compare(memb, right) != BOXTYPECMP_DIFFERENT) {
1026 if (BoxTypeIter_Has_Items(& iter))
1027 /* Match with one of the species' sources: need to expand! */
1028 return BOXTYPECMP_MATCHING;
1029 else
1030 /* Match with species' target: no need to expand! */
1031 return BOXTYPECMP_EQUAL;
1032 }
1033 }
1034
1035 return BOXTYPECMP_DIFFERENT;
1036 }
1037
1038 case BOXTYPECLASS_STRUCTURE:
1039 /* Note that two structures do match when the types of their members do
1040 * match, even if the names of the members are different. For example,
1041 *
1042 * (Real x, y) == (Real z, hgj)
1043 *
1044 * A particular tuple can be raised to make sure it does not match a tuple
1045 * having the same types of members.
1046 */
1047 if (left->type_class == right->type_class) {
1048 BoxTypeIter liter, riter;
1049 BoxType *lnode, *rnode;
1050
1051 BoxTypeIter_Init(& liter, left);
1052 BoxTypeIter_Init(& riter, right);
1053
1054 /* Check we do have the same number of nodes. */
1055 if (BoxType_Get_Structure_Num_Members(left)
1056 == BoxType_Get_Structure_Num_Members(right)) {
1057 BoxTypeCmp ret = BOXTYPECMP_EQUAL;
1058
1059 for (; (BoxTypeIter_Get_Next(& liter, & lnode)
1060 && BoxTypeIter_Get_Next(& riter, & rnode)); ) {
1061 BoxType *lmemb = BoxType_Get_Structure_Member_Type(lnode),
1062 *rmemb = BoxType_Get_Structure_Member_Type(rnode);
1063
1064 ret &= BoxType_Compare(lmemb, rmemb);
1065 if (ret == BOXTYPECMP_DIFFERENT)
1066 return BOXTYPECMP_DIFFERENT;
1067 }
1068
1069 return ret;
1070 }
1071 }
1072
1073 return BOXTYPECMP_DIFFERENT;
1074
1075 case BOXTYPECLASS_ANY:
1076 if (right->type_class == BOXTYPECLASS_PRIMARY) {
1077 BoxTypePrimary *rtd = BoxType_Get_Data(right);
1078 switch (rtd->id) {
1079 case BOXTYPEID_VOID:
1080 case BOXTYPEID_INIT:
1081 case BOXTYPEID_FINISH:
1082 case BOXTYPEID_BEGIN:
1083 case BOXTYPEID_END:
1084 return BOXTYPECMP_DIFFERENT;
1085 default:
1086 break;
1087 }
1088 }
1089
1090 return BOXTYPECMP_MATCHING;
1091
1092 default:
1093 MSG_ERROR("BoxType_Compare: not fully implemented!");
1094 return BOXTYPECMP_DIFFERENT;
1095 }
1096 }
1097
1098 /* Get the stem type of a type. */
BoxType_Get_Stem(BoxType * type)1099 BoxType *BoxType_Get_Stem(BoxType *type) {
1100 return BoxType_Resolve(type, BOXTYPERESOLVE_IDENT
1101 | BOXTYPERESOLVE_SPECIES
1102 | BOXTYPERESOLVE_RAISED, 0);
1103 }
1104
1105 /* Get the container type associated with a given type.
1106 * The container type is strictly related to the way the compiler handles types
1107 * (e.g. register types).
1108 */
BoxType_Get_Cont_Type(BoxType * t)1109 BoxContType BoxType_Get_Cont_Type(BoxType *t) {
1110 BoxType *stem;
1111
1112 if (!t)
1113 return BOXCONTTYPE_VOID;
1114
1115 stem = BoxType_Get_Stem(t);
1116
1117 /* Char, Int, ... are V.I.P. objects which have their own container types. */
1118 if (stem->type_class == BOXTYPECLASS_PRIMARY) {
1119 BoxTypePrimary *td = BoxType_Get_Data(stem);
1120 BoxTypeId id = td->id;
1121
1122 /* Here we assume BoxTypeCont and BoxTypeId are defined consistently. */
1123 if (id >= BOXTYPEID_CHAR && id <= BOXTYPEID_PTR)
1124 return (BoxContType) id;
1125 else
1126 return (td->size == 0) ? BOXCONTTYPE_VOID : BOXCONTTYPE_OBJ;
1127
1128 } else if (stem->type_class == BOXTYPECLASS_INTRINSIC) {
1129 BoxTypeIntrinsic *td = BoxType_Get_Data(stem);
1130 return (td->size == 0) ? BOXCONTTYPE_VOID : BOXCONTTYPE_OBJ;
1131
1132 } else
1133 return (BoxType_Get_Size(stem) == 0) ? BOXCONTTYPE_VOID : BOXCONTTYPE_OBJ;
1134 }
1135
1136 /* Whether the type is a void type (contains nothing). */
BoxType_Is_Empty(BoxType * t)1137 BoxBool BoxType_Is_Empty(BoxType *t) {
1138 return (BoxType_Get_Size(t) == 0);
1139 }
1140
1141 /* Whether the given type is an Any type. */
BoxType_Is_Any(BoxType * t)1142 BoxBool BoxType_Is_Any(BoxType *t) {
1143 BoxType *stem = BoxType_Get_Stem(t);
1144 return stem && stem->type_class == BOXTYPECLASS_ANY;
1145 }
1146
1147 /* Whether the type is a fast type. */
BoxType_Is_Fast(BoxType * t)1148 BoxBool BoxType_Is_Fast(BoxType *t) {
1149 BoxType *stem = BoxType_Get_Stem(t);
1150 if (stem && stem->type_class == BOXTYPECLASS_PRIMARY) {
1151 BoxTypePrimary *td = BoxType_Get_Data(stem);
1152 return (td->id >= BOXTYPEID_FAST_LOWER && td->id <= BOXTYPEID_FAST_UPPER);
1153 }
1154
1155 return BOXBOOL_FALSE;
1156 }
1157
1158 /* Get a string representation of the given type. */
BoxType_Get_Repr(BoxType * t)1159 char *BoxType_Get_Repr(BoxType *t) {
1160 if (!t)
1161 return Box_Mem_Strdup("<null>");
1162
1163 switch (t->type_class) {
1164 case BOXTYPECLASS_STRUCTURE_NODE:
1165 case BOXTYPECLASS_SPECIES_NODE:
1166 case BOXTYPECLASS_ENUM_NODE:
1167 return Box_Mem_Strdup("<invalid>");
1168
1169 case BOXTYPECLASS_COMB_NODE:
1170 {
1171 BoxType *parent;
1172 BoxTypeCombNode *td = BoxType_Get_Data(t);
1173 const char *callable_type_repr = NULL;
1174
1175 switch (td->comb_type) {
1176 case BOXCOMBTYPE_AT:
1177 callable_type_repr = "@";
1178 break;
1179 case BOXCOMBTYPE_COPY:
1180 callable_type_repr = "(=)";
1181 break;
1182 default:
1183 return Box_Mem_Strdup("<invalid-combination>");
1184 }
1185
1186 parent = BoxType_Get_Callable_Parent(BoxSPtr_Get_Type(td->callable));
1187 return Box_SPrintF("%~s%s%~s", BoxType_Get_Repr(td->child),
1188 callable_type_repr, BoxType_Get_Repr(parent));
1189 }
1190
1191 case BOXTYPECLASS_SUBTYPE_NODE:
1192 {
1193 BoxTypeSubtypeNode *td = BoxType_Get_Data(t);
1194 return Box_SPrintF("%~s.%s", BoxType_Get_Repr(td->parent), td->name);
1195 }
1196
1197 case BOXTYPECLASS_IDENT:
1198 {
1199 BoxTypeIdent *td = BoxType_Get_Data(t);
1200 return Box_Mem_Strdup(td->name);
1201 }
1202
1203 case BOXTYPECLASS_PRIMARY:
1204 {
1205 BoxTypePrimary *td = BoxType_Get_Data(t);
1206 return Box_SPrintF("<primary:id=%d,size=%d,align=%d>",
1207 (int) td->id, (int) td->size, (int) td->alignment);
1208 }
1209
1210 case BOXTYPECLASS_INTRINSIC:
1211 {
1212 BoxTypeIntrinsic *td = BoxType_Get_Data(t);
1213 return Box_SPrintF("<intrinsic:size=%d,align=%d>",
1214 (int) td->size, (int) td->alignment);
1215 }
1216
1217 case BOXTYPECLASS_RAISED:
1218 {
1219 BoxTypeRaised *td = BoxType_Get_Data(t);
1220 return Box_SPrintF("^%~s", BoxType_Get_Repr(td->source));
1221 }
1222
1223 case BOXTYPECLASS_SPECIES:
1224 {
1225 char *str = NULL;
1226 BoxTypeIter iter;
1227 BoxType *node;
1228
1229 for (BoxTypeIter_Init(& iter, t);
1230 BoxTypeIter_Get_Next(& iter, & node);) {
1231 BoxType *memb_type = BoxType_Get_Species_Member_Type(node);
1232 char *memb_repr;
1233
1234 memb_repr = (memb_type
1235 ? BoxType_Get_Repr(memb_type)
1236 : Box_Mem_Strdup("<err>"));
1237
1238 str = (str ? Box_SPrintF("%~s=>%~s", str, memb_repr) : memb_repr);
1239 }
1240
1241 return Box_SPrintF("(%~s)", str);
1242 }
1243
1244 case BOXTYPECLASS_STRUCTURE:
1245 {
1246 char *str = NULL;
1247 BoxTypeIter iter;
1248 BoxType *node, *prev_type;
1249 BoxBool has_prev_type = BOXBOOL_FALSE;
1250 size_t num_membs = 0;
1251
1252 for (BoxTypeIter_Init(& iter, t);
1253 BoxTypeIter_Get_Next(& iter, & node); num_membs++) {
1254 char *memb_name;
1255 BoxType *memb_type;
1256 char *memb_repr;
1257
1258 if (BoxType_Get_Structure_Member(node, & memb_name, NULL,
1259 NULL, & memb_type)) {
1260 if (!memb_name)
1261 memb_repr = BoxType_Get_Repr(memb_type);
1262
1263 else if (has_prev_type && memb_type == prev_type)
1264 memb_repr = Box_Mem_Strdup(memb_name);
1265
1266 else
1267 memb_repr= Box_SPrintF("%~s %s",
1268 BoxType_Get_Repr(memb_type), memb_name);
1269
1270 has_prev_type = BOXBOOL_TRUE;
1271 prev_type = memb_type;
1272
1273 } else {
1274 memb_repr = Box_Mem_Strdup("<err>");
1275 has_prev_type = BOXBOOL_FALSE;
1276 }
1277
1278 str = (str ? Box_SPrintF("%~s, %~s", str, memb_repr) : memb_repr);
1279 }
1280
1281 return ((num_membs > 1) ?
1282 Box_SPrintF("(%~s)", str) : Box_SPrintF("(%~s,)", str));
1283 }
1284
1285 case BOXTYPECLASS_ANY:
1286 return Box_Mem_Strdup("Any");
1287
1288 default:
1289 return NULL;
1290 }
1291 }
1292