diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 7bca53a21..10191fb72 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -41,8 +41,12 @@ typedef struct class_s { struct methodlist_s *methods; struct protocollist_s *protocols; struct def_s *def; + struct type_s *type; } class_t; +extern class_t class_id; + +struct expr_s; struct method_s; struct protocol_s; struct type_s; @@ -54,6 +58,7 @@ void class_add_protocol (class_t *class, struct protocol_s *protocol); void class_check_ivars (class_t *class, struct type_s *ivars); void class_finish (class_t *class); struct method_s *class_find_method (class_t *class, struct method_s *method); +struct method_s *class_message_response (class_t *class, struct expr_s *sel); struct def_s *class_def (class_t *class); class_t *get_category (const char *class_name, const char *category_name, int create); diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index 62b4dd65c..b93c8c4fb 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -41,6 +41,8 @@ typedef struct method_s { param_t *params; type_t *type; def_t *def; + char *name; + char *types; } method_t; typedef struct methodlist_s { @@ -70,7 +72,7 @@ int method_compare (method_t *m1, method_t *m2); keywordarg_t *new_keywordarg (const char *selector, struct expr_s *expr); -struct expr_s *send_message (void); +struct expr_s *send_message (int super); void selector_name (struct dstring_s *sel_id, keywordarg_t *selector); void selector_types (struct dstring_s *sel_types, keywordarg_t *selector); diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 04e3aff14..df48a7289 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -294,6 +294,7 @@ typedef struct type_s struct hashtab_s *struct_fields; struct struct_field_s *struct_head; struct struct_field_s **struct_tail; + struct class_s *class; // for ev_class } type_t; typedef struct statref_s { diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 1b80771d7..0854cd42d 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -66,6 +66,7 @@ type_t *get_typedef (const char *name); type_t *pointer_type (type_t *aux); void print_type (type_t *type); void encode_type (struct dstring_s *encodking, type_t *type); +int type_assignable (type_t *dst, type_t *src); int type_size (type_t *type); void init_types (void); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 3d54a407e..8525f0d57 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -46,6 +46,8 @@ static hashtab_t *class_hash; static hashtab_t *category_hash; static hashtab_t *protocol_hash; +class_t class_id = {1, "id", 0, 0, 0, 0, 0, 0, &type_id}; + static const char * class_get_key (void *class, void *unused) { @@ -62,6 +64,7 @@ class_t * get_class (const char *name, int create) { class_t *c; + type_t new; if (!class_hash) class_hash = Hash_NewTable (1021, class_get_key, 0, 0); @@ -73,6 +76,9 @@ get_class (const char *name, int create) c = calloc (sizeof (class_t), 1); c->class_name = name; + new = *type_Class.aux_type; + new.class = c; + c->type = pointer_type (find_type (&new)); if (name) Hash_Add (class_hash, c); return c; @@ -183,6 +189,31 @@ class_find_method (class_t *class, method_t *method) return method; } +method_t * +class_message_response (class_t *class, expr_t *sel) +{ + pr_sel_t *selector; + char *sel_name; + method_t *m; + class_t *c = class; + + if (sel->type != ex_pointer && sel->e.pointer.type != type_SEL.aux_type) { + error (sel, "not a selector"); + return 0; + } + selector = &G_STRUCT (pr_sel_t, sel->e.pointer.val); + sel_name = strings + selector->sel_id; + while (c) { + for (m = c->methods->head; m; m = m->next) { + if (strcmp (sel_name, m->name) == 0) + return m; + } + c = c->super_class; + } + warning (sel, "%s does not respond to %s", class->class_name, sel_name); + return 0; +} + static unsigned long category_get_hash (void *_c, void *unused) { @@ -236,7 +267,7 @@ get_category (const char *class_name, const char *category_name, int create) def_t * class_def (class_t *class) { - return PR_GetDef (&type_Class, class->class_name, 0, &numpr_globals); + return PR_GetDef (class->type, class->class_name, 0, &numpr_globals); } protocol_t * diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 78f27862b..ae185b3c7 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -353,6 +353,14 @@ new_label_name (void) return lname; } +expr_t * +new_error_expr () +{ + expr_t *e = new_expr (); + e->type = ex_error; + return e; +} + expr_t * new_label_expr (void) { @@ -1521,7 +1529,7 @@ function_expr (expr_t *e1, expr_t *e2) t = ftype->parm_types[i]; e->type = expr_types[t->type]; } - if (t != ftype->parm_types[i]) { + if (!type_assignable (ftype->parm_types[i], t)) { print_type (ftype->parm_types[i]); puts(""); print_type (t); puts(""); err = error (e, "type mismatch for parameter %d of %s", @@ -1831,14 +1839,12 @@ assign_expr (expr_t *e1, expr_t *e2) e2->rvalue = 1; - if (t1 != t2) { + if (!type_assignable (t1, t2)) { if (!options.traditional || t1->type != ev_func || t2->type != ev_func) return type_mismatch (e1, e2, op); warning (e1, "assignment between disparate function types"); - type = t1; - } else { - type = t1; } + type = t1; if (is_indirect (e1) && is_indirect (e2)) { expr_t *temp = new_temp_def_expr (t1); @@ -1976,8 +1982,26 @@ message_expr (expr_t *receiver, keywordarg_t *message) { expr_t *args = 0, **a = &args; expr_t *selector = selector_expr (message); + expr_t *call; keywordarg_t *m; + int super = 0; + type_t *rec_type; + class_t *class; + method_t *method; + if (receiver->type == ex_name + && strcmp (receiver->e.string_val, "super") == 0) { + super = 1; + } + rec_type = get_type (receiver); + if (rec_type->type != ev_pointer || rec_type->aux_type->type != ev_class) + return error (receiver, "not a class object"); + class = rec_type->aux_type->class; + if (rec_type != &type_id) { + method = class_message_response (class, selector); + if (method) + rec_type = method->type->aux_type; + } for (m = message; m; m = m->next) { *a = m->expr; while ((*a)) @@ -1986,5 +2010,7 @@ message_expr (expr_t *receiver, keywordarg_t *message) *a = selector; a = &(*a)->next; *a = receiver; - return function_expr (send_message (), args); + call = function_expr (send_message (super), args); + call->e.block.result->e.def->type = rec_type; + return call; } diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 93b7242f8..2a40f9063 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -44,6 +44,8 @@ static const char rcsid[] = static def_t *send_message_def; static function_t *send_message_func; +static def_t *send_message_super_def; +static function_t *send_message_super_func; method_t * new_method (type_t *ret_type, param_t *selector, param_t *opt_parms) @@ -51,6 +53,8 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_parms) method_t *meth = malloc (sizeof (method_t)); param_t *cmd = new_param (0, &type_pointer, "_cmd"); param_t *self = new_param (0, &type_id, "self"); + dstring_t *name = dstring_newstr (); + dstring_t *types = dstring_newstr (); opt_parms = reverse_params (opt_parms); selector = _reverse_params (selector, opt_parms); @@ -62,6 +66,14 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_parms) meth->selector = selector; meth->params = self; meth->type = parse_params (ret_type, meth->params); + + selector_name (name, (keywordarg_t *)selector); + selector_types (types, (keywordarg_t *)selector); + meth->name = name->str; + meth->types = types->str; + free (name); + free (types); + //print_type (meth->type); puts (""); meth->def = 0; return meth; @@ -83,24 +95,21 @@ def_t * method_def (class_t *class, method_t *method) { dstring_t *str = dstring_newstr (); - dstring_t *sel = dstring_newstr (); def_t *def; char *s; - selector_name (sel, (keywordarg_t *)method->selector); dsprintf (str, "_%c_%s_%s_%s", method->instance ? 'i' : 'c', class->class_name, class->category_name ? class->category_name : "", - sel->str); + method->name); for (s = str->str; *s; s++) if (*s == ':') *s = '_'; - //printf ("%s\n", str->str); + //printf ("%s %s %s\n", method->name, method->types, str->str); // FIXME need a file scope def = PR_GetDef (method->type, str->str, 0, &numpr_globals); dstring_delete (str); - dstring_delete (sel); return def; } @@ -129,24 +138,10 @@ copy_methods (methodlist_t *dst, methodlist_t *src) int method_compare (method_t *m1, method_t *m2) { - dstring_t *s1 = dstring_newstr (); - dstring_t *s2 = dstring_newstr (); - dstring_t *t1 = dstring_newstr (); - dstring_t *t2 = dstring_newstr (); int res; - selector_name (s1, (keywordarg_t *)m1->selector); - selector_name (s2, (keywordarg_t *)m2->selector); - selector_types (t1, (keywordarg_t *)m1->selector); - selector_types (t2, (keywordarg_t *)m2->selector); - - res = strcmp (s1->str, s2->str) == 0 - && strcmp (t1->str, t2->str) == 0; - - dstring_delete (s1); - dstring_delete (s2); - dstring_delete (t1); - dstring_delete (t2); + res = strcmp (m1->name, m2->name) == 0 + && strcmp (m1->types, m2->types) == 0; return res; } @@ -162,23 +157,32 @@ new_keywordarg (const char *selector, struct expr_s *expr) return k; } +static void +make_message_def (const char *name, def_t **def, function_t **func) +{ + *def = PR_GetDef (&type_IMP, "obj_msgSend", + 0, &numpr_globals); + *func = new_function (); + (*func)->builtin = 0; + (*func)->def = *def; + build_function (*func); + finish_function (*func); +} + expr_t * -send_message (void) +send_message (int super) { expr_t *e; if (!send_message_def) { - send_message_def = PR_GetDef (&type_IMP, "obj_msgSend", - 0, &numpr_globals); - send_message_func = new_function (); - send_message_func->builtin = 0; - send_message_func->def = send_message_def; - build_function (send_message_func); - finish_function (send_message_func); + make_message_def ("obj_msgSend", + &send_message_def, &send_message_func); + make_message_def ("obj_msgSend_super", + &send_message_super_def, &send_message_super_func); } e = new_expr (); e->type = ex_def; - e->e.def = send_message_def; + e->e.def = super ? send_message_super_def : send_message_def; return e; } @@ -213,8 +217,8 @@ sel_def_get_hash (void *_sel_def, void *unused) sel_def_t *sel_def = (sel_def_t*)_sel_def; unsigned long hash; - hash = Hash_String (G_STRING (sel_def->sel_id)) - ^ Hash_String (G_STRING (sel_def->sel_types)); + hash = Hash_String (strings + sel_def->sel_id) + ^ Hash_String (strings + sel_def->sel_types); return hash; } @@ -225,10 +229,10 @@ sel_def_compare (void *_sd1, void *_sd2, void *unused) sel_def_t *sd2 = (sel_def_t*)_sd2; int cmp; - cmp = strcmp (G_STRING (sd1->sel_id), G_STRING (sd2->sel_id)) == 0; + cmp = strcmp (strings + sd1->sel_id, strings + sd2->sel_id) == 0; if (cmp) - cmp = strcmp (G_STRING (sd1->sel_types), - G_STRING (sd2->sel_types)) == 0; + cmp = strcmp (strings + sd1->sel_types, + strings + sd2->sel_types) == 0; return cmp; } @@ -267,7 +271,6 @@ emit_methods (methodlist_t *_methods, const char *name, int instance) def_t *methods_def; pr_method_list_t *methods; type_t *method_list; - dstring_t *tmp = dstring_newstr (); for (count = 0, method = _methods->head; method; method = method->next) if (!method->instance == !instance) @@ -285,14 +288,12 @@ emit_methods (methodlist_t *_methods, const char *name, int instance) for (i = 0, method = _methods->head; method; method = method->next) { if (!method->instance != !instance) continue; - selector_name (tmp, (keywordarg_t *)method->selector); - methods->method_list[i].method_name.sel_id = ReuseString (tmp->str); - selector_name (tmp, (keywordarg_t *)method->selector); - methods->method_list[i].method_name.sel_types = ReuseString (tmp->str); + methods->method_list[i].method_name.sel_id = ReuseString (method->name); + methods->method_list[i].method_name.sel_types = + ReuseString (method->types); methods->method_list[i].method_types = methods->method_list[i].method_name.sel_types; methods->method_list[i].method_imp = method->def->ofs; } - dstring_delete (tmp); return methods_def->ofs; } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 1fe988386..72180130c 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -257,6 +257,7 @@ type type_name : TYPE { $$ = $1; } + | class_name { $$ = $1->type; } ; function_decl diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 8950283dd..9964c13f0 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -176,15 +176,21 @@ emit_struct(type_t *strct, const char *name) pr_ivar_list_t *ivars; type_t *ivar_list; dstring_t *encoding = dstring_newstr (); + dstring_t *ivars_name = dstring_newstr (); + if (!strct) + return 0; for (count = 0, field = strct->struct_head; field; field = field->next) count++; ivar_list = new_struct (0); new_struct_field (ivar_list, &type_integer, "ivar_count", vis_public); for (i = 0; i < count; i++) new_struct_field (ivar_list, type_ivar, 0, vis_public); - ivars_def = PR_GetDef (ivar_list, va ("_OBJ_INSTANCE_VARIABLES_%s", name), - 0, &numpr_globals); + dsprintf (ivars_name, "_OBJ_INSTANCE_VARIABLES_%s", name); + ivars_def = PR_GetDef (ivar_list, ivars_name->str, 0, 0); + if (ivars_def) + goto done; + ivars_def = PR_GetDef (ivar_list, ivars_name->str, 0, &numpr_globals); ivars = &G_STRUCT (pr_ivar_list_t, ivars_def->ofs); ivars->ivar_count = count; for (i = 0, field = strct->struct_head; field; i++, field = field->next) { @@ -194,7 +200,9 @@ emit_struct(type_t *strct, const char *name) ivars->ivar_list[i].ivar_offset = field->offset; dstring_clearstr (encoding); } + done: dstring_delete (encoding); + dstring_delete (ivars_name); return ivars_def->ofs; } diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 4b3994455..5d916a4bc 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -32,11 +32,13 @@ static const char rcsid[] = #include +#include "QF/dstring.h" #include "QF/hash.h" #include "QF/sys.h" -#include "QF/dstring.h" +#include "QF/va.h" #include "qfcc.h" +#include "class.h" #include "function.h" #include "struct.h" #include "type.h" @@ -101,7 +103,8 @@ find_type (type_t *type) for (check = pr.types; check; check = check->next) { if (check->type != type->type || check->aux_type != type->aux_type - || check->num_parms != type->num_parms) + || check->num_parms != type->num_parms + || check->class != type->class) continue; if (check->type != ev_func) @@ -196,6 +199,8 @@ array_type (type_t *aux, int size) void print_type (type_t *type) { + class_t *class; + if (!type) { printf (" (null)"); return; @@ -232,6 +237,12 @@ print_type (type_t *type) else printf ("[]"); break; + case ev_class: + class = type->class; + printf (" %s %s%s", pr_type_name[type->type], + class->class_name, + class->category_name ? va (" (%s)", class->category_name) + : ""); default: printf(" %s", pr_type_name[type->type]); break; @@ -319,6 +330,34 @@ encode_type (dstring_t *encoding, type_t *type) _encode_type (encoding, type, 0); } +int +type_assignable (type_t *dst, type_t *src) +{ + class_t *dst_class, *src_class; + + if (dst == src) + return 1; + if (dst->type != ev_pointer || src->type != ev_pointer) + return 0; + dst = dst->aux_type; + src = src->aux_type; + if (dst->type != ev_class || src->type != ev_class) + return 0; + dst_class = dst->class; + src_class = src->class; + //printf ("%s %s\n", dst_class->class_name, src_class->class_name); + if (!dst_class || dst_class == &class_id) + return 1; + while (dst_class != src_class && src_class) { + src_class = src_class->super_class; + //if (src_class) + // printf ("%s %s\n", dst_class->class_name, src_class->class_name); + } + if (dst_class == src_class) + return 1; + return 0; +} + int type_size (type_t *type) { @@ -388,6 +427,7 @@ init_types (void) chain_type (type_method); type = type_Class.aux_type = new_struct ("Class"); + type->type = ev_class; new_struct_field (type, &type_Class, "class_pointer", vis_public); new_struct_field (type, &type_Class, "super_class", vis_public); new_struct_field (type, &type_string, "name", vis_public); @@ -404,6 +444,7 @@ init_types (void) chain_type (&type_Class); type = type_Protocol.aux_type = new_struct ("Protocol"); + type->type = ev_class; new_struct_field (type, &type_Class, "class_pointer", vis_public); new_struct_field (type, &type_string, "protocol_name", vis_public); new_struct_field (type, &type_pointer, "protocol_list", vis_public); @@ -412,6 +453,9 @@ init_types (void) chain_type (&type_Protocol); type = type_id.aux_type = new_struct ("id"); + type->type = ev_class; + type->class = &class_id; + class_id.ivars = type_id.aux_type; new_struct_field (type, &type_Class, "class_pointer", vis_public); chain_type (&type_id);