diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 5d6b77290..42e1b2e91 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -45,6 +45,8 @@ typedef struct class_s { } class_t; extern class_t class_id; +extern class_t class_Class; +extern class_t class_Protocol; struct expr_s; struct method_s; @@ -55,9 +57,12 @@ 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, expr_t *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); +struct struct_field_s *class_find_ivar (class_t *class, int protected, + const char *name); 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); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index d523c843e..df1a25370 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -48,6 +48,8 @@ static hashtab_t *category_hash; static hashtab_t *protocol_hash; class_t class_id = {1, "id", 0, 0, 0, 0, 0, 0, &type_id}; +class_t class_Class = {1, "Class", 0, 0, 0, 0, 0, 0, &type_Class}; +class_t class_Protocol = {1, "Protocl", 0, 0, 0, 0, 0, 0, &type_Protocol}; static const char * class_get_key (void *class, void *unused) @@ -163,7 +165,8 @@ class_begin (class_t *class) class->def->initialized = class->def->constant = 1; cls = &G_STRUCT (pr_class_t, class->def->ofs); cls->class_pointer = meta_def->ofs; - if (class->super_class) + if (class->super_class + && class->super_class->def) //FIXME implementation only cls->super_class = class->super_class->def->ofs; cls->name = meta->name; cls->protocols = meta->protocols; @@ -193,6 +196,31 @@ class_finish (class_t *class) } } +struct_field_t * +class_find_ivar (class_t *class, int protected, const char *name) +{ + struct_field_t *ivar; + class_t *c; + + ivar = struct_find_field (class->ivars, name); + if (ivar) + return ivar; + for (c = class->super_class; c; c = c->super_class) { + ivar = struct_find_field (c->ivars, name); + if (ivar) { + if (ivar->visibility == vis_private + || (protected && ivar->visibility == vis_protected)) { + error (0, "%s.%s is not accessable here", + class->class_name, name); + return 0; + } + return ivar; + } + } + error (0, "%s.%s does not exist", class->class_name, name); + return 0; +} + method_t * class_find_method (class_t *class, method_t *method) { @@ -253,6 +281,12 @@ category_compare (void *_c1, void *_c2, void *unused) && strcmp (c1->category_name, c2->category_name) == 0; } +void +class_add_ivars (class_t *class, struct type_s *ivars) +{ + class->ivars = ivars; +} + void class_check_ivars (class_t *class, struct type_s *ivars) { @@ -295,8 +329,10 @@ class_def (class_t *class) def = PR_GetDef (class->type, va ("_OBJ_CLASS_POINTER_%s", class->class_name), 0, &numpr_globals); - def->initialized = def->constant = 1; - G_INT (def->ofs) = class->def->ofs; + if (class->def) { //FIXME need externals? + def->initialized = def->constant = 1; + G_INT (def->ofs) = class->def->ofs; + } return def; } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ae185b3c7..183de5a4a 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -969,16 +969,33 @@ field_expr (expr_t *e1, expr_t *e2) e = unary_expr ('.', address_expr (e1, e2, field->type)); return e; case ev_pointer: - if (t1->aux_type->type == ev_struct) { - if (e2->type == ex_name) { - field = struct_find_field (t1->aux_type, e2->e.string_val); - if (!field) - return error (e2, "structure has no field %s", - e2->e.string_val); - e2->type = ex_short; - e2->e.short_val = field->offset; - t1 = pointer_type (field->type); - } + switch (t1->aux_type->type) { + case ev_struct: + if (e2->type == ex_name) { + field = struct_find_field (t1->aux_type, + e2->e.string_val); + if (!field) + return error (e2, "structure has no field %s", + e2->e.string_val); + e2->type = ex_short; + e2->e.short_val = field->offset; + t1 = pointer_type (field->type); + } + break; + case ev_class: + if (e2->type == ex_name) { + field = class_find_ivar (t1->aux_type->class, + 0, + e2->e.string_val); + if (!field) + return new_error_expr (); + e2->type = ex_short; + e2->e.short_val = field->offset; + t1 = pointer_type (field->type); + } + break; + default: + break; } if (e1->type == ex_pointer) { if (e2->type == ex_short) { @@ -1807,16 +1824,17 @@ assign_expr (expr_t *e1, expr_t *e2) type_t *t1, *t2, *type; expr_t *e; + convert_name (e1); + convert_name (e2); + if (e1->type == ex_error) return e1; if (e2->type == ex_error) return e2; - convert_name (e1); if (e1->type == ex_def) PR_DefInitialized (e1->e.def); //XXX func = func ??? - convert_name (e2); check_initialized (e2); t1 = get_type (e1); t2 = get_type (e2); @@ -1992,6 +2010,7 @@ 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"; } rec_type = get_type (receiver); if (rec_type->type != ev_pointer || rec_type->aux_type->type != ev_class) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index a09cf0e79..a8be6332d 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -158,8 +158,7 @@ new_keywordarg (const char *selector, struct expr_s *expr) static void make_message_def (const char *name, def_t **def, function_t **func) { - *def = PR_GetDef (&type_IMP, "obj_msgSend", - 0, &numpr_globals); + *def = PR_GetDef (&type_IMP, name, 0, &numpr_globals); *func = new_function (); (*func)->builtin = 0; (*func)->def = *def; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 93b0b871e..bb5f4918b 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -938,6 +938,7 @@ new_class_with_super { $1->super_class = $3; $$ = $1; + current_class = $$; } ; @@ -980,7 +981,7 @@ protocol_name classdef : INTERFACE new_class_name protocolrefs { class_add_protocol_methods ($2, $3);} - '{' ivar_decl_list '}' { $2->ivars = $6; } + '{' ivar_decl_list '}' { class_add_ivars ($2, $6); } methodprotolist { class_add_methods ($2, $9); } END { current_class = 0; } | INTERFACE new_class_name @@ -989,7 +990,7 @@ classdef END { current_class = 0; } | INTERFACE new_class_with_super protocolrefs { class_add_protocol_methods ($2, $3);} - '{' ivar_decl_list '}' { $2->ivars = $6; } + '{' ivar_decl_list '}' { class_add_ivars ($2, $6); } methodprotolist { class_add_methods ($2, $9); } END { current_class = 0; } | INTERFACE new_class_with_super @@ -1022,7 +1023,15 @@ protocolrefs ; ivar_decl_list - : { current_ivars = new_struct (0); } ivar_decl_list_2 + : /* */ + { + current_ivars = new_struct (0); + if (current_class->super_class) + new_struct_field (current_ivars, + current_class->super_class->ivars, 0, + vis_private); + } + ivar_decl_list_2 { $$ = current_ivars; current_ivars = 0; @@ -1129,11 +1138,13 @@ methodproto : '+' methoddecl ';' { $2->instance = 0; + $2->params->type = &type_Class; $$ = $2; } | '-' methoddecl ';' { $2->instance = 1; + $2->params->type = current_class->type; $$ = $2; } ; diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 9a2cdd32d..7d047d053 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -428,6 +428,8 @@ init_types (void) type = type_Class.aux_type = new_struct ("Class"); type->type = ev_class; + type->class = &class_Class; + class_Class.ivars = type_Class.aux_type; 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); @@ -445,6 +447,8 @@ init_types (void) type = type_Protocol.aux_type = new_struct ("Protocol"); type->type = ev_class; + type->class = &class_Protocol; + class_Protocol.ivars = type_Protocol.aux_type; 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);