diff --git a/include/QF/pr_obj.h b/include/QF/pr_obj.h index 94b12ab62..167916a05 100644 --- a/include/QF/pr_obj.h +++ b/include/QF/pr_obj.h @@ -160,4 +160,9 @@ typedef struct pr_module_s { pointer_t symtab; // pr_symtab_t } pr_module_t; +typedef struct pr_super_s { + pointer_t self; + pointer_t class; +} pr_super_t; + #endif//__pr_obj_h diff --git a/libs/gamecode/engine/pr_obj.c b/libs/gamecode/engine/pr_obj.c index 2f27136d8..eb7425a12 100644 --- a/libs/gamecode/engine/pr_obj.c +++ b/libs/gamecode/engine/pr_obj.c @@ -283,19 +283,15 @@ obj_msg_lookup (progs_t *pr, pr_id_t *receiver, pr_sel_t *op) } static func_t -obj_msg_lookup_super (progs_t *pr, pr_id_t *receiver, pr_sel_t *op) +obj_msg_lookup_super (progs_t *pr, pr_super_t *super, pr_sel_t *op) { pr_class_t *class; - pr_class_t *super = 0; - if (!receiver) + + if (!super->self) return 0; - class = &G_STRUCT (pr, pr_class_t, receiver->class_pointer); - if (class->super_class) - super = &G_STRUCT (pr, pr_class_t, class->super_class); - if (!super) - PR_RunError (pr, "%s has no super class", - PR_GetString (pr, class->name)); - return obj_find_message (pr, super, op); + + class = &G_STRUCT (pr, pr_class_t, super->class); + return obj_find_message (pr, class, op); } static void @@ -339,9 +335,10 @@ pr_obj_msg_lookup (progs_t *pr) static void pr_obj_msg_lookup_super (progs_t *pr) { - pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); - pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup_super (pr, receiver, op); + pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); + pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); + + R_INT (pr) = obj_msg_lookup_super (pr, super, _cmd); } static void @@ -450,21 +447,18 @@ pr_obj_msgSend (progs_t *pr) static void pr_obj_msgSend_super (progs_t *pr) { - pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); + pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; - if (!self) { - R_INT (pr) = R_INT (pr); - return; - } - if (!_cmd) - PR_RunError (pr, "null selector"); - imp = obj_msg_lookup_super (pr, self, _cmd); - if (!imp) + imp = obj_msg_lookup_super (pr, super, _cmd); + if (!imp) { + pr_id_t *self = &G_STRUCT (pr, pr_id_t, super->self); PR_RunError (pr, "%s does not respond to %s", PR_GetString (pr, object_get_class_name (pr, self)), PR_GetString (pr, _cmd->sel_id)); + } + P_POINTER (pr, 0) = super->self; call_function (pr, imp); } diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index 9ab8c3700..7979ca3a5 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -10,7 +10,7 @@ typedef enum { @extern void (id object, integer code, string fmt, @va_list args) obj_verror; //obj_error_handler (objc_error_handler func) obj_set_error_handler = #0; @extern IMP (id receiver, SEL op) obj_msg_lookup; -@extern IMP (id receiver, SEL op) obj_msg_lookup_super; +@extern IMP (Super class, SEL op) obj_msg_lookup_super; //retval_t (id receiver, SEL op, @va_list args) obj_msg_sendv; @extern (void []) (integer size) obj_malloc; @extern (void []) (integer size) obj_atomic_malloc; diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index 59c9d4f63..22fa5250c 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -5,9 +5,9 @@ void (id object, integer code, string fmt, ...) obj_error = #0; void (id object, integer code, string fmt, @va_list args) obj_verror = #0; //obj_error_handler (objc_error_handler func) obj_set_error_handler = #0; IMP (id receiver, SEL op) obj_msg_lookup = #0; -IMP (id receiver, SEL op) obj_msg_lookup_super = #0; +IMP (Super class, SEL op) obj_msg_lookup_super = #0; id (id receiver, SEL op, ...) obj_msgSend = #0; -id (id receiver, SEL op, ...) obj_msgSend_super = #0; +id (Super class, SEL op, ...) obj_msgSend_super = #0; //retval_t (id receiver, SEL op, @va_list args) obj_msg_sendv = #0; (void []) (integer size) obj_malloc = #0; (void []) (integer size) obj_atomic_malloc = #0; diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 6e1524c94..b009d2849 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -83,6 +83,8 @@ typedef struct { struct def_s *def; } ex_pointer_t; +#define POINTER_VAL(p) (((p).def ? (p).def->ofs : 0) + (p).val) + typedef struct expr_s { struct expr_s *next; expr_type type; @@ -193,9 +195,11 @@ const char *get_op_string (int op); extern int lineno_base; struct keywordarg_s; +struct class_type_s; expr_t *selector_expr (struct keywordarg_s *selector); expr_t *protocol_expr (const char *protocol); expr_t *encode_expr (struct type_s *type); +expr_t *super_expr (struct class_type_s *class_type); expr_t *message_expr (expr_t *receiver, struct keywordarg_s *message); expr_t *sizeof_expr (expr_t *expr, struct type_s *type); diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index f36dd423f..deb93d9f9 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -67,11 +67,13 @@ extern type_t type_Class; extern type_t type_Protocol; extern type_t type_SEL; extern type_t type_IMP; +extern type_t type_supermsg; extern type_t type_obj_exec_class; extern type_t type_Method; extern type_t *type_category; extern type_t *type_ivar; extern type_t *type_module; +extern type_t type_Super; extern type_t type_va_list; extern type_t type_param; extern type_t type_zero; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 20f20bcc8..3054c7342 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -432,7 +432,7 @@ class_message_response (class_t *class, expr_t *sel) error (sel, "not a selector"); return 0; } - selector = &G_STRUCT (pr_sel_t, sel->e.pointer.val); + selector = &G_STRUCT (pr_sel_t, POINTER_VAL (sel->e.pointer)); sel_name = G_GETSTR (selector->sel_id); while (c) { if (c->methods) { diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 1c0d51b82..8bf8bdcde 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -386,8 +386,9 @@ emit_deref_expr (expr_t *e, def_t *dest) if (e->e.pointer.def) { d = new_def (e->e.pointer.type, 0, current_scope); d->local = e->e.pointer.def->local; - d->ofs = e->e.pointer.def->ofs; - d->alias = e->e.pointer.def; + d->ofs = POINTER_VAL (e->e.pointer); + if (d->ofs == e->e.pointer.def->ofs) + d->alias = e->e.pointer.def; } else if (e->e.pointer.val >= 0 && e->e.pointer.val < 65536) { d = new_def (e->e.pointer.type, 0, current_scope); d->ofs = e->e.pointer.val; @@ -400,9 +401,7 @@ emit_deref_expr (expr_t *e, def_t *dest) } return d; } - if (!dest && (e->type != ex_pointer - || !(e->e.pointer.val > 0 - && e->e.pointer.val < 65536))) { + if (!dest) { dest = get_tempdef (type, current_scope); dest->users += 2; } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 3e8745eff..daf8017d3 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1125,6 +1125,7 @@ field_expr (expr_t *e1, expr_t *e2) t1 = get_type (e1); switch (t1->type) { case ev_struct: + case ev_class: check_initialized (e1); if (e2->type != ex_name) return error (e2, "structure field name expected"); @@ -1225,7 +1226,7 @@ field_expr (expr_t *e1, expr_t *e2) e = new_expr (); e->type = ex_pointer; e1 = e1->e.expr.e1; - i = e1->e.pointer.val; + i = POINTER_VAL (e1->e.pointer); e->e.pointer.val = i + field->offset; e->e.pointer.type = field->type; return unary_expr ('.', e); @@ -2065,17 +2066,20 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) case ex_def: { def_t *def = e1->e.def; + def->used = 1; type = def->type; - if (type->type == ev_struct) { - e = e1; + if (type->type == ev_struct || type->type == ev_class) { + e = new_expr (); + e->line = e1->line; + e->file = e1->file; e->type = ex_pointer; - e->e.pointer.val = def->ofs; + e->e.pointer.val = 0; e->e.pointer.type = t; e->e.pointer.def = def; } else if (type->type == ev_array) { e = e1; e->type = ex_pointer; - e->e.pointer.val = def->ofs; + e->e.pointer.val = 0; e->e.pointer.type = t; e->e.pointer.def = def; } else { @@ -2135,8 +2139,10 @@ is_indirect (expr_t *e) return 0; e = e->e.expr.e1; if (e->type != ex_pointer - || !(e->e.pointer.val > 0 && e->e.pointer.val < 65536)) + || !(POINTER_VAL (e->e.pointer) >= 0 + && POINTER_VAL (e->e.pointer) < 65536)) { return 1; + } return 0; } @@ -2215,7 +2221,8 @@ assign_expr (expr_t *e1, expr_t *e2) } else { e = e1->e.expr.e1; if (e->type != ex_pointer - || !(e->e.pointer.val > 0 && e->e.pointer.val < 65536)) { + || !(POINTER_VAL (e->e.pointer) > 0 + && POINTER_VAL (e->e.pointer) < 65536)) { e1 = e; op = PAS; } @@ -2228,7 +2235,8 @@ assign_expr (expr_t *e1, expr_t *e2) if (e2->type == ex_uexpr) { e = e2->e.expr.e1; if (e->type != ex_pointer - || !(e->e.pointer.val > 0 && e->e.pointer.val < 65536)) { + || !(POINTER_VAL (e->e.pointer) > 0 + && POINTER_VAL (e->e.pointer) < 65536)) { if (e->type == ex_expr && e->e.expr.op == '&' && e->e.expr.type->type == ev_pointer && e->e.expr.e1->type < ex_string) { @@ -2390,6 +2398,40 @@ encode_expr (type_t *type) return e; } +expr_t * +super_expr (class_type_t *class) +{ + def_t *super_d; + expr_t *super; + expr_t *e; + expr_t *super_block; + + if (!class) + return error (0, "`super' used outside of class implementation"); + + //if (!class->super_class) + // return error (0, "%s has no super class", class->name); + + super_d = get_def (type_Super.aux_type, ".super", current_func->scope, + st_local); + def_initialized (super_d); + super = new_def_expr (super_d); + super_block = new_block_expr (); + + e = assign_expr (binary_expr ('.', super, new_name_expr ("self")), + new_name_expr ("self")); + append_expr (super_block, e); + + e = new_def_expr (class_def (class, 1)); + e = assign_expr (binary_expr ('.', super, new_name_expr ("class")), + binary_expr ('.', e, new_name_expr ("super_class"))); + append_expr (super_block, e); + + e = address_expr (super, 0, 0); + super_block->e.block.result = e; + return super_block; +} + expr_t * message_expr (expr_t *receiver, keywordarg_t *message) { @@ -2405,18 +2447,28 @@ message_expr (expr_t *receiver, keywordarg_t *message) if (receiver->type == ex_name && strcmp (receiver->e.string_val, "super") == 0) { super = 1; - receiver->e.string_val = "self"; + + receiver = super_expr (current_class); + + if (receiver->type == ex_error) + return receiver; + if (current_class->is_class) + class = current_class->c.class; + else + class = current_class->c.category->class; + rec_type = class->type; + } else { + rec_type = get_type (receiver); + + if (receiver->type == ex_error) + return receiver; + + if (rec_type->type != ev_pointer + || (rec_type->aux_type->type != ev_object + && rec_type->aux_type->type != ev_class)) + return error (receiver, "not a class/object"); + class = rec_type->aux_type->class; } - rec_type = get_type (receiver); - - if (receiver->type == ex_error) - return receiver; - - if (rec_type->type != ev_pointer - || (rec_type->aux_type->type != ev_object - && 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) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index f1b074ef2..2efe6b40a 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -193,9 +193,12 @@ copy_keywordargs (const keywordarg_t *kwargs) expr_t * send_message (int super) { - return new_def_expr (get_def (&type_IMP, - super ? "obj_msgSend_super" : "obj_msgSend", - pr.scope, st_extern)); + if (super) + return new_def_expr (get_def (&type_supermsg, "obj_msgSend_super", + pr.scope, st_extern)); + else + return new_def_expr (get_def (&type_IMP, "obj_msgSend", pr.scope, + st_extern)); } void diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index b9d8281dd..a49a1a129 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -300,6 +300,7 @@ static keyword_t keywords[] = { {"Class", TYPE, &type_Class, 0, PROG_VERSION}, {"Protocol", TYPE, &type_Protocol, 0, PROG_VERSION}, {"Method", TYPE, &type_Method, 0, PROG_VERSION}, + {"Super", TYPE, &type_Super, 0, PROG_VERSION}, {"SEL", TYPE, &type_SEL, 0, PROG_VERSION}, {"IMP", TYPE, &type_IMP, 0, PROG_VERSION}, {"local", LOCAL, 0, 1, PROG_ID_VERSION}, diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 9ff0ffa4a..f1ade9ddf 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -86,8 +86,11 @@ type_t type_Protocol = { ev_pointer, "Protocol" }; type_t type_SEL = { ev_pointer, "SEL" }; type_t type_IMP = { ev_func, "IMP", NULL, &type_id, -3, { &type_id, &type_SEL }}; +type_t type_supermsg = { ev_func, ".supermsg", NULL, &type_id, -3, + { 0, &type_SEL }}; type_t type_obj_exec_class = { ev_func, "function", NULL, &type_void, 1, { 0 }}; type_t type_Method = { ev_pointer, "Method" }; +type_t type_Super = { ev_pointer, "Super" }; type_t *type_category; type_t *type_ivar; type_t *type_module; @@ -684,6 +687,10 @@ init_types (void) new_struct_field (&type_va_list, &type_integer, "count", vis_public); new_struct_field (&type_va_list, pointer_type (&type_param), "list", vis_public); + + type = type_Super.aux_type = new_struct ("Super"); + new_struct_field (type, &type_id, "self", vis_public); + new_struct_field (type, &type_Class, "class", vis_public); #if 0 type = type_module = new_struct ("obj_module_t"); new_struct_field (type, &type_integer, "version", vis_public); @@ -718,6 +725,7 @@ chain_initial_types (void) chain_type (&type_short); chain_type (&type_struct); chain_type (&type_IMP); + chain_type (&type_Super); chain_type (&type_SEL); chain_type (&type_Method); @@ -727,6 +735,9 @@ chain_initial_types (void) chain_type (type_category); chain_type (type_ivar); + type_supermsg.parm_types[0] = &type_Super; + chain_type (&type_supermsg); + type_module = new_struct ("obj_module_t"); new_struct_field (type_module, &type_integer, "version", vis_public); new_struct_field (type_module, &type_integer, "size", vis_public);