mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-21 18:01:15 +00:00
[qfcc] Fix protocol adorned id as message receiver
This took a bit as type_id has no class data, only protocols attached to the type_obj_object instance, and then protocol lists can get deep.
This commit is contained in:
parent
ea042cf87a
commit
0fe3fda44d
5 changed files with 138 additions and 67 deletions
|
@ -113,6 +113,7 @@ struct dstring_s;
|
|||
struct expr_s;
|
||||
struct method_s;
|
||||
struct symbol_s;
|
||||
struct selector_s;
|
||||
|
||||
int obj_is_id (const struct type_s *type) __attribute__((pure));
|
||||
int obj_is_class (const struct type_s *type) __attribute__((pure));
|
||||
|
@ -141,7 +142,7 @@ void class_finish_ivar_scope (class_type_t *class_type,
|
|||
struct symtab_s *param_scope);
|
||||
struct method_s *class_find_method (class_type_t *class_type,
|
||||
struct method_s *method);
|
||||
struct method_s *class_message_response (class_t *class, int class_msg,
|
||||
struct method_s *class_message_response (struct type_s *clstype, int class_msg,
|
||||
struct expr_s *sel);
|
||||
struct symbol_s *class_pointer_symbol (class_t *class_type);
|
||||
category_t *get_category (struct symbol_s *class_name,
|
||||
|
@ -161,6 +162,11 @@ struct def_s *protocol_def (protocol_t *protocol);
|
|||
protocollist_t *new_protocol_list (void);
|
||||
protocollist_t *add_protocol (protocollist_t *protocollist, const char *name);
|
||||
int procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) __attribute__((pure));
|
||||
struct method_s *protocollist_find_method (protocollist_t *protocollist,
|
||||
struct selector_s *selector,
|
||||
int nstance)
|
||||
__attribute__((pure));
|
||||
|
||||
int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) __attribute__((pure));
|
||||
void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist);
|
||||
struct def_s *emit_protocol (protocol_t *protocol);
|
||||
|
|
|
@ -98,6 +98,9 @@ keywordarg_t *copy_keywordargs (const keywordarg_t *kwargs);
|
|||
struct expr_s *send_message (int super);
|
||||
|
||||
method_t *find_method (const char *sel_name);
|
||||
method_t *methodlist_find_method (methodlist_t *methodlist,
|
||||
selector_t *selector, int instance)
|
||||
__attribute__((pure));
|
||||
|
||||
void selector_name (struct dstring_s *sel_id, keywordarg_t *selector);
|
||||
void method_types (struct dstring_s *sel_types, method_t *method);
|
||||
|
|
|
@ -1104,42 +1104,79 @@ class_find_method (class_type_t *class_type, method_t *method)
|
|||
return method;
|
||||
}
|
||||
|
||||
static method_t *
|
||||
cls_find_method (methodlist_t *methodlist, selector_t *selector,
|
||||
int class_msg, int is_root)
|
||||
{
|
||||
method_t *m = 0;
|
||||
m = methodlist_find_method (methodlist, selector, !class_msg);
|
||||
if (!m && is_root && class_msg
|
||||
&& (m = methodlist_find_method (methodlist, selector, 1))) {
|
||||
return m;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
method_t *
|
||||
class_message_response (class_t *class, int class_msg, expr_t *sel)
|
||||
class_message_response (type_t *clstype, int class_msg, expr_t *sel)
|
||||
{
|
||||
selector_t *selector;
|
||||
method_t *m;
|
||||
class_t *c = class;
|
||||
class_t *c;
|
||||
class_t *class = 0;
|
||||
category_t *cat;
|
||||
dstring_t *dstr;
|
||||
|
||||
selector = get_selector (sel);
|
||||
if (!selector)
|
||||
return 0;
|
||||
if (class && class->type != &type_obj_object) {
|
||||
if (!class->interface_declared) {
|
||||
class->interface_declared = 1;
|
||||
warning (0, "cannot find interface declaration for `%s'",
|
||||
class->name);
|
||||
|
||||
if (!obj_is_classptr (clstype) && !obj_is_class (clstype)) {
|
||||
error (0, "neither class nor object");
|
||||
return 0;
|
||||
}
|
||||
if (obj_is_id (clstype)) {
|
||||
protocollist_t *protos = clstype->t.fldptr.type->protos;
|
||||
if (protos) {
|
||||
if ((m = protocollist_find_method (protos, selector, !class_msg))) {
|
||||
return m;
|
||||
}
|
||||
dstr = dstring_new ();
|
||||
print_protocollist (dstr, protos);
|
||||
warning (sel, "id%s may not respond to %c%s", dstr->str,
|
||||
class_msg ? '+' : '-', selector->name);
|
||||
dstring_delete (dstr);
|
||||
}
|
||||
while (c) {
|
||||
for (cat = c->categories; cat; cat = cat->next) {
|
||||
for (m = cat->methods->head; m; m = m->next) {
|
||||
if (((!c->super_class && class_msg)
|
||||
|| class_msg != m->instance)
|
||||
&& strcmp (selector->name, m->name) == 0)
|
||||
} else {
|
||||
if (obj_is_class (clstype)) {
|
||||
class = clstype->t.class;
|
||||
} else if (obj_is_class (clstype->t.fldptr.type)) {
|
||||
class = clstype->t.fldptr.type->t.class;
|
||||
}
|
||||
if (class && class->type != &type_obj_object) {
|
||||
if (!class->interface_declared) {
|
||||
class->interface_declared = 1;
|
||||
warning (0, "cannot find interface declaration for `%s'",
|
||||
class->name);
|
||||
}
|
||||
c = class;
|
||||
while (c) {
|
||||
for (cat = c->categories; cat; cat = cat->next) {
|
||||
if ((m = cls_find_method (cat->methods, selector,
|
||||
class_msg,
|
||||
!c->super_class))) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (m = c->methods->head; m; m = m->next) {
|
||||
if (((!c->super_class && class_msg)
|
||||
|| class_msg != m->instance)
|
||||
&& strcmp (selector->name, m->name) == 0)
|
||||
if ((m = cls_find_method (c->methods, selector, class_msg,
|
||||
!c->super_class))) {
|
||||
return m;
|
||||
}
|
||||
c = c->super_class;
|
||||
}
|
||||
c = c->super_class;
|
||||
warning (sel, "%s may not respond to %c%s", class->name,
|
||||
class_msg ? '+' : '-', selector->name);
|
||||
}
|
||||
warning (sel, "%s may not respond to %c%s", class->name,
|
||||
class_msg ? '+' : '-', selector->name);
|
||||
}
|
||||
m = find_method (selector->name);
|
||||
if (!m && (!class || class->type == &type_obj_object)) {
|
||||
|
@ -1592,6 +1629,34 @@ procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static method_t *
|
||||
protocol_find_method (protocol_t *protocol, selector_t *selector, int instance)
|
||||
{
|
||||
method_t *m = 0;
|
||||
if (protocol->methods) {
|
||||
m = methodlist_find_method (protocol->methods, selector, instance);
|
||||
}
|
||||
if (!m && protocol->protocols) {
|
||||
return protocollist_find_method (protocol->protocols, selector,
|
||||
instance);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
method_t *
|
||||
protocollist_find_method (protocollist_t *protocollist, selector_t *selector,
|
||||
int instance)
|
||||
{
|
||||
method_t *m;
|
||||
for (int i = 0; i < protocollist->count; i++) {
|
||||
if ((m = protocol_find_method (protocollist->list[i], selector,
|
||||
instance))) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
compare_protocols (protocollist_t *protos1, protocollist_t *protos2)
|
||||
{
|
||||
|
|
|
@ -179,62 +179,45 @@ message_expr (expr_t *receiver, keywordarg_t *message)
|
|||
expr_t *selector = selector_expr (message);
|
||||
expr_t *call;
|
||||
keywordarg_t *m;
|
||||
int self = 0, super = 0, class_msg = 0;
|
||||
type_t *rec_type;
|
||||
int super = 0, class_msg = 0;
|
||||
type_t *rec_type = 0;
|
||||
type_t *return_type;
|
||||
type_t *method_type = &type_IMP;
|
||||
class_t *class = 0;
|
||||
method_t *method;
|
||||
expr_t *send_msg;
|
||||
|
||||
if (receiver->type == ex_symbol
|
||||
&& strcmp (receiver->e.symbol->name, "super") == 0) {
|
||||
super = 1;
|
||||
if (receiver->type == ex_nil) {
|
||||
rec_type = &type_id;
|
||||
convert_nil (receiver, rec_type);
|
||||
} else if (receiver->type == ex_symbol) {
|
||||
if (strcmp (receiver->e.symbol->name, "self") == 0) {
|
||||
rec_type = get_type (receiver);
|
||||
} else if (strcmp (receiver->e.symbol->name, "super") == 0) {
|
||||
super = 1;
|
||||
|
||||
receiver = super_expr (current_class);
|
||||
receiver = super_expr (current_class);
|
||||
|
||||
if (receiver->type == ex_error)
|
||||
return receiver;
|
||||
receiver = cast_expr (&type_id, receiver); //FIXME better way?
|
||||
class = extract_class (current_class);
|
||||
} else {
|
||||
if (receiver->type == ex_symbol) {
|
||||
if (strcmp (receiver->e.symbol->name, "self") == 0)
|
||||
self = 1;
|
||||
if (receiver->e.symbol->sy_type == sy_class) {
|
||||
class = receiver->e.symbol->type->t.class;
|
||||
class_msg = 1;
|
||||
receiver = new_symbol_expr (class_pointer_symbol (class));
|
||||
}
|
||||
} else if (receiver->type == ex_nil) {
|
||||
convert_nil (receiver, &type_id);
|
||||
}
|
||||
rec_type = get_type (receiver);
|
||||
|
||||
if (receiver->type == ex_error)
|
||||
return receiver;
|
||||
|
||||
if (rec_type == &type_id || rec_type == &type_Class) {
|
||||
} else {
|
||||
if (rec_type->type == ev_pointer)
|
||||
rec_type = rec_type->t.fldptr.type;
|
||||
if (!obj_is_class (rec_type))
|
||||
return error (receiver, "not a class/object");
|
||||
|
||||
if (self) {
|
||||
if (!class)
|
||||
class = extract_class (current_class);
|
||||
if (rec_type == &type_obj_class)
|
||||
class_msg = 1;
|
||||
} else {
|
||||
if (!class)
|
||||
class = rec_type->t.class;
|
||||
}
|
||||
if (receiver->type == ex_error)
|
||||
return receiver;
|
||||
receiver = cast_expr (&type_id, receiver); //FIXME better way?
|
||||
rec_type = extract_class (current_class)->type;
|
||||
} else if (receiver->e.symbol->sy_type == sy_class) {
|
||||
class_t *class;
|
||||
rec_type = receiver->e.symbol->type;
|
||||
class = rec_type->t.class;
|
||||
class_msg = 1;
|
||||
receiver = new_symbol_expr (class_pointer_symbol (class));
|
||||
}
|
||||
}
|
||||
if (!rec_type) {
|
||||
rec_type = get_type (receiver);
|
||||
}
|
||||
|
||||
if (receiver->type == ex_error)
|
||||
return receiver;
|
||||
|
||||
return_type = &type_id;
|
||||
method = class_message_response (class, class_msg, selector);
|
||||
method = class_message_response (rec_type, class_msg, selector);
|
||||
if (method)
|
||||
return_type = method->type->t.func.type;
|
||||
|
||||
|
|
|
@ -375,6 +375,20 @@ find_method (const char *sel_name)
|
|||
return Hash_Find (known_methods, sel_name);
|
||||
}
|
||||
|
||||
method_t *
|
||||
methodlist_find_method (methodlist_t *methodlist, selector_t *selector,
|
||||
int instance)
|
||||
{
|
||||
method_t *m;
|
||||
|
||||
for (m = methodlist->head; m; m = m->next) {
|
||||
if (m->instance == instance && strcmp (selector->name, m->name) == 0) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
selector_name (dstring_t *sel_id, keywordarg_t *selector)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue