gravity_semacheck2.c 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  1. //
  2. // gravity_semacheck2.c
  3. // gravity
  4. //
  5. // Created by Marco Bambini on 12/09/14.
  6. // Copyright (c) 2014 CreoLabs. All rights reserved.
  7. //
  8. #include "gravity_symboltable.h"
  9. #include "gravity_semacheck2.h"
  10. #include "gravity_compiler.h"
  11. #include "gravity_visitor.h"
  12. #include "gravity_core.h"
  13. struct semacheck_t {
  14. gnode_r *declarations; // declarations stack
  15. uint16_r statements; // statements stack
  16. uint32_t lasterror; // last error line number to prevent reporting more than one error per line
  17. };
  18. typedef struct semacheck_t semacheck_t;
  19. #define REPORT_ERROR(node,...) report_error(self, GRAVITY_ERROR_SEMANTIC, (gnode_t *)node, __VA_ARGS__);
  20. #define REPORT_WARNING(node,...) report_error(self, GRAVITY_WARNING, (gnode_t *)node, __VA_ARGS__)
  21. #define STATEMENTS ((semacheck_t *)self->data)->statements
  22. #define PUSH_STATEMENT(stat) marray_push(uint16_t, STATEMENTS, (uint16_t)stat)
  23. #define POP_STATEMENT() marray_pop(STATEMENTS)
  24. #define TOP_STATEMENT() (marray_size(STATEMENTS) ? marray_last(STATEMENTS) : 0)
  25. #define TOP_STATEMENT_ISA(stat) (TOP_STATEMENT() == stat)
  26. #define TOP_STATEMENT_ISA_SWITCH() (TOP_STATEMENT_ISA(TOK_KEY_SWITCH))
  27. #define TOP_STATEMENT_ISA_LOOP() ((TOP_STATEMENT_ISA(TOK_KEY_WHILE)) || \
  28. (TOP_STATEMENT_ISA(TOK_KEY_REPEAT)) || \
  29. (TOP_STATEMENT_ISA(TOK_KEY_FOR)))
  30. #define PUSH_DECLARATION(node) gnode_array_push(((semacheck_t *)self->data)->declarations, (gnode_t*)node)
  31. #define POP_DECLARATION() gnode_array_pop(((semacheck_t *)self->data)->declarations)
  32. #define TOP_DECLARATION() gnode_array_get(((semacheck_t *)self->data)->declarations, gnode_array_size(((semacheck_t *)self->data)->declarations)-1)
  33. #define ISA(n1,_tag) ((n1) ? (((gnode_t *)n1)->tag == _tag) : 0)
  34. #define ISA_CLASS(n1) (((gnode_t *)n1)->tag == NODE_CLASS_DECL)
  35. #define ISA_VAR_DECLARATION(n1) (((gnode_t *)n1)->tag == NODE_VARIABLE_DECL)
  36. #define ISA_VARIABLE(n1) (((gnode_t *)n1)->tag == NODE_VARIABLE)
  37. #define ISA_LITERAL(n1) (((gnode_t *)n1)->tag == NODE_LITERAL_EXPR)
  38. #define ISA_IDENTIFIER(n1) (((gnode_t *)n1)->tag == NODE_IDENTIFIER_EXPR)
  39. #define ISA_ID(n1) (((gnode_t *)n1)->tag == NODE_ID_EXPR)
  40. #define SET_LOCAL_INDEX(var, symtable) var->index = (uint16_t)symboltable_local_index(symtable)
  41. #define SET_NODE_LOCATION(_node, _type, _idx, _nup) _node->location.type = _type; _node->location.index = _idx; _node->location.nup = _nup;
  42. // MARK: -
  43. static void report_error (gvisitor_t *self, error_type_t error_type, gnode_t *node, const char *format, ...) {
  44. semacheck_t *current = (semacheck_t *)self->data;
  45. // check last error line in order to prevent to emit multiple errors for the same row
  46. if (node && node->token.lineno == current->lasterror) return;
  47. // increment internal error counter (and save last reported line) only if it was a real error
  48. if (error_type != GRAVITY_WARNING) {
  49. ++self->nerr;
  50. current->lasterror = (node) ? node->token.lineno : 0;
  51. }
  52. // get error callback (if any)
  53. void *data = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->xdata : NULL;
  54. gravity_error_callback error_fn = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->error_callback : NULL;
  55. // build error message
  56. char buffer[1024];
  57. va_list arg;
  58. if (format) {
  59. va_start (arg, format);
  60. vsnprintf(buffer, sizeof(buffer), format, arg);
  61. va_end (arg);
  62. }
  63. // setup error struct
  64. error_desc_t error_desc = {
  65. .lineno = (node) ? node->token.lineno : 0,
  66. .colno = (node) ? node->token.colno : 0,
  67. .fileid = (node) ? node->token.fileid : 0,
  68. .offset = (node) ? node->token.position : 0
  69. };
  70. // finally call error callback
  71. if (error_fn) error_fn(NULL, error_type, buffer, error_desc, data);
  72. else printf("%s\n", buffer);
  73. }
  74. static symboltable_t *symtable_from_node (gnode_t *node) {
  75. // globals
  76. if (ISA(node, NODE_LIST_STAT)) return ((gnode_compound_stmt_t *)node)->symtable;
  77. // class symtable
  78. if (ISA(node, NODE_CLASS_DECL)) return ((gnode_class_decl_t *)node)->symtable;
  79. // enum symtable
  80. if (ISA(node, NODE_ENUM_DECL)) return ((gnode_enum_decl_t *)node)->symtable;
  81. // module symtable
  82. if (ISA(node, NODE_MODULE_DECL)) return ((gnode_module_decl_t *)node)->symtable;
  83. // function symtable
  84. if (ISA(node, NODE_FUNCTION_DECL)) return ((gnode_function_decl_t *)node)->symtable;
  85. // should never reach this point
  86. return NULL;
  87. }
  88. // lookup identifier into node
  89. static gnode_t *lookup_node (gnode_t *node, const char *identifier) {
  90. symboltable_t *symtable = symtable_from_node(node);
  91. if (!symtable) return NULL;
  92. return symboltable_lookup(symtable, identifier);
  93. }
  94. // lookup an identifier into a stack of symbol tables
  95. // location inside node is updated with the result
  96. // and node found is returned
  97. static gnode_t *lookup_identifier (gvisitor_t *self, const char *identifier, gnode_identifier_expr_t *node) {
  98. gnode_r *decls = ((semacheck_t *)self->data)->declarations;
  99. size_t len = gnode_array_size(decls);
  100. if (len == 0) return NULL;
  101. uint16_t nf = 0; // number of functions traversed
  102. uint16_t nc = 0; // number of classes traversed
  103. char buffer[512];
  104. // get first node (the latest in the decls stack)
  105. gnode_t *base_node = gnode_array_get(decls, len-1);
  106. bool base_is_class = ISA(base_node, NODE_CLASS_DECL);
  107. bool base_is_static_function = (ISA(base_node, NODE_FUNCTION_DECL) && ((gnode_function_decl_t*)base_node)->storage == TOK_KEY_STATIC);
  108. for (int i=(int)len-1; i>=0; --i) {
  109. gnode_t *target = gnode_array_get(decls, i);
  110. // identify target type
  111. bool target_is_global = ISA(target, NODE_LIST_STAT);
  112. bool target_is_function = ISA(target, NODE_FUNCTION_DECL);
  113. bool target_is_class = ISA(target, NODE_CLASS_DECL);
  114. bool target_is_module = ISA(target, NODE_MODULE_DECL);
  115. // count number of traversed func/class
  116. if (target_is_function) ++nf;
  117. else if (target_is_class) ++nc;
  118. // if identifier has been declared in a static func
  119. // and lookup target is a class, then use its special
  120. // reserved name to perform the lookup
  121. const char *id = identifier;
  122. if (base_is_static_function && target_is_class) {
  123. snprintf(buffer, sizeof(buffer), "$%s", identifier);
  124. id = (const char *)buffer;
  125. }
  126. // lookup identifier is current target (obtained traversing the declaration stack)
  127. gnode_t *symbol = lookup_node(target, id);
  128. // sanity check: if base_node is a class and symbol was found inside a func then report an error
  129. if (symbol && target_is_function && base_is_class) {
  130. // added to explicitly prevent cases like:
  131. /*
  132. func foo() {
  133. var a;
  134. class b {
  135. func bar() {return a;}
  136. }
  137. }
  138. */
  139. REPORT_ERROR(node, "Unable to access local func var %s from within a class.", identifier);
  140. return NULL;
  141. }
  142. // if target is class and symbol is not found then lookup also its superclass hierarchy
  143. if (!symbol && target_is_class) {
  144. // lookup identifier in super (if not found target class)
  145. gnode_class_decl_t *c = (gnode_class_decl_t *)target;
  146. gnode_class_decl_t *super = (gnode_class_decl_t *)c->superclass;
  147. if (super && !NODE_ISA(super, NODE_CLASS_DECL)) {
  148. REPORT_ERROR(node, "Cannot set superclass of %s to non class object.", c->identifier);
  149. return NULL;
  150. }
  151. while (super) {
  152. symbol = lookup_node((gnode_t *)super, identifier);
  153. if (symbol) {
  154. if (NODE_ISA(symbol, NODE_VARIABLE)) {
  155. gnode_var_t *p = (gnode_var_t *)symbol;
  156. if (p->access == TOK_KEY_PRIVATE) {
  157. REPORT_ERROR(node, "Forbidden access to private ivar %s from a subclass.", p->identifier);
  158. return NULL;
  159. }
  160. }
  161. break;
  162. }
  163. super = (gnode_class_decl_t *)super->superclass;
  164. }
  165. }
  166. // continue lookup in declaration stack is symbol is not found
  167. if (!symbol) continue;
  168. // symbol found so process it bases on target type
  169. if (target_is_global) {
  170. DEBUG_LOOKUP("Identifier %s found in GLOBALS", identifier);
  171. // identifier found in global no other information is needed
  172. if (node) {
  173. SET_NODE_LOCATION(node, LOCATION_GLOBAL, 0, 0);
  174. node->symbol = symbol;
  175. }
  176. return symbol;
  177. }
  178. // if symbol is a variable then copy its index
  179. uint16_t index = UINT16_MAX;
  180. if (NODE_ISA(symbol, NODE_VARIABLE)) {
  181. gnode_var_t *p = (gnode_var_t *)symbol;
  182. if (!p->iscomputed) index = p->index;
  183. }
  184. if (target_is_function) {
  185. // Symbol found in a function
  186. if (nf > 1) {
  187. assert(ISA(base_node, NODE_FUNCTION_DECL));
  188. // symbol is upvalue and its index represents an index inside uplist
  189. gnode_var_t *var = (gnode_var_t *)symbol;
  190. gnode_function_decl_t *f = ((gnode_function_decl_t *)base_node);
  191. uint16_t n = nf - 1;
  192. gupvalue_t *upvalue = gnode_function_add_upvalue(f, var, n);
  193. // add upvalue to all enclosing functions
  194. // base_node has index = len - 1 so from (len - 2) up to n-1 levels
  195. uint16_t idx = (uint16_t)(len - 2);
  196. while (n > 1) {
  197. gnode_t *enc_node = gnode_array_get(decls, idx);
  198. if (!(ISA(enc_node, NODE_FUNCTION_DECL))) {
  199. REPORT_ERROR(node, "An error occurred while setting upvalue for enclosing functions.");
  200. return NULL;
  201. }
  202. gnode_function_add_upvalue((gnode_function_decl_t *)enc_node, var, --n);
  203. --idx;
  204. }
  205. var->upvalue = true;
  206. node->upvalue = upvalue;
  207. SET_NODE_LOCATION(node, LOCATION_UPVALUE, index, nf);
  208. } else {
  209. // symbol is local
  210. SET_NODE_LOCATION(node, LOCATION_LOCAL, index, nf);
  211. }
  212. DEBUG_LOOKUP("Identifier %s found in FUNCTION %s (nf: %d index: %d)", identifier, ((gnode_function_decl_t *)target)->identifier, nf-1, index);
  213. }
  214. else if (target_is_class) {
  215. // Symbol found in a class
  216. SET_NODE_LOCATION(node, (nc == 1) ? LOCATION_CLASS_IVAR_SAME : LOCATION_CLASS_IVAR_OUTER, index, nc-1);
  217. DEBUG_LOOKUP("Identifier %s found in CLASS %s (up to %d outer levels)", identifier, ((gnode_class_decl_t *)target)->identifier, nc-1);
  218. }
  219. else if (target_is_module) {
  220. // Symbol found in a module
  221. // Module support not yet ready
  222. }
  223. else {
  224. // Should never reach this point
  225. assert(0);
  226. }
  227. node->symbol = symbol;
  228. return symbol;
  229. }
  230. DEBUG_LOOKUP("Identifier %s NOT FOUND\n", identifier);
  231. return NULL;
  232. }
  233. static gnode_t *lookup_symtable_id (gvisitor_t *self, gnode_identifier_expr_t *id, bool isclass) {
  234. gnode_t *target = NULL;
  235. gnode_t *target1 = lookup_identifier(self, id->value, id);
  236. if (!target1) {REPORT_ERROR((gnode_t *)id, "%s %s not found.", (isclass) ? "Class" : "Protocol", id->value); return NULL;}
  237. target = target1;
  238. if (id->value2) {
  239. gnode_t *target2 = lookup_node(target1, id->value2);
  240. if (!target2) {REPORT_ERROR((gnode_t *)id, "%s %s not found in %s.", (isclass) ? "Class" : "Protocol", id->value2, id->value); return NULL;}
  241. target = target2;
  242. }
  243. return target;
  244. }
  245. // MARK: -
  246. static bool is_expression (gnode_t *node) {
  247. gnode_n tag = NODE_TAG(node);
  248. return ((tag >= NODE_BINARY_EXPR) && (tag <= NODE_ACCESS_EXPR));
  249. }
  250. static bool is_expression_assignment (gnode_t *node) {
  251. if (!node) return false;
  252. gnode_n tag = NODE_TAG(node);
  253. if (tag == NODE_BINARY_EXPR) {
  254. gnode_binary_expr_t *expr = (gnode_binary_expr_t *)node;
  255. return (expr->op == TOK_OP_ASSIGN);
  256. }
  257. return false;
  258. }
  259. static bool is_expression_range (gnode_t *node) {
  260. gnode_n tag = NODE_TAG(node);
  261. if (tag == NODE_BINARY_EXPR) {
  262. gnode_binary_expr_t *expr = (gnode_binary_expr_t *)node;
  263. return ((expr->op == TOK_OP_RANGE_INCLUDED) || (expr->op == TOK_OP_RANGE_EXCLUDED));
  264. }
  265. return false;
  266. }
  267. static bool is_expression_valid (gnode_t *node) {
  268. if (!node) return false;
  269. /*
  270. From: http://c2.com/cgi/wiki?FirstClass
  271. | Class of value
  272. Manipulation | First Second Third
  273. ===============================+================================
  274. Pass value as a parameter | yes yes no
  275. Return value from a procedure | yes no no
  276. Assign value into a variable | yes no no
  277. */
  278. /*
  279. NODE_LIST_STAT, NODE_COMPOUND_STAT, NODE_LABEL_STAT, NODE_FLOW_STAT, NODE_JUMP_STAT,
  280. NODE_LOOP_STAT, NODE_EMPTY_STAT,
  281. // declarations: 6
  282. NODE_ENUM_DECL, NODE_FUNCTION_DECL, NODE_VARIABLE_DECL, NODE_CLASS_DECL, NODE_MODULE_DECL,
  283. NODE_VARIABLE,
  284. // expressions: 8
  285. NODE_BINARY_EXPR, NODE_UNARY_EXPR, NODE_FILE_EXPR,
  286. NODE_LIST_EXPR, NODE_LITERAL_EXPR, NODE_IDENTIFIER_EXPR, NODE_KEYWORD_EXPR,
  287. NODE_FUNCTION_EXPR,
  288. // postfix expression type: 2 + NODE_IDENTIFIER_EXPR
  289. NODE_CALL, NODE_SUBSCRIPT
  290. */
  291. // fixme
  292. gnode_n tag = NODE_TAG(node);
  293. switch (tag) {
  294. case NODE_UNARY_EXPR: {
  295. return is_expression_valid(((gnode_unary_expr_t *)node)->expr);
  296. }
  297. case NODE_BINARY_EXPR: {
  298. gnode_binary_expr_t *expr = (gnode_binary_expr_t *)node;
  299. if (expr->op == TOK_OP_ASSIGN) return false;
  300. if (!is_expression_valid(expr->left)) return false;
  301. return is_expression_valid(expr->right);
  302. }
  303. case NODE_IDENTIFIER_EXPR: {
  304. return true;
  305. }
  306. case NODE_MODULE_DECL:
  307. case NODE_ENUM_DECL: {
  308. return false;
  309. }
  310. default: break;
  311. }
  312. return true;
  313. }
  314. static bool is_init_function (gnode_t *node) {
  315. if (ISA(node, NODE_FUNCTION_DECL)) {
  316. gnode_function_decl_t *f = (gnode_function_decl_t *)node;
  317. if (!f->identifier) return false;
  318. return (strcmp(f->identifier, CLASS_CONSTRUCTOR_NAME) == 0);
  319. }
  320. return false;
  321. }
  322. static bool is_init_infinite_loop(gvisitor_t *self, gnode_identifier_expr_t *identifier, gnode_r *list) {
  323. // for example:
  324. // class c1 {
  325. // func init() {
  326. // var a = c1(); // INFINITE LOOP
  327. // var a = self(); // INFINITE LOOP
  328. // }
  329. // }
  330. // conditions for an infinite loop in init:
  331. // 1. there should be at least 2 declarations in the stack
  332. gnode_r *decls = ((semacheck_t *)self->data)->declarations;
  333. size_t len = gnode_array_size(decls);
  334. if (len < 2) return false;
  335. // 2. current function is init
  336. if (!is_init_function(gnode_array_get(decls, len-1))) return false;
  337. // 3. outer declaration is a class
  338. gnode_t *target_node = gnode_array_get(decls, len-2);
  339. if (!ISA(target_node, NODE_CLASS_DECL)) return false;
  340. // 4. identifier is self OR identifier->symbol points to target_node
  341. bool continue_check = false;
  342. if (identifier->symbol) continue_check = target_node == identifier->symbol;
  343. else continue_check = ((identifier->value) && (strcmp(identifier->value, SELF_PARAMETER_NAME) == 0));
  344. if (!continue_check) return false;
  345. // 5. check if next node is a call
  346. size_t count = gnode_array_size(list);
  347. if (count < 1) return false;
  348. gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *)gnode_array_get(list, 0);
  349. return (subnode->base.tag == NODE_CALL_EXPR);
  350. }
  351. static void check_access_storage_specifiers (gvisitor_t *self, gnode_t *node, gnode_n env, gtoken_t access, gtoken_t storage) {
  352. // check for module node
  353. if (NODE_TAG(node) == NODE_MODULE_DECL) {
  354. if (access != 0) REPORT_ERROR(node, "Access specifier cannot be used for module.");
  355. if (storage != 0) REPORT_ERROR(node, "Storage specifier cannot be used for module.");
  356. }
  357. // check fo access specifiers here
  358. // access specifier does make sense only inside module or class declaration
  359. // in any other enclosing environment must be considered a semantic error
  360. if ((access != 0) && (env != NODE_CLASS_DECL) && (env != NODE_MODULE_DECL)) {
  361. REPORT_ERROR(node, "Access specifier does not make sense here.");
  362. }
  363. // storage specifier (STATIC) makes sense only inside a class declaration
  364. if ((storage == TOK_KEY_STATIC) && (env != NODE_CLASS_DECL)) {
  365. REPORT_ERROR(node, "Static storage specifier does not make sense outside a class declaration.");
  366. }
  367. }
  368. static bool check_assignment_expression (gvisitor_t *self, gnode_binary_expr_t *node) {
  369. // in case of assignment check left node: assure assignment is made to identifier or other valid expressions
  370. // for example left expression cannot be a literal (to prevent 3 = 2)
  371. gnode_n tag = NODE_TAG(node->left);
  372. bool result = ((tag == NODE_IDENTIFIER_EXPR) || (tag == NODE_FILE_EXPR) || (tag == NODE_POSTFIX_EXPR));
  373. // more checks in the postfix case
  374. if (tag == NODE_POSTFIX_EXPR) {
  375. gnode_postfix_expr_t *expr = (gnode_postfix_expr_t *)node->left;
  376. // in case of postfix expression
  377. // enum has already been processed so it appears as a literal with expr->list NULL
  378. // inside a postfix expression node
  379. // check enum case (enum cannot be assigned)
  380. if (ISA(expr->id, NODE_LITERAL_EXPR)) {
  381. result = false;
  382. } else {
  383. if (!expr->list) return false;
  384. // basically the LATEST node of a postfix expression cannot be a CALL in an assignment
  385. // so we are avoiding expressions like: a(123) = ...; or a.b.c(1,2) = ...;
  386. size_t count = gnode_array_size(expr->list);
  387. gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *)gnode_array_get(expr->list, count-1);
  388. if (!subnode) return false;
  389. result = (NODE_TAG(subnode) != NODE_CALL_EXPR);
  390. }
  391. }
  392. // set is_assignment flag (default to false)
  393. node->left->is_assignment = result;
  394. if (!result) REPORT_ERROR(node->left, "Wrong assignment expression.");
  395. return result;
  396. }
  397. static bool check_range_expression (gvisitor_t *self, gnode_binary_expr_t *node) {
  398. // simple check, if nodes are literals then they must be INT
  399. gnode_t *r[2] = {node->left, node->right};
  400. for (int i=0; i<2; ++i) {
  401. gnode_t *range = r[i];
  402. if (ISA_LITERAL(range)) {
  403. gnode_literal_expr_t *expr = (gnode_literal_expr_t *)range;
  404. if (expr->type != LITERAL_INT) {REPORT_ERROR(node, "Range must be integer."); return false;}
  405. }
  406. }
  407. return true;
  408. }
  409. static bool check_class_ivar (gvisitor_t *self, gnode_class_decl_t *classnode, gnode_variable_decl_t *node) {
  410. size_t count = gnode_array_size(node->decls);
  411. gnode_class_decl_t *supernode = (gnode_class_decl_t *)classnode->superclass;
  412. if (!NODE_ISA(supernode, NODE_CLASS_DECL)) return false;
  413. for (size_t i=0; i<count; ++i) {
  414. gnode_var_t *p = (gnode_var_t *)gnode_array_get(node->decls, i);
  415. if (!p) continue;
  416. DEBUG_SEMA2("check_ivar %s", p->identifier);
  417. // do not check internal outer var
  418. if (string_cmp(p->identifier, OUTER_IVAR_NAME) == 0) continue;
  419. while (supernode) {
  420. symboltable_t *symtable = supernode->symtable;
  421. if (symboltable_lookup(symtable, p->identifier) != NULL) {
  422. REPORT_WARNING((gnode_t *)node, "Property '%s' defined in class '%s' already defined in its superclass %s.",
  423. p->identifier, classnode->identifier, supernode->identifier);
  424. }
  425. if (supernode->superclass && !NODE_ISA(supernode->superclass, NODE_CLASS_DECL)) {
  426. REPORT_ERROR(supernode, "Unable to find superclass %s for class %s.", supernode->identifier, ((gnode_identifier_expr_t *)supernode->superclass)->value);
  427. supernode->superclass = NULL;
  428. return false;
  429. }
  430. supernode = (gnode_class_decl_t *)supernode->superclass;
  431. }
  432. }
  433. return true;
  434. }
  435. static void free_postfix_subexpr (gnode_postfix_subexpr_t *subnode) {
  436. // check refcount
  437. if (subnode->base.refcount > 0) {--subnode->base.refcount; return;}
  438. // manually free postfix subnode
  439. gnode_n tag = subnode->base.tag;
  440. if (tag == NODE_CALL_EXPR) {
  441. if (subnode->args) {
  442. gnode_array_each(subnode->args, gnode_free(val););
  443. gnode_array_free(subnode->args);
  444. }
  445. } else {
  446. gnode_free(subnode->expr);
  447. }
  448. mem_free((gnode_t*)subnode);
  449. }
  450. // MARK: - Statements -
  451. static void visit_list_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
  452. DEBUG_SEMA2("visit_list_stmt");
  453. PUSH_DECLARATION(node);
  454. gnode_array_each(node->stmts, {visit(val);});
  455. POP_DECLARATION();
  456. }
  457. static void visit_compound_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
  458. DEBUG_SEMA2("visit_compound_stmt");
  459. gnode_t *top = TOP_DECLARATION();
  460. symboltable_t *symtable = symtable_from_node(top);
  461. if (!symtable) return;
  462. symboltable_enter_scope(symtable);
  463. gnode_array_each(node->stmts, {visit(val);});
  464. symboltable_exit_scope(symtable, &node->nclose);
  465. }
  466. static void visit_label_stmt (gvisitor_t *self, gnode_label_stmt_t *node) {
  467. DEBUG_SEMA2("visit_label_stmt");
  468. gtoken_t type = NODE_TOKEN_TYPE(node);
  469. if (!TOP_STATEMENT_ISA_SWITCH()) {
  470. if (type == TOK_KEY_DEFAULT) REPORT_ERROR(node, "'default' statement not in switch statement.");
  471. if (type == TOK_KEY_CASE) REPORT_ERROR(node, "'case' statement not in switch statement.");
  472. }
  473. if (type == TOK_KEY_DEFAULT) {visit(node->stmt);}
  474. else if (type == TOK_KEY_CASE) {visit(node->expr); visit(node->stmt);}
  475. }
  476. static void visit_flow_stmt (gvisitor_t *self, gnode_flow_stmt_t *node) {
  477. DEBUG_SEMA2("visit_flow_stmt");
  478. // assignment has no side effect so report error in case of assignment
  479. if (is_expression_assignment(node->cond)) REPORT_ERROR(node->cond, "Assignment not allowed here");
  480. gtoken_t type = NODE_TOKEN_TYPE(node);
  481. if (type == TOK_KEY_IF) {
  482. visit(node->cond);
  483. visit(node->stmt);
  484. if (node->elsestmt) visit(node->elsestmt);
  485. } else if (type == TOK_KEY_SWITCH) {
  486. PUSH_STATEMENT(type);
  487. visit(node->cond);
  488. visit(node->stmt);
  489. POP_STATEMENT();
  490. } else if (type == TOK_OP_TERNARY) {
  491. visit(node->cond);
  492. visit(node->stmt);
  493. visit(node->elsestmt);
  494. }
  495. }
  496. static void visit_loop_stmt (gvisitor_t *self, gnode_loop_stmt_t *node) {
  497. DEBUG_SEMA2("visit_loop_stmt");
  498. gtoken_t type = NODE_TOKEN_TYPE(node);
  499. PUSH_STATEMENT(type);
  500. // check pre-conditions
  501. const char *LOOP_NAME = NULL;
  502. gnode_t *cond = NULL;
  503. if (type == TOK_KEY_WHILE) {LOOP_NAME = "WHILE"; cond = node->cond;}
  504. else if (type == TOK_KEY_REPEAT) {LOOP_NAME = "REPEAT"; cond = node->expr;}
  505. else if (type == TOK_KEY_FOR) {LOOP_NAME = "FOR"; cond = node->cond;}
  506. // sanity check
  507. if (type == TOK_KEY_WHILE) {
  508. if (!node->cond) {REPORT_ERROR(node, "Missing %s condition.", LOOP_NAME); return;}
  509. if (!node->stmt) {REPORT_ERROR(node, "Missing %s statement.", LOOP_NAME); return;}
  510. } else if (type == TOK_KEY_REPEAT) {
  511. if (!node->stmt) {REPORT_ERROR(node, "Missing %s statement.", LOOP_NAME); return;}
  512. if (!node->expr) {REPORT_ERROR(node, "Missing %s expression.", LOOP_NAME); return;}
  513. } else if (type == TOK_KEY_FOR) {
  514. if (!node->cond) {REPORT_ERROR(node, "Missing %s condition.", LOOP_NAME); return;}
  515. if (!node->expr) {REPORT_ERROR(node, "Missing %s expression.", LOOP_NAME); return;}
  516. if (!node->stmt) {REPORT_ERROR(node, "Missing %s statement.", LOOP_NAME); return;}
  517. }
  518. if (is_expression_assignment(cond)) {
  519. REPORT_ERROR(cond, "Assignments in Gravity does not return a value so cannot be used inside a %s condition.", LOOP_NAME);
  520. return;
  521. }
  522. // FOR condition MUST be a VARIABLE declaration or an IDENTIFIER
  523. if (type == TOK_KEY_FOR) {
  524. bool type_check = (NODE_ISA(node->cond, NODE_VARIABLE_DECL) || NODE_ISA(node->cond, NODE_IDENTIFIER_EXPR));
  525. if (!type_check) REPORT_ERROR(cond, "FOR declaration must be a variable declaration or a local identifier.");
  526. if (NODE_ISA(node->cond, NODE_VARIABLE_DECL)) {
  527. gnode_variable_decl_t *var = (gnode_variable_decl_t *)node->cond;
  528. // assure var declares just ONE variable
  529. if (gnode_array_size(var->decls) > 1) REPORT_ERROR(cond, "Cannot declare more than one variable inside a FOR loop.");
  530. // assure that there is no assignment expression
  531. gnode_var_t *p = (gnode_var_t *)gnode_array_get(var->decls, 0);
  532. if (p->expr) REPORT_ERROR(cond, "Assignment expression prohibited in a FOR loop.");
  533. }
  534. }
  535. if (type == TOK_KEY_WHILE) {
  536. visit(node->cond);
  537. visit(node->stmt);
  538. } else if (type == TOK_KEY_REPEAT) {
  539. visit(node->stmt);
  540. visit(node->expr);
  541. } else if (type == TOK_KEY_FOR) {
  542. symboltable_t *symtable = symtable_from_node(TOP_DECLARATION());
  543. symboltable_enter_scope(symtable);
  544. visit(node->cond);
  545. if (NODE_ISA(node->cond, NODE_IDENTIFIER_EXPR)) {
  546. //if cond is not a var declaration then it must be a local identifier
  547. gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)node->cond;
  548. if (expr->location.type != LOCATION_LOCAL) REPORT_ERROR(cond, "FOR declaration must be a variable declaration or a local identifier.");
  549. }
  550. visit(node->expr);
  551. visit(node->stmt);
  552. symboltable_exit_scope(symtable, &node->nclose);
  553. }
  554. POP_STATEMENT();
  555. }
  556. static void visit_jump_stmt (gvisitor_t *self, gnode_jump_stmt_t *node) {
  557. DEBUG_SEMA2("visit_jump_stmt");
  558. gtoken_t type = NODE_TOKEN_TYPE(node);
  559. if (type == TOK_KEY_BREAK) {
  560. if (!(TOP_STATEMENT_ISA_LOOP() || TOP_STATEMENT_ISA_SWITCH()))
  561. REPORT_ERROR(node, "'break' statement not in loop or switch statement.");
  562. }
  563. else if (type == TOK_KEY_CONTINUE) {
  564. if (!TOP_STATEMENT_ISA_LOOP()) REPORT_ERROR(node, "'continue' statement not in loop statement.");
  565. }
  566. else if (type == TOK_KEY_RETURN) {
  567. gnode_t *n1 = TOP_DECLARATION(); // n1 == NULL means globals
  568. if (!ISA(n1, NODE_FUNCTION_DECL)) REPORT_ERROR(node, "'return' statement not in a function definition.");
  569. if (node->expr) {
  570. visit(node->expr);
  571. if (!is_expression_valid(node->expr)) {
  572. REPORT_ERROR(node->expr, "Invalid expression.");
  573. return;
  574. }
  575. }
  576. } else {
  577. assert(0);
  578. }
  579. }
  580. static void visit_empty_stmt (gvisitor_t *self, gnode_empty_stmt_t *node) {
  581. DEBUG_SEMA2("visit_empty_stmt");
  582. // get top declaration
  583. gnode_t *top = TOP_DECLARATION();
  584. if (!NODE_ISA_FUNCTION(top)) REPORT_ERROR(node, "Extraneous semicolon error.");
  585. return;
  586. }
  587. // MARK: - Declarations -
  588. static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node) {
  589. DEBUG_SEMA2("visit_function_decl %s", node->identifier);
  590. // set top declaration
  591. gnode_t *top = TOP_DECLARATION();
  592. // check if optional access and storage specifiers make sense in current context
  593. check_access_storage_specifiers(self, (gnode_t *)node, NODE_TAG(top), node->access, node->storage);
  594. // get enclosing declaration
  595. node->env = top;
  596. // enter function scope
  597. PUSH_DECLARATION(node);
  598. symboltable_t *symtable = symboltable_create(SYMTABLE_TAG_FUNC);
  599. symboltable_enter_scope(symtable);
  600. // process parameters
  601. node->symtable = symtable;
  602. if (node->params) {
  603. gnode_array_each(node->params, {
  604. gnode_var_t *p = (gnode_var_t *)val;
  605. p->env = (gnode_t*)node;
  606. if (!symboltable_insert(symtable, p->identifier, (void *)p)) {
  607. REPORT_ERROR(p, "Parameter %s redeclared.", p->identifier);
  608. continue;
  609. }
  610. SET_LOCAL_INDEX(p, symtable);
  611. DEBUG_SEMA2("Local:%s index:%d", p->identifier, p->index);
  612. });
  613. }
  614. // process inner block
  615. gnode_compound_stmt_t *block = node->block;
  616. if (block) {gnode_array_each(block->stmts, {visit(val);});}
  617. // exit function scope
  618. uint16_t nparams = (node->params) ? (uint16_t)marray_size(*node->params) : 0;
  619. uint32_t nlocals = symboltable_exit_scope(symtable, NULL);
  620. if (nlocals > MAX_LOCALS) {
  621. REPORT_ERROR(node, "Maximum number of local variables reached in function %s (max:%d found:%d).",
  622. node->identifier, MAX_LOCALS, nlocals);
  623. } else {
  624. node->nlocals = (uint16_t)nlocals - nparams;
  625. node->nparams = nparams;
  626. }
  627. // check upvalue limit
  628. uint32_t nupvalues = (node->uplist) ? (uint32_t)marray_size(*node->uplist) : 0;
  629. if (nupvalues > MAX_UPVALUES) REPORT_ERROR(node, "Maximum number of upvalues reached in function %s (max:%d found:%d).",
  630. node->identifier, MAX_LOCALS, nupvalues);
  631. POP_DECLARATION();
  632. DEBUG_SEMA2("MAX LOCALS for function %s: %d", node->identifier, node->nlocals);
  633. }
  634. static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
  635. gnode_t *top = TOP_DECLARATION();
  636. symboltable_t *symtable = symtable_from_node(top);
  637. size_t count = gnode_array_size(node->decls);
  638. gnode_n env = NODE_TAG(top);
  639. bool env_is_function = (env == NODE_FUNCTION_DECL);
  640. // check if optional access and storage specifiers make sense in current context
  641. check_access_storage_specifiers(self, (gnode_t *)node, env, node->access, node->storage);
  642. // loop to check each individual declaration
  643. for (size_t i=0; i<count; ++i) {
  644. gnode_var_t *p = (gnode_var_t *)gnode_array_get(node->decls, i);
  645. DEBUG_SEMA2("visit_variable_decl %s", p->identifier);
  646. // set enclosing environment
  647. p->env = top;
  648. // visit expression first in order to prevent var a = a
  649. // variable with a initial value (or with a getter/setter)
  650. if (p->expr) visit(p->expr);
  651. if (NODE_ISA(p->expr, NODE_ENUM_DECL)) continue;
  652. // // check for manifest type
  653. // if (p->annotation_type) {
  654. // // struct gnode_var_t was modified with
  655. // // // untagged union, if no type is declared then this union is NULL otherwise
  656. // // union {
  657. // // const char *annotation_type; // optional annotation type
  658. // // gnode_class_decl_t *class_type; // class type (set in semacheck2 if annotation_type is not NULL)
  659. // // };
  660. // gnode_t *class_type = lookup_identifier(self, p->annotation_type, NULL);
  661. // if (!class_type) {REPORT_WARNING(p, "Unable to find type %s.", p->annotation_type);}
  662. // // if (!NODE_ISA(class_type, NODE_CLASS_DECL)) {REPORT_ERROR(p, "Unable to set non class type %s.", p->annotation_type); continue;}
  663. // // p->class_type = (gnode_class_decl_t *)class_type;
  664. // }
  665. if (env_is_function) {
  666. // local variable defined inside a function
  667. if (!symboltable_insert(symtable, p->identifier, (void *)p)) {
  668. REPORT_ERROR(p, "Identifier %s redeclared.", p->identifier);
  669. continue;
  670. }
  671. SET_LOCAL_INDEX(p, symtable);
  672. DEBUG_SEMA2("Local:%s index:%d", p->identifier, p->index);
  673. } else if (env == NODE_CLASS_DECL) {
  674. if (p->iscomputed) continue;
  675. // variable defined inside a class => property
  676. gnode_class_decl_t *c = (gnode_class_decl_t *)top;
  677. // compute new ivar index
  678. (node->storage == TOK_KEY_STATIC) ? ++c->nsvar : ++c->nivar;
  679. // super class is a static information so I can solve the fragile class problem at compilation time
  680. gnode_class_decl_t *super = (gnode_class_decl_t *)c->superclass;
  681. if (super && !NODE_ISA(super, NODE_CLASS_DECL)) return;
  682. uint32_t n2 = 0;
  683. while (super) {
  684. n2 += (node->storage == TOK_KEY_STATIC) ? super->nsvar : super->nivar;
  685. super = (gnode_class_decl_t *)super->superclass;
  686. }
  687. p->index += n2;
  688. DEBUG_SEMA2("Class: %s property:%s index:%d (static %d)", c->identifier, p->identifier, p->index, (node->storage == TOK_KEY_STATIC));
  689. }
  690. }
  691. }
  692. static void visit_enum_decl (gvisitor_t *self, gnode_enum_decl_t *node) {
  693. DEBUG_SEMA2("visit_enum_decl %s", node->identifier);
  694. // check if optional access and storage specifiers make sense in current context
  695. gnode_t *top = TOP_DECLARATION();
  696. check_access_storage_specifiers(self, (gnode_t *)node, NODE_TAG(top), node->access, node->storage);
  697. if (NODE_ISA_FUNCTION(top)) {
  698. // it is a local defined enum
  699. symboltable_t *symtable = symtable_from_node(top);
  700. if (!symboltable_insert(symtable, node->identifier, (void *)node)) {
  701. REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
  702. }
  703. }
  704. }
  705. static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
  706. DEBUG_SEMA2("visit_class_decl %s", node->identifier);
  707. gnode_t *top = TOP_DECLARATION();
  708. // check if optional access and storage specifiers make sense in current context
  709. check_access_storage_specifiers(self, (gnode_t *)node, NODE_TAG(top), node->access, node->storage);
  710. // set class enclosing (can be globals, a class or a function)
  711. node->env = top;
  712. // sanity check on class name
  713. if (string_cmp(node->identifier, CLASS_CONSTRUCTOR_NAME) == 0) {
  714. REPORT_ERROR(node, "%s is a special name and cannot be used as class identifier.", CLASS_CONSTRUCTOR_NAME);
  715. return;
  716. }
  717. // check superclass
  718. if (node->superclass) {
  719. // get super class identifier and reset the field (so in case of error it cannot be accessed)
  720. gnode_identifier_expr_t *id = (gnode_identifier_expr_t *)node->superclass;
  721. node->superclass = NULL;
  722. // sanity check
  723. if (gravity_core_class_from_name(id->value)) {
  724. REPORT_ERROR(id, "Unable to subclass built-in core class %s.", id->value);
  725. return;
  726. }
  727. // lookup super node
  728. gnode_t *target = lookup_symtable_id(self, id, true);
  729. node->superclass = target;
  730. if (!target) {
  731. REPORT_ERROR(id, "Unable to find superclass %s for class %s.", id->value, node->identifier);
  732. } else {
  733. gnode_class_decl_t *target_class = (gnode_class_decl_t *)gnode2class(target, &node->super_extern);
  734. if (!target_class) {
  735. REPORT_ERROR(id, "Unable to set non class %s as superclass of %s.", id->value, node->identifier);
  736. } else if ((gnode_class_decl_t *)node == (gnode_class_decl_t *)target_class->superclass) {
  737. REPORT_ERROR(id, "Unable to set circular class hierarchies (%s <-> %s).", id->value, node->identifier);
  738. gnode_free((gnode_t*)id);
  739. return;
  740. }
  741. }
  742. gnode_free((gnode_t*)id);
  743. }
  744. // check protocols (disable in this version because protocols are not yet supported)
  745. // if (node->protocols) {
  746. // gnode_array_each(node->protocols, {
  747. // gnode_id_expr_t *id = (gnode_id_expr_t *)val;
  748. // gnode_t *target = lookup_symtable_id(self, id, false);
  749. // if (!target) continue;
  750. // id->symbol = target;
  751. // });
  752. // }
  753. PUSH_DECLARATION(node);
  754. gnode_array_each(node->decls, {
  755. if ((node->superclass) && (ISA_VAR_DECLARATION(val))) {
  756. // check for redeclared ivar and if found report a warning
  757. check_class_ivar(self, (gnode_class_decl_t *)node, (gnode_variable_decl_t *)val);
  758. }
  759. visit(val);
  760. });
  761. POP_DECLARATION();
  762. }
  763. static void visit_module_decl (gvisitor_t *self, gnode_module_decl_t *node) {
  764. DEBUG_SEMA2("visit_module_decl %s", node->identifier);
  765. gnode_t *top = TOP_DECLARATION();
  766. // set and check module enclosing (only in file)
  767. node->env = top;
  768. if (NODE_TAG(top) != NODE_LIST_STAT) REPORT_ERROR(node, "Module %s cannot be declared here.", node->identifier);
  769. // check if optional access and storage specifiers make sense in current context
  770. check_access_storage_specifiers(self, (gnode_t *)node, NODE_TAG(top), node->access, node->storage);
  771. PUSH_DECLARATION(node);
  772. gnode_array_each(node->decls, {visit(val);});
  773. POP_DECLARATION();
  774. }
  775. // MARK: - Expressions -
  776. static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
  777. DEBUG_SEMA2("visit_binary_expr %s", token_name(node->op));
  778. // sanity check
  779. if (!is_expression(node->left)) REPORT_ERROR(node->left, "LValue must be an expression.");
  780. if (!is_expression(node->right)) REPORT_ERROR(node->right, "RValue must be an expression.");
  781. // fill missing symbols
  782. visit(node->left);
  783. visit(node->right);
  784. if (!is_expression_valid(node->left)) REPORT_ERROR(node->left, "Invalid left expression.");
  785. if (!is_expression_valid(node->right)) REPORT_ERROR(node->right, "Invalid right expression.");
  786. // sanity check binary expressions
  787. if (is_expression_assignment((gnode_t*)node)) check_assignment_expression(self, node);
  788. else if (is_expression_range((gnode_t*)node)) check_range_expression(self, node);
  789. }
  790. static void visit_unary_expr (gvisitor_t *self, gnode_unary_expr_t *node) {
  791. DEBUG_SEMA2("visit_unary_expr %s", token_name(node->op));
  792. visit(node->expr);
  793. if (!is_expression_valid(node->expr)) REPORT_ERROR(node->expr, "Invalid expression.");
  794. }
  795. static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
  796. DEBUG_SEMA2("visit_postfix_expr");
  797. // sanity check
  798. if (!node->id) {REPORT_ERROR(node, "Invalid postfix expression."); return;}
  799. // a postfix expression is an expression that requires an in-context lookup that depends on id
  800. // in a statically typed language the loop should check every member of the postfix expression
  801. // usign the context of the previous lookup, for example:
  802. // a.b.c.d.e
  803. // means
  804. // lookup a and get its associated symbol table
  805. // lookup b in a
  806. // lookup c in the context of the previous lookup
  807. // lookup d in the context of the previous lookup
  808. // and so on in a loop
  809. // Gravity is a dynamically typed language so we cannot statically check membership in a statically way
  810. // because the lookup context can vary at runtime, for example
  811. // class C1 {...}
  812. // class C2 {...}
  813. // func foo(n) {if (n % 2 == 0) return C1(); else return C2();}
  814. // var c = foo(rand()).bar;
  815. // should bar be lookup in C1 or in C2?
  816. // we really can't know at compile time but only at runtime
  817. // lookup common part (and generate an error if id cannot be found)
  818. // id can be a primary expression
  819. visit(node->id);
  820. // try to obtain symbol table from id (if any)
  821. gnode_t *target = NULL;
  822. if (ISA(node->id, NODE_IDENTIFIER_EXPR)) {
  823. target = ((gnode_identifier_expr_t *)node->id)->symbol;
  824. if (ISA(target, NODE_VARIABLE)) target = NULL; // a variable does not contain a symbol table
  825. }
  826. // special enum case on list[0] (it is a static case)
  827. if (ISA(target, NODE_ENUM_DECL)) {
  828. // check first expression in the list (in case of enum MUST BE an identifier)
  829. gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, 0);
  830. // enum sanity checks
  831. gnode_n tag = subnode->base.tag;
  832. if (tag != NODE_ACCESS_EXPR) {REPORT_ERROR(node->id, "Invalid enum expression."); return;}
  833. if (node->base.is_assignment) {REPORT_ERROR(node, "Assignment not allowed for an enum type."); return;}
  834. if (!ISA(subnode->expr, NODE_IDENTIFIER_EXPR)) {REPORT_ERROR(subnode, "Invalid enum expression."); return;}
  835. // lookup enum value
  836. gnode_identifier_expr_t *expr = (gnode_identifier_expr_t *)subnode->expr;
  837. const char *value = expr->value;
  838. gnode_t *v = lookup_node(target, value);
  839. if (!v) {REPORT_ERROR(subnode, "Unable to find %s in enum %s.", value, ((gnode_enum_decl_t *)target)->identifier); return;}
  840. // node.subnode must be replaced by a literal enum expression (returned by v)
  841. size_t n = gnode_array_size(node->list);
  842. if (n == 1) {
  843. // replace the entire gnode_postfix_expr_t node with v literal value
  844. // gnode_replace(node, v); NODE REPLACEMENT FUNCTION TO BE IMPLEMENTED
  845. gnode_free(node->id);
  846. // we need to explicitly free postfix subexpression here
  847. gnode_postfix_subexpr_t *subexpr = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, 0);
  848. free_postfix_subexpr(subexpr);
  849. // list cannot be NULL in a postfix expression, we'll use this flag to identify a transformed enum expression
  850. gnode_array_free(node->list);
  851. node->list = NULL;
  852. node->id = gnode_duplicate(v, false);
  853. } else {
  854. // postfix expression contains more access nodes so just transform current postfix expression
  855. // 1. replace id node
  856. gnode_free(node->id);
  857. node->id = gnode_duplicate(v, false);
  858. // 2. free first node from node->list
  859. gnode_postfix_subexpr_t *subexpr = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, 0);
  860. free_postfix_subexpr(subexpr);
  861. // 3. remove first node from node->list
  862. node->list = gnode_array_remove_byindex(node->list, 0);
  863. }
  864. return;
  865. }
  866. // check to avoid infinite loop in init
  867. if (ISA(node->id, NODE_IDENTIFIER_EXPR)) {
  868. if (is_init_infinite_loop(self, (gnode_identifier_expr_t *)node->id, node->list)) {
  869. REPORT_ERROR(node, "Infinite loop detected in init func.");
  870. }
  871. }
  872. bool is_super = (NODE_ISA(node->id, NODE_KEYWORD_EXPR) && (((gnode_keyword_expr_t *)node->id)->base.token.type == TOK_KEY_SUPER));
  873. bool is_assignment = node->base.is_assignment;
  874. // process each subnode
  875. size_t count = gnode_array_size(node->list);
  876. for (size_t i=0; i<count; ++i) {
  877. gnode_postfix_subexpr_t *subnode = (gnode_postfix_subexpr_t *)gnode_array_get(node->list, i);
  878. // identify postfix type: NODE_CALL_EXPR, NODE_ACCESS_EXPR, NODE_SUBSCRIPT_EXPR
  879. gnode_n tag = subnode->base.tag;
  880. // check assignment flag
  881. bool is_real_assigment = (is_assignment && (i+1 == count));
  882. // assignment sanity check
  883. if (is_real_assigment) {
  884. if (tag == NODE_CALL_EXPR) {REPORT_ERROR((gnode_t *)subnode, "Unable to assign a value to a function call."); return;}
  885. if (is_super) {REPORT_ERROR((gnode_t *)subnode, "Unable to explicitly modify super."); return;}
  886. }
  887. // for a function/method call visit each argument
  888. if (tag == NODE_CALL_EXPR) {
  889. size_t n = gnode_array_size(subnode->args);
  890. for (size_t j=0; j<n; ++j) {
  891. gnode_t *val = (gnode_t *)gnode_array_get(subnode->args, j);
  892. if (is_expression_assignment(val)) {REPORT_ERROR(val, "Assignment does not have side effects and so cannot be used as function argument."); return;}
  893. visit(val);
  894. }
  895. continue;
  896. }
  897. // for a subscript just visit its index expression
  898. if (tag == NODE_SUBSCRIPT_EXPR) {
  899. if (subnode->expr) visit(subnode->expr);
  900. continue;
  901. }
  902. // for a member access check each lookup type (but do not perform a lookup)
  903. if (tag == NODE_ACCESS_EXPR) {
  904. if (!ISA(subnode->expr, NODE_IDENTIFIER_EXPR)) REPORT_ERROR(subnode->expr, "Invalid access expression.");
  905. continue;
  906. }
  907. // should never reach this point
  908. DEBUG_SEMA2("UNRECOGNIZED POSTFIX OPTIONAL EXPRESSION");
  909. assert(0);
  910. }
  911. }
  912. static void visit_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
  913. DEBUG_SEMA2("visit_file_expr");
  914. gnode_r *decls = ((semacheck_t *)self->data)->declarations;
  915. gnode_t *globals = gnode_array_get(decls, 0);
  916. gnode_t *target = globals;
  917. size_t n = gnode_array_size(node->identifiers);
  918. assert(n);
  919. // no need to scan the entire list because lookup must be performed at runtime so check just the first element
  920. n = 1;
  921. for (size_t i=0; i<n; ++i) {
  922. const char *identifier = gnode_array_get(node->identifiers, i);
  923. DEBUG_SEMA2("LOOKUP %s", identifier);
  924. gnode_t *symbol = lookup_node(target, identifier);
  925. if (!symbol) {REPORT_ERROR(node, "Module identifier %s not found.", identifier); break;}
  926. SET_NODE_LOCATION(node, LOCATION_GLOBAL, 0, 0);
  927. target = symbol;
  928. }
  929. }
  930. static void visit_literal_expr (gvisitor_t *self, gnode_literal_expr_t *node) {
  931. #pragma unused(self, node)
  932. #if GRAVITY_SEMANTIC_DEBUG
  933. char value[256];
  934. gnode_literal_dump(node, value, sizeof(value));
  935. DEBUG_SEMA2("visit_literal_expr %s", value);
  936. DEBUG_SEMA2("end visit_literal_expr");
  937. #endif
  938. if (node->type == LITERAL_STRING_INTERPOLATED) {
  939. gnode_array_each(node->value.r, {
  940. visit(val);
  941. });
  942. }
  943. }
  944. static void visit_identifier_expr (gvisitor_t *self, gnode_identifier_expr_t *node) {
  945. DEBUG_SEMA2("visit_identifier_expr %s", node->value);
  946. gnode_t *symbol = lookup_identifier(self, node->value, node);
  947. if (!symbol) REPORT_ERROR(node, "Identifier %s not found.", node->value);
  948. }
  949. static void visit_keyword_expr (gvisitor_t *self, gnode_keyword_expr_t *node) {
  950. #pragma unused(self, node)
  951. DEBUG_SEMA2("visit_keyword_expr %s", token_name(node->base.token.type));
  952. }
  953. static void visit_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
  954. size_t n = gnode_array_size(node->list1);
  955. bool ismap = (node->list2 != NULL);
  956. DEBUG_SEMA2("visit_list_expr (n: %zu ismap: %d)", n, ismap);
  957. for (size_t j=0; j<n; ++j) {
  958. gnode_t *e = gnode_array_get(node->list1, j);
  959. visit(e);
  960. if (ismap) {
  961. // key must be unique
  962. for (size_t k=0; k<n; ++k) {
  963. if (k == j) continue; // do not check itself
  964. gnode_t *key = gnode_array_get(node->list1, k);
  965. if (gnode_is_equal(e, key)) {
  966. if (gnode_is_literal_string(key)) {
  967. gnode_literal_expr_t *v = (gnode_literal_expr_t *)key;
  968. REPORT_ERROR(key, "Duplicated key %s in map.", v->value.str);
  969. } else REPORT_ERROR(key, "Duplicated key in map.");
  970. }
  971. }
  972. e = gnode_array_get(node->list2, j);
  973. visit(e);
  974. }
  975. }
  976. }
  977. // MARK: -
  978. bool gravity_semacheck2 (gnode_t *node, gravity_delegate_t *delegate) {
  979. semacheck_t data = {.declarations = gnode_array_create(), .lasterror = 0};
  980. marray_init(data.statements);
  981. gvisitor_t visitor = {
  982. .nerr = 0, // used to store number of found errors
  983. .data = (void *)&data, // used to store a pointer to the semantic check struct
  984. .delegate = (void *)delegate, // compiler delegate to report errors
  985. // COMMON
  986. .visit_pre = NULL,
  987. .visit_post = NULL,
  988. // STATEMENTS: 7
  989. .visit_list_stmt = visit_list_stmt,
  990. .visit_compound_stmt = visit_compound_stmt,
  991. .visit_label_stmt = visit_label_stmt,
  992. .visit_flow_stmt = visit_flow_stmt,
  993. .visit_loop_stmt = visit_loop_stmt,
  994. .visit_jump_stmt = visit_jump_stmt,
  995. .visit_empty_stmt = visit_empty_stmt,
  996. // DECLARATIONS: 5
  997. .visit_function_decl = visit_function_decl,
  998. .visit_variable_decl = visit_variable_decl,
  999. .visit_enum_decl = visit_enum_decl,
  1000. .visit_class_decl = visit_class_decl,
  1001. .visit_module_decl = visit_module_decl,
  1002. // EXPRESSIONS: 8
  1003. .visit_binary_expr = visit_binary_expr,
  1004. .visit_unary_expr = visit_unary_expr,
  1005. .visit_file_expr = visit_file_expr,
  1006. .visit_literal_expr = visit_literal_expr,
  1007. .visit_identifier_expr = visit_identifier_expr,
  1008. .visit_keyword_expr = visit_keyword_expr,
  1009. .visit_list_expr = visit_list_expr,
  1010. .visit_postfix_expr = visit_postfix_expr,
  1011. };
  1012. DEBUG_SEMA2("=== SEMANTIC CHECK STEP 2 ===");
  1013. gvisit(&visitor, node);
  1014. DEBUG_SEMA2("\n");
  1015. marray_destroy(data.statements);
  1016. gnode_array_free(data.declarations);
  1017. return (visitor.nerr == 0);
  1018. }