1 //
2 //  gravity_ast.c
3 //  gravity
4 //
5 //  Created by Marco Bambini on 02/09/14.
6 //  Copyright (c) 2014 CreoLabs. All rights reserved.
7 //
8 
9 #include <inttypes.h>
10 #include "gravity_ast.h"
11 #include "gravity_hash.h"
12 #include "gravity_utils.h"
13 #include "gravity_visitor.h"
14 #include "gravity_symboltable.h"
15 
16 #define SETBASE(node,tagv,_tok)         node->base.tag = tagv; node->base.token = _tok
17 #define SETDECL(node,_decl)             node->base.decl = _decl
18 #define CHECK_REFCOUNT(_node)           if (_node->base.refcount > 0) {--_node->base.refcount; return;}
19 
20 // MARK: -
21 
void_array_create(void)22 void_r *void_array_create (void) {
23     void_r *r = mem_alloc(NULL, sizeof(void_r));
24     marray_init(*r);
25     return r;
26 }
27 
cstring_array_create(void)28 cstring_r *cstring_array_create (void) {
29     cstring_r *r = mem_alloc(NULL, sizeof(cstring_r));
30     gnode_array_init(r);
31     return r;
32 }
33 
gnode_array_create(void)34 gnode_r *gnode_array_create (void) {
35     gnode_r *r = mem_alloc(NULL, sizeof(gnode_r));
36     gnode_array_init(r);
37     return r;
38 }
39 
gnode_array_sethead(gnode_r * list,gnode_t * node)40 void gnode_array_sethead(gnode_r *list, gnode_t *node) {
41     if (!list || !node) return;
42 
43     // get old size
44     size_t list_size = gnode_array_size(list);
45 
46     // push node at the end to trigger memory allocation (if needed)
47     gnode_array_push(list, node);
48 
49     // shift elements in array
50     for (size_t i=list_size; i>0; --i) {
51         list->p[i] = list->p[i-1];
52     }
53 
54     // set new array head
55     list->p[0] = node;
56 }
57 
gnode_array_remove_byindex(gnode_r * old_list,size_t index)58 gnode_r *gnode_array_remove_byindex(gnode_r *old_list, size_t index) {
59     // get old size
60     size_t list_size = gnode_array_size(old_list);
61     if (index >= list_size) return NULL;
62 
63     gnode_r *new_list = gnode_array_create();
64     for (size_t i=0; i<list_size; ++i) {
65         if (i == index) continue;
66         gnode_t *node = gnode_array_get(old_list, i);
67         gnode_array_push(new_list, node);
68     }
69     gnode_array_free(old_list);
70     return new_list;
71 }
72 
gnode_function_add_upvalue(gnode_function_decl_t * f,gnode_var_t * symbol,uint16_t n)73 gupvalue_t *gnode_function_add_upvalue(gnode_function_decl_t *f, gnode_var_t *symbol, uint16_t n) {
74     // create uplist if necessary
75     if (!f->uplist) {
76         f->uplist = mem_alloc(NULL, sizeof(gupvalue_r));
77         gnode_array_init(f->uplist);
78     }
79 
80     // lookup symbol in uplist (if any)
81     gtype_array_each(f->uplist, {
82         // symbol already found in uplist so return its index
83         gnode_var_t *node = (gnode_var_t *)val->node;
84         if (strcmp(node->identifier, symbol->identifier) == 0) return val;
85     }, gupvalue_t *);
86 
87     // symbol not found in uplist so add it
88     gupvalue_t *upvalue = mem_alloc(NULL, sizeof(gupvalue_t));
89     upvalue->node = (gnode_t *)symbol;
90     upvalue->index = (n == 1) ? symbol->index : (uint32_t)gnode_array_size(f->uplist);
91     upvalue->selfindex = (uint32_t)gnode_array_size(f->uplist);
92     upvalue->is_direct = (n == 1);
93     marray_push(gupvalue_t*, *f->uplist, upvalue);
94 
95     // return symbol position in uplist
96     return upvalue;
97 }
98 
gnode2class(gnode_t * node,bool * isextern)99 gnode_t *gnode2class (gnode_t *node, bool *isextern) {
100     if (isextern) *isextern = false;
101 
102     if (NODE_ISA_CLASS(node)) {
103         gnode_class_decl_t *c = (gnode_class_decl_t *)node;
104         if (isextern) *isextern = (c->storage == TOK_KEY_EXTERN);
105         return node;
106     }
107     else if (NODE_ISA(node, NODE_VARIABLE)) {
108         gnode_var_t *var = (gnode_var_t *)node;
109         const char *class_manifest_type = gravity_class_class->identifier;
110         if ((var->annotation_type) && (string_cmp(var->annotation_type, class_manifest_type) == 0) && (NODE_ISA_CLASS(var->expr))) return var->expr;
111 
112         gnode_variable_decl_t *vdecl = var->vdecl;
113         if (vdecl && isextern && (vdecl->storage == TOK_KEY_EXTERN)) {
114             *isextern = true;
115             return node;
116         }
117     }
118     return NULL;
119 }
120 
121 // MARK: - Statements initializers -
122 
gnode_jump_stat_create(gtoken_s token,gnode_t * expr,gnode_t * decl)123 gnode_t *gnode_jump_stat_create (gtoken_s token, gnode_t *expr, gnode_t *decl) {
124     gnode_jump_stmt_t *node = (gnode_jump_stmt_t *)mem_alloc(NULL, sizeof(gnode_jump_stmt_t));
125 
126     SETBASE(node, NODE_JUMP_STAT, token);
127     SETDECL(node, decl);
128     node->expr = expr;
129     return (gnode_t *)node;
130 }
131 
gnode_label_stat_create(gtoken_s token,gnode_t * expr,gnode_t * stmt,gnode_t * decl)132 gnode_t *gnode_label_stat_create (gtoken_s token, gnode_t *expr, gnode_t *stmt, gnode_t *decl) {
133     gnode_label_stmt_t *node = (gnode_label_stmt_t *)mem_alloc(NULL, sizeof(gnode_label_stmt_t));
134 
135     SETBASE(node, NODE_LABEL_STAT, token);
136     SETDECL(node, decl);
137     node->expr = expr;
138     node->stmt = stmt;
139     return (gnode_t *)node;
140 }
141 
gnode_flow_stat_create(gtoken_s token,gnode_t * cond,gnode_t * stmt1,gnode_t * stmt2,gnode_t * decl,uint32_t block_length)142 gnode_t *gnode_flow_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt1, gnode_t *stmt2, gnode_t *decl, uint32_t block_length) {
143     gnode_flow_stmt_t *node = (gnode_flow_stmt_t *)mem_alloc(NULL, sizeof(gnode_flow_stmt_t));
144 
145     SETBASE(node, NODE_FLOW_STAT, token);
146     SETDECL(node, decl);
147 	node->base.block_length = block_length;
148     node->cond = cond;
149     node->stmt = stmt1;
150     node->elsestmt = stmt2;
151     return (gnode_t *)node;
152 }
153 
gnode_loop_stat_create(gtoken_s token,gnode_t * cond,gnode_t * stmt,gnode_t * expr,gnode_t * decl,uint32_t block_length)154 gnode_t *gnode_loop_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt, gnode_t *expr, gnode_t *decl, uint32_t block_length) {
155     gnode_loop_stmt_t *node = (gnode_loop_stmt_t *)mem_alloc(NULL, sizeof(gnode_loop_stmt_t));
156 
157     SETBASE(node, NODE_LOOP_STAT, token);
158     SETDECL(node, decl);
159     node->base.block_length = block_length;
160     node->cond = cond;
161     node->stmt = stmt;
162     node->expr = expr;
163     node->nclose = UINT32_MAX;
164     return (gnode_t *)node;
165 }
166 
gnode_block_stat_create(gnode_n type,gtoken_s token,gnode_r * stmts,gnode_t * decl,uint32_t block_length)167 gnode_t *gnode_block_stat_create (gnode_n type, gtoken_s token, gnode_r *stmts, gnode_t *decl, uint32_t block_length) {
168     gnode_compound_stmt_t *node = (gnode_compound_stmt_t *)mem_alloc(NULL, sizeof(gnode_compound_stmt_t));
169 
170     SETBASE(node, type, token);
171     SETDECL(node, decl);
172 	node->base.block_length = block_length;
173     node->stmts = stmts;
174     node->nclose = UINT32_MAX;
175     return (gnode_t *)node;
176 }
177 
gnode_empty_stat_create(gtoken_s token,gnode_t * decl)178 gnode_t *gnode_empty_stat_create (gtoken_s token, gnode_t *decl) {
179     gnode_empty_stmt_t *node = (gnode_empty_stmt_t *)mem_alloc(NULL, sizeof(gnode_empty_stmt_t));
180 
181     SETBASE(node, NODE_EMPTY_STAT, token);
182     SETDECL(node, decl);
183     return (gnode_t *)node;
184 }
185 
186 // MARK: - Declarations initializers -
187 
gnode_class_decl_create(gtoken_s token,const char * identifier,gtoken_t access_specifier,gtoken_t storage_specifier,gnode_t * superclass,gnode_r * protocols,gnode_r * declarations,bool is_struct,gnode_t * decl)188 gnode_t *gnode_class_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_t *superclass,
189                                   gnode_r *protocols, gnode_r *declarations, bool is_struct, gnode_t *decl) {
190     gnode_class_decl_t *node = (gnode_class_decl_t *)mem_alloc(NULL, sizeof(gnode_class_decl_t));
191     node->is_struct = is_struct;
192 
193     SETBASE(node, NODE_CLASS_DECL, token);
194     SETDECL(node, decl);
195     node->bridge = false;
196     node->identifier = identifier;
197     node->access = access_specifier;
198     node->storage = storage_specifier;
199     node->superclass = superclass;
200     node->protocols = protocols;
201     node->decls = declarations;
202     node->nivar = 0;
203     node->nsvar = 0;
204 
205     return (gnode_t *)node;
206 }
207 
gnode_module_decl_create(gtoken_s token,const char * identifier,gtoken_t access_specifier,gtoken_t storage_specifier,gnode_r * declarations,gnode_t * decl)208 gnode_t *gnode_module_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *declarations,  gnode_t *decl) {
209     gnode_module_decl_t *node = (gnode_module_decl_t *)mem_alloc(NULL, sizeof(gnode_module_decl_t));
210 
211     SETBASE(node, NODE_MODULE_DECL, token);
212     SETDECL(node, decl);
213     node->identifier = identifier;
214     node->access = access_specifier;
215     node->storage = storage_specifier;
216     node->decls = declarations;
217 
218     return (gnode_t *)node;
219 }
220 
gnode_enum_decl_create(gtoken_s token,const char * identifier,gtoken_t access_specifier,gtoken_t storage_specifier,symboltable_t * symtable,gnode_t * decl)221 gnode_t *gnode_enum_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, symboltable_t *symtable, gnode_t *decl) {
222     gnode_enum_decl_t *node = (gnode_enum_decl_t *)mem_alloc(NULL, sizeof(gnode_enum_decl_t));
223 
224     SETBASE(node, NODE_ENUM_DECL, token);
225     SETDECL(node, decl);
226     node->identifier = identifier;
227     node->access = access_specifier;
228     node->storage = storage_specifier;
229     node->symtable= symtable;
230 
231     return (gnode_t *)node;
232 }
233 
gnode_function_decl_create(gtoken_s token,const char * identifier,gtoken_t access_specifier,gtoken_t storage_specifier,gnode_r * params,gnode_compound_stmt_t * block,gnode_t * decl)234 gnode_t *gnode_function_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *params,
235                                      gnode_compound_stmt_t *block, gnode_t *decl) {
236     gnode_function_decl_t *node = (gnode_function_decl_t *)mem_alloc(NULL, sizeof(gnode_function_decl_t));
237 
238     SETBASE(node, NODE_FUNCTION_DECL, token);
239     SETDECL(node, decl);
240     node->identifier = identifier;
241     node->access = access_specifier;
242     node->storage = storage_specifier;
243     node->params = params;
244     node->block = block;
245     node->nlocals = 0;
246     node->uplist = NULL;
247 
248     return (gnode_t *)node;
249 }
250 
gnode_variable_decl_create(gtoken_s token,gtoken_t type,gtoken_t access_specifier,gtoken_t storage_specifier,gnode_r * declarations,gnode_t * decl)251 gnode_t *gnode_variable_decl_create (gtoken_s token, gtoken_t type, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *declarations, gnode_t *decl) {
252     gnode_variable_decl_t *node = (gnode_variable_decl_t *)mem_alloc(NULL, sizeof(gnode_variable_decl_t));
253 
254     SETBASE(node, NODE_VARIABLE_DECL, token);
255     SETDECL(node, decl);
256     node->type = type;
257     node->access = access_specifier;
258     node->storage = storage_specifier;
259     node->decls = declarations;
260 
261     return (gnode_t *)node;
262 }
263 
gnode_variable_create(gtoken_s token,const char * identifier,const char * annotation_type,gnode_t * expr,gnode_t * decl,gnode_variable_decl_t * vdecl)264 gnode_t *gnode_variable_create (gtoken_s token, const char *identifier, const char *annotation_type, gnode_t *expr, gnode_t *decl, gnode_variable_decl_t *vdecl) {
265     gnode_var_t *node = (gnode_var_t *)mem_alloc(NULL, sizeof(gnode_var_t));
266 
267     SETBASE(node, NODE_VARIABLE, token);
268     SETDECL(node, decl);
269     node->identifier = identifier;
270     node->annotation_type = annotation_type;
271     node->expr = expr;
272     node->vdecl = vdecl;
273     node->iscomputed = false;
274     return (gnode_t *)node;
275 }
276 
277 // MARK: - Expressions initializers -
278 
gnode_is_equal(gnode_t * node1,gnode_t * node2)279 bool gnode_is_equal (gnode_t *node1, gnode_t *node2) {
280     // very simple gnode verification for map key uniqueness
281     gnode_base_t *_node1 = (gnode_base_t *)node1;
282     gnode_base_t *_node2 = (gnode_base_t *)node2;
283     if (_node1->base.tag != _node2->base.tag) return false;
284     if (gnode_is_literal(node1)) {
285         gnode_literal_expr_t *e1 = (gnode_literal_expr_t *)node1;
286         gnode_literal_expr_t *e2 = (gnode_literal_expr_t *)node2;
287         if (e1->type != e2->type) return false;
288         // LITERAL_STRING, LITERAL_FLOAT, LITERAL_INT, LITERAL_BOOL, LITERAL_STRING_INTERPOLATED
289         if (e1->type == LITERAL_BOOL) return (e1->value.n64 == e2->value.n64);
290         if (e1->type == LITERAL_INT) return (e1->value.n64 == e2->value.n64);
291         if (e1->type == LITERAL_FLOAT) return (e1->value.d == e2->value.d);
292         if (e1->type == LITERAL_STRING) return (strcmp(e1->value.str, e2->value.str)==0);
293         // there is no way to check node equality for a LITERAL_STRING_INTERPOLATED at compile time
294     }
295     return false;
296 }
297 
gnode_is_expression(gnode_t * node)298 bool gnode_is_expression (gnode_t *node) {
299     gnode_base_t *_node = (gnode_base_t *)node;
300     return ((_node->base.tag >= NODE_BINARY_EXPR) && (_node->base.tag <= NODE_KEYWORD_EXPR));
301 }
302 
gnode_is_literal(gnode_t * node)303 bool gnode_is_literal (gnode_t *node) {
304     gnode_base_t *_node = (gnode_base_t *)node;
305     return (_node->base.tag == NODE_LITERAL_EXPR);
306 }
307 
gnode_is_literal_int(gnode_t * node)308 bool gnode_is_literal_int (gnode_t *node) {
309     if (gnode_is_literal(node) == false) return false;
310     gnode_literal_expr_t *_node = (gnode_literal_expr_t *)node;
311     return (_node->type == LITERAL_INT);
312 }
313 
gnode_is_literal_string(gnode_t * node)314 bool gnode_is_literal_string (gnode_t *node) {
315     if (gnode_is_literal(node) == false) return false;
316     gnode_literal_expr_t *_node = (gnode_literal_expr_t *)node;
317     return (_node->type == LITERAL_STRING);
318 }
319 
gnode_is_literal_number(gnode_t * node)320 bool gnode_is_literal_number (gnode_t *node) {
321     if (gnode_is_literal(node) == false) return false;
322     gnode_literal_expr_t *_node = (gnode_literal_expr_t *)node;
323     return (_node->type != LITERAL_STRING && _node->type != LITERAL_STRING_INTERPOLATED);
324 }
325 
gnode_binary_expr_create(gtoken_t op,gnode_t * left,gnode_t * right,gnode_t * decl)326 gnode_t *gnode_binary_expr_create (gtoken_t op, gnode_t *left, gnode_t *right, gnode_t *decl) {
327     if (!left || !right) return NULL;
328 
329     gnode_binary_expr_t    *node = (gnode_binary_expr_t *)mem_alloc(NULL, sizeof(gnode_binary_expr_t));
330     SETBASE(node, NODE_BINARY_EXPR, left->token);
331     SETDECL(node, decl);
332     node->op = op;
333     node->left = left;
334     node->right = right;
335     return (gnode_t *)node;
336 }
337 
gnode_unary_expr_create(gtoken_t op,gnode_t * expr,gnode_t * decl)338 gnode_t *gnode_unary_expr_create (gtoken_t op, gnode_t *expr, gnode_t *decl) {
339     if (!expr) return NULL;
340 
341     gnode_unary_expr_t *node = (gnode_unary_expr_t *)mem_alloc(NULL, sizeof(gnode_unary_expr_t));
342     SETBASE(node, NODE_UNARY_EXPR, expr->token);
343     SETDECL(node, decl);
344     node->op = op;
345     node->expr = expr;
346     return (gnode_t *)node;
347 }
348 
gnode_file_expr_create(gtoken_s token,cstring_r * list,gnode_t * decl)349 gnode_t *gnode_file_expr_create (gtoken_s token, cstring_r *list, gnode_t *decl) {
350     if (!list) return NULL;
351 
352     gnode_file_expr_t *node = (gnode_file_expr_t *)mem_alloc(NULL, sizeof(gnode_file_expr_t));
353     SETBASE(node, NODE_FILE_EXPR, token);
354     SETDECL(node, decl);
355     node->identifiers = list;
356     return (gnode_t *)node;
357 }
358 
gnode_identifier_expr_create(gtoken_s token,const char * identifier,const char * identifier2,gnode_t * decl)359 gnode_t *gnode_identifier_expr_create (gtoken_s token, const char *identifier, const char *identifier2, gnode_t *decl) {
360     if (!identifier) return NULL;
361 
362     gnode_identifier_expr_t *node = (gnode_identifier_expr_t *)mem_alloc(NULL, sizeof(gnode_identifier_expr_t));
363     SETBASE(node, NODE_IDENTIFIER_EXPR, token);
364     SETDECL(node, decl);
365     node->value = identifier;
366     node->value2 = identifier2;
367     return (gnode_t *)node;
368 }
369 
gnode_literal_dump(gnode_literal_expr_t * node,char * buffer,int buffersize)370 void gnode_literal_dump (gnode_literal_expr_t *node, char *buffer, int buffersize) {
371     switch (node->type) {
372         case LITERAL_STRING_INTERPOLATED: snprintf(buffer, buffersize, "INTERPOLATED: %d", (uint32_t)gnode_array_size(node->value.r)); break;
373         case LITERAL_STRING: snprintf(buffer, buffersize, "STRING: %.*s", node->len, node->value.str); break;
374         case LITERAL_FLOAT: snprintf(buffer, buffersize, "FLOAT: %.2f", node->value.d); break;
375         case LITERAL_INT: snprintf(buffer, buffersize, "INT: %" PRId64, (int64_t)node->value.n64); break;
376         case LITERAL_BOOL: snprintf(buffer, buffersize, "BOOL: %d", (int32_t)node->value.n64); break;
377         default: assert(0); // should never reach this point
378     }
379 }
380 
gnode_literal_value_expr_create(gtoken_s token,gliteral_t type,const char * s,double d,int64_t n64,gnode_t * decl)381 static gnode_t *gnode_literal_value_expr_create (gtoken_s token, gliteral_t type, const char *s, double d, int64_t n64, gnode_t *decl) {
382     gnode_literal_expr_t *node = (gnode_literal_expr_t *)mem_alloc(NULL, sizeof(gnode_literal_expr_t));
383 
384     SETBASE(node, NODE_LITERAL_EXPR, token);
385     SETDECL(node, decl);
386     node->type = type;
387     node->len = 0;
388 
389     switch (type) {
390         case LITERAL_STRING: node->value.str = (char *)s; break;
391         case LITERAL_FLOAT: node->value.d = d; node->len = (d < FLT_MAX) ? 32 : 64; break;
392         case LITERAL_INT: node->value.n64 = n64; node->len = (n64 < 2147483647) ? 32 : 64; break;
393         case LITERAL_BOOL: node->value.n64 = n64; node->len = 32; break;
394         case LITERAL_STRING_INTERPOLATED: break;
395         default: assert(0); // should never reach this point
396     }
397 
398     return (gnode_t *)node;
399 }
400 
gnode_string_interpolation_create(gtoken_s token,gnode_r * r,gnode_t * decl)401 gnode_t *gnode_string_interpolation_create (gtoken_s token, gnode_r *r, gnode_t *decl) {
402     gnode_literal_expr_t *node = (gnode_literal_expr_t *)gnode_literal_value_expr_create(token, LITERAL_STRING_INTERPOLATED, NULL, 0, 0, decl);
403     node->value.r = r;
404     return (gnode_t *)node;
405 }
406 
gnode_literal_string_expr_create(gtoken_s token,char * s,uint32_t len,bool allocated,gnode_t * decl)407 gnode_t *gnode_literal_string_expr_create (gtoken_s token, char *s, uint32_t len, bool allocated, gnode_t *decl) {
408     gnode_literal_expr_t *node = (gnode_literal_expr_t *)gnode_literal_value_expr_create(token, LITERAL_STRING, NULL, 0, 0, decl);
409 
410     node->len = len;
411     if (allocated) {
412         node->value.str = s;
413     } else {
414         node->value.str = (char *)mem_alloc(NULL, len+1);
415         memcpy((void *)node->value.str, (const void *)s, len);
416     }
417 
418     return (gnode_t *)node;
419 }
420 
gnode_literal_float_expr_create(gtoken_s token,double d,gnode_t * decl)421 gnode_t *gnode_literal_float_expr_create (gtoken_s token, double d, gnode_t *decl) {
422     return gnode_literal_value_expr_create(token, LITERAL_FLOAT, NULL, d, 0, decl);
423 }
424 
gnode_literal_int_expr_create(gtoken_s token,int64_t n,gnode_t * decl)425 gnode_t *gnode_literal_int_expr_create (gtoken_s token, int64_t n, gnode_t *decl) {
426     return gnode_literal_value_expr_create(token, LITERAL_INT, NULL, 0, n, decl);
427 }
428 
gnode_literal_bool_expr_create(gtoken_s token,int32_t n,gnode_t * decl)429 gnode_t *gnode_literal_bool_expr_create (gtoken_s token, int32_t n, gnode_t *decl) {
430     return gnode_literal_value_expr_create(token, LITERAL_BOOL, NULL, 0, n, decl);
431 }
432 
gnode_keyword_expr_create(gtoken_s token,gnode_t * decl)433 gnode_t *gnode_keyword_expr_create (gtoken_s token, gnode_t *decl) {
434     gnode_keyword_expr_t *node = (gnode_keyword_expr_t *)mem_alloc(NULL, sizeof(gnode_keyword_expr_t));
435 
436     SETBASE(node, NODE_KEYWORD_EXPR, token);
437     SETDECL(node, decl);
438     return (gnode_t *)node;
439 }
440 
gnode_postfix_subexpr_create(gtoken_s token,gnode_n type,gnode_t * expr,gnode_r * list,gnode_t * decl)441 gnode_t *gnode_postfix_subexpr_create (gtoken_s token, gnode_n type, gnode_t *expr, gnode_r *list, gnode_t *decl) {
442     gnode_postfix_subexpr_t *node = (gnode_postfix_subexpr_t *)mem_alloc(NULL, sizeof(gnode_postfix_subexpr_t));
443 
444     SETBASE(node, type, token);
445     SETDECL(node, decl);
446     if (type == NODE_CALL_EXPR)
447         node->args = list;
448     else
449         node->expr = expr;
450     return (gnode_t *)node;
451 }
452 
gnode_postfix_expr_create(gtoken_s token,gnode_t * id,gnode_r * list,gnode_t * decl)453 gnode_t *gnode_postfix_expr_create (gtoken_s token, gnode_t *id, gnode_r *list, gnode_t *decl) {
454     gnode_postfix_expr_t *node = (gnode_postfix_expr_t *)mem_alloc(NULL, sizeof(gnode_postfix_expr_t));
455 
456     SETBASE(node, NODE_POSTFIX_EXPR, token);
457     SETDECL(node, decl);
458     node->id = id;
459     node->list = list;
460     return (gnode_t *)node;
461 }
462 
gnode_list_expr_create(gtoken_s token,gnode_r * list1,gnode_r * list2,bool ismap,gnode_t * decl)463 gnode_t *gnode_list_expr_create (gtoken_s token, gnode_r *list1, gnode_r *list2, bool ismap, gnode_t *decl) {
464     gnode_list_expr_t *node = (gnode_list_expr_t *)mem_alloc(NULL, sizeof(gnode_list_expr_t));
465 
466     SETBASE(node, NODE_LIST_EXPR, token);
467     SETDECL(node, decl);
468     node->ismap = ismap;
469     node->list1 = list1;
470     node->list2 = list2;
471     return (gnode_t *)node;
472 }
473 
474 // MARK: -
475 
gnode_duplicate(gnode_t * node,bool deep)476 gnode_t *gnode_duplicate (gnode_t *node, bool deep) {
477     if (!node) return NULL;
478 
479     if (deep == true) {
480         // deep is true so I need to examine node and perform a real duplication (only of the outer nodes)
481         // deep is true ONLY when node can also be part of an assignment and its assignment flag can be
482         // true is node is on the left and false when node is on the right
483         // true flag is used only by adjust_assignment_expression in parser.c
484 
485         // node can be: identifier, file or postfix
486         if (NODE_ISA(node, NODE_IDENTIFIER_EXPR)) {
487             gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)node;
488             return gnode_identifier_expr_create(expr->base.token, string_dup(expr->value), (expr->value2) ? string_dup(expr->value2) : NULL, expr->base.decl);
489         } else if (NODE_ISA(node, NODE_FILE_EXPR)) {
490             gnode_file_expr_t *expr = (gnode_file_expr_t *)node;
491             cstring_r *list = cstring_array_create();
492             size_t count = gnode_array_size(expr->identifiers);
493             for (size_t i=0; i<count; ++i) {
494                 const char *identifier = gnode_array_get(expr->identifiers, i);
495                 cstring_array_push(list, string_dup(identifier));
496             }
497             return gnode_file_expr_create(expr->base.token, list, expr->base.decl);
498         } else if (NODE_ISA(node, NODE_POSTFIX_EXPR)) {
499             gnode_postfix_expr_t *expr = (gnode_postfix_expr_t *)node;
500             gnode_t *id = gnode_duplicate(expr->id, false);
501             gnode_r *list = gnode_array_create();
502             gnode_array_each(expr->list, {gnode_array_push(list, gnode_duplicate(val, false));});
503             return gnode_postfix_expr_create(expr->base.token, id, list, expr->base.decl);
504         } else {
505             // gnode_duplicate UNHANDLED case
506             return NULL;
507         }
508         // just return the original node and since it is invalid for an assignment a semantic error will be generated
509     }
510 
511     // it means that I can perform a light duplication where
512     // duplicating a node means increase its refcount so it isn't freed more than once
513     ++node->refcount;
514     return node;
515 }
516 
gnode_identifier(gnode_t * node)517 const char *gnode_identifier (gnode_t *node) {
518     if (NODE_ISA(node, NODE_VARIABLE)) return ((gnode_var_t *)node)->identifier;
519     if (NODE_ISA(node, NODE_CLASS_DECL)) return ((gnode_class_decl_t *)node)->identifier;
520     if (NODE_ISA(node, NODE_IDENTIFIER_EXPR)) return ((gnode_identifier_expr_t *)node)->value;
521 
522     if (NODE_ISA(node, NODE_FUNCTION_DECL)) return ((gnode_function_decl_t *)node)->identifier;
523     if (NODE_ISA(node, NODE_ENUM_DECL)) return ((gnode_enum_decl_t *)node)->identifier;
524     if (NODE_ISA(node, NODE_MODULE_DECL)) return ((gnode_module_decl_t *)node)->identifier;
525 
526     return NULL;
527 }
528 
529 // MARK: - AST deallocator -
530 
531 // STATEMENTS
free_list_stmt(gvisitor_t * self,gnode_compound_stmt_t * node)532 static void free_list_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
533     CHECK_REFCOUNT(node);
534     gnode_array_each(node->stmts, {visit(val);});
535     if (node->stmts) gnode_array_free(node->stmts);
536 
537     if (node->symtable) symboltable_free(node->symtable);
538     mem_free((gnode_t*)node);
539 }
540 
free_compound_stmt(gvisitor_t * self,gnode_compound_stmt_t * node)541 static void free_compound_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
542     CHECK_REFCOUNT(node);
543     gnode_array_each(node->stmts, {visit(val);});
544     if (node->stmts) gnode_array_free(node->stmts);
545 
546     if (node->symtable) symboltable_free(node->symtable);
547     mem_free((gnode_t*)node);
548 }
549 
free_label_stmt(gvisitor_t * self,gnode_label_stmt_t * node)550 static void free_label_stmt (gvisitor_t *self, gnode_label_stmt_t *node) {
551     CHECK_REFCOUNT(node);
552     if (node->expr) visit(node->expr);
553     if (node->stmt) visit(node->stmt);
554     mem_free((gnode_t*)node);
555 }
556 
free_flow_stmt(gvisitor_t * self,gnode_flow_stmt_t * node)557 static void free_flow_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
558     CHECK_REFCOUNT(node);
559     if (node->cond) visit(node->cond);
560     if (node->stmt) visit(node->stmt);
561     if (node->elsestmt) visit(node->elsestmt);
562     mem_free((gnode_t*)node);
563 }
564 
free_loop_stmt(gvisitor_t * self,gnode_loop_stmt_t * node)565 static void free_loop_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
566     CHECK_REFCOUNT(node);
567     if (node->stmt) visit(node->stmt);
568     if (node->cond) visit(node->cond);
569     if (node->expr) visit(node->expr);
570     mem_free((gnode_t*)node);
571 }
572 
free_jump_stmt(gvisitor_t * self,gnode_jump_stmt_t * node)573 static void free_jump_stmt (gvisitor_t *self, gnode_jump_stmt_t *node) {
574     CHECK_REFCOUNT(node);
575     if (node->expr) visit(node->expr);
576     mem_free((gnode_t*)node);
577 }
578 
free_empty_stmt(gvisitor_t * self,gnode_empty_stmt_t * node)579 static void free_empty_stmt (gvisitor_t *self, gnode_empty_stmt_t *node) {
580     #pragma unused(self)
581     CHECK_REFCOUNT(node);
582     mem_free((gnode_t*)node);
583 }
584 
free_variable(gvisitor_t * self,gnode_var_t * p)585 static void free_variable (gvisitor_t *self, gnode_var_t *p) {
586     CHECK_REFCOUNT(p);
587     if (p->identifier) mem_free((void *)p->identifier);
588     if (p->annotation_type) mem_free((void *)p->annotation_type);
589     if (p->expr) visit(p->expr);
590     mem_free((void *)p);
591 }
592 
free_function_decl(gvisitor_t * self,gnode_function_decl_t * node)593 static void free_function_decl (gvisitor_t *self, gnode_function_decl_t *node) {
594     CHECK_REFCOUNT(node);
595     if (node->symtable) symboltable_free(node->symtable);
596     if (node->identifier) mem_free((void *)node->identifier);
597     if (node->params) {
598         gnode_array_each(node->params, {free_variable(self, (gnode_var_t *)val);});
599         gnode_array_free(node->params);
600     }
601 
602     if (node->block) visit((gnode_t *)node->block);
603     if (node->uplist) {
604         gtype_array_each(node->uplist, {mem_free(val);}, gupvalue_t*);
605         gnode_array_free(node->uplist);
606     }
607     mem_free((gnode_t*)node);
608 }
609 
free_variable_decl(gvisitor_t * self,gnode_variable_decl_t * node)610 static void free_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
611     CHECK_REFCOUNT(node);
612     if (node->decls) {
613         gnode_array_each(node->decls, {free_variable(self, (gnode_var_t *)val);});
614         gnode_array_free(node->decls);
615     }
616     mem_free((gnode_t*)node);
617 }
618 
free_enum_decl(gvisitor_t * self,gnode_enum_decl_t * node)619 static void free_enum_decl (gvisitor_t *self, gnode_enum_decl_t *node) {
620     #pragma unused(self)
621     CHECK_REFCOUNT(node);
622     if (node->identifier) mem_free((void *)node->identifier);
623     if (node->symtable) symboltable_free(node->symtable);
624     mem_free((gnode_t*)node);
625 }
626 
free_class_decl(gvisitor_t * self,gnode_class_decl_t * node)627 static void free_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
628     CHECK_REFCOUNT(node);
629     if (node->identifier) mem_free((void *)node->identifier);
630     if (node->decls) {
631         gnode_array_each(node->decls, {visit(val);});
632         gnode_array_free(node->decls);
633     }
634     if (node->symtable) symboltable_free(node->symtable);
635     mem_free((gnode_t*)node);
636 }
637 
free_module_decl(gvisitor_t * self,gnode_module_decl_t * node)638 static void free_module_decl (gvisitor_t *self, gnode_module_decl_t *node) {
639     CHECK_REFCOUNT(node);
640     if (node->identifier) mem_free((void *)node->identifier);
641     if (node->decls) {
642         gnode_array_each(node->decls, {visit(val);});
643         gnode_array_free(node->decls);
644     }
645     if (node->symtable) symboltable_free(node->symtable);
646     mem_free((gnode_t*)node);
647 }
648 
free_binary_expr(gvisitor_t * self,gnode_binary_expr_t * node)649 static void free_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
650     CHECK_REFCOUNT(node);
651     if (node->left) visit(node->left);
652     if (node->right) visit(node->right);
653     mem_free((gnode_t*)node);
654 }
655 
free_unary_expr(gvisitor_t * self,gnode_unary_expr_t * node)656 static void free_unary_expr (gvisitor_t *self, gnode_unary_expr_t *node) {
657     CHECK_REFCOUNT(node);
658     if (node->expr) visit(node->expr);
659     mem_free((gnode_t*)node);
660 }
661 
free_postfix_subexpr(gvisitor_t * self,gnode_postfix_subexpr_t * subnode)662 static void free_postfix_subexpr (gvisitor_t *self, gnode_postfix_subexpr_t *subnode) {
663     CHECK_REFCOUNT(subnode);
664 
665     gnode_n tag = subnode->base.tag;
666     if (tag == NODE_CALL_EXPR) {
667         if (subnode->args) {
668             gnode_array_each(subnode->args, visit(val););
669             gnode_array_free(subnode->args);
670         }
671     } else {
672         visit(subnode->expr);
673     }
674 
675     mem_free((gnode_t*)subnode);
676 }
677 
free_postfix_expr(gvisitor_t * self,gnode_postfix_expr_t * node)678 static void free_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
679     CHECK_REFCOUNT(node);
680 
681     visit(node->id);
682 
683     // node->list can be NULL due to enum static conversion
684     size_t count = gnode_array_size(node->list);
685     for (size_t i=0; i<count; ++i) {
686         gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *) gnode_array_get(node->list, i);
687         free_postfix_subexpr(self, subnode);
688     }
689     if (node->list) gnode_array_free(node->list);
690     mem_free((gnode_t*)node);
691 }
692 
free_file_expr(gvisitor_t * self,gnode_file_expr_t * node)693 static void free_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
694     #pragma unused(self)
695     CHECK_REFCOUNT(node);
696     cstring_array_each(node->identifiers, {
697         mem_free((void *)val);
698     });
699 
700     if (node->identifiers) gnode_array_free(node->identifiers);
701     mem_free((void *)node);
702 }
703 
free_literal_expr(gvisitor_t * self,gnode_literal_expr_t * node)704 static void free_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
705     #pragma unused(self)
706     CHECK_REFCOUNT(node);
707     if (node->type == LITERAL_STRING) mem_free((void *)node->value.str);
708     else if (node->type == LITERAL_STRING_INTERPOLATED) {
709         gnode_array_each(node->value.r, {visit(val);})
710         gnode_array_free(node->value.r);
711     }
712     mem_free((void *)node);
713 }
714 
free_identifier_expr(gvisitor_t * self,gnode_identifier_expr_t * node)715 static void free_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *node) {
716     #pragma unused(self, node)
717     CHECK_REFCOUNT(node);
718     if (node->value) mem_free((void *)node->value);
719     if (node->value2) mem_free((void *)node->value2);
720     mem_free((void *)node);
721 }
722 
free_keyword_expr(gvisitor_t * self,gnode_keyword_expr_t * node)723 static void free_keyword_expr (gvisitor_t *self, gnode_keyword_expr_t *node) {
724     #pragma unused(self)
725     CHECK_REFCOUNT(node);
726     mem_free((void *)node);
727 }
728 
free_list_expr(gvisitor_t * self,gnode_list_expr_t * node)729 static void free_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
730     CHECK_REFCOUNT(node);
731     if (node->list1) {
732         gnode_array_each(node->list1, {visit(val);});
733         gnode_array_free(node->list1);
734     }
735     if (node->list2) {
736         gnode_array_each(node->list2, {visit(val);});
737         gnode_array_free(node->list2);
738     }
739     mem_free((gnode_t*)node);
740 }
741 
742 // MARK: -
743 
gnode_free(gnode_t * ast)744 void gnode_free (gnode_t *ast) {
745     gvisitor_t visitor = {
746         .nerr = 0,
747         .data = NULL,
748         .delegate = NULL,
749 
750         // COMMON
751         .visit_pre = NULL,
752         .visit_post = NULL,
753 
754         // STATEMENTS: 7
755         .visit_list_stmt = free_list_stmt,
756         .visit_compound_stmt = free_compound_stmt,
757         .visit_label_stmt = free_label_stmt,
758         .visit_flow_stmt = free_flow_stmt,
759         .visit_loop_stmt = free_loop_stmt,
760         .visit_jump_stmt = free_jump_stmt,
761         .visit_empty_stmt = free_empty_stmt,
762 
763         // DECLARATIONS: 5
764         .visit_function_decl = free_function_decl,
765         .visit_variable_decl = free_variable_decl,
766         .visit_enum_decl = free_enum_decl,
767         .visit_class_decl = free_class_decl,
768         .visit_module_decl = free_module_decl,
769 
770         // EXPRESSIONS: 7+1
771         .visit_binary_expr = free_binary_expr,
772         .visit_unary_expr = free_unary_expr,
773         .visit_file_expr = free_file_expr,
774         .visit_literal_expr = free_literal_expr,
775         .visit_identifier_expr = free_identifier_expr,
776         .visit_keyword_expr = free_keyword_expr,
777         .visit_list_expr = free_list_expr,
778         .visit_postfix_expr = free_postfix_expr
779     };
780 
781     gvisit(&visitor, ast);
782 }
783