Browse Source

Fixed an issue with static var/func declared inside a class.

Marco Bambini 7 years ago
parent
commit
30d8828108
2 changed files with 49 additions and 4 deletions
  1. 36 3
      src/compiler/gravity_semacheck1.c
  2. 13 1
      src/compiler/gravity_semacheck2.c

+ 36 - 3
src/compiler/gravity_semacheck1.c

@@ -80,7 +80,18 @@ static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node)
 	DEBUG_SYMTABLE("function: %s", node->identifier);
 	DEBUG_SYMTABLE("function: %s", node->identifier);
 
 
 	// function identifier
 	// function identifier
-    if (!symboltable_insert(symtable, node->identifier, (void *)node)) {
+    const char *identifier = node->identifier;
+    
+    // reserve a special name for static objects defined inside a class
+    // to avoid name collision between class ivar and meta-class ivar
+    char buffer[512];
+    if ((symboltable_tag(symtable) == SYMTABLE_TAG_CLASS) && node->storage == TOK_KEY_STATIC) {
+        snprintf(buffer, sizeof(buffer), "$%s", identifier);
+        identifier = (const char *)buffer;
+    }
+    
+	// function identifier
+    if (!symboltable_insert(symtable, identifier, (void *)node)) {
 		REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
 		REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
     }
     }
 
 
@@ -90,12 +101,23 @@ static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node)
 
 
 static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
 static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
 	DECLARE_SYMTABLE();
 	DECLARE_SYMTABLE();
+    char buffer[512];
 
 
     bool is_static = (node->storage == TOK_KEY_STATIC);
     bool is_static = (node->storage == TOK_KEY_STATIC);
 	gnode_array_each(node->decls, {
 	gnode_array_each(node->decls, {
 		gnode_var_t *p = (gnode_var_t *)val;
 		gnode_var_t *p = (gnode_var_t *)val;
         
         
-        if (!symboltable_insert(symtable, p->identifier, (void *)p)) {
+        // variable identifier
+        const char  *identifier = p->identifier;
+        
+        // reserve a special name for static objects defined inside a class
+        // to avoid name collision between class ivar and meta-class ivar
+        if ((symboltable_tag(symtable) == SYMTABLE_TAG_CLASS) && is_static) {
+            snprintf(buffer, sizeof(buffer), "$%s", identifier);
+            identifier = (const char *)buffer;
+        }
+        
+        if (!symboltable_insert(symtable, identifier, (void *)p)) {
 			REPORT_ERROR(p, "Identifier %s redeclared.", p->identifier);
 			REPORT_ERROR(p, "Identifier %s redeclared.", p->identifier);
         }
         }
         
         
@@ -126,7 +148,18 @@ static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
 	DEBUG_SYMTABLE("class: %s", node->identifier);
 	DEBUG_SYMTABLE("class: %s", node->identifier);
 
 
 	// class identifier
 	// class identifier
-    if (!symboltable_insert(symtable, node->identifier, (void *)node)) {
+    const char *identifier = node->identifier;
+    
+    // reserve a special name for static objects defined inside a class
+    // to avoid name collision between class ivar and meta-class ivar
+    char buffer[512];
+    if ((symboltable_tag(symtable) == SYMTABLE_TAG_CLASS) && node->storage == TOK_KEY_STATIC) {
+        snprintf(buffer, sizeof(buffer), "$%s", identifier);
+        identifier = (const char *)buffer;
+    }
+    
+	// class identifier
+    if (!symboltable_insert(symtable, identifier, (void *)node)) {
 		REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
 		REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
     }
     }
 
 

+ 13 - 1
src/compiler/gravity_semacheck2.c

@@ -121,10 +121,12 @@ static gnode_t *lookup_identifier (gvisitor_t *self, const char *identifier, gno
 
 
 	uint16_t nf = 0; // number of functions traversed
 	uint16_t nf = 0; // number of functions traversed
 	uint16_t nc = 0; // number of classes traversed
 	uint16_t nc = 0; // number of classes traversed
+    char buffer[512];
 
 
 	// get first node (the latest in the decls stack)
 	// get first node (the latest in the decls stack)
 	gnode_t	*base_node = gnode_array_get(decls, len-1);
 	gnode_t	*base_node = gnode_array_get(decls, len-1);
 	bool base_is_class = ISA(base_node, NODE_CLASS_DECL);
 	bool base_is_class = ISA(base_node, NODE_CLASS_DECL);
+    bool base_is_static_function = (ISA(base_node, NODE_FUNCTION_DECL) && ((gnode_function_decl_t*)base_node)->storage == TOK_KEY_STATIC);
 
 
 	for (int i=(int)len-1; i>=0; --i) {
 	for (int i=(int)len-1; i>=0; --i) {
 		gnode_t	*target = gnode_array_get(decls, i);
 		gnode_t	*target = gnode_array_get(decls, i);
@@ -135,11 +137,21 @@ static gnode_t *lookup_identifier (gvisitor_t *self, const char *identifier, gno
 		bool target_is_class = ISA(target, NODE_CLASS_DECL);
 		bool target_is_class = ISA(target, NODE_CLASS_DECL);
 		bool target_is_module = ISA(target, NODE_MODULE_DECL);
 		bool target_is_module = ISA(target, NODE_MODULE_DECL);
 
 
+        // count number of traversed func/class
 		if (target_is_function) ++nf;
 		if (target_is_function) ++nf;
 		else if (target_is_class) ++nc;
 		else if (target_is_class) ++nc;
 
 
+		// if identifier has been declared in a static func
+        // and lookup target is a class, then use its special
+        // reserved name to perform the lookup
+        const char *id = identifier;
+        if (base_is_static_function && target_is_class) {
+            snprintf(buffer, sizeof(buffer), "$%s", identifier);
+            id = (const char *)buffer;
+        }
+        
 		// lookup identifier is current target (obtained traversing the declaration stack)
 		// lookup identifier is current target (obtained traversing the declaration stack)
-		gnode_t	*symbol = lookup_node(target, identifier);
+		gnode_t	*symbol = lookup_node(target, id);
 
 
 		// sanity check: if base_node is a class and symbol was found inside a func then report an error
 		// sanity check: if base_node is a class and symbol was found inside a func then report an error
 		if (symbol && target_is_function && base_is_class) {
 		if (symbol && target_is_function && base_is_class) {