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