mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-23 10:50:58 +00:00
[qfcc] Allow inherited methods to satisfy protocols
I suspect that the current state of things will produce problems later on, but this works for now.
This commit is contained in:
parent
1459361cbd
commit
65a5e4f2a4
3 changed files with 72 additions and 5 deletions
|
@ -58,6 +58,10 @@ typedef struct methodlist_s {
|
|||
int instance; ///< used only for emitting
|
||||
} methodlist_t;
|
||||
|
||||
typedef struct methodset_s {
|
||||
struct hashtab_s *tab;
|
||||
} methodset_t;
|
||||
|
||||
typedef struct keywordarg_s {
|
||||
// the first two fields match the first two fields of param_t in
|
||||
// functionl.h
|
||||
|
@ -80,9 +84,12 @@ struct symbol_s *method_symbol (struct class_type_s *class_type,
|
|||
void method_set_param_names (method_t *dst, method_t *src);
|
||||
|
||||
methodlist_t *new_methodlist (void);
|
||||
methodset_t *new_methodset (void);
|
||||
void methodset_add_methods (methodset_t *methodset, methodlist_t *methods);
|
||||
int methodset_contains_method (methodset_t *methodset, method_t *method);
|
||||
//NOTE frees the source list and any methods not copied
|
||||
void merge_method_lists (methodlist_t *dst, methodlist_t *src);
|
||||
void copy_methods (methodlist_t *dst, methodlist_t *src);
|
||||
void copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except);
|
||||
int method_compare (method_t *m1, method_t *m2);
|
||||
|
||||
keywordarg_t *new_keywordarg (const char *selector, struct expr_s *expr);
|
||||
|
|
|
@ -642,16 +642,23 @@ class_add_protocols (class_t *class, protocollist_t *protocols)
|
|||
int i;
|
||||
protocol_t *p;
|
||||
methodlist_t *methods;
|
||||
methodset_t *except;
|
||||
class_t *super;
|
||||
|
||||
if (!protocols)
|
||||
return;
|
||||
|
||||
methods = class->methods;
|
||||
|
||||
except = new_methodset ();
|
||||
for (super = class->super_class; super; super = super->super_class) {
|
||||
methodset_add_methods (except, super->methods);
|
||||
}
|
||||
|
||||
for (i = 0; i < protocols->count; i++) {
|
||||
p = protocols->list[i];
|
||||
if (p->methods) {
|
||||
copy_methods (methods, p->methods);
|
||||
copy_methods (methods, p->methods, except);
|
||||
} else {
|
||||
warning (0, "definition of protocol `%s' not found", p->name);
|
||||
}
|
||||
|
@ -1269,15 +1276,22 @@ category_add_protocols (category_t *category, protocollist_t *protocols)
|
|||
int i;
|
||||
protocol_t *p;
|
||||
methodlist_t *methods;
|
||||
methodset_t *except;
|
||||
class_t *class;
|
||||
|
||||
if (!protocols)
|
||||
return;
|
||||
|
||||
methods = category->methods;
|
||||
|
||||
except = new_methodset ();
|
||||
for (class = category->class; class; class = class->super_class) {
|
||||
methodset_add_methods (except, class->methods);
|
||||
}
|
||||
|
||||
for (i = 0; i < protocols->count; i++) {
|
||||
p = protocols->list[i];
|
||||
copy_methods (methods, p->methods);
|
||||
copy_methods (methods, p->methods, except);
|
||||
if (p->protocols)
|
||||
category_add_protocols (category, p->protocols);
|
||||
}
|
||||
|
|
|
@ -205,6 +205,52 @@ new_methodlist (void)
|
|||
return l;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
methodset_get_hash (const void *_method, void *unused)
|
||||
{
|
||||
method_t *method = (method_t *) _method;
|
||||
uintptr_t hash;
|
||||
|
||||
hash = Hash_String (method->name);
|
||||
return hash ^ (method->instance << 3);
|
||||
}
|
||||
|
||||
static int
|
||||
methodset_compare (const void *_m1, const void *_m2, void *unused)
|
||||
{
|
||||
method_t *m1 = (method_t *) _m1;
|
||||
method_t *m2 = (method_t *) _m2;
|
||||
int cmp;
|
||||
|
||||
cmp = strcmp (m1->name, m2->name) == 0;
|
||||
return cmp && m1->instance == m2->instance;
|
||||
}
|
||||
|
||||
methodset_t *
|
||||
new_methodset (void)
|
||||
{
|
||||
methodset_t *s = malloc (sizeof (*s));
|
||||
s->tab = Hash_NewTable (31, 0, 0, 0);
|
||||
Hash_SetHashCompare (s->tab, methodset_get_hash, methodset_compare);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
methodset_add_methods (methodset_t *methodset, methodlist_t *methods)
|
||||
{
|
||||
method_t *m;
|
||||
|
||||
for (m = methods->head; m; m = m->next) {
|
||||
Hash_AddElement (methodset->tab, m);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
methodset_contains_method (methodset_t *methodset, method_t *method)
|
||||
{
|
||||
return Hash_FindElement (methodset->tab, method) != 0;
|
||||
}
|
||||
|
||||
static int __attribute__((pure))
|
||||
method_in_list (methodlist_t *method_list, method_t *method)
|
||||
{
|
||||
|
@ -238,13 +284,13 @@ merge_method_lists (methodlist_t *dst, methodlist_t *src)
|
|||
}
|
||||
|
||||
void
|
||||
copy_methods (methodlist_t *dst, methodlist_t *src)
|
||||
copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except)
|
||||
{
|
||||
method_t *s, *d;
|
||||
param_t *self;
|
||||
|
||||
for (s = src->head; s; s = s->next) {
|
||||
if (method_in_list (dst, s)) {
|
||||
if (methodset_contains_method (except, s) || method_in_list (dst, s)) {
|
||||
debug (0, "skipping duplicate method: %s", s->name);
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue