Rework class_type_t to be more useful.

This allows current_class to refer to procols as well (for error
reporting).
This commit is contained in:
Bill Currie 2010-12-31 15:44:54 +09:00
parent f738ef5dba
commit 530e8fae34
4 changed files with 214 additions and 143 deletions

View file

@ -32,11 +32,18 @@
#ifndef __class_h
#define __class_h
typedef enum {
ct_class,
ct_category,
ct_protocol,
} ct_type_t;
typedef struct class_type_s {
int is_class;
ct_type_t type;
union {
struct category_s *category;
struct class_s *class;
struct protocol_s *protocol;
} c;
} class_type_t;
@ -68,6 +75,7 @@ typedef struct protocol_s {
const char *name;
struct methodlist_s *methods;
struct protocollist_s *protocols;
class_type_t class_type;
} protocol_t;
typedef struct protocollist_s {
@ -85,6 +93,8 @@ struct expr_s;
struct method_s;
struct protocol_s;
class_t *extract_class (class_type_t *class_type);
const char *get_class_name (class_type_t *class_type, int pretty);
struct def_s *class_def (class_type_t *class_type, int external);
void class_init (void);
class_t *get_class (const char *name, int create);

View file

@ -81,6 +81,28 @@ protocol_get_key (void *protocol, void *unused)
return ((protocol_t *) protocol)->name;
}
const char *
get_class_name (class_type_t *class_type, int pretty)
{
switch (class_type->type) {
case ct_class:
if (pretty)
return class_type->c.class->name;
else
return va ("%s_", class_type->c.class->name);
case ct_category:
if (pretty)
return va ("%s (%s)", class_type->c.category->class->name,
class_type->c.category->name);
else
return va ("%s_%s", class_type->c.category->class->name,
class_type->c.category->name);
case ct_protocol:
return va ("<%s>", class_type->c.protocol->name);
}
return "???";
}
void
class_init (void)
{
@ -91,17 +113,23 @@ class_init (void)
def_t *
class_def (class_type_t *class_type, int external)
{
const char *name;
type_t *type;
const char *name = 0;
type_t *type = 0;
storage_class_t storage = external ? st_extern : st_global;
if (!class_type->is_class) {
name = va ("_OBJ_CATEGORY_%s_%s", class_type->c.category->class->name,
class_type->c.category->name);
type = type_category;
} else {
name = va ("_OBJ_CLASS_%s", class_type->c.class->name);
type = type_Class.aux_type;
switch (class_type->type) {
case ct_category:
name = va ("_OBJ_CATEGORY_%s_%s",
class_type->c.category->class->name,
class_type->c.category->name);
type = type_category;
break;
case ct_class:
name = va ("_OBJ_CLASS_%s", class_type->c.class->name);
type = type_Class.aux_type;
break;
case ct_protocol:
return 0; // probably in error recovery
}
return get_def (type, name, pr.scope, storage);
}
@ -132,7 +160,7 @@ get_class (const char *name, int create)
new.s.class = c;
c->type = pointer_type (find_type (&new));
c->methods = new_methodlist ();
c->class_type.is_class = 1;
c->class_type.type = ct_class;
c->class_type.c.class = c;
if (name)
Hash_Add (class_hash, c);
@ -191,62 +219,77 @@ class_add_protocols (class_t *class, protocollist_t *protocols)
class->protocols = protocols;
}
static void
begin_category (category_t *category)
{
pr_category_t *pr_category;
class_t *class = category->class;
current_class = &category->class_type;
category->def = class_def (current_class, 0);
category->def->initialized = category->def->constant = 1;
category->def->nosave = 1;
pr_category = &G_STRUCT (pr_category_t, category->def->ofs);
EMIT_STRING (pr_category->category_name, category->name);
EMIT_STRING (pr_category->class_name, class->name);
EMIT_DEF (pr_category->protocols,
emit_protocol_list (category->protocols,
va ("%s_%s", class->name, category->name)));
}
static void
begin_class (class_t *class)
{
def_t *meta_def;
pr_class_t *meta;
pr_class_t *cls;
current_class = &class->class_type;
class->def = class_def (current_class, 0);
meta_def = get_def (type_Class.aux_type,
va ("_OBJ_METACLASS_%s", class->name),
pr.scope, st_static);
meta_def->initialized = meta_def->constant = 1;
meta_def->nosave = 1;
meta = &G_STRUCT (pr_class_t, meta_def->ofs);
EMIT_STRING (meta->class_pointer, class->name);
if (class->super_class)
EMIT_STRING (meta->super_class, class->super_class->name);
EMIT_STRING (meta->name, class->name);
meta->info = _PR_CLS_META;
meta->instance_size = type_size (type_Class.aux_type);
EMIT_DEF (meta->ivars,
emit_struct (type_Class.aux_type->s.class->ivars,
"Class"));
class->def->initialized = class->def->constant = 1;
class->def->nosave = 1;
cls = &G_STRUCT (pr_class_t, class->def->ofs);
EMIT_DEF (cls->class_pointer, meta_def);
if (class->super_class) {
class_type_t class_type = {ct_class, {0}};
class_type.c.class = class->super_class;
EMIT_STRING (cls->super_class, class->super_class->name);
class_def (&class_type, 1);
}
EMIT_STRING (cls->name, class->name);
cls->info = _PR_CLS_CLASS;
EMIT_DEF (cls->protocols,
emit_protocol_list (class->protocols, class->name));
}
void
class_begin (class_type_t *class_type)
{
if (!class_type->is_class) {
pr_category_t *pr_category;
category_t *category = class_type->c.category;
class_t *class = category->class;
current_class = &category->class_type;
category->def = class_def (class_type, 0);
category->def->initialized = category->def->constant = 1;
category->def->nosave = 1;
pr_category = &G_STRUCT (pr_category_t, category->def->ofs);
EMIT_STRING (pr_category->category_name, category->name);
EMIT_STRING (pr_category->class_name, class->name);
EMIT_DEF (pr_category->protocols,
emit_protocol_list (category->protocols,
va ("%s_%s", class->name,
category->name)));
} else {
def_t *meta_def;
pr_class_t *meta;
pr_class_t *cls;
class_t *class = class_type->c.class;
current_class = &class->class_type;
class->def = class_def (class_type, 0);
meta_def = get_def (type_Class.aux_type,
va ("_OBJ_METACLASS_%s", class->name),
pr.scope, st_static);
meta_def->initialized = meta_def->constant = 1;
meta_def->nosave = 1;
meta = &G_STRUCT (pr_class_t, meta_def->ofs);
EMIT_STRING (meta->class_pointer, class->name);
if (class->super_class)
EMIT_STRING (meta->super_class, class->super_class->name);
EMIT_STRING (meta->name, class->name);
meta->info = _PR_CLS_META;
meta->instance_size = type_size (type_Class.aux_type);
EMIT_DEF (meta->ivars,
emit_struct (type_Class.aux_type->s.class->ivars, "Class"));
class->def->initialized = class->def->constant = 1;
class->def->nosave = 1;
cls = &G_STRUCT (pr_class_t, class->def->ofs);
EMIT_DEF (cls->class_pointer, meta_def);
if (class->super_class) {
class_type_t class_type = {1, {0}};
class_type.c.class = class->super_class;
EMIT_STRING (cls->super_class, class->super_class->name);
class_def (&class_type, 1);
}
EMIT_STRING (cls->name, class->name);
cls->info = _PR_CLS_CLASS;
EMIT_DEF (cls->protocols,
emit_protocol_list (class->protocols, class->name));
switch (class_type->type) {
case ct_category:
begin_category (class_type->c.category);
break;
case ct_class:
begin_class (class_type->c.class);
break;
case ct_protocol:
return; // probably error recovery
}
}
@ -319,55 +362,87 @@ emit_category_name (const char *class_name, const char *category_name)
G_INT (def->ofs) = 0;
}
static void
finish_category (category_t *category)
{
pr_category_t *pr_category;
class_t *class = category->class;
char *name;
if (!category->def) // probably in error recovery
return;
name = nva ("%s_%s", class->name, category->name);
pr_category = &G_STRUCT (pr_category_t, category->def->ofs);
EMIT_DEF (pr_category->instance_methods,
emit_methods (category->methods, name, 1));
EMIT_DEF (pr_category->class_methods,
emit_methods (category->methods, name, 0));
free (name);
emit_class_ref (class->name);
emit_category_name (class->name, category->name);
}
static void
finish_class (class_t *class)
{
pr_class_t *meta;
pr_class_t *cls;
if (!class->def) // probably in error recovery
return;
cls = &G_STRUCT (pr_class_t, class->def->ofs);
meta = &G_STRUCT (pr_class_t, cls->class_pointer);
EMIT_DEF (meta->methods, emit_methods (class->methods,
class->name, 0));
cls->instance_size = class->ivars ? type_size (class->ivars->type)
: 0;
EMIT_DEF (cls->ivars, emit_struct (class->ivars, class->name));
EMIT_DEF (cls->methods, emit_methods (class->methods,
class->name, 1));
if (class->super_class)
emit_class_ref (class->super_class->name);
emit_class_name (class->name);
}
void
class_finish (class_type_t *class_type)
{
if (!class_type->is_class) {
pr_category_t *pr_category;
category_t *category = class_type->c.category;
class_t *class = category->class;
char *name;
name = nva ("%s_%s", class->name, category->name);
pr_category = &G_STRUCT (pr_category_t, category->def->ofs);
EMIT_DEF (pr_category->instance_methods,
emit_methods (category->methods, name, 1));
EMIT_DEF (pr_category->class_methods,
emit_methods (category->methods, name, 0));
free (name);
emit_class_ref (class->name);
emit_category_name (class->name, category->name);
} else {
pr_class_t *meta;
pr_class_t *cls;
class_t *class = class_type->c.class;
cls = &G_STRUCT (pr_class_t, class->def->ofs);
meta = &G_STRUCT (pr_class_t, cls->class_pointer);
EMIT_DEF (meta->methods, emit_methods (class->methods,
class->name, 0));
cls->instance_size = class->ivars? type_size (class->ivars->type) : 0;
EMIT_DEF (cls->ivars, emit_struct (class->ivars, class->name));
EMIT_DEF (cls->methods, emit_methods (class->methods,
class->name, 1));
if (class->super_class)
emit_class_ref (class->super_class->name);
emit_class_name (class->name);
switch (class_type->type) {
case ct_category:
finish_category (class_type->c.category);
break;
case ct_class:
finish_class (class_type->c.class);
break;
case ct_protocol:
return; // probably in error recovery
}
}
class_t *
extract_class (class_type_t *class_type)
{
switch (class_type->type) {
case ct_class:
return current_class->c.class;
case ct_category:
return current_class->c.category->class;
case ct_protocol:
return 0; // probably in error recovery
}
return 0; // should not happen
}
int
class_access (class_type_t *current_class, class_t *class)
class_access (class_type_t *class_type, class_t *class)
{
class_t *cur;
if (current_class) {
if (current_class->is_class)
cur = current_class->c.class;
else
cur = current_class->c.category->class;
if (class_type) {
if (!(cur = extract_class (class_type)))
return vis_private;
if (cur == class)
return vis_private;
cur = cur->super_class;
@ -407,14 +482,9 @@ class_ivar_expr (class_type_t *class_type, const char *name)
struct_field_t *ivar;
class_t *c, *class;
if (!class_type)
if (!class_type || !(class = extract_class (class_type)))
return 0;
if (class_type->is_class) {
class = class_type->c.class;
} else {
class = class_type->c.category->class;
}
ivar = struct_find_field (class->ivars, name);
if (!ivar) {
for (c = class->super_class; c; c = c->super_class) {
@ -431,20 +501,25 @@ class_ivar_expr (class_type_t *class_type, const char *name)
method_t *
class_find_method (class_type_t *class_type, method_t *method)
{
methodlist_t *methods, *start_methods;
methodlist_t *methods = 0, *start_methods;
method_t *m;
dstring_t *sel;
class_t *class, *start_class;
class_t *class = 0, *start_class;
const char *class_name;
const char *category_name = 0;
if (!class_type->is_class) {
methods = class_type->c.category->methods;
category_name = class_type->c.category->name;
class = class_type->c.category->class;
} else {
class = class_type->c.class;
methods = class->methods;
switch (class_type->type) {
case ct_category:
methods = class_type->c.category->methods;
category_name = class_type->c.category->name;
class = class_type->c.category->class;
break;
case ct_class:
class = class_type->c.class;
methods = class->methods;
break;
case ct_protocol:
return 0; // probably in error recovery
}
class_name = class->name;
start_methods = methods;
@ -603,7 +678,7 @@ get_category (const char *class_name, const char *category_name, int create)
category->name = category_name;
category->class = class;
category->methods = new_methodlist ();
category->class_type.is_class = 0;
category->class_type.type = ct_category;
category->class_type.c.category = category;
if (class_name && category_name)
Hash_AddElement (category_hash, category);
@ -647,7 +722,7 @@ def_t *
class_pointer_def (class_t *class)
{
def_t *def;
class_type_t class_type = {1, {0}};
class_type_t class_type = {ct_class, {0}};
class_type.c.class = class;
@ -785,6 +860,8 @@ get_protocol (const char *name, int create)
p = calloc (sizeof (protocol_t), 1);
p->name = name;
p->methods = new_methodlist ();
p->class_type.type = ct_protocol;
p->class_type.c.protocol = p;
if (name)
Hash_Add (protocol_hash, p);
return p;

View file

@ -2745,10 +2745,7 @@ super_expr (class_type_t *class_type)
return error (new_expr (),
"`super' used outside of class implementation");
if (class_type->is_class)
class = class_type->c.class;
else
class = class_type->c.category->class;
class = extract_class (class_type);
if (!class->super_class)
return error (new_expr (), "%s has no super class", class->name);
@ -2763,7 +2760,7 @@ super_expr (class_type_t *class_type)
new_name_expr ("self"));
append_expr (super_block, e);
_class_type.is_class = 1;
_class_type.type = ct_class;
_class_type.c.class = class;
e = new_def_expr (class_def (&_class_type, 1));
e = assign_expr (binary_expr ('.', super, new_name_expr ("class")),
@ -2795,10 +2792,7 @@ message_expr (expr_t *receiver, keywordarg_t *message)
if (receiver->type == ex_error)
return receiver;
if (current_class->is_class)
class = current_class->c.class;
else
class = current_class->c.category->class;
class = extract_class (current_class);
rec_type = class->type;
} else {
if (receiver->type == ex_name) {
@ -2817,10 +2811,7 @@ message_expr (expr_t *receiver, keywordarg_t *message)
&& rec_type->aux_type->type != ev_class))
return error (receiver, "not a class/object");
if (self) {
if (current_class->is_class)
class = current_class->c.class;
else
class = current_class->c.category->class;
class = extract_class (current_class);
if (rec_type == &type_Class)
class_msg = 1;
} else {

View file

@ -151,19 +151,12 @@ method_def (class_type_t *class_type, method_t *method)
def_t *def;
char *s;
const char *class_name;
const char *category_name = "";
if (class_type->is_class) {
class_name = class_type->c.class->name;
} else {
class_name = class_type->c.category->class->name;
category_name = class_type->c.category->name;
}
class_name = get_class_name (class_type, 0);
dsprintf (str, "_%c_%s_%s_%s",
dsprintf (str, "_%c_%s_%s",
method->instance ? 'i' : 'c',
class_name,
category_name,
method->name);
for (s = str->str; *s; s++)
if (*s == ':')