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