ast_t* symtab_find_case(symtab_t* symtab, const char* name, sym_status_t* status) { // Same as symtab_get, but is partially case insensitive. That is, type names // are compared as uppercase and other symbols are compared as lowercase. symbol_t s1 = {name, NULL, SYM_NONE, 0}; symbol_t* s2 = symtab_get(symtab, &s1); if(s2 != NULL) { if(status != NULL) *status = s2->status; return s2->def; } const char* no_case = name_without_case(name); if(no_case != name) return symtab_find_case(symtab, no_case, status); if(status != NULL) *status = SYM_NONE; return NULL; }
ast_t* ast_get_case(ast_t* ast, const char* name, sym_status_t* status) { // Same as ast_get, but is partially case insensitive. That is, type names // are compared as uppercase and other symbols are compared as lowercase. if(status != NULL) *status = SYM_NONE; do { if(ast->symtab != NULL) { sym_status_t status2; ast_t* value = (ast_t*)symtab_find_case(ast->symtab, name, &status2); if((status != NULL) && (*status == SYM_NONE)) *status = status2; if(value != NULL) return value; } ast = ast->parent; } while((ast != NULL) && (token_get_id(ast->t) != TK_PROGRAM)); return NULL; }
bool symtab_can_merge_public(symtab_t* dst, symtab_t* src) { size_t i = HASHMAP_BEGIN; symbol_t* sym; while((sym = symtab_next(src, &i)) != NULL) { if(is_name_private(sym->name) || (sym->status == SYM_NOCASE) || !strcmp(sym->name, "Main")) continue; if(symtab_find_case(dst, sym->name, NULL) != NULL) return false; } return true; }
// Add the given method to the relevant name list in the given symbol table static bool add_method_to_list(ast_t* method, methods_t* method_info, const char *entity_name) { assert(method != NULL); assert(method_info != NULL); assert(entity_name != NULL); const char* name = ast_name(ast_childidx(method, 1)); assert(name != NULL); symtab_t* symtab = method_info->symtab; assert(symtab != NULL); // Entity doesn't yet have method, add it to our list for later ast_t* list = (ast_t*)symtab_find(symtab, name, NULL); if(list == NULL) { ast_t* case_clash = (ast_t*)symtab_find_case(symtab, name, NULL); if(case_clash != NULL) { ast_error(case_clash, "in %s method name differs only in case", entity_name); ast_error(method, "previous definition is here"); return false; } // First instance of this name list = ast_blank(TK_ID); ast_set_name(list, name); symtab_add(symtab, name, (void*)list, SYM_NONE); if(method_info->last_list == NULL) ast_add(method_info->name_lists, list); else ast_add_sibling(method_info->last_list, list); method_info->last_list = list; } ast_add(list, method); return true; }
bool ast_set(ast_t* ast, const char* name, ast_t* value, sym_status_t status, bool allow_shadowing) { while(ast->symtab == NULL) ast = ast->parent; if(allow_shadowing) { // Only check the local scope. if(symtab_find_case(ast->symtab, name, NULL) != NULL) return false; } else { // Check the local scope and all parent scopes. if(ast_get_case(ast, name, NULL) != NULL) return false; } return symtab_add(ast->symtab, name, value, status); }