1 /****************************************************************************
2  * Copyright (C) 2009-2013 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 
24 #include "types.h"
25 #include "mem.h"
26 #include "array.h"
27 #include "ast.h"
28 #include "value.h"
29 #include "vmcode.h"
30 #include "operator.h"
31 #include "namespace.h"
32 #include "messages.h"
33 #include "parserh.h"
34 #include "combs.h"
35 #include "vmsymstuff.h"
36 
37 #include "compiler_priv.h"
38 
39 /* For now it is safer not to cache const values!
40  * (will make easier to detect reference count problems)
41  */
42 #define DONT_CACHE_CONST_VALUES 1
43 
44 /**
45  * @brief Type of items which may be inserted inside the compiler stack.
46  * @see StackItem
47  */
48 typedef enum {
49   STACKITEM_ERROR,
50   STACKITEM_VALUE
51 } StackItemType;
52 
53 /**
54  * @brief Called when removing the item from the stack.
55  * @see StackItem
56  */
57 typedef void (*StackItemDestructor)(void *item);
58 
59 /**
60  * The compiler has a stack of values which are currently being
61  * processed. This structure describes one of such values.
62  * We actually store a pointer to the item and an integer number, which
63  * identifies the type of such item. The type introduces some redundancy
64  * which may help to track down bugs...
65  */
66 typedef struct {
67   StackItemType       type;
68   void                *item;
69   StackItemDestructor destructor;
70 } StackItem;
71 
72 /**
73  * Here we define, once for all, a number of useful Value instances which
74  * are used massively in the compiler. We could just allocate and create
75  * them whenever needed, but we do it here and just return new references
76  * to them whenever it is needed, with the hope to improve performance.
77  */
My_Init_Const_Values(BoxCmp * c)78 static void My_Init_Const_Values(BoxCmp *c) {
79   Value_Init(& c->value.error, & c->main_proc);
80   Value_Init(& c->value.void_val, & c->main_proc);
81   Value_Setup_As_Void(& c->value.void_val);
82   BoxCont_Set(& c->cont.pass_child, "go", 2);
83   BoxCont_Set(& c->cont.pass_parent, "go", 1);
84 
85   Value_Init(& c->value.create, & c->main_proc);
86   Value_Setup_As_Type(& c->value.create, Box_Get_Core_Type(BOXTYPEID_INIT));
87   Value_Init(& c->value.destroy, & c->main_proc);
88   Value_Setup_As_Type(& c->value.destroy, Box_Get_Core_Type(BOXTYPEID_FINISH));
89   Value_Init(& c->value.begin, & c->main_proc);
90   Value_Setup_As_Type(& c->value.begin, Box_Get_Core_Type(BOXTYPEID_BEGIN));
91   Value_Init(& c->value.end, & c->main_proc);
92   Value_Setup_As_Type(& c->value.end, Box_Get_Core_Type(BOXTYPEID_END));
93   Value_Init(& c->value.pause, & c->main_proc);
94   Value_Setup_As_Temp(& c->value.pause, Box_Get_Core_Type(BOXTYPEID_PAUSE));
95 }
96 
My_Finish_Const_Values(BoxCmp * c)97 void My_Finish_Const_Values(BoxCmp *c) {
98   Value_Unlink(& c->value.error);
99   Value_Unlink(& c->value.void_val);
100   Value_Unlink(& c->value.create);
101   Value_Unlink(& c->value.destroy);
102   Value_Unlink(& c->value.pause);
103 }
104 
105 /** Return a new error value (actually a new reference to it,
106  * see My_Init_Const_Values)
107  */
My_Value_New_Error(BoxCmp * c)108 Value *My_Value_New_Error(BoxCmp *c) {
109 #if DONT_CACHE_CONST_VALUES == 1
110   return Value_New(c->cur_proc);
111 #else
112   Value_Link(c->value.error);
113   return & c->value.error; /* return an error value */
114 #endif
115 }
116 
117 /* We may optimize this later, by just passing a reference to a Value
118  * object which is created once for all at the beginning!
119  */
My_Get_Void_Value(BoxCmp * c)120 static Value *My_Get_Void_Value(BoxCmp *c) {
121 #if DONT_CACHE_CONST_VALUES == 1
122   Value *v = Value_New(c->cur_proc);
123   Value_Setup_As_Void(v);
124   return v;
125 #else
126   Value_Link(& c->value.void_val);
127   return & c->value.void_val;
128 #endif
129 }
130 
BoxCmp_Init(BoxCmp * c,BoxVM * target_vm)131 void BoxCmp_Init(BoxCmp *c, BoxVM *target_vm) {
132   c->attr.own_vm = (target_vm == NULL);
133   c->vm = (target_vm != NULL) ? target_vm : BoxVM_Create();
134 
135   BoxArr_Init(& c->stack, sizeof(StackItem), 32);
136 
137   BoxBool success = Box_Initialize_Type_System();
138   assert(success);
139 
140   BoxCmp_Init__Operators(c);
141 
142   BoxVMCode_Init(& c->main_proc, c, BOXVMCODESTYLE_MAIN);
143   BoxVMCode_Set_Alter_Name(& c->main_proc, "main");
144   c->cur_proc = & c->main_proc;
145 
146   My_Init_Const_Values(c);
147   Namespace_Init(& c->ns);
148   Bltin_Init(c);
149 
150   BoxSrcPos_Init(& c->src_pos, NULL);
151 }
152 
BoxCmp_Finish(BoxCmp * c)153 void BoxCmp_Finish(BoxCmp *c) {
154   Bltin_Finish(c);
155   Namespace_Finish(& c->ns);
156   My_Finish_Const_Values(c);
157   BoxVMCode_Finish(& c->main_proc);
158 
159   if (BoxArr_Num_Items(& c->stack) != 0)
160     MSG_WARNING("BoxCmp_Finish: stack is not empty at compiler destruction.");
161   BoxArr_Finish(& c->stack);
162 
163   BoxCmp_Finish__Operators(c);
164 
165   if (c->attr.own_vm)
166     BoxVM_Destroy(c->vm);
167 }
168 
BoxCmp_Create(BoxVM * target_vm)169 BoxCmp *BoxCmp_Create(BoxVM *target_vm) {
170   BoxCmp *c = Box_Mem_Alloc(sizeof(BoxCmp));
171   if (c)
172     BoxCmp_Init(c, target_vm);
173   return c;
174 }
175 
BoxCmp_Destroy(BoxCmp * c)176 void BoxCmp_Destroy(BoxCmp *c) {
177   BoxCmp_Finish(c);
178   Box_Mem_Free(c);
179 }
180 
BoxCmp_Steal_VM(BoxCmp * c)181 BoxVM *BoxCmp_Steal_VM(BoxCmp *c) {
182   BoxVM *vm = c->vm;
183   c->attr.own_vm = 0;
184   c->vm = 0;
185   return vm;
186 }
187 
188 /* Function which does all the steps needed to get from a Box source file
189  * to a VM with the corresponding compiled bytecode.
190  */
Box_Compile_To_VM_From_File(BoxVMCallNum * main,BoxVM * target_vm,FILE * file,const char * file_name,const char * setup_file_name,BoxPaths * paths)191 BoxVM *Box_Compile_To_VM_From_File(BoxVMCallNum *main, BoxVM *target_vm,
192                                    FILE *file, const char *file_name,
193                                    const char *setup_file_name,
194                                    BoxPaths *paths) {
195   ASTNode *program_node;
196   BoxCmp *compiler;
197   BoxVM *vm;
198   BoxVMCallNum dummy_cn;
199 
200   if (main == NULL)
201     main = & dummy_cn;
202 
203   compiler = BoxCmp_Create(target_vm);
204   program_node = Parser_Parse(file, file_name, setup_file_name, paths);
205   BoxCmp_Compile(compiler, program_node);
206   ASTNode_Destroy(program_node);
207   *main = BoxVMCode_Install(& compiler->main_proc);
208   vm = BoxCmp_Steal_VM(compiler);
209   BoxCmp_Destroy(compiler);
210   return vm;
211 }
212 
BoxCmp_Remove_Any(BoxCmp * c,int num_items_to_remove)213 void BoxCmp_Remove_Any(BoxCmp *c, int num_items_to_remove) {
214   int i;
215   for(i = 0; i < num_items_to_remove; i++) {
216     StackItem *si = (StackItem *) BoxArr_Last_Item_Ptr(& c->stack);
217     if (si->type == STACKITEM_VALUE)
218       Value_Unlink((Value *) si->item);
219     if (si->destructor != NULL)
220       si->destructor(si->item);
221     (void) BoxArr_Pop(& c->stack, NULL);
222   }
223 }
224 
225 /** Used to push an error into the stack. Errors are propagated. For example:
226  * a binary operation where one of the two arguments is an error returns
227  * silently an error into the stack.
228  */
BoxCmp_Push_Error(BoxCmp * c,int num_errors)229 void BoxCmp_Push_Error(BoxCmp *c, int num_errors) {
230   int i;
231   for(i = 0; i < num_errors; i++) {
232     StackItem *si = (StackItem *) BoxArr_Push(& c->stack, NULL);
233     si->type = STACKITEM_ERROR;
234     si->item = NULL;
235     si->destructor = NULL;
236   }
237 }
238 
239 /** Check the last 'items_to_pop' stack entries for errors. If all these
240  * entries have no errors, then do nothing and return 0. If one or more
241  * of these entries have errors, then removes all of them from the stack,
242  * push the given number of errors and return 1.
243  */
BoxCmp_Pop_Errors(BoxCmp * c,int items_to_pop,int errors_to_push)244 int BoxCmp_Pop_Errors(BoxCmp *c, int items_to_pop, int errors_to_push) {
245   BoxInt n = BoxArr_Num_Items(& c->stack), i;
246   int no_err = 1;
247 
248   for(i = 0; i < items_to_pop; i++) {
249     StackItem *si = (StackItem *) BoxArr_Item_Ptr(& c->stack, n - i);
250 
251     if (si->type == STACKITEM_VALUE) {
252       Value *v = (Value *) si->item;
253       if (Value_Is_Err(v)) {
254         no_err = 0;
255         break;
256       }
257 
258     } else if (si->type == STACKITEM_ERROR) {
259       no_err = 0;
260       break;
261     }
262   }
263 
264   if (no_err)
265     return 0;
266 
267   else {
268     BoxCmp_Remove_Any(c, items_to_pop);
269     BoxCmp_Push_Error(c, errors_to_push);
270     return 1;
271   }
272 }
273 
274 /** Pushes the given value 'v' into the compiler stack, stealing a reference
275  * to it.
276  * REFERENCES: v: -1;
277  */
BoxCmp_Push_Value(BoxCmp * c,Value * v)278 void BoxCmp_Push_Value(BoxCmp *c, Value *v) {
279   if (v != NULL) {
280     StackItem *si = (StackItem *) BoxArr_Push(& c->stack, NULL);
281     si->type = STACKITEM_VALUE;
282     si->item = v;
283     si->destructor = NULL;
284 
285   } else
286     BoxCmp_Push_Error(c, 1);
287 }
288 
289 /** Pops the last value in the compiler stack and returns it, together with
290  * the corresponding reference.
291  * REFERENCES: return: new;
292  */
BoxCmp_Pop_Value(BoxCmp * c)293 Value *BoxCmp_Pop_Value(BoxCmp *c) {
294   StackItem *si = BoxArr_Last_Item_Ptr(& c->stack);
295   Value *v;
296 
297   switch(si->type) {
298   case STACKITEM_ERROR:
299     (void) BoxArr_Pop(& c->stack, NULL);
300     return My_Value_New_Error(c); /* return an error value */
301 
302   case STACKITEM_VALUE:
303     v = (Value *) si->item; /* return the value and its reference */
304     (void) BoxArr_Pop(& c->stack, NULL);
305     return v;
306 
307   default:
308     MSG_FATAL("BoxCmp_Pop_Value: want value, but top of stack contains "
309               "incompatible item.");
310     assert(0);
311   }
312 }
313 
BoxCmp_Get_Value(BoxCmp * c,BoxInt pos)314 Value *BoxCmp_Get_Value(BoxCmp *c, BoxInt pos) {
315   BoxInt n = BoxArr_Num_Items(& c->stack);
316   StackItem *si = BoxArr_Item_Ptr(& c->stack, n - pos);
317   switch(si->type) {
318   case STACKITEM_ERROR:
319     return My_Value_New_Error(c); /* return an error value */
320 
321   case STACKITEM_VALUE:
322     return (Value *) si->item;
323 
324   default:
325     MSG_FATAL("BoxCmp_Get_Value: want value, but top of stack contains "
326               "incompatible item.");
327     assert(0);
328   }
329 }
330 
331 static void My_Compile_Any(BoxCmp *c, ASTNode *node);
332 static void My_Compile_Error(BoxCmp *c, ASTNode *node);
333 static void My_Compile_TypeName(BoxCmp *c, ASTNode *node);
334 static void My_Compile_TypeTag(BoxCmp *c, ASTNode *node);
335 static void My_Compile_Subtype(BoxCmp *c, ASTNode *node);
336 static void My_Compile_Box(BoxCmp *c, ASTNode *box,
337                            BoxType *child_t, BoxType *parent_t);
338 static void My_Compile_Instance(BoxCmp *c, ASTNode *instance);
339 static void My_Compile_String(BoxCmp *c, ASTNode *node);
340 static void My_Compile_Const(BoxCmp *c, ASTNode *n);
341 static void My_Compile_Var(BoxCmp *c, ASTNode *n);
342 static void My_Compile_Ignore(BoxCmp *c, ASTNode *n);
343 static void My_Compile_UnOp(BoxCmp *c, ASTNode *n);
344 static void My_Compile_BinOp(BoxCmp *c, ASTNode *n);
345 static void My_Compile_Struc(BoxCmp *c, ASTNode *n);
346 static void My_Compile_MemberGet(BoxCmp *c, ASTNode *n);
347 static void My_Compile_SubtypeBld(BoxCmp *c, ASTNode *n);
348 static void My_Compile_SelfGet(BoxCmp *c, ASTNode *n);
349 static void My_Compile_ProcDef(BoxCmp *c, ASTNode *n);
350 static void My_Compile_TypeDef(BoxCmp *c, ASTNode *n);
351 static void My_Compile_StrucType(BoxCmp *c, ASTNode *n);
352 static void My_Compile_SpecType(BoxCmp *c, ASTNode *n);
353 static void My_Compile_RaiseType(BoxCmp *c, ASTNode *n);
354 static void My_Compile_Raise(BoxCmp *c, ASTNode *n);
355 
BoxCmp_Compile(BoxCmp * c,ASTNode * program)356 void BoxCmp_Compile(BoxCmp *c, ASTNode *program) {
357   if (!program)
358     return;
359 
360   My_Compile_Any(c, program);
361   BoxCmp_Remove_Any(c, 1);
362 }
363 
My_Compile_Any(BoxCmp * c,ASTNode * node)364 static void My_Compile_Any(BoxCmp *c, ASTNode *node) {
365   BoxSrc *prev_src_of_err = Msg_Set_Src(& node->src);
366   BoxSrcPos *new_src_pos = & node->src.end;
367 
368   /* Output line information to current procedure */
369   if (/*c->src_pos.file_name != NULL && */ new_src_pos->line != 0 &&
370       (new_src_pos->file_name != c->src_pos.file_name
371        || new_src_pos->line != c->src_pos.line)) {
372     BoxVMCode_Associate_Source(c->cur_proc, new_src_pos);
373     c->src_pos = *new_src_pos;
374   }
375 
376   switch(node->type) {
377   case ASTNODETYPE_ERROR:
378     My_Compile_Error(c, node); break;
379   case ASTNODETYPE_TYPENAME:
380     My_Compile_TypeName(c, node); break;
381   case ASTNODETYPE_TYPETAG:
382     My_Compile_TypeTag(c, node); break;
383   case ASTNODETYPE_SUBTYPE:
384     My_Compile_Subtype(c, node); break;
385   case ASTNODETYPE_INSTANCE:
386     My_Compile_Instance(c, node); break;
387   case ASTNODETYPE_BOX:
388     My_Compile_Box(c, node, NULL, NULL); break;
389   case ASTNODETYPE_STRING:
390     My_Compile_String(c, node); break;
391   case ASTNODETYPE_CONST:
392     My_Compile_Const(c, node); break;
393   case ASTNODETYPE_VAR:
394     My_Compile_Var(c, node); break;
395   case ASTNODETYPE_IGNORE:
396     My_Compile_Ignore(c, node); break;
397   case ASTNODETYPE_UNOP:
398     My_Compile_UnOp(c, node); break;
399   case ASTNODETYPE_BINOP:
400     My_Compile_BinOp(c, node); break;
401   case ASTNODETYPE_STRUC:
402     My_Compile_Struc(c, node); break;
403   case ASTNODETYPE_MEMBERGET:
404     My_Compile_MemberGet(c, node); break;
405   case ASTNODETYPE_RAISE:
406     My_Compile_Raise(c, node); break;
407   case ASTNODETYPE_SUBTYPEBLD:
408     My_Compile_SubtypeBld(c, node); break;
409   case ASTNODETYPE_SELFGET:
410     My_Compile_SelfGet(c, node); break;
411   case ASTNODETYPE_PROCDEF:
412     My_Compile_ProcDef(c, node); break;
413   case ASTNODETYPE_TYPEDEF:
414     My_Compile_TypeDef(c, node); break;
415   case ASTNODETYPE_STRUCTYPE:
416     My_Compile_StrucType(c, node); break;
417   case ASTNODETYPE_SPECTYPE:
418     My_Compile_SpecType(c, node); break;
419   case ASTNODETYPE_RAISETYPE:
420     My_Compile_RaiseType(c, node); break;
421   default:
422     printf("Compilation of node is not implemented, yet!\n");
423     break;
424   }
425 
426   (void) Msg_Set_Src(prev_src_of_err);
427 }
428 
My_Compile_Error(BoxCmp * c,ASTNode * node)429 static void My_Compile_Error(BoxCmp *c, ASTNode *node) {
430   BoxCmp_Push_Value(c, Value_New(c->cur_proc));
431 }
432 
My_Compile_TypeName(BoxCmp * c,ASTNode * n)433 static void My_Compile_TypeName(BoxCmp *c, ASTNode *n) {
434   Value *v;
435   char *type_name = n->attr.var.name;
436   NmspFloor f;
437 
438   assert(n->type == ASTNODETYPE_TYPENAME);
439 
440   f = NMSPFLOOR_DEFAULT;
441   v = Namespace_Get_Value(& c->ns, f, type_name);
442   if (v) {
443     /* We return a copy, not the original! */
444     Value *v_copy = Value_New(c->cur_proc);
445     Value_Setup_As_Weak_Copy(v_copy, v);
446     Value_Unlink(v);
447     BoxCmp_Push_Value(c, v_copy);
448 
449   } else {
450     v = Value_Create(c->cur_proc);
451     Value_Setup_As_Type_Name(v, type_name);
452     Namespace_Add_Value(& c->ns, f, type_name, v);
453     BoxCmp_Push_Value(c, v);
454   }
455 }
456 
My_Compile_TypeTag(BoxCmp * c,ASTNode * n)457 static void My_Compile_TypeTag(BoxCmp *c, ASTNode *n) {
458   Value *v;
459 
460   assert(n->type == ASTNODETYPE_TYPETAG);
461 
462   /* Should we use c->value.create, etc. ? */
463   v = Value_Create(c->cur_proc);
464   Value_Setup_As_Type(v, Box_Get_Core_Type(n->attr.typetag.type));
465   BoxCmp_Push_Value(c, v);
466 }
467 
My_Compile_Subtype(BoxCmp * c,ASTNode * p)468 static void My_Compile_Subtype(BoxCmp *c, ASTNode *p) {
469   Value *parent_type;
470   const char *name = p->attr.subtype.name;
471   BoxType *new_subtype = NULL;
472 
473   assert(p->type == ASTNODETYPE_SUBTYPE);
474   assert(p->attr.subtype.parent);
475 
476   My_Compile_Any(c, p->attr.subtype.parent);
477   if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push err */ 1))
478     return;
479 
480   parent_type = BoxCmp_Pop_Value(c);
481   if (Value_Want_Has_Type(parent_type)) {
482     BoxType *pt = parent_type->type;
483     if (BoxType_Is_Subtype(pt)) {
484       /* Our parent is already a subtype (example X.Y) and we want X.Y.Z:
485        * we then require X.Y to be a registered subtype
486        */
487       if (BoxType_Is_Registered_Subtype(pt)) {
488         new_subtype = BoxType_Find_Subtype(pt, name);
489         if (!new_subtype)
490           new_subtype = BoxType_Create_Subtype(pt, name, NULL);
491       } else {
492         MSG_ERROR("Cannot build subtype '%s' of undefined subtype '%T'.",
493                   name, parent_type->type);
494       }
495 
496     } else {
497       new_subtype = BoxType_Find_Subtype(pt, name);
498       if (!new_subtype)
499         new_subtype = BoxType_Create_Subtype(pt, name, NULL);
500     }
501   }
502 
503   Value_Unlink(parent_type);
504 
505   if (new_subtype) {
506     Value *v = Value_Create(c->cur_proc);
507     Value_Setup_As_Type(v, new_subtype);
508     (void) BoxType_Unlink(new_subtype);
509     BoxCmp_Push_Value(c, v);
510   } else
511     BoxCmp_Push_Error(c, 1);
512 }
513 
My_Compile_Statement(BoxCmp * c,ASTNode * s)514 static void My_Compile_Statement(BoxCmp *c, ASTNode *s) {
515   assert(s->type == ASTNODETYPE_STATEMENT);
516 
517   if (s->attr.statement.target != NULL) {
518     assert(s->attr.statement.sep == ASTSEP_VOID);
519     My_Compile_Any(c, s->attr.statement.target);
520 
521   } else {
522     assert(s->attr.statement.sep != ASTSEP_VOID);
523     Value_Link(& c->value.pause);
524     BoxCmp_Push_Value(c, & c->value.pause);
525   }
526 }
527 
My_Compile_Instance(BoxCmp * c,ASTNode * instance)528 static void My_Compile_Instance(BoxCmp *c, ASTNode *instance) {
529   assert(instance->type == ASTNODETYPE_INSTANCE);
530 
531   My_Compile_Any(c, instance->attr.instance.type);
532   if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push */ 1))
533     return;
534 
535   else {
536     Value *instance = Value_To_Temp_Or_Target(BoxCmp_Pop_Value(c));
537     BoxCmp_Push_Value(c, instance);
538   }
539 }
540 
541 typedef enum {
542   MYBOXSTATE_INITIAL,
543   MYBOXSTATE_GOT_IF,
544   MYBOXSTATE_GOT_ELSE
545 } MyBoxState;
546 
My_Compile_Box(BoxCmp * c,ASTNode * box,BoxType * t_child,BoxType * t_parent)547 static void My_Compile_Box(BoxCmp *c, ASTNode *box,
548                            BoxType *t_child, BoxType *t_parent) {
549   ASTNode *s;
550   Value *parent = NULL, *outer_parent = NULL;
551   BoxBool parent_is_err = 0, need_floor_down;
552   BoxVMSymID jump_label_begin, jump_label_end, jump_label_next;
553   MyBoxState state;
554 
555   assert(box->type == ASTNODETYPE_BOX);
556 
557   if (box->attr.box.parent == NULL) {
558     Value *v_void = My_Get_Void_Value(c);
559     BoxCmp_Push_Value(c, v_void);
560 
561     parent = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "#");
562     if (parent == NULL)
563       parent = v_void;
564     else
565       outer_parent = parent;
566 
567   } else {
568     Value *parent_type;
569     My_Compile_Any(c, box->attr.box.parent);
570     parent_type = BoxCmp_Pop_Value(c);
571     parent = Value_To_Temp_Or_Target(parent_type);
572     parent_is_err = Value_Is_Err(parent);
573     Value_Unlink(parent_type); /* XXX */
574     BoxCmp_Push_Value(c, parent);
575   }
576 
577   Namespace_Floor_Up(& c->ns); /* variables defined in this box will be
578                                   destroyed when it gets closed! */
579 
580   /* Add $ (the child) to namespace */
581   if (t_child) {
582     Value *v_child = Value_New(c->cur_proc);
583     Value_Setup_As_Child(v_child, t_child);
584     Namespace_Add_Value(& c->ns, NMSPFLOOR_DEFAULT, "$", v_child);
585     Value_Unlink(v_child);
586   }
587 
588   /* Add $$ (the parent) to namespace */
589   if (t_parent) {
590     Value *v_parent = Value_New(c->cur_proc);
591     Value_Setup_As_Parent(v_parent, t_parent);
592     Namespace_Add_Value(& c->ns, NMSPFLOOR_DEFAULT, "$$", v_parent);
593     Value_Unlink(v_parent); /* has already a link from the namespace */
594     parent = v_parent;      /* So that Int@X[] behaves somewhat like X[] */
595   }
596 
597   {
598     /* # represents internally the object the Box is constructing, so that
599      * implicit members can access it. Like:
600      *   X = (Real a, b)
601      *   x = X[.a = 1.0]
602      * It also works in procedure definitions:
603      *   Int@X[.a = $]
604      * The implicit member is .a and internally it is treated as #.a, even
605      * if such syntax is not available to the user.
606      *
607      * NOTE: the following works also when parent = ERROR
608      */
609     Value *v_parent = Value_New(c->cur_proc);
610     Value_Setup_As_Weak_Copy(v_parent, parent);
611     v_parent = Value_Promote_Temp_To_Target(v_parent);
612     /* ^^^ Promote # (the Box object) to a target so that it can be
613      * changed inside the Box
614      */
615     Namespace_Add_Value(& c->ns, NMSPFLOOR_DEFAULT, "#", v_parent);
616     /* ^^^ adding # to the namespace removes all spurious error messages
617      *     for parent == NULL.
618      */
619     Value_Unlink(v_parent);
620   }
621 
622   /* Invoke the opening procedure */
623   if (box->attr.box.parent != NULL) {
624     Value_Link(& c->value.begin);
625     (void) Value_Emit_Call_Or_Blacklist(parent, & c->value.begin);
626   }
627 
628   /* Create jump-labels for If and For */
629   jump_label_begin = BoxVMCode_Jump_Label_Here(c->cur_proc);
630   jump_label_next = BoxVMCode_Jump_Label_New(c->cur_proc);
631   jump_label_end = BOXVMSYMID_NONE;
632 
633   /* Save previous source position */
634   BoxSrc *prev_src_of_err = Msg_Set_Src(& box->src);
635 
636   need_floor_down = BOXBOOL_FALSE;
637 
638   /* Loop over all the statements of the box */
639   for(s = box->attr.box.first_statement, state = MYBOXSTATE_INITIAL;
640       s != NULL;
641       s = s->attr.statement.next_statement) {
642 
643     Value *stmt_val;
644 
645     /* Set the source position to the current statement */
646     Msg_Set_Src(& s->src);
647 
648     My_Compile_Statement(c, s);
649     stmt_val = BoxCmp_Pop_Value(c);
650 
651     if (!(parent_is_err || Value_Is_Ignorable(stmt_val))) {
652       if (Value_Want_Has_Type(stmt_val)) {
653         BoxTask emit_task;
654         stmt_val = Value_Emit_Call(parent, stmt_val, & emit_task);
655 
656         if (stmt_val) {
657           assert(emit_task == BOXTASK_FAILURE);
658 
659           /* Handle the case where stmt_val is an If[] or For[] value */
660           if (BoxType_Compare(stmt_val->type,
661                               Box_Get_Core_Type(BOXTYPEID_IF))) {
662             Value_Emit_CJump(stmt_val, jump_label_next);
663 
664             if (state != MYBOXSTATE_GOT_IF) {
665               assert(!need_floor_down);
666               Namespace_Floor_Up(& c->ns);
667               need_floor_down = BOXBOOL_TRUE;
668             }
669             state = MYBOXSTATE_GOT_IF;
670 
671 #if 0
672           } else if (BoxType_Compare(stmt_val->type,
673                                    Box_Get_Core_Type(BOXTYPEID_ELIF))) {
674             if (jump_label_end == BOXVMSYMID_NONE)
675               jump_label_end = BoxVMCode_Jump_Label_New(c->cur_proc);
676             BoxVMCode_Assemble_Jump(c->cur_proc, jump_label_end);
677             BoxVMCode_Jump_Label_Define(c->cur_proc, jump_label_next);
678             BoxVMCode_Jump_Label_Release(c->cur_proc, jump_label_next);
679             jump_label_next = BoxVMCode_Jump_Label_New(c->cur_proc);
680             Value_Emit_CJump(stmt_val, jump_label_next);
681 
682             if (state != MYBOXSTATE_GOT_IF) {
683               assert(!need_floor_down);
684               Namespace_Floor_Up(& c->ns);
685               need_floor_down = BOXBOOL_TRUE;
686             }
687             state = MYBOXSTATE_GOT_IF;
688 #endif
689           } else if (BoxType_Compare(stmt_val->type,
690                                      Box_Get_Core_Type(BOXTYPEID_ELSE))) {
691             if (state == MYBOXSTATE_GOT_IF) {
692               if (jump_label_end == BOXVMSYMID_NONE)
693                 jump_label_end = BoxVMCode_Jump_Label_New(c->cur_proc);
694               BoxVMCode_Assemble_Jump(c->cur_proc, jump_label_end);
695               BoxVMCode_Jump_Label_Define(c->cur_proc, jump_label_next);
696               BoxVMCode_Jump_Label_Release(c->cur_proc, jump_label_next);
697               jump_label_next = BoxVMCode_Jump_Label_New(c->cur_proc);
698 
699               assert(need_floor_down);
700               Namespace_Floor_Down(& c->ns);
701               need_floor_down = BOXBOOL_FALSE;
702 
703             } else {
704               if (state == MYBOXSTATE_GOT_ELSE)
705                 MSG_ERROR("Double 'Else'.");
706               else
707                 MSG_ERROR("'Else' without 'If'.");
708             }
709             Value_Unlink(stmt_val);
710             state = MYBOXSTATE_GOT_ELSE;
711 
712           } else if (BoxType_Compare(stmt_val->type,
713                                      Box_Get_Core_Type(BOXTYPEID_FOR)))
714             Value_Emit_CJump(stmt_val, jump_label_begin);
715 
716           else {
717             MSG_WARNING("Don't know how to use '%T' expressions inside "
718                         "a '%T' box.", stmt_val->type, parent->type);
719             Value_Unlink(stmt_val);
720           }
721 
722           stmt_val = NULL; /* To prevent double unlink */
723         }
724       }
725     }
726 
727     Value_Unlink(stmt_val);
728   }
729 
730   if (need_floor_down)
731     Namespace_Floor_Down(& c->ns);
732 
733   /* Restore previous source position */
734   (void) Msg_Set_Src(prev_src_of_err);
735 
736   /* Define the end label and release it together with the begin label */
737   BoxVMCode_Jump_Label_Define(c->cur_proc, jump_label_next);
738   BoxVMCode_Jump_Label_Release(c->cur_proc, jump_label_begin);
739   BoxVMCode_Jump_Label_Release(c->cur_proc, jump_label_next);
740 
741   /* Define the end label, if used at all! */
742   if (jump_label_end != BOXVMSYMID_NONE) {
743     BoxVMCode_Jump_Label_Define(c->cur_proc, jump_label_end);
744     BoxVMCode_Jump_Label_Release(c->cur_proc, jump_label_end);
745   }
746 
747   /* Invoke the closing procedure */
748   if (box->attr.box.parent) {
749     Value_Link(& c->value.end);
750     (void) Value_Emit_Call_Or_Blacklist(parent, & c->value.end);
751   }
752 
753   Namespace_Floor_Down(& c->ns); /* close the scope unit */
754 
755   if (outer_parent)
756     Value_Unlink(outer_parent);
757 }
758 
My_Compile_String(BoxCmp * c,ASTNode * node)759 static void My_Compile_String(BoxCmp *c, ASTNode *node) {
760   Value *v_str;
761 
762   assert(node->type == ASTNODETYPE_STRING);
763 
764   v_str = Value_New(c->cur_proc);
765   Value_Setup_As_String(v_str, node->attr.string.str);
766   BoxCmp_Push_Value(c, v_str);
767 }
768 
My_Compile_Var(BoxCmp * c,ASTNode * n)769 static void My_Compile_Var(BoxCmp *c, ASTNode *n) {
770   Value *v;
771   char *item_name = n->attr.var.name;
772 
773   assert(n->type == ASTNODETYPE_VAR);
774 
775   v = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, item_name);
776   if (v != NULL) {
777     /* We just return a copy of the Value object corresponding to the
778      * variable
779      */
780     Value *v_copy = Value_New(c->cur_proc);
781     Value_Setup_As_Weak_Copy(v_copy, v);
782     BoxCmp_Push_Value(c, v_copy);
783     Value_Unlink(v);
784 
785   } else {
786     v = Value_New(c->cur_proc);
787     Value_Setup_As_Var_Name(v, item_name);
788     Namespace_Add_Value(& c->ns, NMSPFLOOR_DEFAULT, item_name, v);
789     BoxCmp_Push_Value(c, v);
790   }
791 }
792 
My_Compile_Ignore(BoxCmp * c,ASTNode * n)793 static void My_Compile_Ignore(BoxCmp *c, ASTNode *n) {
794   Value *operand;
795 
796   assert(n->type == ASTNODETYPE_IGNORE);
797 
798   /* Compile operand and get it from the stack */
799   My_Compile_Any(c, n->attr.ignore.expr);
800   operand = BoxCmp_Get_Value(c, 0);
801 
802   Value_Set_Ignorable(operand, n->attr.ignore.ignore);
803 }
804 
My_Compile_Const(BoxCmp * c,ASTNode * n)805 static void My_Compile_Const(BoxCmp *c, ASTNode *n) {
806   Value *v;
807   assert(n->type == ASTNODETYPE_CONST);
808   v = Value_New(c->cur_proc);
809   switch(n->attr.constant.type) {
810   case ASTCONSTTYPE_CHAR:
811     Value_Setup_As_Imm_Char(v, n->attr.constant.value.c);
812     break;
813   case ASTCONSTTYPE_INT:
814     Value_Setup_As_Imm_Int(v, n->attr.constant.value.i);
815     break;
816   case ASTCONSTTYPE_REAL:
817     Value_Setup_As_Imm_Real(v, n->attr.constant.value.r);
818     break;
819   }
820   BoxCmp_Push_Value(c, v);
821 }
822 
My_Compile_UnOp(BoxCmp * c,ASTNode * n)823 static void My_Compile_UnOp(BoxCmp *c, ASTNode *n) {
824   Value *operand, *v_result = NULL;
825 
826   assert(n->type == ASTNODETYPE_UNOP);
827 
828   /* Compile operand and get it from the stack */
829   My_Compile_Any(c, n->attr.un_op.expr);
830   if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push err */ 1))
831     return;
832 
833   operand = BoxCmp_Pop_Value(c);
834   if (Value_Want_Value(operand))
835     v_result = BoxCmp_Opr_Emit_UnOp(c, n->attr.un_op.operation, operand);
836   else
837     Value_Unlink(operand);
838 
839   BoxCmp_Push_Value(c, v_result);
840 }
841 
842 /** Deal with assignments.
843  * REFERENCES: result: new, left: -1, right: -1;
844  */
My_Compile_Assignment(BoxCmp * c,Value * left,Value * right)845 static Value *My_Compile_Assignment(BoxCmp *c, Value *left, Value *right) {
846   if (Value_Want_Value(right)) {
847     /* Subtypes are always expanded in assignments */
848     left = Value_Expand_Subtype(left);
849     /* ^^^ XXX NOTE: The species expansion above is used to allow
850      * the following:
851      *
852      *   P = Point
853      *   P.Y = Real
854      *   P.Y[$$ = $.y]
855      *
856      * To expand $$ to the child and assign to it the value 1.
857      * If we remove this expansion, then $$ = $.y fails, because $$ is seen as
858      * an object of type P.Y, rather than an object of type Real.
859      */
860     right = Value_Expand_Subtype(right);
861     /* XXX NOTE: The line above will never allow one to have a variable with
862      * type X.Y
863      * Can we live with that?
864      * Maybe, we should expand types only when necessary...
865      */
866 
867     /* If the value is an identifier (thing without type, nor value),
868      * then we transform it to a proper target.
869      */
870     if (BoxValue_Is_Var_Name(left)) {
871       BoxValue_Assign(left, right);
872       Value_Set_Ignorable(left, 1);
873       return left;
874 
875     } else if (Value_Is_Target(left)) {
876       Value_Move_Content(left, right);
877       Value_Set_Ignorable(left, 1);
878       /*return BoxCmp_Opr_Emit_BinOp(c, ASTBINOP_ASSIGN, left, right);*/
879       return left;
880 
881     } else {
882       MSG_ERROR("Invalid target for assignment (%s).",
883                 ValueKind_To_Str(left->kind));
884       Value_Unlink(left);
885       Value_Unlink(right);
886       return NULL;
887     }
888 
889   } else {
890     Value_Unlink(left);
891     Value_Unlink(right);
892     return NULL;
893   }
894 }
895 
My_Compile_BinOp(BoxCmp * c,ASTNode * n)896 static void My_Compile_BinOp(BoxCmp *c, ASTNode *n) {
897   assert(n->type == ASTNODETYPE_BINOP);
898 
899   My_Compile_Any(c, n->attr.bin_op.left);
900   My_Compile_Any(c, n->attr.bin_op.right);
901   if (BoxCmp_Pop_Errors(c, /* pop */ 2, /* push err */ 1))
902     return;
903 
904   else {
905     Value *left, *right, *result = NULL;
906     ASTBinOp op;
907 
908     /* Get values from stack */
909     right = BoxCmp_Pop_Value(c);
910     left  = BoxCmp_Pop_Value(c);
911 
912     op = n->attr.bin_op.operation;
913     if (op == ASTBINOP_ASSIGN) {
914       result = My_Compile_Assignment(c, left, right);
915 
916     } else {
917       if (Value_Want_Value(left) & Value_Want_Value(right))
918         /* NOTE: ^^^ We use & rather than &&*/
919         result = BoxCmp_Opr_Emit_BinOp(c, op, left, right);
920       else {
921         Value_Unlink(left);
922         Value_Unlink(right);
923       }
924     }
925 
926     BoxCmp_Push_Value(c, result);
927   }
928 }
929 
My_Compile_Struc(BoxCmp * c,ASTNode * n)930 static void My_Compile_Struc(BoxCmp *c, ASTNode *n) {
931   int i, num_members;
932   ASTNode *member;
933   BoxType *t_struc;
934   Value *v_struc;
935   ValueStrucIter vsi;
936   int no_err;
937 
938   assert(n->type == ASTNODETYPE_STRUC);
939 
940   /* Compile the members, check their types and leave them on the stack */
941   num_members = 0;
942   no_err = 1;
943   for(member = n->attr.struc.first_member;
944       member != NULL;
945       member = member->attr.member.next) {
946     Value *v_member;
947 
948     assert(member->type == ASTNODETYPE_MEMBER);
949 
950     My_Compile_Any(c, member->attr.member.expr);
951     v_member = BoxCmp_Get_Value(c, 0);
952 
953     no_err &= Value_Want_Value(v_member);
954 
955     ++num_members;
956   }
957 
958   /* Check for errors */
959   if (!no_err) {
960     BoxCmp_Remove_Any(c, num_members);
961     BoxCmp_Push_Error(c, 1);
962     return;
963   }
964 
965   /* built the type for the structure */
966   i = num_members;
967   t_struc = BoxType_Create_Structure();
968   for(member = n->attr.struc.first_member; member;
969       member = member->attr.member.next) {
970     Value *v_member = BoxCmp_Get_Value(c, --i);
971     BoxType_Add_Member_To_Structure(t_struc, v_member->type,
972                                     member->attr.member.name);
973   }
974 
975   /* create and populate the structure */
976   v_struc = Value_New(c->cur_proc);
977   Value_Setup_As_Temp(v_struc, t_struc);
978 
979   for(ValueStrucIter_Init(& vsi, v_struc, c->cur_proc);
980       vsi.has_next; ValueStrucIter_Do_Next(& vsi)) {
981     Value *v_member = BoxCmp_Get_Value(c, num_members - vsi.index - 1);
982     Value_Link(v_member);
983     Value_Move_Content(& vsi.v_member, v_member);
984   }
985 
986   ValueStrucIter_Finish(& vsi);
987 
988   BoxCmp_Remove_Any(c, num_members);
989   BoxCmp_Push_Value(c, v_struc);
990 }
991 
My_Compile_MemberGet(BoxCmp * c,ASTNode * n)992 static void My_Compile_MemberGet(BoxCmp *c, ASTNode *n) {
993   Value *v_struc, *v_memb = NULL;
994   ASTNode *n_struc;
995 
996   assert(n->type == ASTNODETYPE_MEMBERGET);
997 
998   n_struc = n->attr.member_get.struc;
999   if (n_struc == NULL) {
1000     v_struc = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "#");
1001     if (v_struc == NULL) {
1002       MSG_ERROR("Cannot get implicit member '%s'. Default parent is not "
1003                 "defined in current scope.", n->attr.member_get.member);
1004       BoxCmp_Push_Value(c, NULL);
1005       return;
1006     }
1007 
1008   } else {
1009     My_Compile_Any(c, n_struc);
1010     v_struc = BoxCmp_Pop_Value(c);
1011   }
1012 
1013   if (Value_Want_Value(v_struc)) {
1014     v_memb = Value_Struc_Get_Member(v_struc, n->attr.member_get.member);
1015     /* No need to unlink v_struc here */
1016     if (v_memb == NULL)
1017       MSG_ERROR("Cannot find the member '%s' of an object with type '%T'.",
1018                 n->attr.member_get.member, v_struc->type);
1019 
1020   } else
1021     Value_Unlink(v_struc);
1022 
1023   BoxCmp_Push_Value(c, v_memb);
1024 }
1025 
My_Compile_SubtypeBld(BoxCmp * c,ASTNode * n)1026 static void My_Compile_SubtypeBld(BoxCmp *c, ASTNode *n) {
1027   Value *v_parent = NULL, *v_result = NULL;
1028 
1029   assert(n->type == ASTNODETYPE_SUBTYPEBLD);
1030 
1031   if (n->attr.subtype_bld.parent != NULL) {
1032     My_Compile_Any(c, n->attr.subtype_bld.parent);
1033     if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push err */ 1))
1034       return;
1035     v_parent = BoxCmp_Pop_Value(c);
1036 
1037   } else {
1038     v_parent = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "#");
1039     if (v_parent == NULL) {
1040       MSG_ERROR("Cannot get implicit method '%s'. Default parent is not "
1041                 "defined in current scope.", n->attr.subtype_bld.subtype);
1042     }
1043   }
1044 
1045   if (v_parent != NULL) {
1046     if (Value_Want_Value(v_parent))
1047         v_result = Value_Subtype_Build(v_parent, n->attr.subtype_bld.subtype);
1048     else
1049         Value_Unlink(v_parent);
1050   }
1051 
1052   BoxCmp_Push_Value(c, v_result);
1053 }
1054 
My_Compile_SelfGet(BoxCmp * c,ASTNode * n)1055 static void My_Compile_SelfGet(BoxCmp *c, ASTNode *n) {
1056   Value *v_self = NULL;
1057   const char *n_self = NULL;
1058   ASTSelfLevel self_level = n->attr.self_get.level;
1059   int i, promote_to_target = 0, return_weak_copy = 0;
1060 
1061   assert(n->type == ASTNODETYPE_SELFGET);
1062 
1063   switch (self_level) {
1064   case 1:
1065     n_self = "$";
1066     v_self = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "$");
1067     return_weak_copy = 1;
1068     break;
1069 
1070   case 2:
1071     n_self = "$$";
1072     v_self = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "$$");
1073 //     v_self = Value_Subtype_Get_Child(v_self); /* WARNING remove that later */
1074     promote_to_target = 1;
1075     return_weak_copy = 1;
1076     break;
1077 
1078   default:
1079     n_self = "$$, $3, ...";
1080     v_self = Namespace_Get_Value(& c->ns, NMSPFLOOR_DEFAULT, "$$");
1081     for (i = 2; i < self_level && v_self != NULL; i++)
1082       v_self = Value_Subtype_Get_Parent(v_self);
1083       /* FIXME: see Value_Init */
1084     promote_to_target = 1;
1085     return_weak_copy = 0;
1086   }
1087 
1088   if (v_self == NULL) {
1089     MSG_ERROR("%s not defined in the current scope.", n_self);
1090 
1091   } else {
1092     /* Return only a weak copy? */
1093     if (return_weak_copy) {
1094       Value *v_copy = Value_New(c->cur_proc);
1095       Value_Setup_As_Weak_Copy(v_copy, v_self);
1096       Value_Unlink(v_self);
1097       v_self = v_copy;
1098     }
1099 
1100     if (promote_to_target)
1101       v_self = Value_Promote_Temp_To_Target(v_self);
1102   }
1103 
1104   BoxCmp_Push_Value(c, v_self);
1105 }
1106 
My_Compile_ProcDef(BoxCmp * c,ASTNode * n)1107 static void My_Compile_ProcDef(BoxCmp *c, ASTNode *n) {
1108   Value *v_child, *v_parent, *v_ret = NULL;
1109   BoxCombType comb_type;
1110   ASTNode *n_c_name = n->attr.proc_def.c_name,
1111           *n_implem = n->attr.proc_def.implem;
1112   char *c_name = NULL;
1113   BoxType *t_child, *t_parent, *comb;
1114   BoxCallable *comb_callable;
1115   int no_err;
1116 
1117   assert(n->type == ASTNODETYPE_PROCDEF);
1118 
1119   /* first, get the type of child and parent */
1120   My_Compile_Any(c, n->attr.proc_def.child_type);
1121   v_child = BoxCmp_Pop_Value(c);
1122   My_Compile_Any(c, n->attr.proc_def.parent_type);
1123   v_parent = BoxCmp_Pop_Value(c);
1124   comb_type = n->attr.proc_def.combine;
1125 
1126   no_err = Value_Want_Has_Type(v_child) & Value_Want_Has_Type(v_parent);
1127 
1128   /* Get the types from the values, and destroy the latters. */
1129   t_child = BoxType_Link(v_child->type);
1130   t_parent = BoxType_Link(v_parent->type);
1131   Value_Unlink(v_child);
1132   Value_Unlink(v_parent);
1133 
1134   /* now get the C-name, if present */
1135   if (n_c_name) {
1136     assert(n_c_name->type == ASTNODETYPE_STRING);
1137     c_name = n_c_name->attr.string.str;
1138     if (strlen(c_name) < 1) {
1139       /* NOTE: Should we test any other kind of "badness"? */
1140       MSG_ERROR("Empty string in C-name for procedure declaration.");
1141       no_err = 0;
1142     }
1143   }
1144 
1145   /* Now let's find whether a procedure of this kind is already registered. */
1146   if (!no_err) {
1147     /* For now we cowardly refuse to examine the body of the procedure
1148      * and immediately exit pushing an error.
1149      */
1150     BoxCmp_Push_Value(c, v_ret);
1151     (void) BoxType_Unlink(t_child);
1152     (void) BoxType_Unlink(t_parent);
1153     return;
1154   }
1155 
1156   /* Try to find the combination, if already defined. */
1157   comb_callable = NULL;
1158   comb = BoxType_Find_Own_Combination(t_parent, comb_type, t_child, NULL);
1159 
1160   if (comb) {
1161     /* A combination of this kind is already defined: we need to know if
1162      * it is implemented or not.
1163      */
1164     BoxCallable *cb;
1165     BoxBool success, is_already_implemented, has_name;
1166 
1167     success = BoxType_Get_Combination_Info(comb, NULL, & cb);
1168     assert(success);
1169 
1170     is_already_implemented = BoxCallable_Is_Implemented(cb);
1171     has_name = (BoxCallable_Get_Uid(cb) != NULL);
1172 
1173     /* If the procedure is not implemented and has no name then we re-use
1174      * the previous one, without covering the old definition.
1175      */
1176     if (!is_already_implemented && !has_name)
1177       comb_callable = cb;
1178 
1179     /* The following means that X@Y ? has no effect if X@Y is already
1180      * registered (no matter if defined or undefined)
1181      */
1182     if (!c_name && !n_implem)
1183       comb_callable = cb;
1184   }
1185 
1186   /* Define the combination, if necessary. */
1187   if (!comb_callable) {
1188     comb_callable = BoxCallable_Create_Undefined(t_parent, t_child);
1189     comb = BoxType_Define_Combination(t_parent, comb_type, t_child,
1190                                       comb_callable);
1191     Namespace_Add_Procedure(& c->ns, NMSPFLOOR_DEFAULT, t_parent, comb);
1192   }
1193 
1194   /* Set the C-name of the procedure, if given. */
1195   if (c_name) {
1196     BoxCallable_Set_Uid(comb_callable, c_name);
1197     if (!n_implem)
1198       BoxVMSym_Reference_Proc(c->vm, comb_callable);
1199   }
1200 
1201   /* If an implementation is also provided, then we define the procedure */
1202   if (n_implem) {
1203     /* we have the implementation */
1204     BoxVMCode *save_cur_proc = c->cur_proc;
1205     Value *v_implem;
1206     BoxVMCode proc_implem;
1207     BoxVMCallNum cn;
1208 
1209     /* A BoxVMCode object is used to get the procedure symbol and to register
1210      * and assemble it.
1211      */
1212     BoxVMCode_Init(& proc_implem, c, BOXVMCODESTYLE_SUB);
1213 
1214     /* Set the call number. */
1215     if (!BoxType_Generate_Combination_Call_Num(comb, c->vm, & cn))
1216       MSG_FATAL("Cannot generate call number for combination.");
1217     proc_implem.have.call_num = 1;
1218     proc_implem.call_num = cn;
1219 
1220     /* Set the alternative name to make the bytecode more readable */
1221     {
1222       char *alter_name = BoxType_Get_Repr(comb);
1223       assert(alter_name);
1224 
1225       BoxVMCode_Set_Alter_Name(& proc_implem, alter_name);
1226       Box_Mem_Free(alter_name);
1227     }
1228 
1229     /* We change target of the compilation to the new procedure */
1230     c->cur_proc = & proc_implem;
1231 
1232     /* Specify the prototype for the procedure */
1233     BoxVMCode_Set_Prototype(& proc_implem,
1234                             !BoxType_Is_Empty(t_child),
1235                             !BoxType_Is_Empty(t_parent));
1236 
1237     My_Compile_Box(c, n_implem, t_child, t_parent);
1238     v_implem = BoxCmp_Pop_Value(c);
1239     /* NOTE: we should double check that this is void! */
1240     Value_Unlink(v_implem);
1241 
1242     c->cur_proc = save_cur_proc;
1243 
1244     (void) BoxVMCode_Install(& proc_implem);
1245 
1246     BoxVMCode_Finish(& proc_implem);
1247   }
1248 
1249   (void) BoxType_Unlink(t_child);
1250   (void) BoxType_Unlink(t_parent);
1251 
1252   /* NOTE: for now we return Void[]. In future extensions we'll return
1253    * a function object
1254    */
1255   v_ret = My_Get_Void_Value(c);
1256 
1257   /* for now we return v_ret = NULL. We'll return a function, when Box will
1258    * support functions.
1259    */
1260   BoxCmp_Push_Value(c, v_ret);
1261 }
1262 
My_Compile_TypeDef(BoxCmp * c,ASTNode * n)1263 static void My_Compile_TypeDef(BoxCmp *c, ASTNode *n) {
1264   Value *v_name, *v_type, *v_named_type = NULL;
1265 
1266   assert(n->type == ASTNODETYPE_TYPEDEF);
1267 
1268   My_Compile_Any(c, n->attr.type_def.name);
1269   My_Compile_Any(c, n->attr.type_def.src_type);
1270 
1271   v_type = BoxCmp_Pop_Value(c);
1272   v_name = BoxCmp_Pop_Value(c);
1273 
1274   if (Value_Want_Has_Type(v_type)) {
1275     if (Value_Is_Type_Name(v_name)) {
1276       Value *v;
1277       /* Create the new identity type. */
1278       BoxType *ident_type =
1279         BoxType_Create_Ident(BoxType_Link(v_type->type), v_name->name);
1280 
1281       /* Register the type in the proper namespace */
1282       v = Value_Create(c->cur_proc);
1283       Value_Setup_As_Type(v, ident_type);
1284       (void) BoxType_Unlink(ident_type);
1285       Namespace_Add_Value(& c->ns, NMSPFLOOR_DEFAULT, v_name->name, v);
1286 
1287       /* Return a copy of the created type */
1288       v_named_type = Value_Create(c->cur_proc);
1289       Value_Setup_As_Weak_Copy(v_named_type, v);
1290       Value_Unlink(v);
1291 
1292     } else if (Value_Has_Type(v_name)) {
1293       BoxType *t = v_name->type;
1294       if (BoxType_Is_Subtype(t)) {
1295         if (BoxType_Is_Registered_Subtype(t)) {
1296           BoxType *t_child;
1297           BoxBool success = BoxType_Get_Subtype_Info(t, NULL, NULL, & t_child);
1298           assert(success);
1299           if (BoxType_Compare(t_child, v_type->type) == BOXTYPECMP_DIFFERENT)
1300             MSG_ERROR("Inconsistent redefinition of type '%T': was '%T' "
1301                       "and is now '%T'", v_name->type, t_child, v_type->type);
1302 
1303         } else {
1304           (void) BoxType_Register_Subtype(t, v_type->type);
1305           /* ^^^ ignore state of success of operation */
1306         }
1307 
1308       } else if (BoxType_Compare(v_name->type, v_type->type)
1309                  == BOXTYPECMP_DIFFERENT) {
1310         MSG_ERROR("Inconsistent redefinition of type '%T.'", v_name->type);
1311       }
1312 
1313       v_named_type = v_type;
1314       Value_Link(v_type);
1315     }
1316   }
1317 
1318   Value_Unlink(v_type);
1319   Value_Unlink(v_name);
1320 
1321   BoxCmp_Push_Value(c, v_named_type);
1322 }
1323 
My_Compile_StrucType(BoxCmp * c,ASTNode * n)1324 static void My_Compile_StrucType(BoxCmp *c, ASTNode *n) {
1325   int err;
1326   ASTNode *member;
1327   BoxType *previous_type = NULL, *struc_type;
1328   Value *v_struc_type;
1329 
1330   assert(n->type == ASTNODETYPE_STRUCTYPE);
1331 
1332   /* Create a new structure type */
1333   struc_type = BoxType_Create_Structure();
1334 
1335   /* Compile the members, check their types and leave them on the stack */
1336   err = 0;
1337   for(member = n->attr.struc_type.first_member; member;
1338       member = member->attr.member_type.next) {
1339     char *member_name = member->attr.member_type.name;
1340 
1341     assert(member->type == ASTNODETYPE_MEMBERTYPE);
1342 
1343     if (member->attr.member_type.type) {
1344       Value *v_type;
1345       My_Compile_Any(c, member->attr.member_type.type);
1346       v_type = BoxCmp_Pop_Value(c);
1347       if (Value_Want_Has_Type(v_type))
1348         previous_type = v_type->type;
1349       else
1350         err = 1;
1351       Value_Unlink(v_type);
1352     } else {
1353       assert(member);
1354     }
1355 
1356     if (previous_type && !err) {
1357       /* Check for duplicate structure members */
1358       if (member_name) {
1359         if (BoxType_Find_Structure_Member(struc_type, member_name))
1360           MSG_ERROR("Duplicate member '%s' in structure type definition.",
1361                     member_name);
1362       }
1363 
1364       BoxType_Add_Member_To_Structure(struc_type, previous_type, member_name);
1365     }
1366   }
1367 
1368   /* Check for errors */
1369   if (err) {
1370     BoxCmp_Push_Error(c, 1);
1371     return;
1372 
1373   } else {
1374     v_struc_type = Value_Create(c->cur_proc);
1375     Value_Setup_As_Type(v_struc_type, struc_type);
1376     (void) BoxType_Unlink(struc_type);
1377     BoxCmp_Push_Value(c, v_struc_type);
1378   }
1379 }
1380 
My_Compile_SpecType(BoxCmp * c,ASTNode * n)1381 static void My_Compile_SpecType(BoxCmp *c, ASTNode *n) {
1382   BoxType *spec_type;
1383   Value *v_spec_type;
1384   ASTNode *member;
1385 
1386   assert(n->type == ASTNODETYPE_SPECTYPE);
1387 
1388   /* Create a new species type */
1389   spec_type = BoxType_Create_Species();
1390 
1391   for(member = n->attr.spec_type.first_member; member;
1392       member = member->attr.member_type.next) {
1393     Value *v_type;
1394 
1395     assert(member->type == ASTNODETYPE_MEMBERTYPE);
1396     assert(member->attr.member_type.name == NULL
1397            && member->attr.member_type.type != NULL);
1398 
1399     My_Compile_Any(c, member->attr.member_type.type);
1400     v_type = BoxCmp_Pop_Value(c);
1401 
1402     if (Value_Want_Has_Type(v_type)) {
1403       BoxType *memb_type = v_type->type;
1404       /* NOTE: should check for duplicate types in species */
1405       BoxType_Add_Member_To_Species(spec_type, memb_type);
1406     }
1407 
1408     Value_Unlink(v_type);
1409   }
1410 
1411   v_spec_type = Value_Create(c->cur_proc);
1412   Value_Setup_As_Type(v_spec_type, spec_type);
1413   (void) BoxType_Unlink(spec_type);
1414 
1415   BoxCmp_Push_Value(c, v_spec_type);
1416 }
1417 
My_Compile_RaiseType(BoxCmp * c,ASTNode * n)1418 static void My_Compile_RaiseType(BoxCmp *c, ASTNode *n) {
1419   Value *v_type, *v_inc_type = NULL;
1420 
1421   assert(n->type == ASTNODETYPE_RAISETYPE);
1422 
1423   My_Compile_Any(c, n->attr.raise_type.type);
1424   if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push err */ 1))
1425     return;
1426 
1427   v_type = BoxCmp_Pop_Value(c);
1428   if (Value_Want_Has_Type(v_type)) {
1429     BoxType *inc_type = BoxType_Create_Raised(BoxType_Link(v_type->type));
1430     v_inc_type = Value_Create(c->cur_proc);
1431     Value_Setup_As_Type(v_inc_type, inc_type);
1432     (void) BoxType_Unlink(inc_type);
1433   }
1434 
1435   BoxCmp_Push_Value(c, v_inc_type);
1436 }
1437 
My_Compile_Raise(BoxCmp * c,ASTNode * n)1438 static void My_Compile_Raise(BoxCmp *c, ASTNode *n) {
1439   Value *v_operand = NULL;
1440 
1441   assert(n->type == ASTNODETYPE_RAISE);
1442 
1443   My_Compile_Any(c, n->attr.raise.expr);
1444   if (BoxCmp_Pop_Errors(c, /* pop */ 1, /* push err */ 1))
1445     return;
1446 
1447   v_operand = BoxCmp_Pop_Value(c);
1448   if (Value_Want_Value(v_operand)) {
1449     v_operand = Value_Raise(v_operand);
1450 
1451   } else {
1452     Value_Unlink(v_operand);
1453     v_operand = NULL;
1454   }
1455 
1456   BoxCmp_Push_Value(c, v_operand);
1457 
1458 }
1459