diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 7001b0845..75afaef43 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -32,6 +32,14 @@ #ifndef __class_h #define __class_h +typedef struct class_type_s { + int is_class; + union { + struct category_s *category; + struct class_s *class; + } c; +} class_type_t; + typedef struct class_s { int defined; const char *name; @@ -42,45 +50,53 @@ typedef struct class_s { struct protocollist_s *protocols; struct def_s *def; struct type_s *type; + class_type_t class_type; } class_t; typedef struct category_s { struct category_s *next; const char *name; class_t *class; + int defined; struct methodlist_s *methods; struct protocollist_s *protocols; + struct def_s *def; + class_type_t class_type; } category_t; extern class_t class_id; extern class_t class_Class; extern class_t class_Protocol; -extern class_t *current_class; +extern class_type_t *current_class; struct expr_s; struct method_s; struct protocol_s; struct type_s; -struct def_s *class_def (class_t *class, int external); +struct def_s *class_def (class_type_t *class_type, int external); void class_init (void); class_t *get_class (const char *name, int create); void class_add_methods (class_t *class, struct methodlist_s *methods); void class_add_protocol_methods (class_t *class, struct expr_s *protocols); -void class_add_protocol (class_t *class, struct protocol_s *protocol); void class_add_ivars (class_t *class, struct type_s *ivars); void class_check_ivars (class_t *class, struct type_s *ivars); -void class_begin (class_t *class); -void class_finish (class_t *class); +void class_begin (class_type_t *class_type); +void class_finish (class_type_t *class_type); +int class_access (class_type_t *current_class, class_t *class); struct struct_field_s *class_find_ivar (class_t *class, int protected, const char *name); -struct expr_s *class_ivar_expr (class_t *class, const char *name); -struct method_s *class_find_method (class_t *class, struct method_s *method); +struct expr_s *class_ivar_expr (class_type_t *class_type, const char *name); +struct method_s *class_find_method (class_type_t *class_type, + struct method_s *method); struct method_s *class_message_response (class_t *class, struct expr_s *sel); -struct def_s *class_pointer_def (class_t *class); -class_t *get_category (const char *class_name, const char *category_name, - int create); +struct def_s *class_pointer_def (class_t *class_type); +category_t *get_category (const char *class_name, const char *category_name, + int create); +void category_add_methods (category_t *category, struct methodlist_s *methods); +void category_add_protocol_methods (category_t *category, + struct expr_s *protocols); void class_finish_module (void); typedef struct protocol_s { diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index 802e736ef..518bb79d4 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -66,7 +66,7 @@ struct dstring_s; method_t *new_method (struct type_s *ret_type, param_t *selector, param_t *opt_parms); void add_method (methodlist_t *methodlist, method_t *method); -struct def_s *method_def (struct class_s *class, method_t *method); +struct def_s *method_def (struct class_type_s *class_type, method_t *method); methodlist_t *new_methodlist (void); void copy_methods (methodlist_t *dst, methodlist_t *src); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 6809490e9..24ed7128b 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -87,20 +87,18 @@ class_init (void) } def_t * -class_def (class_t *class, int external) +class_def (class_type_t *class_type, int external) { const char *name; type_t *type; storage_class_t storage = external ? st_extern : st_global; - if (!class->name) - return 0; - if (class->categories) { - name = va ("_OBJ_CATEGORY_%s_%s", - class->name, class->categories->name); + if (!class_type->is_class) { + name = va ("_OBJ_CATEGORY_%s_%s", class_type->c.category->class->name, + class_type->c.category->name); type = type_category; } else { - name = va ("_OBJ_CLASS_%s", class->name); + name = va ("_OBJ_CLASS_%s", class_type->c.class->name); type = type_Class.aux_type; } return get_def (type, name, pr.scope, storage); @@ -125,6 +123,8 @@ get_class (const char *name, int create) new = *type_Class.aux_type; new.class = c; c->type = pointer_type (find_type (&new)); + c->class_type.is_class = 1; + c->class_type.c.class = c; if (name) Hash_Add (class_hash, c); return c; @@ -135,18 +135,11 @@ class_add_methods (class_t *class, methodlist_t *methods) { if (!methods) return; - if (class->categories) { - category_t *category = class->categories; - if (!category->methods) - category->methods = new_methodlist (); - *category->methods->tail = methods->head; - category->methods->tail = methods->tail; - } else { - if (!class->methods) - class->methods = new_methodlist (); - *class->methods->tail = methods->head; - class->methods->tail = methods->tail; - } + + if (!class->methods) + class->methods = new_methodlist (); + *class->methods->tail = methods->head; + class->methods->tail = methods->tail; free (methods); } @@ -158,23 +151,13 @@ class_add_protocol_methods (class_t *class, expr_t *protocols) if (!protocol_hash) protocol_hash = Hash_NewTable (1021, protocol_get_key, 0, 0); - if (class->categories) { - if (!class->categories->methods) - class->categories->methods = new_methodlist (); - } else { - if (!class->methods) - class->methods = new_methodlist (); - } + + if (!class->methods) + class->methods = new_methodlist (); for (e = protocols; e; e = e->next) { - methodlist_t *methods; - method_t **m; - - if (class->categories) - methods = class->categories->methods; - else - methods = class->methods; - m = methods->tail; + methodlist_t *methods = class->methods; + method_t **m = methods->tail; if (!(p = get_protocol (e->e.string_val, 0))) { error (e, "undefined protocol `%s'", e->e.string_val); @@ -189,35 +172,32 @@ class_add_protocol_methods (class_t *class, expr_t *protocols) } void -class_add_protocol (class_t *class, protocol_t *protocol) +class_begin (class_type_t *class_type) { - if (!class->protocols) - class->protocols = new_protocollist (); - add_protocol (class->protocols, protocol); -} + if (!class_type->is_class) { + pr_category_t *pr_category; + category_t *category = class_type->c.category; + class_t *class = category->class; -void -class_begin (class_t *class) -{ - current_class = class; - class->def = class_def (class, 0); - if (class->name && class->categories) { - pr_category_t *category; - - class->def->initialized = class->def->constant = 1; - category = &G_STRUCT (pr_category_t, class->def->ofs); - EMIT_STRING (category->category_name, class->categories->name); - EMIT_STRING (category->class_name, class->name); - EMIT_DEF (category->protocols, - emit_protocol_list (class->categories->protocols, + current_class = &category->class_type; + category->def = class_def (class_type, 0); + category->def->initialized = category->def->constant = 1; + pr_category = &G_STRUCT (pr_category_t, category->def->ofs); + EMIT_STRING (pr_category->category_name, category->name); + EMIT_STRING (pr_category->class_name, class->name); + EMIT_DEF (pr_category->protocols, + emit_protocol_list (category->protocols, va ("%s_%s", class->name, - class->categories->name))); - } else if (class->name) { + category->name))); + } else { def_t *meta_def; pr_class_t *meta; pr_class_t *cls; + class_t *class = class_type->c.class; + current_class = &class->class_type; + class->def = class_def (class_type, 0); meta_def = get_def (type_Class.aux_type, va ("_OBJ_METACLASS_%s", class->name), pr.scope, st_static); @@ -237,8 +217,10 @@ class_begin (class_t *class) cls = &G_STRUCT (pr_class_t, class->def->ofs); EMIT_DEF (cls->class_pointer, meta_def); if (class->super_class) { + class_type_t class_type = {1, {0}}; + class_type.c.class = class->super_class; EMIT_STRING (cls->super_class, class->super_class->name); - class_def (class->super_class, 1); + class_def (&class_type, 1); } EMIT_STRING (cls->name, class->name); cls->info = _PR_CLS_CLASS; @@ -247,13 +229,14 @@ class_begin (class_t *class) } void -class_finish (class_t *class) +class_finish (class_type_t *class_type) { - if (class->name && class->categories) { + if (!class_type->is_class) { pr_category_t *pr_category; - category_t *category = class->categories; + category_t *category = class_type->c.category; + class_t *class = category->class; - pr_category = &G_STRUCT (pr_category_t, class->def->ofs); + pr_category = &G_STRUCT (pr_category_t, category->def->ofs); EMIT_DEF (pr_category->instance_methods, emit_methods (category->methods, va ("%s_%s", class->name, @@ -262,9 +245,10 @@ class_finish (class_t *class) emit_methods (category->methods, va ("%s_%s", class->name, category->name), 0)); - } else if (class->name) { + } else { pr_class_t *meta; pr_class_t *cls; + class_t *class = class_type->c.class; cls = &G_STRUCT (pr_class_t, class->def->ofs); @@ -280,6 +264,16 @@ class_finish (class_t *class) } } +int +class_access (class_type_t *current_class, class_t *class) +{ + if (!current_class) + return 1; + if (current_class->is_class) + return current_class->c.class != class; + return current_class->c.category->class != class; +} + struct_field_t * class_find_ivar (class_t *class, int protected, const char *name) { @@ -309,14 +303,19 @@ class_find_ivar (class_t *class, int protected, const char *name) } expr_t * -class_ivar_expr (class_t *class, const char *name) +class_ivar_expr (class_type_t *class_type, const char *name) { struct_field_t *ivar; - class_t *c; + class_t *c, *class; - if (!class) + if (!class_type) return 0; + if (class_type->is_class) { + class = class_type->c.class; + } else { + class = class_type->c.category->class; + } ivar = struct_find_field (class->ivars, name); if (!ivar) { for (c = class->super_class; c; c = c->super_class) { @@ -336,16 +335,22 @@ class_ivar_expr (class_t *class, const char *name) } method_t * -class_find_method (class_t *class, method_t *method) +class_find_method (class_type_t *class_type, method_t *method) { methodlist_t *methods; method_t *m; dstring_t *sel; + const char *class_name; + const char *category_name = 0; - if (class->categories) - methods = class->categories->methods; - else - methods = class->methods; + if (!class_type->is_class) { + methods = class_type->c.category->methods; + category_name = class_type->c.category->name; + class_name = class_type->c.category->class->name; + } else { + methods = class_type->c.class->methods; + class_name = class_type->c.class->name; + } for (m = methods->head; m; m = m->next) if (method_compare (method, m)) return m; @@ -353,8 +358,8 @@ class_find_method (class_t *class, method_t *method) selector_name (sel, (keywordarg_t *)method->selector); warning (0, "%s method %s not in %s%s", method->instance ? "instance" : "class", - sel->str, class->name, - class->categories ? va (" (%s)", class->categories->name) : ""); + sel->str, class_name, + category_name ? va (" (%s)", category_name) : ""); dstring_delete (sel); return method; } @@ -423,10 +428,10 @@ class_check_ivars (class_t *class, struct type_s *ivars) class->ivars = ivars; } -class_t * +category_t * get_category (const char *class_name, const char *category_name, int create) { - category_t *c; + category_t *category; class_t *class; if (!category_hash) { @@ -437,41 +442,76 @@ get_category (const char *class_name, const char *category_name, int create) class = get_class (class_name, 0); if (!class) { error (0, "undefined class %s", class_name); - return get_class (0, 1); + return 0; } if (class_name && category_name) { - class_t _c = {0, category_name, class}; + category_t _c = {0, category_name, class}; - c = Hash_FindElement (category_hash, &_c); - if (c) { - category_t **cat = &class->categories; - category_t *t; - while (*cat != c) - cat = &(*cat)->next; - t = *cat; - *cat = (*cat)->next; - t->next = class->categories; - class->categories = t; - return class; - } - if (!create) - return 0; + category = Hash_FindElement (category_hash, &_c); + if (category || !create) + return category; } - c = calloc (sizeof (category_t), 1); - c->next = class->categories; - class->categories = c; - c->name = category_name; - c->class = class; + category = calloc (sizeof (category_t), 1); + category->next = class->categories; + class->categories = category; + category->name = category_name; + category->class = class; + category->class_type.is_class = 0; + category->class_type.c.category = category; if (class_name && category_name) - Hash_AddElement (category_hash, c); - return c->class; + Hash_AddElement (category_hash, category); + return category; +} + +void +category_add_methods (category_t *category, methodlist_t *methods) +{ + if (!methods) + return; + if (!category->methods) + category->methods = new_methodlist (); + *category->methods->tail = methods->head; + category->methods->tail = methods->tail; + free (methods); +} + +void +category_add_protocol_methods (category_t *category, expr_t *protocols) +{ + expr_t *e; + protocol_t *p; + type_t *type; + + if (!protocol_hash) + protocol_hash = Hash_NewTable (1021, protocol_get_key, 0, 0); + if (!category->methods) + category->methods = new_methodlist (); + type = category->class->type; + + for (e = protocols; e; e = e->next) { + methodlist_t *methods = category->methods; + method_t **m = methods->tail; + + if (!(p = get_protocol (e->e.string_val, 0))) { + error (e, "undefined protocol `%s'", e->e.string_val); + continue; + } + copy_methods (methods, p->methods); + while (*m) { + (*m)->params->type = type; + m = &(*m)->next; + } + } } def_t * class_pointer_def (class_t *class) { def_t *def; + class_type_t class_type = {1, {0}}; + + class_type.c.class = class; def = get_def (class->type, va ("_OBJ_CLASS_POINTER_%s", class->name), @@ -480,7 +520,7 @@ class_pointer_def (class_t *class) return def; def->initialized = def->constant = 1; if (!class->def) - class->def = class_def (class, 1); + class->def = class_def (&class_type, 1); if (!class->def->external) G_INT (def->ofs) = class->def->ofs; reloc_def_def (class->def, def->ofs); @@ -490,9 +530,8 @@ class_pointer_def (class_t *class) void class_finish_module (void) { - class_t **classes = 0; - class_t **categories = 0; - class_t **t; + class_t **classes = 0, **cl; + category_t **categories = 0, **ca; int num_classes = 0; int num_categories = 0; int i; @@ -509,14 +548,14 @@ class_finish_module (void) if (class_hash) { classes = (class_t **) Hash_GetList (class_hash); - for (t = classes; *t; t++) - if ((*t)->def && !(*t)->def->external) + for (cl = classes; *cl; cl++) + if ((*cl)->def && !(*cl)->def->external) num_classes++; } if (category_hash) { - categories = (class_t **) Hash_GetList (category_hash); - for (t = categories; *t; t++) - if ((*t)->def && !(*t)->def->external) + categories = (category_t **) Hash_GetList (category_hash); + for (ca = categories; *ca; ca++) + if ((*ca)->def && !(*ca)->def->external) num_categories++; } if (!num_classes && !num_categories) @@ -534,18 +573,18 @@ class_finish_module (void) symtab->cat_def_cnt = num_categories; def_ptr = symtab->defs; if (classes) { - for (t = classes; *t; t++) { - if ((*t)->def && !(*t)->def->external) { - reloc_def_def ((*t)->def, POINTER_OFS (def_ptr)); - *def_ptr++ = (*t)->def->ofs; + for (cl = classes; *cl; cl++) { + if ((*cl)->def && !(*cl)->def->external) { + reloc_def_def ((*cl)->def, POINTER_OFS (def_ptr)); + *def_ptr++ = (*cl)->def->ofs; } } } if (categories) { - for (t = categories; *t; t++) { - if ((*t)->def && !(*t)->def->external) { - reloc_def_def ((*t)->def, POINTER_OFS (def_ptr)); - *def_ptr++ = (*t)->def->ofs; + for (ca = categories; *ca; ca++) { + if ((*ca)->def && !(*ca)->def->external) { + reloc_def_def ((*ca)->def, POINTER_OFS (def_ptr)); + *def_ptr++ = (*ca)->def->ofs; } } } @@ -639,15 +678,6 @@ new_protocollist (void) return protocollist; } -void -add_protocol (protocollist_t *protocollist, protocol_t *protocol) -{ - protocollist->list = realloc (protocollist->list, - (protocollist->count + 1) - * sizeof (protocollist_t)); - protocollist->list[protocollist->count++] = protocol; -} - def_t * emit_protocol (protocol_t *protocol) { diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 0f6a7da07..ea4e24e3b 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1181,8 +1181,11 @@ field_expr (expr_t *e1, expr_t *e2) case ev_object: case ev_class: if (e2->type == ex_name) { + int protected; + class = t1->aux_type->class; - field = class_find_ivar (class, current_class != class, + protected = class_access (current_class, class); + field = class_find_ivar (class, protected, e2->e.string_val); if (!field) return new_error_expr (); diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 2645426c6..b0e94af09 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -104,16 +104,25 @@ add_method (methodlist_t *methodlist, method_t *method) } def_t * -method_def (class_t *class, method_t *method) +method_def (class_type_t *class_type, method_t *method) { dstring_t *str = dstring_newstr (); def_t *def; char *s; + const char *class_name; + const char *category_name = ""; + + if (class_type->is_class) { + class_name = class_type->c.class->name; + } else { + class_name = class_type->c.category->class->name; + category_name = class_type->c.category->name; + } dsprintf (str, "_%c_%s_%s_%s", method->instance ? 'i' : 'c', - class->name, - class->categories ? class->categories->name : "", + class_name, + category_name, method->name); str->str[--str->size - 1] = 0; for (s = str->str; *s; s++) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 709fba8a4..be5c668f4 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -107,6 +107,8 @@ expr_t *argv_expr (void); struct param_s *param; struct method_s *method; struct class_s *class; + struct category_s *category; + struct class_type_s *class_type; struct protocol_s *protocol; struct keywordarg_s *keywordarg; struct methodlist_s *methodlist; @@ -159,8 +161,9 @@ expr_t *argv_expr (void); %type protocolrefs %type messageargs keywordarg keywordarglist selectorarg %type keywordnamelist keywordname -%type class_name new_class_name class_with_super new_class_with_super -%type category_name new_category_name +%type class_name new_class_name class_with_super new_class_with_super +%type classdef +%type category_name new_category_name %type protocol_name %type methodprotolist methodprotolist2 %type ivar_decl_list @@ -172,7 +175,7 @@ expr_t *argv_expr (void); function_t *current_func; param_t *current_params; expr_t *current_init; -class_t *current_class; +class_type_t *current_class; expr_t *local_expr; expr_t *break_label; expr_t *continue_label; @@ -938,7 +941,6 @@ new_class_name error (0, "redefinition of `%s'", $1); $$ = get_class (0, 1); } - current_class = $$; } ; @@ -956,7 +958,6 @@ new_class_with_super { $1->super_class = $3; $$ = $1; - current_class = $$; } ; @@ -979,7 +980,6 @@ new_category_name error (0, "redefinition of category `%s (%s)'", $1, $3); $$ = get_category (0, 0, 1); } - current_class = $$; } ; @@ -999,38 +999,42 @@ protocol_name classdef : INTERFACE new_class_name protocolrefs { class_add_protocol_methods ($2, $3);} - '{' ivar_decl_list '}' { class_add_ivars ($2, $6); } - methodprotolist { class_add_methods ($2, $9); } + '{' { $$ = $2; } + ivar_decl_list '}' { class_add_ivars ($2, $7); $$ = $2; } + methodprotolist { class_add_methods ($2, $10); } END { current_class = 0; } | INTERFACE new_class_name - protocolrefs { class_add_protocol_methods ($2, $3);} + protocolrefs { class_add_protocol_methods ($2, $3); $$ = $2; } methodprotolist { class_add_methods ($2, $5); } END { current_class = 0; } | INTERFACE new_class_with_super protocolrefs { class_add_protocol_methods ($2, $3);} - '{' ivar_decl_list '}' { class_add_ivars ($2, $6); } - methodprotolist { class_add_methods ($2, $9); } + '{' { $$ = $2; } + ivar_decl_list '}' { class_add_ivars ($2, $7); $$ = $2; } + methodprotolist { class_add_methods ($2, $10); } END { current_class = 0; } | INTERFACE new_class_with_super - protocolrefs { class_add_protocol_methods ($2, $3);} + protocolrefs { class_add_protocol_methods ($2, $3); $$ = $2; } methodprotolist { class_add_methods ($2, $5); } END { current_class = 0; } | INTERFACE new_category_name - protocolrefs { class_add_protocol_methods ($2, $3);} - methodprotolist { class_add_methods ($2, $5); } + protocolrefs { category_add_protocol_methods ($2, $3); $$ = $2->class;} + methodprotolist { category_add_methods ($2, $5); } END { current_class = 0; } - | IMPLEMENTATION class_name { class_begin ($2); } - '{' ivar_decl_list '}' { class_check_ivars ($2, $5); } - | IMPLEMENTATION class_name { class_begin ($2); } - | IMPLEMENTATION class_with_super { class_begin ($2); } - '{' ivar_decl_list '}' { class_check_ivars ($2, $5); } - | IMPLEMENTATION class_with_super { class_begin ($2); } - | IMPLEMENTATION category_name { class_begin ($2); } + | IMPLEMENTATION class_name { class_begin (&$2->class_type); } + '{' { $$ = $2; } + ivar_decl_list '}' { class_check_ivars ($2, $6); } + | IMPLEMENTATION class_name { class_begin (&$2->class_type); } + | IMPLEMENTATION class_with_super { class_begin (&$2->class_type); } + '{' { $$ = $2; } + ivar_decl_list '}' { class_check_ivars ($2, $6); } + | IMPLEMENTATION class_with_super { class_begin (&$2->class_type); } + | IMPLEMENTATION category_name { class_begin (&$2->class_type); } ; protocoldef : PROTOCOL protocol_name - protocolrefs { protocol_add_protocol_methods ($2, $3); } + protocolrefs { protocol_add_protocol_methods ($2, $3); $$ = 0; } methodprotolist { protocol_add_methods ($2, $5); } END ; @@ -1045,9 +1049,9 @@ ivar_decl_list { current_visibility = vis_protected; current_ivars = new_struct (0); - if (current_class->super_class) + if ($0->super_class) new_struct_field (current_ivars, - current_class->super_class->ivars, 0, + $0->super_class->ivars, 0, vis_private); } ivar_decl_list_2 @@ -1158,10 +1162,10 @@ methodprotolist ; methodprotolist2 - : methodproto + : { } methodproto { $$ = new_methodlist (); - add_method ($$, $1); + add_method ($$, $2); } | methodprotolist2 methodproto { @@ -1180,8 +1184,8 @@ methodproto | '-' methoddecl ';' { $2->instance = 1; - if (current_class) - $2->params->type = current_class->type; + if ($-1) + $2->params->type = $-1->type; $$ = $2; } ; diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 95e4bbeb8..5c95e2715 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -235,8 +235,6 @@ array_type (type_t *aux, int size) void print_type (type_t *type) { - class_t *class; - if (!type) { printf (" (null)"); return; @@ -275,11 +273,7 @@ print_type (type_t *type) break; case ev_object: case ev_class: - class = type->class; - printf (" %s%s", - class->name, - class->categories ? va (" (%s)", class->categories->name) - : ""); + printf (" %s", type->class->name); break; case ev_struct: printf (" %s %s", pr_type_name[type->type], type->name);