2
0

gravity_codegen.c 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614
  1. //
  2. // gravity_codegen.c
  3. // gravity
  4. //
  5. // Created by Marco Bambini on 09/10/14.
  6. // Copyright (c) 2014 CreoLabs. All rights reserved.
  7. //
  8. #include "gravity_codegen.h"
  9. #include "gravity_symboltable.h"
  10. #include "gravity_optimizer.h"
  11. #include "gravity_visitor.h"
  12. #include "gravity_ircode.h"
  13. #include "gravity_utils.h"
  14. #include "gravity_array.h"
  15. #include "gravity_hash.h"
  16. typedef marray_t(gnode_class_decl_t *) gnode_class_r;
  17. struct codegen_t {
  18. gravity_object_r context;
  19. gnode_class_r superfix;
  20. gravity_vm *vm;
  21. };
  22. typedef struct codegen_t codegen_t;
  23. #define CONTEXT_PUSH(x) marray_push(gravity_object_t*, ((codegen_t *)self->data)->context, (gravity_object_t*)x)
  24. #define CONTEXT_POP() marray_pop(((codegen_t *)self->data)->context)
  25. #define CONTEXT_GET() marray_last(((codegen_t *)self->data)->context)
  26. #define CONTEXT_IS_MODULE(x) ((OBJECT_ISA_FUNCTION(x)) && (string_cmp(((gravity_function_t *)x)->identifier, INITMODULE_NAME) == 0))
  27. #define DECLARE_CONTEXT() gravity_object_t *context_object = CONTEXT_GET();
  28. #define DECLARE_FUNCTION_CONTEXT() DECLARE_CONTEXT(); \
  29. assert(OBJECT_ISA_FUNCTION(context_object)); \
  30. gravity_function_t *context_function = (gravity_function_t *)context_object;
  31. #define DECLARE_CLASS_CONTEXT() DECLARE_CONTEXT(); \
  32. assert(OBJECT_ISA_CLASS(context_object)); \
  33. gravity_class_t *context_class = (gravity_class_t *)context_object;
  34. #define DECLARE_CODE() DECLARE_FUNCTION_CONTEXT(); \
  35. ircode_t *code = (ircode_t *)context_function->bytecode;
  36. #define IS_IMPLICIT_SELF(_expr) (NODE_ISA(_expr, NODE_IDENTIFIER_EXPR) && \
  37. (((gnode_identifier_expr_t *)_expr)->location.type == LOCATION_CLASS_IVAR_SAME) && \
  38. (((gnode_identifier_expr_t *)_expr)->location.nup == 0) && \
  39. (((gnode_identifier_expr_t *)_expr)->location.index == UINT16_MAX))
  40. #define IS_SUPER(_expr) (NODE_ISA(_expr, NODE_KEYWORD_EXPR) && (((gnode_keyword_expr_t *)_expr)->base.token.type == TOK_KEY_SUPER))
  41. #define GET_VM() ((codegen_t *)self->data)->vm
  42. #define IS_LAST_LOOP(n1,n2) (n1+1==n2)
  43. #if 1
  44. #define CODEGEN_COUNT_REGISTERS(_n) uint32_t _n = ircode_register_count(code)
  45. #define CODEGEN_ASSERT_REGISTERS(_n1,_n2,_v) assert(_n2 -_n1 == (_v))
  46. #else
  47. #define CODEGEN_COUNT_REGISTERS(_n)
  48. #define CODEGEN_ASSERT_REGISTERS(_n1,_n2,_v)
  49. #endif
  50. // MARK: -
  51. static void report_error (gvisitor_t *self, gnode_t *node, const char *format, ...) {
  52. // increment internal error counter
  53. ++self->nerr;
  54. // get error callback (if any)
  55. void *data = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->xdata : NULL;
  56. gravity_error_callback error_fn = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->error_callback : NULL;
  57. // build error message
  58. char buffer[1024];
  59. va_list arg;
  60. if (format) {
  61. va_start (arg, format);
  62. vsnprintf(buffer, sizeof(buffer), format, arg);
  63. va_end (arg);
  64. }
  65. // setup error struct
  66. error_desc_t error_desc = {
  67. .code = 0,
  68. .lineno = node->token.lineno,
  69. .colno = node->token.colno,
  70. .fileid = node->token.fileid,
  71. .offset = node->token.position
  72. };
  73. // finally call error callback
  74. if (error_fn) error_fn(GRAVITY_ERROR_SEMANTIC, buffer, error_desc, data);
  75. else printf("%s\n", buffer);
  76. }
  77. // MARK: -
  78. static opcode_t token2opcode(gtoken_t op) {
  79. switch (op) {
  80. // BIT
  81. case TOK_OP_SHIFT_LEFT: return LSHIFT;
  82. case TOK_OP_SHIFT_RIGHT: return RSHIFT;
  83. case TOK_OP_BIT_NOT: return BNOT;
  84. case TOK_OP_BIT_AND: return BAND;
  85. case TOK_OP_BIT_OR: return BOR;
  86. case TOK_OP_BIT_XOR: return BXOR;
  87. // MATH
  88. case TOK_OP_ADD: return ADD;
  89. case TOK_OP_SUB: return SUB;
  90. case TOK_OP_DIV: return DIV;
  91. case TOK_OP_MUL: return MUL;
  92. case TOK_OP_REM: return REM;
  93. // NEG not handled here
  94. // COMPARISON
  95. case TOK_KEY_ISA: return ISA;
  96. case TOK_OP_LESS: return LT;
  97. case TOK_OP_GREATER: return GT;
  98. case TOK_OP_LESS_EQUAL: return LEQ;
  99. case TOK_OP_GREATER_EQUAL: return GEQ;
  100. case TOK_OP_ISEQUAL: return EQ;
  101. case TOK_OP_ISNOTEQUAL: return NEQ;
  102. case TOK_OP_ISIDENTICAL: return EQQ;
  103. case TOK_OP_ISNOTIDENTICAL: return NEQQ;
  104. case TOK_OP_PATTERN_MATCH: return MATCH;
  105. // LOGICAL
  106. case TOK_OP_AND: return AND;
  107. case TOK_OP_NOT: return NOT;
  108. case TOK_OP_OR: return OR;
  109. default: assert(0); break; // should never reach this point
  110. }
  111. assert(0);
  112. return NOT; // huehue, geddit?
  113. }
  114. #if 0
  115. static gravity_value_t literal2value (gnode_literal_expr_t *node) {
  116. if (node->type == LITERAL_STRING) return VALUE_FROM_STRING(NULL, node->value.str, node->len);
  117. if (node->type == LITERAL_FLOAT) return VALUE_FROM_FLOAT(node->value.d);
  118. if (node->type == LITERAL_INT) return VALUE_FROM_INT(node->value.n64);
  119. return VALUE_FROM_INT(node->value.n64); // default BOOLEAN case
  120. }
  121. static gravity_list_t *literals2list (gvisitor_t *self, gnode_r *r, uint32_t start, uint32_t stop) {
  122. gravity_list_t *list = gravity_list_new(GET_VM(), stop-start);
  123. for (uint32_t i=start; i<stop; ++i) {
  124. gnode_literal_expr_t *node = (gnode_literal_expr_t *)marray_get(*r, i);
  125. gravity_value_t value = literal2value(node);
  126. marray_push(gravity_value_t, list->array, value);
  127. }
  128. return list;
  129. }
  130. static gravity_map_t *literals2map (gvisitor_t *self, gnode_r *r1, gnode_r *r2, uint32_t start, uint32_t stop) {
  131. gravity_map_t *map = gravity_map_new(GET_VM(), stop-start);
  132. for (uint32_t i=start; i<stop; ++i) {
  133. gnode_literal_expr_t *_key = (gnode_literal_expr_t *)marray_get(*r1, i);
  134. gnode_literal_expr_t *_value = (gnode_literal_expr_t *)marray_get(*r2, i);
  135. // when here I am sure that both key and value are literals
  136. // so they can be LITERAL_STRING, LITERAL_FLOAT, LITERAL_INT, LITERAL_BOOL
  137. gravity_value_t key = literal2value(_key);
  138. gravity_value_t value = literal2value(_value);
  139. gravity_map_insert(NULL, map, key, value);
  140. }
  141. return map;
  142. }
  143. static gravity_map_t *enum2map (gvisitor_t *self, gnode_enum_decl_t *node) {
  144. uint32_t count = symboltable_count(node->symtable, 0);
  145. gravity_map_t *map = gravity_map_new(GET_VM(), count);
  146. // FixMe
  147. return map;
  148. }
  149. static bool check_literals_list (gvisitor_t *self, gnode_list_expr_t *node, bool ismap, size_t idxstart, size_t idxend, uint32_t dest) {
  150. DEBUG_CODEGEN("check_literal_list_expr");
  151. DECLARE_CODE();
  152. // first check if all nodes inside this chuck are all literals
  153. // and in this case apply a more efficient SETLIST variant
  154. for (size_t j=idxstart; j < idxend; ++j) {
  155. gnode_t *e = gnode_array_get(node->list1, j);
  156. if (!gnode_is_literal(e)) return false;
  157. if (ismap) {
  158. // additional check on key that must be a string literal in case of a map
  159. if (!gnode_is_literal_string(e)) return false;
  160. e = gnode_array_get(node->list2, j);
  161. if (!gnode_is_literal(e)) return false;
  162. }
  163. }
  164. // emit optimized (cpoll based) version
  165. gravity_value_t v;
  166. if (ismap) {
  167. gravity_map_t *map = literals2map(self, node->list1, node->list2, (uint32_t)idxstart, (uint32_t)idxend);
  168. v = VALUE_FROM_OBJECT(map);
  169. } else {
  170. gravity_list_t *list = literals2list(self, node->list1, (uint32_t)idxstart, (uint32_t)idxend);
  171. v = VALUE_FROM_OBJECT(list);
  172. }
  173. uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, v);
  174. ircode_add(code, SETLIST, dest, 0, index);
  175. return true;
  176. }
  177. #endif
  178. static uint32_t node2index(gnode_t * node) {
  179. // node can be a VARIABLE declaration or a local IDENTIFIER
  180. if (NODE_ISA(node, NODE_VARIABLE_DECL)) {
  181. gnode_variable_decl_t *expr = (gnode_variable_decl_t *)node;
  182. assert(gnode_array_size(expr->decls) == 1);
  183. gnode_var_t *var = (gnode_var_t *)gnode_array_get(expr->decls, 0);
  184. return var->index;
  185. }
  186. if (NODE_ISA(node, NODE_IDENTIFIER_EXPR)) {
  187. gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)node;
  188. assert(expr->location.type == LOCATION_LOCAL);
  189. return expr->location.index;
  190. }
  191. // should never reach this point because semacheck2 should take care of the check
  192. assert(0);
  193. return UINT32_MAX;
  194. }
  195. static void fix_superclasses(gvisitor_t *self) {
  196. // this function cannot fail because superclasses was already checked in samecheck2 so I am sure that they exist somewhere
  197. codegen_t *data = (codegen_t *)self->data;
  198. gnode_class_r *superfix = &data->superfix;
  199. size_t count = gnode_array_size(superfix);
  200. for (size_t i=0; i<count; ++i) {
  201. gnode_class_decl_t *node = (gnode_class_decl_t *)gnode_array_get(superfix, i);
  202. gnode_class_decl_t *super = (gnode_class_decl_t *)node->superclass;
  203. gravity_class_t *c = (gravity_class_t *)node->data;
  204. gravity_class_setsuper(c, (gravity_class_t *)super->data);
  205. }
  206. }
  207. // MARK: - Statements -
  208. static void visit_list_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
  209. DEBUG_CODEGEN("visit_list_stmt");
  210. gnode_array_each(node->stmts, {visit(val);});
  211. }
  212. static void visit_compound_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
  213. DEBUG_CODEGEN("visit_compound_stmt");
  214. gnode_array_each(node->stmts, {visit(val);});
  215. if (node->nclose != UINT32_MAX) {
  216. DECLARE_CODE();
  217. ircode_add(code, CLOSE, node->nclose, 0, 0);
  218. }
  219. }
  220. static void visit_label_stmt (gvisitor_t *self, gnode_label_stmt_t *node) {
  221. DEBUG_CODEGEN("visit_label_stmt");
  222. gtoken_t type = NODE_TOKEN_TYPE(node);
  223. assert((type == TOK_KEY_DEFAULT) || (type == TOK_KEY_CASE));
  224. if (type == TOK_KEY_DEFAULT) {visit(node->stmt);}
  225. else if (type == TOK_KEY_CASE) {visit(node->expr); visit(node->stmt);}
  226. }
  227. static void visit_flow_if_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
  228. DEBUG_CODEGEN("visit_flow_if_stmt");
  229. DECLARE_CODE();
  230. /*
  231. <condition>
  232. if-false: goto $end
  233. <then-part>
  234. goto $true
  235. $end:
  236. <else-part>
  237. $true:
  238. TRUE := getLabel
  239. FALSE := getLabel
  240. compile condition
  241. emit ifeq FALSE
  242. compile stm1
  243. emit goto TRUE
  244. emit FALSE
  245. compile stm2
  246. emit TRUE
  247. */
  248. uint32_t labelTrue = ircode_newlabel(code);
  249. uint32_t labelFalse = ircode_newlabel(code);
  250. visit(node->cond);
  251. ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
  252. visit(node->stmt);
  253. if (node->elsestmt) ircode_add(code, JUMP, labelTrue, 0, 0);
  254. ircode_marklabel(code, labelFalse);
  255. if (node->elsestmt) {
  256. visit(node->elsestmt);
  257. ircode_marklabel(code, labelTrue);
  258. }
  259. }
  260. static void visit_flow_switch_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
  261. DEBUG_CODEGEN("visit_flow_switch_stmt");
  262. visit(node->cond);
  263. visit(node->stmt);
  264. }
  265. static void visit_flow_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
  266. DEBUG_CODEGEN("visit_flow_stmt");
  267. gtoken_t type = NODE_TOKEN_TYPE(node);
  268. assert((type == TOK_KEY_IF) || (type == TOK_KEY_SWITCH));
  269. if (type == TOK_KEY_IF) {
  270. visit_flow_if_stmt(self, node);
  271. } else if (type == TOK_KEY_SWITCH) {
  272. visit_flow_switch_stmt(self, node);
  273. }
  274. }
  275. static void visit_loop_while_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
  276. DEBUG_CODEGEN("visit_loop_while_stmt");
  277. DECLARE_CODE();
  278. /*
  279. $start: <condition>
  280. if-false: goto $end
  281. <body>
  282. goto $start
  283. $end:
  284. START := getLabel
  285. END := getLabel
  286. emit START
  287. compile exp
  288. emit ifeq END
  289. compile stm
  290. emit goto START
  291. emit END
  292. */
  293. uint32_t labelTrue = ircode_newlabel(code);
  294. uint32_t labelFalse = ircode_newlabel(code);
  295. ircode_setlabel_true(code, labelTrue);
  296. ircode_setlabel_false(code, labelFalse);
  297. ircode_marklabel(code, labelTrue);
  298. visit(node->cond);
  299. ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
  300. visit(node->stmt);
  301. ircode_add(code, JUMP, labelTrue, 0, 0);
  302. ircode_marklabel(code, labelFalse);
  303. ircode_unsetlabel_true(code);
  304. ircode_unsetlabel_false(code);
  305. }
  306. static void visit_loop_repeat_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
  307. DEBUG_CODEGEN("visit_loop_repeat_stmt");
  308. DECLARE_CODE();
  309. /*
  310. $start: <body>
  311. <expression>
  312. if-false: goto $start
  313. $end:
  314. */
  315. uint32_t labelTrue = ircode_newlabel(code);
  316. uint32_t labelFalse = ircode_newlabel(code); // end label is necessary to handle optional break statement
  317. ircode_setlabel_true(code, labelTrue);
  318. ircode_setlabel_false(code, labelFalse);
  319. ircode_marklabel(code, labelTrue);
  320. visit(node->stmt);
  321. visit(node->expr);
  322. ircode_add(code, JUMPF, ircode_register_pop(code), labelFalse, 0);
  323. ircode_add(code, JUMP, labelTrue, 0, 0);
  324. ircode_marklabel(code, labelFalse);
  325. ircode_unsetlabel_true(code);
  326. ircode_unsetlabel_false(code);
  327. }
  328. static void visit_loop_for_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
  329. // https://www.natashatherobot.com/swift-alternatives-to-c-style-for-loops/
  330. DEBUG_CODEGEN("visit_loop_for_stmt");
  331. DECLARE_CODE();
  332. // FOR loop is transformed to a WHILE loop
  333. //
  334. // from:
  335. // for (cond in expr) {
  336. // stmp;
  337. // }
  338. //
  339. // to:
  340. // {
  341. // var $expr = expr;
  342. // var $value = $expr.iterate(null);
  343. // while ($value) {
  344. // cond = $expr.next($value);
  345. // stmp;
  346. // $value = $expr.iterate($value);
  347. // }
  348. // }
  349. uint32_t $expr = ircode_register_push_temp(code); // ++TEMP => 1
  350. uint32_t $value = ircode_register_push_temp(code); // ++TEMP => 2
  351. uint16_t iterate_idx = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, ITERATOR_INIT_FUNCTION));
  352. uint16_t next_idx = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, ITERATOR_NEXT_FUNCTION));
  353. uint32_t cond_idx = node2index(node->cond);
  354. // generate code for $expr = expr (so expr is only evaluated once)
  355. visit(node->expr);
  356. uint32_t once_expr = ircode_register_pop(code);
  357. ircode_add(code, MOVE, $expr, once_expr, 0);
  358. // generate code for $value = $expr.iterate(null);
  359. uint32_t iterate_fn = ircode_register_push_temp(code); // ++TEMP => 3
  360. ircode_add(code, LOADK, iterate_fn, iterate_idx, 0);
  361. ircode_add(code, LOAD, iterate_fn, $expr, iterate_fn);
  362. uint32_t next_fn = ircode_register_push_temp(code); // ++TEMP => 4
  363. ircode_add(code, LOADK, next_fn, next_idx, 0);
  364. ircode_add(code, LOAD, next_fn, $expr, next_fn);
  365. uint32_t temp1 = ircode_register_push_temp(code); // ++TEMP => 5
  366. ircode_add(code, MOVE, temp1, iterate_fn, 0);
  367. uint32_t temp2 = ircode_register_push_temp(code); // ++TEMP => 6
  368. ircode_add(code, MOVE, temp2, $expr, 0);
  369. temp2 = ircode_register_push_temp(code); // ++TEMP => 7
  370. ircode_add(code, LOADK, temp2, CPOOL_VALUE_NULL, 0);
  371. ircode_add(code, CALL, $value, temp1, 2);
  372. ircode_register_pop(code); // --TEMP => 6
  373. ircode_register_pop(code); // --TEMP => 5
  374. ircode_register_pop(code); // --TEMP => 4
  375. // while code
  376. uint32_t labelTrue = ircode_newlabel(code);
  377. uint32_t labelFalse = ircode_newlabel(code);
  378. ircode_setlabel_true(code, labelTrue);
  379. ircode_setlabel_false(code, labelFalse);
  380. ircode_marklabel(code, labelTrue);
  381. ircode_add(code, JUMPF, $value, labelFalse, 1); // flag JUMPF instruction to check ONLY BOOL values
  382. // cond = $expr.next($value);
  383. // cond is a local variable
  384. temp1 = ircode_register_push_temp(code); // ++TEMP => 5
  385. ircode_add(code, MOVE, temp1, next_fn, 0);
  386. temp2 = ircode_register_push_temp(code); // ++TEMP => 6
  387. ircode_add(code, MOVE, temp2, $expr, 0);
  388. temp2 = ircode_register_push_temp(code); // ++TEMP => 7
  389. ircode_add(code, MOVE, temp2, $value, 0);
  390. ircode_add(code, CALL, cond_idx, temp1, 2);
  391. // process statement
  392. visit(node->stmt);
  393. // pop next_fn temp register AFTER user code because function ptr must be protected inside loop
  394. ircode_register_pop(code); // --TEMP => 6
  395. ircode_register_pop(code); // --TEMP => 5
  396. ircode_register_pop(code); // --TEMP => 4
  397. // update $value for the next check
  398. // $value = $expr.iterate($value);
  399. temp1 = ircode_register_push_temp(code); // ++TEMP => 5
  400. ircode_add(code, MOVE, temp1, iterate_fn, 0);
  401. temp2 = ircode_register_push_temp(code); // ++TEMP => 6
  402. ircode_add(code, MOVE, temp2, $expr, 0);
  403. temp2 = ircode_register_push_temp(code); // ++TEMP => 7
  404. ircode_add(code, MOVE, temp2, $value, 0);
  405. ircode_add(code, CALL, $value, temp1, 2);
  406. ircode_register_pop(code); // --TEMP => 6
  407. ircode_register_pop(code); // --TEMP => 5
  408. ircode_register_pop(code); // --TEMP => 4
  409. ircode_add(code, JUMP, labelTrue, 0, 0);
  410. ircode_marklabel(code, labelFalse);
  411. ircode_unsetlabel_true(code);
  412. ircode_unsetlabel_false(code);
  413. ircode_register_pop(code); // --TEMP => 3
  414. ircode_register_pop(code); // --TEMP => 2
  415. ircode_register_pop(code); // --TEMP => 1
  416. ircode_register_pop(code); // --TEMP => 0
  417. if (node->nclose != UINT32_MAX) {
  418. ircode_add(code, CLOSE, node->nclose, 0, 0);
  419. }
  420. }
  421. static void visit_loop_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
  422. DEBUG_CODEGEN("visit_loop_stmt");
  423. gtoken_t type = NODE_TOKEN_TYPE(node);
  424. assert((type == TOK_KEY_WHILE) || (type == TOK_KEY_REPEAT) || (type == TOK_KEY_FOR));
  425. if (type == TOK_KEY_WHILE) {
  426. visit_loop_while_stmt(self, node);
  427. } else if (type == TOK_KEY_REPEAT) {
  428. visit_loop_repeat_stmt(self, node);
  429. } else if (type == TOK_KEY_FOR) {
  430. visit_loop_for_stmt(self, node);
  431. }
  432. }
  433. static void visit_jump_stmt (gvisitor_t *self, gnode_jump_stmt_t *node) {
  434. DEBUG_CODEGEN("visit_jump_stmt");
  435. DECLARE_CODE();
  436. gtoken_t type = NODE_TOKEN_TYPE(node);
  437. assert((type == TOK_KEY_BREAK) || (type == TOK_KEY_CONTINUE) || (type == TOK_KEY_RETURN));
  438. if (type == TOK_KEY_BREAK) {
  439. uint32_t label = ircode_getlabel_false(code);
  440. ircode_add(code, JUMP, label, 0, 0); // goto $end;
  441. } else if (type == TOK_KEY_CONTINUE) {
  442. uint32_t label = ircode_getlabel_true(code);
  443. ircode_add(code, JUMP, label, 0, 0); // goto $start;
  444. } else if (type == TOK_KEY_RETURN) {
  445. if (node->expr) {
  446. visit(node->expr);
  447. ircode_add(code, RET, ircode_register_pop(code), 0, 0);
  448. } else {
  449. ircode_add(code, RET0, 0, 0, 0);
  450. }
  451. }
  452. }
  453. static void visit_empty_stmt (gvisitor_t *self, gnode_empty_stmt_t *node) {
  454. #pragma unused(self, node)
  455. DEBUG_CODEGEN("visit_empty_stmt");
  456. DECLARE_CODE();
  457. ircode_add(code, NOP, 0, 0, 0);
  458. }
  459. // MARK: - Declarations -
  460. static void store_declaration (gvisitor_t *self, gravity_object_t *obj, bool is_static, gnode_function_decl_t *node) {
  461. DEBUG_CODEGEN("store_object_declaration");
  462. assert(obj);
  463. DECLARE_CONTEXT();
  464. bool is_module = CONTEXT_IS_MODULE(context_object);
  465. bool is_class = OBJECT_ISA_CLASS(context_object);
  466. bool is_local = ((is_module == false) && (is_class == false));
  467. if (is_static) assert(is_class); // static makes sense only for class objects
  468. if (is_local || is_module) {
  469. gravity_function_t *context_function = (gravity_function_t *)context_object;
  470. ircode_t *code = (ircode_t *)context_function->bytecode;
  471. // add object to cpool and get its index
  472. uint16_t index = gravity_function_cpool_add(NULL, context_function, VALUE_FROM_OBJECT(obj));
  473. // if it is a function then generate a CLOSURE opcode instead of LOADK
  474. if (OBJECT_ISA_FUNCTION(obj)) {
  475. gravity_function_t *f = (gravity_function_t *)obj;
  476. uint32_t regnum = ircode_register_push_temp(code);
  477. ircode_add(code, CLOSURE, regnum, index, 0);
  478. uint32_t upindex = 0;
  479. for (uint16_t i=0; i<f->nupvalues; ++i) {
  480. gupvalue_t *upvalue = (gupvalue_t *)gnode_array_get(node->uplist, i);
  481. uint32_t opindex = (upvalue->is_direct) ? upvalue->index : upindex++;
  482. ircode_add(code, MOVE, opindex, (upvalue->is_direct) ? 1 : 0, 0);
  483. }
  484. } else {
  485. ircode_add_constant(code, index);
  486. }
  487. if (is_module && obj->identifier) {
  488. index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, obj->identifier));
  489. ircode_add(code, STOREG, ircode_register_pop(code), index, 0);
  490. }
  491. return;
  492. }
  493. if (is_class) {
  494. gravity_class_t *context_class = (gravity_class_t *)context_object;
  495. context_class = (is_static) ? context_class->objclass : context_class;
  496. gravity_class_bind(context_class, obj->identifier, VALUE_FROM_OBJECT(obj));
  497. return;
  498. }
  499. // should never reach this point
  500. assert(0);
  501. }
  502. // used ONLY by CODEGEN
  503. static gravity_function_t *class_lookup_nosuper (gravity_class_t *c, const char *name) {
  504. STATICVALUE_FROM_STRING(key, name, strlen(name));
  505. gravity_value_t *v = gravity_hash_lookup(c->htable, key);
  506. return (v) ? (gravity_function_t*)v->p : NULL;
  507. }
  508. static void process_constructor (gvisitor_t *self, gravity_class_t *c) {
  509. DEBUG_CODEGEN("process_constructor");
  510. // $init is an internal function used to initialize instance variables to a default value
  511. // in case of subclasses USER is RESPONSIBLE to call super.init();
  512. // in case of subclasses COMPILER is RESPONSIBLE to create the appropriate $init call chain
  513. // check internal $init function
  514. gravity_function_t *internal_init_function = class_lookup_nosuper(c, CLASS_INTERNAL_INIT_NAME);
  515. // check for user constructor function
  516. gravity_function_t *constructor_function = class_lookup_nosuper(c, CLASS_CONSTRUCTOR_NAME);
  517. // build appropriate $init function
  518. gravity_class_t *super = c->superclass;
  519. uint32_t ninit = 2;
  520. while (super) {
  521. gravity_function_t *super_init = class_lookup_nosuper(super, CLASS_INTERNAL_INIT_NAME);
  522. if (super_init) {
  523. // copy super init code to internal_init code
  524. if (!internal_init_function) internal_init_function = gravity_function_new(NULL, CLASS_INTERNAL_INIT_NAME, 1, 0, 0, ircode_create(1));
  525. // build unique internal init name ($init2, $init3 and so on)
  526. char name[256];
  527. snprintf(name, sizeof(name), "%s%d", CLASS_INTERNAL_INIT_NAME, ninit++);
  528. // add new internal init to class and call it from main $init function
  529. // super_init should not be duplicated here because class hash table values are not freed (only keys are freed)
  530. gravity_class_bind(c, name, VALUE_FROM_OBJECT(super_init));
  531. uint16_t index = gravity_function_cpool_add(NULL, internal_init_function, VALUE_FROM_CSTRING(GET_VM(), name));
  532. ircode_patch_init((ircode_t *)internal_init_function->bytecode, index);
  533. }
  534. super = super->superclass;
  535. }
  536. // 4 cases to handle:
  537. // 1. internal_init and constuctor are not present, so nothing to do here
  538. if ((!internal_init_function) && (!constructor_function)) goto check_meta;
  539. // // 2. internal init is present and constructor is not used
  540. // if ((internal_init_function) && (!constructor_function)) {
  541. // // add a RET0 command
  542. // ircode_t *code = (ircode_t *)internal_init_function->bytecode;
  543. // ircode_add(code, RET0, 0, 0, 0);
  544. //
  545. // // bind internal init as constructor
  546. // gravity_class_bind(c, CLASS_CONSTRUCTOR_NAME, VALUE_FROM_OBJECT(internal_init_function));
  547. // gravity_object_setenclosing((gravity_object_t *)internal_init_function, (gravity_object_t *)c);
  548. // goto process_funcs;
  549. // }
  550. // 3. internal init is present so constructor is mandatory
  551. if (internal_init_function) {
  552. // convert ircode to bytecode for $init special function and add a RET0 command
  553. ircode_t *code = (ircode_t *)internal_init_function->bytecode;
  554. ircode_add(code, RET0, 0, 0, 0);
  555. if (constructor_function == NULL) {
  556. constructor_function = gravity_function_new(NULL, CLASS_CONSTRUCTOR_NAME, 1, 0, 2, ircode_create(1));
  557. ircode_t *code2 = (ircode_t *)constructor_function->bytecode;
  558. ircode_add_skip(code2); // LOADK
  559. ircode_add_skip(code2); // LOAD
  560. ircode_add_skip(code2); // MOVE
  561. ircode_add_skip(code2); // CALL
  562. gravity_class_bind(c, CLASS_CONSTRUCTOR_NAME, VALUE_FROM_OBJECT(constructor_function));
  563. }
  564. }
  565. // 4. constructor is present so internal init is optional
  566. if (constructor_function) {
  567. // add an implicit RET 0 (RET self) to the end of the constructor
  568. ircode_t *code = (ircode_t *)constructor_function->bytecode;
  569. ircode_add(code, RET, 0, 0, 0);
  570. if (internal_init_function) {
  571. // if an internal init function is present ($init) then add a call to it as a first instruction
  572. uint16_t index = gravity_function_cpool_add(GET_VM(), constructor_function, VALUE_FROM_CSTRING(NULL, CLASS_INTERNAL_INIT_NAME));
  573. // load constant
  574. uint32_t dest = ircode_register_push_temp(code);
  575. ircode_set_index(0, code, LOADK, dest, index, 0);
  576. // load from lookup
  577. ircode_set_index(1, code, LOAD, dest, 0, dest);
  578. // prepare parameters
  579. uint32_t dest2 = ircode_register_push_temp(code);
  580. ircode_set_index(2, code, MOVE, dest2, 0, 0);
  581. ircode_register_pop(code);
  582. // execute call
  583. ircode_set_index(3, code, CALL, dest, dest, 1);
  584. }
  585. }
  586. //process_funcs:
  587. if (internal_init_function) gravity_optimizer(internal_init_function);
  588. if (constructor_function) gravity_optimizer(constructor_function);
  589. check_meta:
  590. // recursively process constructor but stop when object or class class is found, otherwise an infinite loop is triggered
  591. if ((c->objclass) && (c->objclass->isa) && (c->objclass->isa != c->objclass->objclass)) process_constructor(self, c->objclass);
  592. }
  593. static void process_getter_setter (gvisitor_t *self, gnode_var_t *p, gravity_class_t *c) {
  594. gnode_compound_stmt_t *expr = (gnode_compound_stmt_t *)p->expr;
  595. gnode_function_decl_t *getter = (gnode_function_decl_t *)gnode_array_get(expr->stmts, 0);
  596. gnode_function_decl_t *setter = (gnode_function_decl_t *)gnode_array_get(expr->stmts, 1);
  597. gnode_function_decl_t *f1[2] = {getter, setter};
  598. gravity_function_t *f2[2] = {NULL, NULL};
  599. for (uint16_t i=0; i<2; ++i) {
  600. gnode_function_decl_t *node = f1[i];
  601. if (!node) continue;
  602. // create gravity function
  603. uint16_t nparams = (node->params) ? (uint16_t)marray_size(*node->params) : 0;
  604. f2[i] = gravity_function_new(NULL, NULL, nparams, node->nlocals, 0, ircode_create(node->nlocals+nparams));
  605. // process inner block
  606. CONTEXT_PUSH(f2[i]);
  607. gnode_compound_stmt_t *block = node->block;
  608. if (block) {gnode_array_each(block->stmts, {visit(val);});}
  609. CONTEXT_POP();
  610. gravity_optimizer(f2[i]);
  611. }
  612. // getter and setter NULL means default
  613. // since getter and setter are methods and not simple functions, do not transfer to VM
  614. gravity_function_t *f = gravity_function_new_special(NULL, NULL, GRAVITY_COMPUTED_INDEX, f2[0], f2[1]);
  615. gravity_class_bind(c, p->identifier, VALUE_FROM_OBJECT(f));
  616. }
  617. static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node) {
  618. DEBUG_CODEGEN("visit_function_decl %s", node->identifier);
  619. // extern means it will be provided at runtime by the delegate
  620. if (node->storage == TOK_KEY_EXTERN) return;
  621. DECLARE_CONTEXT();
  622. bool is_class_ctx = OBJECT_ISA_CLASS(context_object);
  623. // create new function object
  624. uint16_t nparams = (node->params) ? (uint16_t)marray_size(*node->params) : 0;
  625. gravity_function_t *f = gravity_function_new((is_class_ctx) ? NULL : GET_VM(), node->identifier,
  626. nparams, node->nlocals, 0, (void *)ircode_create(node->nlocals+nparams));
  627. // check if f is a special constructor function (init)
  628. // name must be CLASS_CONSTRUCTOR_NAME and context_object must be a class
  629. bool is_constructor = (string_cmp(node->identifier, CLASS_CONSTRUCTOR_NAME) == 0) && (is_class_ctx);
  630. CONTEXT_PUSH(f);
  631. if (is_constructor) {
  632. // reserve first four instructions that could be later filled with a CALL to $init
  633. // see process_constructor for more information
  634. ircode_t *code = (ircode_t *)f->bytecode;
  635. ircode_add_skip(code);
  636. ircode_add_skip(code);
  637. ircode_add_skip(code);
  638. ircode_add_skip(code);
  639. }
  640. // process inner block
  641. if (node->block) {gnode_array_each(node->block->stmts, {visit(val);});}
  642. // check for upvalues
  643. if (node->uplist) f->nupvalues = (uint16_t)gnode_array_size(node->uplist);
  644. // remove current function
  645. CONTEXT_POP();
  646. // check for ircode errors
  647. if (ircode_iserror((ircode_t *)f->bytecode))
  648. report_error(self, (gnode_t *)node, "Maximum number of available registers used in function %s.", f->identifier);
  649. // store function in current context
  650. store_declaration(self, (gravity_object_t *)f, (node->storage == TOK_KEY_STATIC), node);
  651. // convert ircode to bytecode (postpone optimization of the constructor)
  652. if (!is_constructor) gravity_optimizer(f);
  653. }
  654. static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
  655. DEBUG_CODEGEN("visit_variable_decl");
  656. DECLARE_CONTEXT();
  657. // no initialization for extern variables since the real value will be provided at runtime
  658. if (node->storage == TOK_KEY_EXTERN) return;
  659. bool is_module = CONTEXT_IS_MODULE(context_object);
  660. bool is_class = OBJECT_ISA_CLASS(context_object);
  661. bool is_local = ((is_module == false) && (is_class == false));
  662. // loop through declarations
  663. size_t count = gnode_array_size(node->decls);
  664. for (size_t i=0; i<count; ++i) {
  665. gnode_var_t *p = (gnode_var_t *)gnode_array_get(node->decls, i);
  666. DEBUG_CODEGEN("visit_variable_decl %s", p->identifier);
  667. // variable declarations can be specified in:
  668. // FUNCTION (local variable)
  669. // MODULE (module variable)
  670. // CLASS (property)
  671. if (is_local) {
  672. // it is a local variable declaration (default initialized to NULL)
  673. // code is generate ONLY if an init expression is specified
  674. //
  675. // example:
  676. //
  677. // func foo () {
  678. // var a = 10;
  679. // }
  680. //
  681. // LOADI 1 10 ; move 10 into register 1
  682. // MOVE 0 1 ; move register 1 into register 0
  683. //
  684. // generate expression code
  685. if (p->expr) visit(p->expr); // context is a function
  686. gravity_function_t *context_function = (gravity_function_t *)context_object;
  687. ircode_t *code = (ircode_t *)context_function->bytecode;
  688. if (p->expr) {
  689. // assign to variable result of the expression
  690. ircode_add(code, MOVE, p->index, ircode_register_pop(code), 0);
  691. } else {
  692. // no default assignment expression found so initialize to NULL
  693. ircode_add(code, LOADK, p->index, CPOOL_VALUE_NULL, 0);
  694. }
  695. continue;
  696. }
  697. if (is_module) {
  698. // it is a module variable (default initialized to null)
  699. // code must ALWAYS be generated
  700. //
  701. // example 1:
  702. // var a;
  703. //
  704. // LOADK 0 NULL ; move null into register 0
  705. // STOREG 0 0 ; move register 0 into hash(constant_pool(0))
  706. //
  707. // example 2:
  708. // var a = 10;
  709. //
  710. // LOADI 0 10 ; move 10 into register 0
  711. // STOREG 0 0 ; move register 0 into hash(constant_pool(0))
  712. //
  713. gravity_function_t *context_function = (gravity_function_t *)context_object;
  714. ircode_t *code = (ircode_t *)context_function->bytecode;
  715. uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, p->identifier));
  716. if (p->expr) {
  717. visit(p->expr); // context is a function
  718. } else {
  719. ircode_add_constant(code, CPOOL_VALUE_NULL);
  720. }
  721. ircode_add(code, STOREG, ircode_register_pop(code), index, 0);
  722. continue;
  723. }
  724. if (is_class) {
  725. bool is_static = (node->storage == TOK_KEY_STATIC);
  726. gravity_class_t *context_class = (is_static) ? ((gravity_class_t *)context_object)->objclass : (gravity_class_t *)context_object;
  727. // check computed property case first
  728. if ((p->expr) && (p->expr->tag == NODE_COMPOUND_STAT)) {
  729. process_getter_setter(self, p, context_class);
  730. continue;
  731. }
  732. // create ivar first
  733. uint16_t ivar_index = (p->index >= 0) ? p->index : gravity_class_add_ivar(context_class, NULL);
  734. // add default getter and setter ONLY if property is public
  735. if (node->access == TOK_KEY_PUBLIC) {
  736. // since getter and setter are methods and not simple functions, do not transfer to VM
  737. gravity_function_t *f = gravity_function_new_special(NULL, NULL, ivar_index, NULL, NULL); // getter and setter NULL means default
  738. gravity_class_bind(context_class, p->identifier, VALUE_FROM_OBJECT(f));
  739. }
  740. DEBUG_CODEGEN("Class: %s (static: %d) property: %s index: %d", context_class->identifier, is_static, p->identifier, ivar_index);
  741. // it is a property (default initialized to null)
  742. // code must be generated ONLY if an init expression is specified
  743. //
  744. // example:
  745. // class foo {
  746. // var a = 10;
  747. // }
  748. //
  749. // get $init function
  750. // depending if variable has been created static
  751. // and push it as current declaration then:
  752. //
  753. // LOADI 0 10 ; move 10 into register 0
  754. // STOREF 0 0 ; move register 0 into property 0
  755. if (p->expr) {
  756. // was gravity_class_lookup but that means than $init or init will be recursively searched also in super classes
  757. gravity_function_t *init_function = class_lookup_nosuper(context_class, CLASS_INTERNAL_INIT_NAME);
  758. if (init_function == NULL) {
  759. // no $init method found so create a new one
  760. init_function = gravity_function_new (NULL, CLASS_INTERNAL_INIT_NAME, 1, 0, 0, ircode_create(1));
  761. gravity_class_bind(context_class, CLASS_INTERNAL_INIT_NAME, VALUE_FROM_OBJECT(init_function));
  762. }
  763. CONTEXT_PUSH(init_function);
  764. ircode_t *code = (ircode_t *)init_function->bytecode;
  765. visit(p->expr);
  766. uint32_t dest = ircode_register_pop(code);
  767. ircode_add(code, STORE, dest, 0, p->index + MAX_REGISTERS);
  768. CONTEXT_POP();
  769. }
  770. continue;
  771. }
  772. // should never reach this point
  773. assert(0);
  774. }
  775. }
  776. static void visit_enum_decl (gvisitor_t *self, gnode_enum_decl_t *node) {
  777. #pragma unused(self,node)
  778. DEBUG_CODEGEN("visit_enum_decl %s", node->identifier);
  779. // enum is a map at runtime
  780. // enum foo {a=1,b=2,...}
  781. // is translated to
  782. // var foo = [a:1,b:2,...]
  783. }
  784. static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
  785. DEBUG_CODEGEN("visit_class_decl %s", node->identifier);
  786. // extern means it will be provided at runtime by the delegate
  787. if (node->storage == TOK_KEY_EXTERN) return;
  788. // create a new pair of classes (class itself and its meta)
  789. gravity_class_t *c = gravity_class_new_pair(GET_VM(), node->identifier, NULL, node->nivar, node->nsvar);
  790. // mark the class as a struct
  791. c->is_struct = node->is_struct;
  792. // check if class has a declared superclass
  793. if (node->superclass) {
  794. // node->superclass should be a gnode_class_decl_t at this point
  795. assert(NODE_ISA_CLASS(node->superclass));
  796. gnode_class_decl_t *super = (gnode_class_decl_t *)node->superclass;
  797. if (super->data) {
  798. // means that superclass has already been processed and its runtime representation is available
  799. gravity_class_setsuper(c, (gravity_class_t *)super->data);
  800. } else {
  801. // superclass has not yet processed so we need recheck the node at the end of the visit
  802. // add node to superfix for later processing
  803. codegen_t *data = (codegen_t *)self->data;
  804. marray_push(gnode_class_decl_t *, data->superfix, node);
  805. }
  806. }
  807. CONTEXT_PUSH(c);
  808. // process inner declarations
  809. gnode_array_each(node->decls, {visit(val);});
  810. // adjust declaration stack
  811. CONTEXT_POP();
  812. // fix constructor chain
  813. process_constructor(self, c);
  814. // store class declaration in current context
  815. store_declaration(self, (gravity_object_t *)c, (node->storage == TOK_KEY_STATIC), NULL);
  816. // save runtime representation
  817. // since this class could be a superclass of another class
  818. // then save opaque gravity_class_t pointer to node->data
  819. node->data = (void *)c;
  820. }
  821. static void visit_module_decl (gvisitor_t *self, gnode_module_decl_t *node) {
  822. #pragma unused(self, node)
  823. DEBUG_CODEGEN("visit_module_decl %s", node->identifier);
  824. // a module should be like a class with static entries
  825. // instantiated with import
  826. // gravity_module_t *module = gravity_module_new(GET_VM(), node->identifier);
  827. // CONTEXT_PUSH(module);
  828. //
  829. // // process inner declarations
  830. // gnode_array_each(node->decls, {visit(val);});
  831. //
  832. // // adjust declaration stack
  833. // CONTEXT_POP();
  834. }
  835. // MARK: - Expressions -
  836. //static void process_special_enum (gvisitor_t *self, gnode_enum_decl_t *node, gnode_identifier_expr_t *identifier) {
  837. // symboltable_t *symtable = node->symtable;
  838. // gnode_t *v = symboltable_lookup(symtable, identifier->value);
  839. // assert(v);
  840. // assert(NODE_ISA(v, NODE_LITERAL_EXPR));
  841. // visit(v);
  842. //}
  843. static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
  844. DEBUG_CODEGEN("visit_binary_expr %s", token_name(node->op));
  845. DECLARE_CODE();
  846. // assignment is right associative
  847. if (node->op == TOK_OP_ASSIGN) {
  848. CODEGEN_COUNT_REGISTERS(n1);
  849. visit(node->right);
  850. visit(node->left); // left expression can be: IDENTIFIER, FILE, POSTIFIX (not a call)
  851. CODEGEN_COUNT_REGISTERS(n2);
  852. CODEGEN_ASSERT_REGISTERS(n1, n2, 0);
  853. return;
  854. }
  855. CODEGEN_COUNT_REGISTERS(n1);
  856. // visiting binary operation from left to right
  857. visit(node->left);
  858. visit(node->right);
  859. uint32_t r3 = ircode_register_pop(code);
  860. uint32_t r2 = ircode_register_pop(code);
  861. uint32_t r1 = ircode_register_push_temp(code);
  862. // a special instruction needs to be generated for a binary expression of type RANGE
  863. if ((node->op == TOK_OP_RANGE_INCLUDED) || (node->op == TOK_OP_RANGE_EXCLUDED)) {
  864. ircode_add_tag(code, RANGENEW, r1, r2, r3, (node->op == TOK_OP_RANGE_INCLUDED) ? RANGE_INCLUDE_TAG : RANGE_EXCLUDE_TAG);
  865. return;
  866. }
  867. // generate code for binary OP
  868. opcode_t op = token2opcode(node->op);
  869. ircode_add(code, op, r1, r2, r3);
  870. CODEGEN_COUNT_REGISTERS(n2);
  871. CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
  872. }
  873. static void visit_unary_expr (gvisitor_t *self, gnode_unary_expr_t *node) {
  874. DEBUG_CODEGEN("visit_unary_expr %s", token_name(node->op));
  875. DECLARE_CODE();
  876. CODEGEN_COUNT_REGISTERS(n1);
  877. // unary expression can be:
  878. // + Unary PLUS
  879. // - Unary MINUS
  880. // ! Logical NOT
  881. // ~ Bitwise NOT
  882. visit(node->expr);
  883. if (node->op == TOK_OP_ADD) {
  884. // +1 is just 1 and more generally +expr is just expr so ignore + and proceed
  885. return;
  886. }
  887. uint32_t r2 = ircode_register_pop(code);
  888. uint32_t r1 = ircode_register_push_temp(code);
  889. opcode_t op = (node->op == TOK_OP_SUB) ? NEG : token2opcode(node->op);
  890. ircode_add(code, op, r1, r2, 0);
  891. CODEGEN_COUNT_REGISTERS(n2);
  892. CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
  893. }
  894. static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
  895. DEBUG_CODEGEN("visit_call_expr");
  896. // node->list usually cannot be NULL, it is NULL only as a result of a static enum transformation (see semacheck2.c)
  897. if (node->list == NULL) {
  898. visit(node->id);
  899. return;
  900. }
  901. DECLARE_CODE();
  902. CODEGEN_COUNT_REGISTERS(n1);
  903. ircode_push_context(code);
  904. // generate code for the common id node
  905. visit(node->id);
  906. bool is_super = IS_SUPER(node->id);
  907. // register that contains callable object
  908. uint32_t target_register = ircode_register_pop_protect(code, true);
  909. // register where to store final result
  910. uint32_t dest_register = target_register;
  911. // mandatory self register (initialized to 0 in case of implicit self or explicit super)
  912. uint32_r self_list; marray_init(self_list);
  913. marray_push(uint32_t, self_list, ((IS_IMPLICIT_SELF(node->id)) || (is_super)) ? 0 : target_register);
  914. // process each subnode and set is_assignment flag
  915. bool is_assignment = node->base.is_assignment;
  916. size_t count = gnode_array_size(node->list);
  917. for (size_t i=0; i<count; ++i) {
  918. // a subnode can be a CALL_EXPR => id.()
  919. // a NODE_ACCESS_EXPR => id.id2
  920. // a NODE_SUBSCRIPT_EXPR => id[]
  921. // or ANY combination of the them! => id.id2.id3()[24]().id5()
  922. gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, i);
  923. // identify postfix type: NODE_CALL_EXPR, NODE_ACCESS_EXPR, NODE_SUBSCRIPT_EXPR
  924. gnode_n tag = subnode->base.tag;
  925. // check assignment flag
  926. bool is_real_assigment = (is_assignment && IS_LAST_LOOP(i, count));
  927. if (tag == NODE_CALL_EXPR) {
  928. // a CALL instruction needs to properly prepare stack before execution
  929. // format is CALL A B C
  930. // where A is the destination register
  931. // B is the callable object
  932. // and C is the number of arguments passed to the CALL
  933. // arguments must be on the stack (so gravity VM can use a register window in order to speed up instruction)
  934. // and are expected to be starting from B+1
  935. // check dest register
  936. bool dest_is_temp = ircode_register_istemp(code, dest_register);
  937. if (!dest_is_temp) dest_register = ircode_register_push_temp(code);
  938. // add target register (must be temp)
  939. uint32_t temp_target_register = ircode_register_push_temp(code);
  940. ircode_add(code, MOVE, temp_target_register, target_register, 0);
  941. ircode_register_pop_protect(code, true);
  942. // always add SELF parameter (must be temp+1)
  943. uint32_t self_register = marray_pop(self_list);
  944. uint32_t temp_self_register = ircode_register_push_temp(code);
  945. ircode_add(code, MOVE, temp_self_register, self_register, 0);
  946. ircode_register_pop_protect(code, true);
  947. // process each parameter (each must be temp+2 ... temp+n)
  948. marray_decl_init(uint32_r, args);
  949. size_t n = gnode_array_size(subnode->args);
  950. for (size_t j=0; j<n; ++j) {
  951. // process each argument
  952. gnode_t *arg = (gnode_t *)gnode_array_get(subnode->args, j);
  953. visit(arg);
  954. uint32_t nreg = ircode_register_pop_protect(code, true);
  955. // make sure args are in consecutive register locations (from temp_target_register + 1 to temp_target_register + n)
  956. if (nreg != temp_target_register + j + 2) {
  957. uint32_t temp = ircode_register_push_temp(code);
  958. if (temp == 0) return; // temp value == 0 means codegen error (error will be automatically reported later in visit_function_decl
  959. ircode_add(code, MOVE, temp, nreg, 0);
  960. nreg = ircode_register_pop_protect(code, true);
  961. }
  962. assert(nreg == temp_target_register + j + 2);
  963. marray_push(uint32_t, args, nreg);
  964. }
  965. // generate instruction CALL with count parameters (taking in account self)
  966. ircode_add(code, CALL, dest_register, temp_target_register, (uint32_t)n+1);
  967. // cleanup temp registers
  968. ircode_register_clean(code, temp_target_register);
  969. ircode_register_clean(code, temp_self_register);
  970. n = gnode_array_size(subnode->args);
  971. for (size_t j=0; j<n; ++j) {
  972. uint32_t reg = marray_get(args, j);
  973. ircode_register_clean(code, reg);
  974. }
  975. // update self list
  976. marray_push(uint32_t, self_list, dest_register);
  977. // a call returns a value
  978. if (IS_LAST_LOOP(i, count)) {
  979. if (ircode_register_count(code)) {
  980. // code added in order to protect the extra register pushed in case
  981. // of code like: f(20)(30)
  982. uint32_t last_register = ircode_register_last(code);
  983. if (dest_is_temp && last_register == dest_register) dest_is_temp = false;
  984. }
  985. if (dest_is_temp) ircode_register_push(code, dest_register);
  986. ircode_register_protect(code, dest_register);
  987. }
  988. // free temp args array
  989. marray_destroy(args);
  990. } else if (tag == NODE_ACCESS_EXPR) {
  991. // process identifier node (semantic check assures that each node is an identifier)
  992. gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)subnode->expr;
  993. uint32_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, expr->value));
  994. uint32_t index_register = ircode_register_push_temp(code);
  995. ircode_add(code, LOADK, index_register, index, 0);
  996. ircode_register_pop(code);
  997. // generate LOAD/STORE instruction
  998. dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
  999. if (is_super) ircode_add(code, LOADS, dest_register, target_register, index_register);
  1000. else ircode_add(code, (is_real_assigment) ? STORE : LOAD, dest_register, target_register, index_register);
  1001. if ((!is_real_assigment) && (i+1<count)) ircode_register_pop_protect(code, true);
  1002. // update self list (if latest instruction)
  1003. // this was added in order to properly emit instructions for nested_class.gravity unit test
  1004. if (!IS_LAST_LOOP(i, count)) {
  1005. gnode_postfix_subexpr_t *nextnode = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, i+1);
  1006. if (nextnode->base.tag != NODE_CALL_EXPR) marray_push(uint32_t, self_list, dest_register);
  1007. }
  1008. } else if (tag == NODE_SUBSCRIPT_EXPR) {
  1009. // process index
  1010. visit(subnode->expr);
  1011. uint32_t index = ircode_register_pop(code);
  1012. // generate LOADAT/STOREAT instruction
  1013. dest_register = (is_real_assigment) ? ircode_register_pop(code) : ircode_register_push_temp(code);
  1014. ircode_add(code, (is_assignment) ? STOREAT : LOADAT, dest_register, target_register, index);
  1015. if ((!is_real_assigment) && (i+1<count)) ircode_register_pop_protect(code, true);
  1016. }
  1017. // reset is_super flag
  1018. is_super = false;
  1019. // update target
  1020. target_register = dest_register;
  1021. }
  1022. marray_destroy(self_list);
  1023. ircode_pop_context(code);
  1024. CODEGEN_COUNT_REGISTERS(n2);
  1025. CODEGEN_ASSERT_REGISTERS(n1, n2, (is_assignment) ? -1 : 1);
  1026. }
  1027. static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
  1028. DEBUG_CODEGEN("visit_file_expr");
  1029. DECLARE_CODE();
  1030. CODEGEN_COUNT_REGISTERS(n1);
  1031. // check if the node is a left expression of an assignment
  1032. bool is_assignment = node->base.is_assignment;
  1033. size_t count = gnode_array_size(node->identifiers);
  1034. for (size_t i=0; i<count; ++i) {
  1035. const char *identifier = gnode_array_get(node->identifiers, i);
  1036. uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
  1037. if ((is_assignment) && (IS_LAST_LOOP(i, count)))
  1038. ircode_add(code, STOREG, ircode_register_pop(code), kindex, 0);
  1039. else
  1040. ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
  1041. }
  1042. CODEGEN_COUNT_REGISTERS(n2);
  1043. CODEGEN_ASSERT_REGISTERS(n1, n2, (is_assignment) ? -1 : 1);
  1044. }
  1045. static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
  1046. /*
  1047. NOTE:
  1048. doubles and int64 should be added to the constant pool but I avoid
  1049. adding them here so the optimizer has a way to perform better constant folding:
  1050. http://en.wikipedia.org/wiki/Constant_folding
  1051. http://www.compileroptimizations.com/category/constant_folding.htm
  1052. */
  1053. DEBUG_CODEGEN("visit_literal_expr");
  1054. DECLARE_CODE();
  1055. CODEGEN_COUNT_REGISTERS(n1);
  1056. switch (node->type) {
  1057. case LITERAL_STRING: {
  1058. // LOADK temp, s
  1059. uint16_t index = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_STRING(NULL, node->value.str, node->len));
  1060. ircode_add_constant(code, index);
  1061. DEBUG_CODEGEN("visit_literal_expr (string) %s", node->value.str);
  1062. } break;
  1063. case LITERAL_FLOAT:
  1064. // LOADI temp, d
  1065. ircode_add_double(code, node->value.d);
  1066. DEBUG_CODEGEN("visit_literal_expr (float) %.2f", node->value.d);
  1067. break;
  1068. case LITERAL_INT:
  1069. // LOADI temp, n
  1070. ircode_add_int(code, node->value.n64);
  1071. DEBUG_CODEGEN("visit_literal_expr (int) %lld", node->value.n64);
  1072. break;
  1073. case LITERAL_BOOL: {
  1074. uint32_t value = (node->value.n64 == 0) ? CPOOL_VALUE_FALSE : CPOOL_VALUE_TRUE;
  1075. ircode_add_constant(code, value);
  1076. DEBUG_CODEGEN("visit_literal_expr (bool) %lld", node->value.n64);
  1077. } break;
  1078. default: assert(0);
  1079. }
  1080. CODEGEN_COUNT_REGISTERS(n2);
  1081. CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
  1082. }
  1083. static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *node) {
  1084. DEBUG_CODEGEN("visit_identifier_expr %s", node->value);
  1085. DECLARE_CODE();
  1086. CODEGEN_COUNT_REGISTERS(n1);
  1087. // check if the node is a left expression of an assignment
  1088. bool is_assignment = node->base.is_assignment;
  1089. const char *identifier = node->value; // identifier as c string
  1090. gnode_location_type type = node->location.type; // location type
  1091. uint16_t index = node->location.index; // symbol index
  1092. uint16_t nup = node->location.nup; // upvalue index or outer index
  1093. switch (type) {
  1094. // local variable
  1095. case LOCATION_LOCAL: {
  1096. if (is_assignment)
  1097. ircode_add(code, MOVE, index, ircode_register_pop(code), 0);
  1098. else
  1099. ircode_register_push(code, index);
  1100. } break;
  1101. // module (global) variable
  1102. case LOCATION_GLOBAL: {
  1103. uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
  1104. if (is_assignment)
  1105. ircode_add(code, STOREG, ircode_register_pop(code), kindex, 0);
  1106. else
  1107. ircode_add(code, LOADG, ircode_register_push_temp(code), kindex, 0);
  1108. } break;
  1109. // upvalue access
  1110. case LOCATION_UPVALUE: {
  1111. gupvalue_t *upvalue = node->upvalue;
  1112. if (is_assignment)
  1113. ircode_add(code, STOREU, ircode_register_pop(code), upvalue->selfindex, 0);
  1114. else
  1115. ircode_add(code, LOADU, ircode_register_push_temp(code), upvalue->selfindex, 0);
  1116. } break;
  1117. // class ivar case (outer case just need a loop lookup before)
  1118. case LOCATION_CLASS_IVAR_OUTER:
  1119. case LOCATION_CLASS_IVAR_SAME: {
  1120. // needs to differentiate ivar (indexed by an integer) from other cases (indexed by a string)
  1121. bool is_ivar = (index != UINT16_MAX);
  1122. uint32_t dest = 0;
  1123. uint32_t target = 0;
  1124. if (type == LOCATION_CLASS_IVAR_OUTER) {
  1125. dest = ircode_register_push_temp(code);
  1126. for (uint16_t i=0; i<nup; ++i) {
  1127. ircode_add(code, LOAD, dest, target, 0 + MAX_REGISTERS);
  1128. target = dest;
  1129. }
  1130. if (is_assignment) ircode_register_pop(code);
  1131. }
  1132. uint32_t index_register;
  1133. if (is_ivar) {
  1134. // ivar case, use an index to load/retrieve it
  1135. index_register = index + MAX_REGISTERS;
  1136. } else {
  1137. // not an ivar so it could be another class declaration like a func, a class or an enum
  1138. // use lookup in order to retrieve it (assignment is handled here so you can change a
  1139. // first class citizen at runtime too)
  1140. uint16_t kindex = gravity_function_cpool_add(GET_VM(), context_function, VALUE_FROM_CSTRING(NULL, identifier));
  1141. index_register = ircode_register_push_temp(code);
  1142. ircode_add(code, LOADK, index_register, kindex, 0);
  1143. ircode_register_pop(code);
  1144. }
  1145. if (is_assignment) {
  1146. // should be prohibited by semantic to store something into a non ivar slot?
  1147. dest = ircode_register_pop(code); // consume temp register
  1148. ircode_add(code, STORE, dest, target, index_register);
  1149. } else {
  1150. dest = (type == LOCATION_CLASS_IVAR_OUTER) ? target : ircode_register_push_temp(code);
  1151. ircode_add(code, LOAD, dest , target, index_register);
  1152. }
  1153. } break;
  1154. }
  1155. CODEGEN_COUNT_REGISTERS(n2);
  1156. CODEGEN_ASSERT_REGISTERS(n1, n2, (is_assignment) ? -1 : 1);
  1157. }
  1158. static void visit_keyword_expr (gvisitor_t *self, gnode_keyword_expr_t *node) {
  1159. DEBUG_CODEGEN("visit_keyword_expr %s", token_name(node->base.token.type));
  1160. DECLARE_CODE();
  1161. CODEGEN_COUNT_REGISTERS(n1);
  1162. gtoken_t type = NODE_TOKEN_TYPE(node);
  1163. switch (type) {
  1164. case TOK_KEY_CURRFUNC:
  1165. ircode_add_constant(code, CPOOL_VALUE_FUNC);
  1166. break;
  1167. case TOK_KEY_NULL:
  1168. ircode_add_constant(code, CPOOL_VALUE_NULL);
  1169. break;
  1170. case TOK_KEY_SUPER:
  1171. ircode_add_constant(code, CPOOL_VALUE_SUPER);
  1172. break;
  1173. case TOK_KEY_CURRARGS:
  1174. // compiler can know in advance if arguments special array is used
  1175. context_function->useargs = true;
  1176. ircode_add_constant(code, CPOOL_VALUE_ARGUMENTS);
  1177. break;
  1178. case TOK_KEY_UNDEFINED:
  1179. ircode_add_constant(code, CPOOL_VALUE_UNDEFINED);
  1180. break;
  1181. case TOK_KEY_TRUE:
  1182. ircode_add_constant(code, CPOOL_VALUE_TRUE);
  1183. break;
  1184. case TOK_KEY_FALSE:
  1185. ircode_add_constant(code, CPOOL_VALUE_FALSE);
  1186. break;
  1187. default:
  1188. // should never reach this point
  1189. assert(0);
  1190. break;
  1191. }
  1192. CODEGEN_COUNT_REGISTERS(n2);
  1193. CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
  1194. }
  1195. static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
  1196. DEBUG_CODEGEN("visit_list_expr");
  1197. DECLARE_CODE();
  1198. CODEGEN_COUNT_REGISTERS(n1);
  1199. bool ismap = node->ismap;
  1200. uint32_t n = (uint32_t)gnode_array_size(node->list1);
  1201. // a map requires twice registers than a list
  1202. uint32_t max_fields = (ismap) ? MAX_FIELDSxFLUSH : MAX_FIELDSxFLUSH*2;
  1203. // destination register of a new instruction is ALWAYS a temp register
  1204. // then the optimizer could decide to optimize and merge the step
  1205. uint32_t dest = ircode_register_push_temp(code);
  1206. ircode_add(code, (ismap) ? MAPNEW : LISTNEW, dest, n, 0);
  1207. if (n == 0) return;
  1208. // this is just like Lua "fields per flush"
  1209. // basically nodes are processed in a finite chunk
  1210. // and then added to the list/map
  1211. uint32_t nloops = n / max_fields;
  1212. if (n % max_fields != 0) ++nloops;
  1213. uint32_t nprocessed = 0;
  1214. while (nprocessed < n) {
  1215. size_t k = (n - nprocessed > max_fields) ? max_fields : (n - nprocessed);
  1216. size_t idxstart = nprocessed;
  1217. size_t idxend = nprocessed + k;
  1218. nprocessed += k;
  1219. // check if this chunk can be optimized
  1220. // if (check_literals_list(self, node, ismap, idxstart, idxend, dest)) continue;
  1221. // save register context
  1222. ircode_push_context(code);
  1223. // process each node
  1224. for (size_t j=idxstart; j<idxend; ++j) {
  1225. gnode_t *e = gnode_array_get(node->list1, j);
  1226. visit(e);
  1227. uint32_t nreg = ircode_register_pop_protect(code, true);
  1228. if (!ircode_register_istemp(code, nreg)) {
  1229. uint32_t temp_register = ircode_register_push_temp(code);
  1230. ircode_add(code, MOVE, temp_register, nreg, 0);
  1231. ircode_register_pop_protect(code, true);
  1232. }
  1233. if (ismap) {
  1234. e = gnode_array_get(node->list2, j);
  1235. visit(e);
  1236. nreg = ircode_register_pop_protect(code, true);
  1237. if (!ircode_register_istemp(code, nreg)) {
  1238. uint32_t temp_register = ircode_register_push_temp(code);
  1239. ircode_add(code, MOVE, temp_register, nreg, 0);
  1240. ircode_register_pop_protect(code, true);
  1241. }
  1242. }
  1243. }
  1244. // emit proper SETLIST instruction
  1245. // since in a map registers are always used in pairs (key, value) it is
  1246. // extremely easier to just set reg1 to be always 0 and use r in a loop
  1247. ircode_add(code, SETLIST, dest, (uint32_t)(idxend-idxstart), 0);
  1248. // restore register context
  1249. ircode_pop_context(code);
  1250. }
  1251. CODEGEN_COUNT_REGISTERS(n2);
  1252. CODEGEN_ASSERT_REGISTERS(n1, n2, 1);
  1253. }
  1254. // MARK: -
  1255. gravity_function_t *gravity_codegen(gnode_t *node, gravity_delegate_t *delegate, gravity_vm *vm) {
  1256. codegen_t data;
  1257. data.vm = vm;
  1258. marray_init(data.context);
  1259. marray_init(data.superfix);
  1260. ircode_t *code = ircode_create(0);
  1261. gravity_function_t *f = gravity_function_new(vm, INITMODULE_NAME, 0, 0, 0, code);
  1262. marray_push(gravity_object_t*, data.context, (gravity_object_t *)f);
  1263. gvisitor_t visitor = {
  1264. .nerr = 0, // used for internal codegen errors
  1265. .data = &data, // used to store a pointer to codegen struct
  1266. .delegate = (void *)delegate, // compiler delegate to report errors
  1267. // STATEMENTS: 7
  1268. .visit_list_stmt = visit_list_stmt,
  1269. .visit_compound_stmt = visit_compound_stmt,
  1270. .visit_label_stmt = visit_label_stmt,
  1271. .visit_flow_stmt = visit_flow_stmt,
  1272. .visit_loop_stmt = visit_loop_stmt,
  1273. .visit_jump_stmt = visit_jump_stmt,
  1274. .visit_empty_stmt = visit_empty_stmt,
  1275. // DECLARATIONS: 5
  1276. .visit_function_decl = visit_function_decl,
  1277. .visit_variable_decl = visit_variable_decl,
  1278. .visit_enum_decl = visit_enum_decl,
  1279. .visit_class_decl = visit_class_decl,
  1280. .visit_module_decl = visit_module_decl,
  1281. // EXPRESSIONS: 8
  1282. .visit_binary_expr = visit_binary_expr,
  1283. .visit_unary_expr = visit_unary_expr,
  1284. .visit_file_expr = visit_file_expr,
  1285. .visit_literal_expr = visit_literal_expr,
  1286. .visit_identifier_expr = visit_identifier_expr,
  1287. .visit_keyword_expr = visit_keyword_expr,
  1288. .visit_list_expr = visit_list_expr,
  1289. .visit_postfix_expr = visit_postfix_expr,
  1290. };
  1291. DEBUG_CODEGEN("=== BEGIN CODEGEN ===");
  1292. gvisit(&visitor, node);
  1293. DEBUG_CODEGEN("\n");
  1294. // check for special superfix
  1295. if (marray_size(data.superfix)) {
  1296. fix_superclasses(&visitor);
  1297. }
  1298. // pop globals instance init special function
  1299. marray_pop(data.context);
  1300. assert(marray_size(data.context) == 0);
  1301. marray_destroy(data.context);
  1302. // in case of codegen errors explicity free code and return NULL
  1303. if (visitor.nerr != 0) {ircode_free(code); f->bytecode = NULL;}
  1304. return (visitor.nerr == 0) ? f : NULL;
  1305. }