MWCC/compiler_and_linker/unsorted/CObjC.c

3103 lines
87 KiB
C

#include "compiler/CObjC.h"
#include "compiler/CABI.h"
#include "compiler/CClass.h"
#include "compiler/CDecl.h"
#include "compiler/CError.h"
#include "compiler/CExpr.h"
#include "compiler/CInit.h"
#include "compiler/CFunc.h"
#include "compiler/CMachine.h"
#include "compiler/CParser.h"
#include "compiler/CPrep.h"
#include "compiler/CPrepTokenizer.h"
#include "compiler/CScope.h"
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/objc.h"
#include "compiler/objects.h"
#include "compiler/scopes.h"
#include "cos.h"
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct ObjCString {
struct ObjCString *next;
Object *object;
char *str;
Section section;
} ObjCString;
typedef struct ObjCCategoryEntry {
struct ObjCCategoryEntry *next;
ObjCCategory *category;
Object *object;
} ObjCCategoryEntry;
#ifdef __MWERKS__
#pragma options align=reset
#endif
Type *cobjc_type_class;
Type *cobjc_type_id;
Type *cobjc_type_sel;
TypeClass *cobjc_currentclass;
ObjCSelector **cobjc_selhashtable;
BClassList *cobjc_classdefs;
ObjCProtocol *cobjc_protocols;
long cobjc_selrefcount;
long cobjc_classrefcount;
long cobjc_stringcount;
Boolean cobjc_encodemethod;
static ObjCCategoryEntry *cobjc_categories;
static ObjCString *cobjc_strings;
// forward decls
static void CObjC_EncodeType(Type *type, UInt32 qual, Boolean flag);
static Object *CObjC_GetProtocolObject(ObjCProtocol *protocol);
void CObjC_Setup(void) {
cobjc_type_class = NULL;
cobjc_type_id = NULL;
cobjc_type_sel = NULL;
cobjc_currentclass = NULL;
cobjc_selhashtable = NULL;
cobjc_strings = NULL;
cobjc_classdefs = NULL;
cobjc_protocols = NULL;
cobjc_categories = NULL;
cobjc_selrefcount = 0;
cobjc_classrefcount = 0;
cobjc_stringcount = 0;
cobjc_encodemethod = 0;
}
void CObjC_Cleanup(void) {
}
static HashNameNode *CObjC_GetSelfName(void) {
return self_name_node;
}
static char *CObjC_StringConcat(char *a, char *b, char *c) {
char *buf;
int len;
len = 1;
if (a)
len += strlen(a);
if (b)
len += strlen(b);
if (c)
len += strlen(c);
buf = galloc(len);
len = 0;
if (a) {
strcpy(&buf[len], a);
len += strlen(a);
}
if (b) {
strcpy(&buf[len], b);
len += strlen(b);
}
if (c) {
strcpy(&buf[len], c);
len += strlen(c);
}
buf[len] = 0;
return buf;
}
static Object *CObjC_SectionString(char *str, Section section) {
ObjCString *objcstr;
Object *object;
for (objcstr = cobjc_strings; objcstr; objcstr = objcstr->next) {
if (objcstr->section == section && !strcmp(str, objcstr->str))
return objcstr->object;
}
object = CParser_NewCompilerDefDataObject();
object->nspace = cscope_root;
object->name = CParser_GetUniqueName();
object->type = CDecl_NewArrayType(TYPE(&stchar), strlen(str) + 1);
object->sclass = TK_STATIC;
object->section = section;
CInit_DeclareData(object, str, NULL, object->type->size);
objcstr = galloc(sizeof(ObjCString));
objcstr->next = cobjc_strings;
cobjc_strings = objcstr;
objcstr->str = str;
objcstr->section = section;
objcstr->object = object;
return objcstr->object;
}
static ObjCProtocol *CObjC_FindProtocol(HashNameNode *name) {
ObjCProtocol *prot;
for (prot = cobjc_protocols; prot; prot = prot->next) {
if (prot->name == name)
break;
}
return prot;
}
static ObjCSelector *CObjC_FindSelector(HashNameNode *name) {
ObjCSelector *sel;
if (!cobjc_selhashtable)
return NULL;
for (sel = cobjc_selhashtable[name->hashval & 0x3FF]; sel; sel = sel->next) {
if (sel->name == name)
break;
}
return sel;
}
static ObjCSelector *CObjC_NewSelector(HashNameNode *name) {
ObjCSelector *sel;
ObjCSelector **ptr;
if (!cobjc_selhashtable) {
cobjc_selhashtable = galloc(sizeof(ObjCSelector *) * 0x400);
memclrw(cobjc_selhashtable, sizeof(ObjCSelector *) * 0x400);
}
sel = galloc(sizeof(ObjCSelector));
sel->selobject = NULL;
sel->name = name;
sel->methods = NULL;
ptr = cobjc_selhashtable + (name->hashval & 0x3FF);
sel->next = *ptr;
*ptr = sel;
return sel;
}
static ObjCSelector *CObjC_FindKeyArgSelector(ObjCNamedArg *arg) {
HashNameNode *name;
if (!arg->next && !arg->expr) {
name = arg->name;
} else {
name_mangle_list.size = 0;
while (arg) {
if (arg->name)
AppendGListName(&name_mangle_list, arg->name->name);
AppendGListByte(&name_mangle_list, ':');
arg = arg->next;
}
AppendGListByte(&name_mangle_list, 0);
COS_LockHandle(name_mangle_list.data);
name = GetHashNameNodeExport(*name_mangle_list.data);
COS_UnlockHandle(name_mangle_list.data);
}
return CObjC_FindSelector(name);
}
static Boolean CObjC_IsSameType(Type *a, Type *b) {
if (!copts.objc_strict && CObjC_IsCompatibleType(a, b))
return 1;
return is_typesame(a, b);
}
static Boolean CObjC_IsSameMethod(ObjCMethod *a, ObjCMethod *b) {
ObjCMethodArg *argA;
ObjCMethodArg *argB;
if (
CObjC_IsSameType(a->return_type, b->return_type) &&
a->return_qual == b->return_qual &&
a->has_valist == b->has_valist
)
{
argA = a->selector_args;
argB = b->selector_args;
while (1) {
if (!argA)
return !argB;
if (!argB)
return 0;
if (argA->selector != argB->selector || argA->qual != argB->qual)
return 0;
if (argA->type) {
// bug?
if (!argB->type || !CObjC_IsSameType(argB->type, argB->type))
return 0;
} else {
if (argB->type)
return 0;
}
argA = argA->next;
argB = argB->next;
}
}
return 0;
}
static ObjCSelector *CObjC_MakeSelector(ObjCMethod *meth) {
ObjCMethodList *methlist;
HashNameNode *selname;
ObjCSelector *sel;
ObjCMethodArg *arg;
if (!meth->selector_args->next && !meth->selector_args->type) {
selname = meth->selector_args->selector;
} else {
name_mangle_list.size = 0;
for (arg = meth->selector_args; arg; arg = arg->next) {
if (arg->selector)
AppendGListName(&name_mangle_list, arg->selector->name);
AppendGListByte(&name_mangle_list, ':');
}
AppendGListByte(&name_mangle_list, 0);
COS_LockHandle(name_mangle_list.data);
selname = GetHashNameNodeExport(*name_mangle_list.data);
COS_UnlockHandle(name_mangle_list.data);
}
sel = CObjC_FindSelector(selname);
if (!sel) {
methlist = galloc(sizeof(ObjCMethodList));
methlist->next = NULL;
methlist->method = meth;
sel = CObjC_NewSelector(selname);
sel->methods = methlist;
} else {
for (methlist = sel->methods; methlist; methlist = methlist->next) {
if (CObjC_IsSameMethod(methlist->method, meth))
break;
}
if (!methlist) {
methlist = galloc(sizeof(ObjCMethodList));
methlist->method = meth;
methlist->next = sel->methods;
sel->methods = methlist;
}
}
meth->selector = sel;
return sel;
}
static Object *CObjC_GetSelectorObject(ObjCSelector *sel) {
Object *nameobj;
Object *dataobj;
char str[32];
OLinkList refs;
char buf[8];
if (!sel->selobject) {
nameobj = CObjC_SectionString(sel->name->name, SECT_OBJC_METH_VAR_NAMES);
sprintf(str, "L_OBJC_SELECTOR_REFERENCES_%" PRId32, cobjc_selrefcount++);
dataobj = CParser_NewCompilerDefDataObject();
dataobj->name = GetHashNameNodeExport(str);
dataobj->sclass = TK_STATIC;
dataobj->type = TYPE(&void_ptr);
dataobj->section = SECT_OBJC_MESSAGE_REFS;
if (CScope_GetLocalObject(cscope_root, dataobj->name))
CError_Error(CErrorStr333, dataobj);
else
CScope_AddGlobalObject(dataobj);
sel->selobject = dataobj;
memclrw(buf, dataobj->type->size);
refs.next = NULL;
refs.obj = nameobj;
refs.offset = 0;
refs.somevalue = 0;
CInit_DeclareData(dataobj, buf, &refs, dataobj->type->size);
}
return sel->selobject;
}
static Object *CObjC_GetClassRefObject(TypeClass *tclass) {
Object *nameobj;
Object *dataobj;
char str[32];
OLinkList refs;
char buf[8];
if (!tclass->objcinfo->classrefobj) {
nameobj = CObjC_SectionString(tclass->classname->name, SECT_OBJC_CLASS_NAMES);
sprintf(str, "L_OBJC_CLASS_REFERENCES_%" PRId32, cobjc_classrefcount++);
dataobj = CParser_NewCompilerDefDataObject();
dataobj->name = GetHashNameNodeExport(str);
dataobj->sclass = TK_STATIC;
dataobj->type = TYPE(&void_ptr);
dataobj->section = SECT_OBJC_CLS_REFS;
if (CScope_GetLocalObject(cscope_root, dataobj->name))
CError_Error(CErrorStr333, dataobj);
else
CScope_AddGlobalObject(dataobj);
tclass->objcinfo->classrefobj = dataobj;
memclrw(buf, dataobj->type->size);
refs.next = NULL;
refs.obj = nameobj;
refs.offset = 0;
refs.somevalue = 0;
CInit_DeclareData(dataobj, buf, &refs, dataobj->type->size);
}
return tclass->objcinfo->classrefobj;
}
static Object *CObjC_MakeObject(char *name1, char *name2, SInt32 size) {
Object *object = CParser_NewCompilerDefDataObject();
object->name = CParser_NameConcat(name1, name2);
object->type = CDecl_NewStructType(size, 4);
CScope_AddObject(object->nspace, object->name, OBJ_BASE(object));
return object;
}
static Object *CObjC_FindRTFunc(char *namestr, char *namestr2) {
NameSpaceObjectList *list;
Object *object;
HashNameNode *name;
NameSpace *saveNSpace;
Boolean savecpp;
savecpp = copts.cplusplus;
name = GetHashNameNodeExport(namestr);
if ((list = CScope_GetLocalObject(cscope_root, name))) {
if (IS_TYPE_FUNC(OBJECT(list->object)->type))
return OBJECT(list->object);
CError_Error(CErrorStr122, name);
}
copts.cplusplus = 0;
saveNSpace = cscope_current;
cscope_current = cscope_root;
object = CParser_NewFunctionObject(NULL);
cscope_current = saveNSpace;
object->type = TYPE(&rt_func);
object->name = name;
if (!list)
CScope_AddObject(cscope_root, name, OBJ_BASE(object));
copts.cplusplus = savecpp;
return object;
}
static Object *CObjC_FindSendMessageRTFunc(Boolean flag1, Boolean flag2) {
if (flag1) {
if (flag2)
return CObjC_FindRTFunc("objc_msgSendSuper_stret", "_objc_msgSendSuper_stret");
else
return CObjC_FindRTFunc("objc_msgSendSuper", "_objc_msgSendSuper");
} else {
if (flag2)
return CObjC_FindRTFunc("objc_msgSend_stret", "_objc_msgSend_stret");
else
return CObjC_FindRTFunc("objc_msgSend", "_objc_msgSend");
}
}
typedef struct RawSymbols {
UInt32 x0;
UInt32 x4;
UInt16 x8;
UInt16 xA;
UInt32 offsets[1];
} RawSymbols;
void CObjC_GenerateModule(void) {
int i;
RawSymbols *symdata;
SInt32 size;
Object *object;
OLinkList *refs;
OLinkList *ref;
int classCount;
int categoryCount;
ObjCCategoryEntry *catEntry;
BClassList *classdef;
UInt32 data[4];
if (copts.objective_c || cobjc_classdefs) {
for (classdef = cobjc_classdefs, classCount = 0; classdef; classdef = classdef->next)
classCount++;
for (catEntry = cobjc_categories, categoryCount = 0; catEntry; catEntry = catEntry->next)
categoryCount++;
size = sizeof(RawSymbols) + 4 * (classCount + categoryCount - 1);
symdata = lalloc(size);
memclrw(symdata, size);
symdata->x0 = CTool_EndianConvertWord32(0);
symdata->x4 = CTool_EndianConvertWord32(0);
symdata->x0 = CTool_EndianConvertWord16(0);
symdata->x8 = CTool_EndianConvertWord16(classCount);
symdata->xA = CTool_EndianConvertWord16(categoryCount);
refs = NULL;
i = 0;
for (classdef = cobjc_classdefs; classdef; classdef = classdef->next) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = TYPE_CLASS(classdef->type)->objcinfo->classobject;
ref->offset = ((char *) &symdata->offsets[i]) - ((char *) symdata);
ref->somevalue = 0;
i++;
}
for (catEntry = cobjc_categories; catEntry; catEntry = catEntry->next) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = catEntry->object;
ref->offset = ((char *) &symdata->offsets[i]) - ((char *) symdata);
ref->somevalue = 0;
i++;
}
object = CObjC_MakeObject("", "L_OBJC_SYMBOLS", size);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_MSYMBOLS;
CInit_DeclareData(object, symdata, refs, object->type->size);
refs = NULL;
data[0] = CTool_EndianConvertWord32(5);
data[1] = CTool_EndianConvertWord32(16);
data[2] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(CPrep_GetFileName(NULL, 1, 0), SECT_OBJC_CLASS_NAMES);
ref->offset = 8;
ref->somevalue = 0;
data[3] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 12;
ref->somevalue = 0;
object = CObjC_MakeObject("", "L_OBJC_MODULES", 16);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_MODULE_INFO;
CInit_DeclareData(object, data, refs, object->type->size);
}
}
static TypeClass *CObjC_FindObjCClass(HashNameNode *name, Boolean flag) {
NameSpaceObjectList *list;
list = CScope_FindName(cscope_root, name);
if (
!list ||
list->object->otype != OT_TYPE ||
!IS_TYPE_CLASS(OBJ_TYPE(list->object)->type) ||
!TYPE_CLASS(OBJ_TYPE(list->object)->type)->objcinfo
)
{
if (list || flag)
CError_Error(CErrorStr292, name->name);
return NULL;
} else {
return TYPE_CLASS(OBJ_TYPE(list->object)->type);
}
}
static Type *CObjC_FindObjCType(char *namestr, Boolean flag) {
NameSpaceObjectList *list;
list = CScope_FindName(cscope_root, GetHashNameNodeExport(namestr));
if (list && list->object->otype == OT_TYPE) {
if (IS_TYPE_POINTER_ONLY(OBJ_TYPE(list->object)->type))
return OBJ_TYPE(list->object)->type;
CError_Error(CErrorStr298, namestr);
} else {
if (flag)
CError_Error(CErrorStr297, namestr);
}
return NULL;
}
static Type *CObjC_GetObjCType_Class(Boolean flag) {
Type *type;
if (cobjc_type_class)
return cobjc_type_class;
type = CObjC_FindObjCType("Class", flag);
if (!type)
return TYPE(&void_ptr);
cobjc_type_class = type;
return type;
}
Type *CObjC_GetObjCType_id(Boolean flag) {
Type *type;
if (cobjc_type_class)
return cobjc_type_id;
type = CObjC_FindObjCType("id", flag);
if (!type)
return TYPE(&void_ptr);
cobjc_type_id = type;
return type;
}
Boolean CObjC_IsType_id(Type *type) {
if (IS_TYPE_POINTER_ONLY(type)) {
if (type == TYPE(&void_ptr))
return 0;
type = TPTR_TARGET(type);
if (type == TPTR_TARGET(CObjC_GetObjCType_id(0)))
return 1;
if (type == TPTR_TARGET(CObjC_GetObjCType_Class(0)))
return 1;
}
return 0;
}
Boolean CObjC_IsCompatibleType(Type *a, Type *b) {
Boolean a_is_id;
Boolean b_is_id;
if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) {
a_is_id = CObjC_IsType_id(a);
b_is_id = CObjC_IsType_id(b);
if (a_is_id && b_is_id)
return 1;
if (a_is_id && IS_TYPE_OBJC_CLASS(TPTR_TARGET(b)))
return 1;
if (b_is_id && IS_TYPE_OBJC_CLASS(TPTR_TARGET(a)))
return 1;
}
return 0;
}
static Type *CObjC_FindObjCType_SEL(void) {
Type *type;
if (cobjc_type_sel)
return cobjc_type_sel;
type = CObjC_FindObjCType("SEL", 1);
if (!type)
return TYPE(&void_ptr);
cobjc_type_sel = type;
return type;
}
static Boolean CObjC_IsType_SEL(Type *type) {
Type *sel;
if (!IS_TYPE_POINTER_ONLY(type))
return 0;
type = TPTR_TARGET(type);
sel = CObjC_FindObjCType_SEL();
CError_ASSERT(847, IS_TYPE_POINTER_ONLY(sel));
return type == TPTR_TARGET(sel);
}
static TypeClass *CObjC_NewObjCClass(HashNameNode *name) {
NameSpaceObjectList *list;
ObjCInfo *info;
TypeClass *tclass;
if ((list = CScope_FindName(cscope_root, name))) {
if (
list->object->otype != OT_TYPE ||
!IS_TYPE_CLASS(tclass = TYPE_CLASS(OBJ_TYPE(list->object)->type)) ||
!tclass->objcinfo
)
{
CError_Error(CErrorStr122, name->name);
return NULL;
}
return tclass;
}
info = galloc(sizeof(ObjCInfo));
memclrw(info, sizeof(ObjCInfo));
tclass = CDecl_DefineClass(cscope_root, name, NULL, CLASS_MODE_2, 1, 1);
tclass->flags |= CLASS_FLAGS_10;
tclass->objcinfo = info;
info->classobject = CObjC_MakeObject("L_OBJC_CLASS_", name->name, 40);
info->classobject->sclass = TK_STATIC;
info->classobject->section = SECT_OBJC_CLASS;
info->metaobject = CObjC_MakeObject("L_OBJC_METACLASS_", name->name, 40);
info->metaobject->sclass = TK_STATIC;
info->metaobject->section = SECT_OBJC_META_CLASS;
return tclass;
}
static void CObjC_ParseTypeName(Type **type, UInt32 *qual) {
DeclInfo di;
tk = lex();
memclrw(&di, sizeof(di));
CParser_GetDeclSpecs(&di, 0);
scandeclarator(&di);
if (tk != ')')
CError_ErrorSkip(CErrorStr115);
else
tk = lex();
if (di.name)
CError_Error(CErrorStr121);
*type = di.x4A ? CObjC_GetObjCType_id(1) : di.thetype;
*qual = di.qual;
}
void CObjC_TranslateSelectorToken(void) {
switch (tk) {
case TK_CLASS:
tkidentifier = GetHashNameNodeExport("class");
tk = TK_IDENTIFIER;
break;
case TK_SELF:
tkidentifier = GetHashNameNodeExport("self");
tk = TK_IDENTIFIER;
break;
case TK_IN:
tkidentifier = GetHashNameNodeExport("in");
tk = TK_IDENTIFIER;
break;
case TK_BREAK:
tkidentifier = GetHashNameNodeExport("break");
tk = TK_IDENTIFIER;
break;
case TK_NEW:
tkidentifier = GetHashNameNodeExport("new");
tk = TK_IDENTIFIER;
break;
case TK_DELETE:
tkidentifier = GetHashNameNodeExport("delete");
tk = TK_IDENTIFIER;
break;
}
}
static ObjCMethod *CObjC_ParseMethod(Boolean is_global) {
ObjCMethod *meth;
ObjCMethodArg *arg;
ObjCMethodArg **ptr;
Boolean argflag;
if (is_global) {
meth = galloc(sizeof(ObjCMethod));
memclrw(meth, sizeof(ObjCMethod));
} else {
meth = lalloc(sizeof(ObjCMethod));
memclrw(meth, sizeof(ObjCMethod));
}
switch (tk) {
case '+':
meth->is_class_method = 1;
break;
case '-':
meth->is_class_method = 0;
break;
default:
CError_FATAL(976);
}
if ((tk = lex()) == '(') {
CObjC_ParseTypeName(&meth->return_type, &meth->return_qual);
CError_QualifierCheck(meth->return_qual & ~(Q_CONST | Q_VOLATILE | Q_BYCOPY | Q_BYREF | Q_ONEWAY));
} else {
meth->return_type = CObjC_GetObjCType_id(1);
}
ptr = &meth->selector_args;
argflag = 1;
while (1) {
if (is_global) {
arg = galloc(sizeof(ObjCMethodArg));
memclrw(arg, sizeof(ObjCMethodArg));
} else {
arg = lalloc(sizeof(ObjCMethodArg));
memclrw(arg, sizeof(ObjCMethodArg));
}
*ptr = arg;
ptr = &arg->next;
CObjC_TranslateSelectorToken();
if (tk == TK_IDENTIFIER) {
arg->selector = tkidentifier;
if ((tk = lex()) != ':') {
if (argflag)
break;
CError_Error(CErrorStr170);
return NULL;
}
}
if (tk != ':') {
CError_Error(CErrorStr170);
return NULL;
}
if ((tk = lex()) == '(') {
CObjC_ParseTypeName(&arg->type, &arg->qual);
if (IS_TYPE_ARRAY(arg->type))
arg->type = CDecl_NewPointerType(TPTR_TARGET(arg->type));
CError_QualifierCheck(arg->qual & ~(Q_CONST | Q_VOLATILE | Q_IN | Q_OUT | Q_INOUT | Q_BYCOPY | Q_BYREF));
if ((arg->qual & (Q_OUT | Q_INOUT)) && !IS_TYPE_POINTER_ONLY(arg->type))
CError_QualifierCheck(arg->qual & (Q_OUT | Q_INOUT));
} else {
arg->type = CObjC_GetObjCType_id(1);
}
if (tk != TK_IDENTIFIER) {
CObjC_TranslateSelectorToken();
if (tk != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
tkidentifier = no_name_node;
}
}
arg->name = tkidentifier;
if ((tk = lex()) == ',') {
if ((tk = lex()) == TK_ELLIPSIS) {
meth->has_valist = 1;
tk = lex();
break;
}
CError_Error(CErrorStr121);
}
CObjC_TranslateSelectorToken();
if (tk != ':' && tk != TK_IDENTIFIER)
break;
argflag = 0;
}
return meth;
}
static ObjCMethod *CObjC_FindMethod(ObjCMethod *methods, ObjCMethod *wanted, Boolean flag1, Boolean flag2) {
ObjCMethod *meth;
ObjCMethodArg *wanted_arg;
ObjCMethodArg *meth_arg;
for (meth = methods; meth; meth = meth->next) {
if (wanted->is_class_method == meth->is_class_method) {
wanted_arg = wanted->selector_args;
meth_arg = meth->selector_args;
while (1) {
if (!wanted_arg || !meth_arg) {
if (wanted_arg)
break;
if (meth_arg)
break;
if (flag1) {
wanted_arg = wanted->selector_args;
meth_arg = meth->selector_args;
while (1) {
if (!wanted_arg)
break;
if (wanted_arg->qual != meth_arg->qual)
break;
if (wanted_arg->type) {
if (!meth_arg->type)
break;
if (!CObjC_IsSameType(wanted_arg->type, meth_arg->type))
break;
} else {
if (meth_arg->type)
break;
}
meth_arg->name = wanted_arg->name;
wanted_arg = wanted_arg->next;
meth_arg = meth_arg->next;
}
if (
wanted_arg ||
wanted->has_valist != meth->has_valist ||
wanted->return_qual != meth->return_qual ||
!CObjC_IsSameType(wanted->return_type, meth->return_type)
)
CError_Error(CErrorStr293, meth);
}
return meth;
}
if (wanted_arg->selector != meth_arg->selector)
break;
if (!wanted_arg->type && meth_arg->type)
break;
if (wanted_arg->type && !meth_arg->type)
break;
wanted_arg = wanted_arg->next;
meth_arg = meth_arg->next;
}
}
}
if (!flag2)
CError_Error(CErrorStr294, wanted);
return NULL;
}
static ObjCMethod *CObjC_CloneMethod(ObjCMethod *meth) {
ObjCMethod *copy;
copy = galloc(sizeof(ObjCMethod));
memclrw(copy, sizeof(ObjCMethod));
copy->selector = meth->selector;
copy->return_type = meth->return_type;
copy->return_qual = meth->return_qual;
copy->selector_args = meth->selector_args;
copy->has_valist = meth->has_valist;
copy->is_class_method = meth->is_class_method;
copy->is_defined = 0;
return copy;
}
static void CObjC_AddProtocolMethods(TypeClass *tclass, ObjCMethod **methods, ObjCProtocolList *protocols) {
ObjCMethod *meth;
ObjCMethod *copy;
while (protocols) {
for (meth = protocols->protocol->methods; meth; meth = meth->next) {
if (!CObjC_FindMethod(*methods, meth, 1, 1)) {
copy = CObjC_CloneMethod(meth);
copy->next = *methods;
*methods = copy;
if (tclass)
CObjC_MakeSelector(copy);
}
}
protocols = protocols->next;
}
}
static void CObjC_AppendArgument(TypeFunc *tfunc, HashNameNode *name, Type *type, UInt32 qual) {
FuncArg *arg;
if (tfunc->args) {
arg = tfunc->args;
while (arg->next)
arg = arg->next;
arg->next = CParser_NewFuncArg();
arg = arg->next;
} else {
arg = CParser_NewFuncArg();
tfunc->args = arg;
}
arg->name = name;
arg->type = type;
arg->qual = qual;
}
static HashNameNode *CObjC_MangleMethodName(TypeClass *tclass, ObjCCategory *cat, ObjCMethod *meth) {
ObjCMethodArg *arg;
HashNameNode *name;
name_mangle_list.size = 0;
if (meth->is_class_method)
AppendGListName(&name_mangle_list, "+[");
else
AppendGListName(&name_mangle_list, "-[");
AppendGListName(&name_mangle_list, tclass->classname->name);
if (cat) {
AppendGListByte(&name_mangle_list, '(');
AppendGListName(&name_mangle_list, cat->name->name);
AppendGListByte(&name_mangle_list, ')');
}
AppendGListByte(&name_mangle_list, ' ');
for (arg = meth->selector_args; arg; arg = arg->next) {
if (arg->selector)
AppendGListName(&name_mangle_list, arg->selector->name);
if (arg->type)
AppendGListByte(&name_mangle_list, ':');
}
AppendGListID(&name_mangle_list, "]");
COS_LockHandle(name_mangle_list.data);
name = GetHashNameNodeExport(*name_mangle_list.data);
COS_UnlockHandle(name_mangle_list.data);
return name;
}
static TypeFunc *CObjC_GetMethodFuncType(ObjCMethod *meth) {
ObjCMethodArg *metharg;
TypeFunc *functype;
FuncArg *funcarg;
if (!meth->functype) {
functype = galloc(sizeof(TypeFunc));
memclrw(functype, sizeof(TypeFunc));
functype->type = TYPEFUNC;
functype->functype = meth->return_type;
functype->qual = meth->return_qual;
functype->flags = FUNC_FLAGS_4000;
CDecl_SetFuncFlags(functype, 1);
CObjC_AppendArgument(functype, CObjC_GetSelfName(), CObjC_GetObjCType_id(1), 0);
CObjC_AppendArgument(functype, GetHashNameNodeExport("_cmd"), CObjC_FindObjCType_SEL(), 0);
for (metharg = meth->selector_args; metharg; metharg = metharg->next) {
if (metharg->type)
CObjC_AppendArgument(functype, metharg->name, metharg->type, metharg->qual);
}
if (meth->has_valist) {
for (funcarg = functype->args; ; funcarg = funcarg->next) {
if (!funcarg->next) {
funcarg->next = &elipsis;
break;
}
}
}
meth->functype = functype;
}
return meth->functype;
}
static Object *CObjC_GetMethodObject(TypeClass *tclass, ObjCCategory *cat, ObjCMethod *meth) {
Object *object;
Boolean saveCPP;
NameSpace *saveNS;
if (!meth->object) {
saveCPP = copts.cplusplus;
copts.cplusplus = 0;
saveNS = cscope_current;
cscope_current = cscope_root;
object = CParser_NewFunctionObject(NULL);
object->nspace = tclass->nspace;
object->type = TYPE(CObjC_GetMethodFuncType(meth));
object->name = CObjC_MangleMethodName(tclass, cat, meth);
object->u.func.linkname = object->name;
object->sclass = TK_STATIC;
meth->object = object;
cscope_current = saveNS;
copts.cplusplus = saveCPP;
}
return meth->object;
}
static void CObjC_AddMethod(TypeClass *tclass) {
ObjCMethod *meth;
ObjCMethod *existing;
if ((meth = CObjC_ParseMethod(1))) {
existing = CObjC_FindMethod(tclass->objcinfo->methods, meth, 0, 1);
if (!existing) {
meth->next = tclass->objcinfo->methods;
tclass->objcinfo->methods = meth;
CObjC_MakeSelector(meth);
} else {
if (copts.objc_strict || !CObjC_IsSameMethod(meth, existing))
CError_Error(CErrorStr293, meth);
}
}
if (tk != ';')
CError_Error(CErrorStr123);
else
tk = lex();
}
static Boolean CObjC_IsSameProtocolList(ObjCProtocolList *a, ObjCProtocolList *b) {
while (1) {
if (!a)
return !b;
if (!b || a->protocol != b->protocol)
return 0;
a = a->next;
b = b->next;
}
}
static ObjCProtocolList *CObjC_ParserProtocolList(void) {
ObjCProtocolList *list;
ObjCProtocolList *entry;
ObjCProtocol *protocol;
list = NULL;
tk = lex();
while (1) {
if (tk != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
break;
}
if ((protocol = CObjC_FindProtocol(tkidentifier))) {
for (entry = list; entry; entry = entry->next) {
if (entry->protocol == protocol)
break;
}
if (!entry) {
entry = galloc(sizeof(ObjCProtocolList));
entry->next = list;
entry->protocol = protocol;
list = entry;
} else {
CError_Error(CErrorStr310, tkidentifier->name);
}
} else {
CError_Error(CErrorStr309, tkidentifier->name);
}
if ((tk = lex()) == '>') {
tk = lex();
break;
}
if (tk != ',') {
CError_Error(CErrorStr116);
break;
}
tk = lex();
}
return list;
}
static void CObjC_AddClassMembers(TypeStruct *tstruct, TypeClass *tclass) {
ObjMemberVar *ivar;
StructMember *member;
if (tclass->bases)
CObjC_AddClassMembers(tstruct, tclass->bases->base);
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
member = galloc(sizeof(StructMember));
memclrw(member, sizeof(StructMember));
member->name = ivar->name;
member->type = ivar->type;
member->qual = ivar->qual;
member->offset = ivar->offset;
appendmember(tstruct, member);
}
}
void CObjC_ParseDefs(TypeStruct *tstruct) {
TypeClass *tclass;
if ((tk = lex()) == '(') {
if ((tk = lex()) == TK_IDENTIFIER) {
if ((tclass = CObjC_FindObjCClass(tkidentifier, 1))) {
if (tclass->flags & CLASS_FLAGS_2) {
tstruct->size = tclass->size;
tstruct->align = tclass->align;
CObjC_AddClassMembers(tstruct, tclass);
} else {
CError_Error(CErrorStr136, tclass, 0);
}
}
if ((tk = lex()) != ')')
CError_Error(CErrorStr115);
} else {
CError_Error(CErrorStr107);
}
} else {
CError_Error(CErrorStr114);
}
}
Type *CObjC_ParseID(void) {
TypeObjCID *type;
if ((tk = lex()) == '<') {
type = galloc(sizeof(TypeObjCID));
memclrw(type, sizeof(TypeObjCID));
type->pointer = *TYPE_POINTER(CObjC_GetObjCType_id(1));
type->protocols = CObjC_ParserProtocolList();
type->pointer.qual |= Q_100000;
return TYPE(type);
} else {
return CObjC_GetObjCType_id(1);
}
}
Type *CObjC_ParseTypeProtocol(TypeClass *tclass) {
CError_ASSERT(1526, tk == '<');
CObjC_ParserProtocolList();
return TYPE(tclass);
}
static void CObjC_ParseCategoryInterface(TypeClass *tclass) {
ObjCCategory *cat;
ObjCMethod *meth;
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
return;
}
for (cat = tclass->objcinfo->categories; cat; cat = cat->next) {
if (cat->name == tkidentifier) {
CError_Error(CErrorStr311, tkidentifier->name);
break;
}
}
cat = galloc(sizeof(ObjCCategory));
memclrw(cat, sizeof(ObjCCategory));
cat->name = tkidentifier;
if ((tk = lex()) != ')') {
CError_Error(CErrorStr115);
return;
}
tk = lex();
if (tk == '<') {
cat->protocols = CObjC_ParserProtocolList();
CObjC_AddProtocolMethods(tclass, &cat->methods, cat->protocols);
}
while (1) {
switch (tk) {
case '-':
case '+':
if ((meth = CObjC_ParseMethod(1))) {
if (!CObjC_FindMethod(cat->methods, meth, 0, 1)) {
meth->next = cat->methods;
cat->methods = meth;
CObjC_MakeSelector(meth);
} else {
CError_Error(CErrorStr293, meth);
}
}
if (tk != ';')
CError_Error(CErrorStr123);
else
tk = lex();
continue;
case TK_AT_END:
break;
default:
CParser_ParseGlobalDeclaration();
continue;
}
break;
}
cat->next = tclass->objcinfo->categories;
tclass->objcinfo->categories = cat;
}
static void CObjC_DefineMethod(TypeClass *tclass, ObjCCategory *category, ObjCMethod **methods) {
ObjCMethod *meth30;
Object *object;
ObjCMethod *meth26;
FuncArg *funcarg;
ObjCMethodArg *selarg;
DeclInfo di;
meth26 = CObjC_ParseMethod(1);
if (!meth26)
return;
meth30 = CObjC_FindMethod(*methods, meth26, 1, 1);
if (!meth30) {
meth30 = meth26;
meth26->next = *methods;
*methods = meth26;
CObjC_MakeSelector(meth26);
}
if (meth30->is_defined)
CError_Error(CErrorStr300, meth30);
object = CObjC_GetMethodObject(tclass, category, meth30);
CError_ASSERT(1627, IS_TYPE_FUNC(object->type));
if ((funcarg = TYPE_FUNC(object->type)->args)) {
funcarg->type = CDecl_NewPointerType(TYPE(tclass));
if (funcarg->next && funcarg->next->next) {
funcarg = funcarg->next->next;
selarg = meth26->selector_args;
while (selarg && funcarg) {
funcarg->name = selarg->name;
funcarg->type = selarg->type;
funcarg->qual |= selarg->qual;
selarg = selarg->next;
funcarg = funcarg->next;
}
}
}
if (tk == ';') {
if (copts.objc_strict)
CError_Warning(CErrorStr135);
tk = lex();
}
memclrw(&di, sizeof(di));
CFunc_ParseFuncDef(object, &di, tclass, 1, meth30->is_class_method, NULL);
meth30->is_defined = 1;
tk = lex();
}
static void CObjC_EncodeTypeStruct(TypeStruct *tstruct, Boolean flag) {
StructMember *member;
AppendGListByte(&name_mangle_list, (tstruct->stype == STRUCT_TYPE_UNION) ? '(' : '{');
if (cobjc_encodemethod)
AppendGListByte(&name_mangle_list, '?');
else if (tstruct->name)
AppendGListName(&name_mangle_list, tstruct->name->name);
if (flag) {
AppendGListByte(&name_mangle_list, '=');
for (member = tstruct->members; member; member = member->next)
CObjC_EncodeType(member->type, member->qual, 1);
}
AppendGListByte(&name_mangle_list, (tstruct->stype == STRUCT_TYPE_UNION) ? ')' : '}');
}
static void CObjC_EncodeTypeClass(TypeClass *tclass, Boolean flag) {
ObjMemberVar *ivar;
if (CClass_IsPODClass(tclass)) {
AppendGListByte(&name_mangle_list, (tclass->mode == CLASS_MODE_1) ? '(' : '{');
if (cobjc_encodemethod)
AppendGListByte(&name_mangle_list, '?');
else if (tclass->classname)
AppendGListName(&name_mangle_list, tclass->classname->name);
if (flag) {
AppendGListByte(&name_mangle_list, '=');
for (ivar = tclass->ivars; ivar; ivar = ivar->next)
CObjC_EncodeType(ivar->type, ivar->qual, 1);
}
AppendGListByte(&name_mangle_list, (tclass->mode == CLASS_MODE_1) ? ')' : '}');
} else {
AppendGListByte(&name_mangle_list, '?');
}
}
static void CObjC_EncodeTypeMethod(ObjCMethod *meth, Boolean flag) {
ObjCMethodArg *arg;
char buf[16];
if (meth->return_qual & Q_IN)
AppendGListByte(&name_mangle_list, 'n');
if (meth->return_qual & Q_OUT)
AppendGListByte(&name_mangle_list, 'o');
if (meth->return_qual & Q_INOUT)
AppendGListByte(&name_mangle_list, 'N');
if (meth->return_qual & Q_BYCOPY)
AppendGListByte(&name_mangle_list, 'O');
if (meth->return_qual & Q_ONEWAY)
AppendGListByte(&name_mangle_list, 'V');
if (meth->return_type)
CObjC_EncodeType(meth->return_type, 0, flag);
else
AppendGListByte(&name_mangle_list, '@');
sprintf(buf, "%" PRId32, CodeGen_objc_method_args_size(meth));
AppendGListName(&name_mangle_list, buf);
AppendGListByte(&name_mangle_list, '@');
sprintf(buf, "%" PRId32, CodeGen_objc_method_self_offset(meth));
AppendGListName(&name_mangle_list, buf);
AppendGListByte(&name_mangle_list, ':');
sprintf(buf, "%" PRId32, CodeGen_objc_method_sel_offset(meth));
AppendGListName(&name_mangle_list, buf);
for (arg = meth->selector_args; arg; arg = arg->next) {
if (arg->type) {
if (arg->qual & Q_CONST)
AppendGListByte(&name_mangle_list, 'r');
CObjC_EncodeType(arg->type, 0, flag);
sprintf(buf, "%" PRId32, CodeGen_objc_method_arg_offset(meth, arg));
AppendGListName(&name_mangle_list, buf);
}
}
}
static void CObjC_EncodeType(Type *type, UInt32 qual, Boolean flag) {
char buf[16];
while (1) {
switch (type->type) {
case TYPEVOID:
AppendGListByte(&name_mangle_list, 'v');
return;
case TYPEINT:
case TYPEFLOAT:
switch (TYPE_INTEGRAL(type)->integral) {
case IT_BOOL:
AppendGListByte(&name_mangle_list, 'C');
return;
case IT_CHAR:
AppendGListByte(&name_mangle_list, copts.unsigned_char ? 'C' : 'c');
return;
case IT_UCHAR:
AppendGListByte(&name_mangle_list, 'C');
return;
case IT_SCHAR:
AppendGListByte(&name_mangle_list, 'c');
return;
case IT_WCHAR_T:
AppendGListByte(&name_mangle_list, 'i');
return;
case IT_SHORT:
AppendGListByte(&name_mangle_list, 's');
return;
case IT_USHORT:
AppendGListByte(&name_mangle_list, 'S');
return;
case IT_INT:
AppendGListByte(&name_mangle_list, 'i');
return;
case IT_UINT:
AppendGListByte(&name_mangle_list, 'I');
return;
case IT_LONG:
AppendGListByte(&name_mangle_list, 'l');
return;
case IT_ULONG:
AppendGListByte(&name_mangle_list, 'L');
return;
case IT_LONGLONG:
AppendGListByte(&name_mangle_list, 'q');
return;
case IT_ULONGLONG:
AppendGListByte(&name_mangle_list, 'Q');
return;
case IT_FLOAT:
AppendGListByte(&name_mangle_list, 'f');
return;
case IT_SHORTDOUBLE:
AppendGListByte(&name_mangle_list, 'd');
return;
case IT_DOUBLE:
AppendGListByte(&name_mangle_list, 'd');
return;
case IT_LONGDOUBLE:
AppendGListByte(&name_mangle_list, 'D');
return;
default:
CError_FATAL(1841);
}
case TYPEENUM:
type = TYPE_ENUM(type)->enumtype;
continue;
case TYPEPOINTER:
if (CObjC_IsType_id(type)) {
AppendGListByte(&name_mangle_list, '@');
return;
}
if (CObjC_IsType_SEL(type)) {
AppendGListByte(&name_mangle_list, ':');
return;
}
type = TPTR_TARGET(type);
if (type == TYPE(&stchar)) {
AppendGListByte(&name_mangle_list, '*');
return;
}
if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->objcinfo) {
AppendGListByte(&name_mangle_list, '@');
return;
}
AppendGListByte(&name_mangle_list, '^');
flag = cobjc_encodemethod;
continue;
case TYPEARRAY:
AppendGListByte(&name_mangle_list, '[');
if (TPTR_TARGET(type)->size) {
sprintf(buf, "%" PRId32, type->size / TPTR_TARGET(type)->size);
AppendGListName(&name_mangle_list, buf);
} else {
AppendGListByte(&name_mangle_list, '0');
}
CObjC_EncodeType(TPTR_TARGET(type), 0, 1);
AppendGListByte(&name_mangle_list, ']');
return;
case TYPEBITFIELD:
AppendGListByte(&name_mangle_list, 'b');
sprintf(buf, "%" PRId32, TYPE_BITFIELD(type)->unkB);
AppendGListName(&name_mangle_list, buf);
return;
case TYPESTRUCT:
CObjC_EncodeTypeStruct(TYPE_STRUCT(type), flag);
return;
case TYPECLASS:
CObjC_EncodeTypeClass(TYPE_CLASS(type), flag);
return;
case TYPEFUNC:
case TYPETEMPLATE:
case TYPEMEMBERPOINTER:
AppendGListByte(&name_mangle_list, '?');
return;
default:
CError_FATAL(1892);
}
break;
}
}
static char *CObjC_EncodeMethodTypeString(ObjCMethod *meth, int unused) {
char *buf;
cobjc_encodemethod = 1;
name_mangle_list.size = 0;
CObjC_EncodeTypeMethod(meth, 1);
AppendGListByte(&name_mangle_list, 0);
buf = galloc(name_mangle_list.size);
memcpy(buf, *name_mangle_list.data, name_mangle_list.size);
cobjc_encodemethod = 0;
return buf;
}
static char *CObjC_EncodeTypeString(Type *type, UInt32 qual) {
char *buf;
name_mangle_list.size = 0;
CObjC_EncodeType(type, qual, 1);
AppendGListByte(&name_mangle_list, 0);
buf = galloc(name_mangle_list.size);
memcpy(buf, *name_mangle_list.data, name_mangle_list.size);
return buf;
}
typedef struct RawIVar {
UInt32 name;
UInt32 typestring;
UInt32 offset;
} RawIVar;
typedef struct RawIVarList {
UInt32 count;
RawIVar ivars[1];
} RawIVarList;
static Object *CObjC_DefineIVarListObject(TypeClass *tclass) {
Object *object;
RawIVarList *data;
ObjMemberVar *ivar;
OLinkList *refs;
OLinkList *ref;
RawIVar *rawvar;
int i;
SInt32 size;
char *str;
for (ivar = tclass->ivars, i = 0; ivar; ivar = ivar->next)
i++;
if (i) {
size = sizeof(RawIVarList) + sizeof(RawIVar) * (i - 1);
data = lalloc(size);
memclrw(data, size);
object = CObjC_MakeObject(
"L_OBJC_INSTANCE_VARIABLES_", tclass->classname->name,
size);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_INSTANCE_VARS;
refs = NULL;
data->count = CTool_EndianConvertWord32(i);
for (ivar = tclass->ivars, rawvar = data->ivars; ivar; ivar = ivar->next, rawvar++) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(ivar->name->name, SECT_OBJC_METH_VAR_NAMES);
ref->offset = ((char *) &rawvar->name) - ((char *) data);
ref->somevalue = 0;
str = CObjC_EncodeTypeString(ivar->type, ivar->qual);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(str, SECT_OBJC_METH_VAR_TYPES);
ref->offset = ((char *) &rawvar->typestring) - ((char *) data);
ref->somevalue = 0;
rawvar->offset = CTool_EndianConvertWord32(ivar->offset);
}
CInit_DeclareData(object, data, refs, object->type->size);
} else {
object = NULL;
}
return object;
}
typedef struct RawMethod {
UInt32 name;
UInt32 typestring;
UInt32 offset;
} RawMethod;
typedef struct RawMethodList {
UInt32 x0;
UInt32 count;
RawMethod methods[1];
} RawMethodList;
static Object *CObjC_DefineMethodListObject(TypeClass *tclass, ObjCCategory *cat, ObjCMethod *methods, char *name1, char *name2, Section sectionID, Boolean doing_class_methods) {
Object *object;
RawMethodList *data;
ObjCMethod *meth;
OLinkList *refs;
OLinkList *ref;
RawMethod *rawmeth;
int i;
SInt32 size;
for (meth = methods, i = 0; meth; meth = meth->next) {
if (doing_class_methods == meth->is_class_method)
i++;
}
if (i) {
size = sizeof(RawMethodList) + sizeof(RawMethod) * (i - 1);
data = lalloc(size);
memclrw(data, size);
object = CObjC_MakeObject(name1, name2, size);
object->sclass = TK_STATIC;
object->section = sectionID;
refs = NULL;
data->count = CTool_EndianConvertWord32(i);
for (meth = methods, rawmeth = data->methods; meth; meth = meth->next) {
if (doing_class_methods == meth->is_class_method) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(meth->selector->name->name, SECT_OBJC_METH_VAR_NAMES);
ref->offset = ((char *) &rawmeth->name) - ((char *) data);
ref->somevalue = 0;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(CObjC_EncodeMethodTypeString(meth, 0), SECT_OBJC_METH_VAR_TYPES);
ref->offset = ((char *) &rawmeth->typestring) - ((char *) data);
ref->somevalue = 0;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_GetMethodObject(tclass, cat, meth);
ref->offset = ((char *) &rawmeth->offset) - ((char *) data);
ref->somevalue = 0;
rawmeth++;
}
}
CInit_DeclareData(object, data, refs, object->type->size);
} else {
object = NULL;
}
return object;
}
typedef struct RawProtocolList {
UInt32 offset;
} RawProtocolList;
typedef struct RawProtocolListList {
UInt32 x0;
UInt32 count;
RawProtocolList lists[1];
} RawProtocolListList;
static Object *CObjC_DefineProtocolListObject(ObjCProtocolList *list, char *str) {
Object *object;
RawProtocolListList *data;
ObjCProtocolList *scan;
OLinkList *refs;
OLinkList *ref;
int i;
SInt32 size;
for (scan = list, i = 0; scan; scan = scan->next)
i++;
if (i) {
size = sizeof(RawProtocolListList) + sizeof(RawProtocolList) * (i - 1);
data = lalloc(size);
memclrw(data, size);
object = CObjC_MakeObject("L_OBJC_PROTOCOLS_", str, size);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_PROTOCOL;
refs = NULL;
data->count = CTool_EndianConvertWord32(i);
for (scan = list, i = 0; scan; scan = scan->next, i++) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_GetProtocolObject(scan->protocol);
ref->offset = ((char *) &data->lists[i].offset) - ((char *) data);
ref->somevalue = 0;
}
CInit_DeclareData(object, data, refs, object->type->size);
} else {
object = NULL;
}
return object;
}
typedef struct RawProtocolMethodList {
UInt32 name;
UInt32 typestring;
} RawProtocolMethodList;
typedef struct RawProtocolMethodListList {
UInt32 count;
RawProtocolMethodList methods[1];
} RawProtocolMethodListList;
static Object *CObjC_DefineProtocolMethodListObject(ObjCProtocol *protocol, char *name, Section sectionID, Boolean doing_class_methods) {
Object *object;
ObjCMethod *meth;
OLinkList *refs;
OLinkList *ref;
RawProtocolMethodList *rawmeth;
RawProtocolMethodListList *data;
int i;
SInt32 size;
for (meth = protocol->methods, i = 0; meth; meth = meth->next) {
if (doing_class_methods == meth->is_class_method)
i++;
}
if (i) {
size = sizeof(RawProtocolMethodListList) + sizeof(RawProtocolMethodList) * (i - 1);
data = lalloc(size);
memclrw(data, size);
object = CObjC_MakeObject(name, protocol->name->name, size);
object->sclass = TK_STATIC;
object->section = sectionID;
refs = NULL;
data->count = CTool_EndianConvertWord32(i);
for (meth = protocol->methods, rawmeth = data->methods; meth; meth = meth->next) {
if (doing_class_methods == meth->is_class_method) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(meth->selector->name->name, SECT_OBJC_METH_VAR_NAMES);
ref->offset = ((char *) &rawmeth->name) - ((char *) data);
ref->somevalue = 0;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(CObjC_EncodeMethodTypeString(meth, 0), SECT_OBJC_METH_VAR_TYPES);
ref->offset = ((char *) &rawmeth->typestring) - ((char *) data);
ref->somevalue = 0;
rawmeth++;
}
}
CInit_DeclareData(object, data, refs, object->type->size);
} else {
object = NULL;
}
return object;
}
typedef struct RawProtocol {
UInt32 x0;
UInt32 x4;
UInt32 x8;
UInt32 xC;
UInt32 x10;
} RawProtocol;
static Object *CObjC_GetProtocolObject(ObjCProtocol *protocol) {
TypeClass *protocolType;
OLinkList *refs;
OLinkList *ref;
Object *object;
char *str;
RawProtocol data;
refs = NULL;
if (!protocol->object) {
if ((protocolType = CObjC_FindObjCClass(GetHashNameNodeExport("Protocol"), 1))) {
data.x0 = 0;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(protocolType->classname->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 0;
ref->somevalue = 0;
data.x4 = 0;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(protocol->name->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 4;
ref->somevalue = 0;
data.x8 = 0;
if (protocol->protocols) {
str = CObjC_StringConcat(protocol->name->name, "_PROTOCOLS", NULL);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_DefineProtocolListObject(protocol->protocols, str);
ref->offset = 8;
ref->somevalue = 0;
}
data.xC = 0;
object = CObjC_DefineProtocolMethodListObject(protocol, "L_OBJC_PROTOCOL_INSTANCE_METHODS_", SECT_OBJC_CAT_INST_METH, 0);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0xC;
ref->somevalue = 0;
}
data.x10 = 0;
object = CObjC_DefineProtocolMethodListObject(protocol, "L_OBJC_PROTOCOL_CLASS_METHODS_", SECT_OBJC_CAT_CLS_METH, 1);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0x10;
ref->somevalue = 0;
}
object = CObjC_MakeObject("L_OBJC_PROTOCOL_", protocol->name->name, sizeof(data));
protocol->object = object;
object->type = TYPE(protocolType);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_PROTOCOL;
if (object->type->size != sizeof(data)) {
if (object->type->size == 0)
object->type = CDecl_NewStructType(sizeof(data), 4);
else
CError_FATAL(2262);
}
CInit_DeclareData(object, &data, refs, object->type->size);
object->type = TYPE(protocolType);
}
if (!protocol->object)
protocol->object = CObjC_SectionString(protocol->name->name, SECT_OBJC_PROTOCOL);
}
return protocol->object;
}
static void CObjC_DefineClassObjects(TypeClass *tclass) {
Object *protocollistobj;
Object *classobject;
Object *classnameobj;
OLinkList *refs;
Object *metaobject;
OLinkList *ref;
Object *object;
TypeClass *basescan;
UInt32 data[10];
metaobject = tclass->objcinfo->metaobject;
classobject = tclass->objcinfo->classobject;
classnameobj = CObjC_SectionString(tclass->classname->name, SECT_OBJC_CLASS_NAMES);
protocollistobj = CObjC_DefineProtocolListObject(tclass->objcinfo->protocols, tclass->classname->name);
// part 1
data[0] = CTool_EndianConvertWord32(0);
data[1] = CTool_EndianConvertWord32(0);
basescan = tclass;
while (basescan->bases)
basescan = basescan->bases->base;
refs = NULL;
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(basescan->classname->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 0;
ref->somevalue = 0;
if (tclass->bases) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(tclass->bases->base->classname->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 4;
ref->somevalue = 0;
}
data[2] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = classnameobj;
ref->offset = 8;
ref->somevalue = 0;
data[3] = CTool_EndianConvertWord32(0);
data[4] = CTool_EndianConvertWord32(2);
data[5] = CTool_EndianConvertWord32(sizeof(data));
data[6] = CTool_EndianConvertWord32(0);
data[7] = CTool_EndianConvertWord32(0);
object = CObjC_DefineMethodListObject(
tclass, NULL, tclass->objcinfo->methods, "L_OBJC_CLASS_METHODS_",
tclass->classname->name, SECT_OBJC_CLS_METH, 1);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0x1C;
ref->somevalue = 0;
}
data[8] = CTool_EndianConvertWord32(0);
data[9] = CTool_EndianConvertWord32(0);
if (protocollistobj) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = protocollistobj;
ref->offset = 0x24;
ref->somevalue = 0;
}
CError_ASSERT(2367, metaobject->type->size == sizeof(data));
CInit_DeclareData(metaobject, data, refs, metaobject->type->size);
// part 2
refs = NULL;
data[0] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = metaobject;
ref->offset = 0;
ref->somevalue = 0;
data[1] = CTool_EndianConvertWord32(0);
if (tclass->bases) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(tclass->bases->base->classname->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 4;
ref->somevalue = 0;
}
data[2] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = classnameobj;
ref->offset = 8;
ref->somevalue = 0;
data[3] = CTool_EndianConvertWord32(0);
data[4] = CTool_EndianConvertWord32(1);
data[5] = CTool_EndianConvertWord32(tclass->size);
data[6] = CTool_EndianConvertWord32(0);
object = CObjC_DefineIVarListObject(tclass);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0x18;
ref->somevalue = 0;
}
data[7] = CTool_EndianConvertWord32(0);
object = CObjC_DefineMethodListObject(
tclass, NULL, tclass->objcinfo->methods, "L_OBJC_INSTANCE_METHODS_",
tclass->classname->name, SECT_OBJC_INST_METH, 0);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0x1C;
ref->somevalue = 0;
}
data[8] = CTool_EndianConvertWord32(0);
data[9] = CTool_EndianConvertWord32(0);
if (protocollistobj) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = protocollistobj;
ref->offset = 0x24;
ref->somevalue = 0;
}
CError_ASSERT(2437, classobject->type->size == sizeof(data));
CInit_DeclareData(classobject, data, refs, classobject->type->size);
}
static void CObjC_DefineCategoryObjects(TypeClass *tclass, ObjCCategory *cat) {
OLinkList *refs;
Object *categoryObj;
char *namestr;
OLinkList *ref;
Object *object;
ObjCCategoryEntry *entry;
UInt32 data[5];
namestr = CObjC_StringConcat(tclass->classname->name, "_", cat->name->name);
categoryObj = CObjC_MakeObject("L_OBJC_CATEGORY_", namestr, sizeof(data));
categoryObj->sclass = TK_STATIC;
categoryObj->section = SECT_OBJC_CATEGORY;
refs = NULL;
data[0] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(cat->name->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 0;
ref->somevalue = 0;
data[1] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_SectionString(tclass->classname->name, SECT_OBJC_CLASS_NAMES);
ref->offset = 4;
ref->somevalue = 0;
data[2] = CTool_EndianConvertWord32(0);
object = CObjC_DefineMethodListObject(
tclass, cat, cat->methods, "L_OBJC_CATEGORY_INSTANCE_METHODS_",
namestr, SECT_OBJC_CAT_INST_METH, 0);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 8;
ref->somevalue = 0;
}
data[3] = CTool_EndianConvertWord32(0);
object = CObjC_DefineMethodListObject(
tclass, cat, cat->methods, "L_OBJC_CATEGORY_CLASS_METHODS_",
namestr, SECT_OBJC_CAT_CLS_METH, 1);
if (object) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0xC;
ref->somevalue = 0;
}
data[4] = CTool_EndianConvertWord32(0);
if (cat->protocols) {
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CObjC_DefineProtocolListObject(cat->protocols, namestr);
ref->offset = 0x10;
ref->somevalue = 0;
}
CInit_DeclareData(categoryObj, data, refs, categoryObj->type->size);
entry = galloc(sizeof(ObjCCategoryEntry));
entry->category = cat;
entry->object = categoryObj;
entry->next = cobjc_categories;
cobjc_categories = entry;
}
static void CObjC_ParseCategoryImplementation(TypeClass *tclass) {
ObjCCategory *cat;
ObjCMethod *meth;
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
return;
}
for (cat = tclass->objcinfo->categories; cat; cat = cat->next) {
if (cat->name == tkidentifier)
break;
}
if (!cat) {
if (copts.objc_strict)
CError_Warning(CErrorStr312, tkidentifier->name);
cat = galloc(sizeof(ObjCCategory));
memclrw(cat, sizeof(ObjCCategory));
cat->name = tkidentifier;
cat->next = tclass->objcinfo->categories;
tclass->objcinfo->categories = cat;
}
if ((tk = lex()) != ')') {
CError_Error(CErrorStr115);
return;
}
tk = lex();
while (1) {
switch (tk) {
case '-':
case '+':
CObjC_DefineMethod(tclass, cat, &cat->methods);
continue;
case TK_AT_END:
break;
default:
CParser_ParseGlobalDeclaration();
continue;
}
break;
}
for (meth = cat->methods; meth; meth = meth->next) {
if (!meth->is_defined)
CError_Warning(CErrorStr299, meth);
}
CObjC_DefineCategoryObjects(tclass, cat);
}
static Boolean CObjC_IsSameMemberList(ObjMemberVar *a, ObjMemberVar *b) {
while (1) {
if (!a)
return !b;
if (
!b ||
a->name != b->name ||
a->qual != b->qual ||
a->access != b->access ||
!is_typesame(a->type, b->type)
)
return 0;
a = a->next;
b = b->next;
}
}
static void CObjC_ParseInstanceVariables(TypeClass *tclass, Boolean checkOnly) {
AccessType access;
ObjMemberVar *first;
ObjMemberVar *ivar;
ObjMemberVar *scan;
BigDeclInfo bdi;
tk = lex();
access = ACCESSPROTECTED;
for (first = NULL; ; tk = lex()) {
if (tk == '}') {
tk = lex();
break;
}
switch (tk) {
case TK_AT_PRIVATE:
access = ACCESSPRIVATE;
continue;
case TK_AT_PROTECTED:
access = ACCESSPROTECTED;
continue;
case TK_AT_PUBLIC:
access = ACCESSPUBLIC;
continue;
}
memclrw(&bdi, sizeof(bdi));
CParser_GetDeclSpecs(&bdi.declinfo, 0);
if (bdi.declinfo.storageclass || bdi.declinfo.x44) {
CError_Error(CErrorStr131);
return;
}
if (tk != ';') {
while (1) {
CDecl_ScanStructDeclarator(&bdi);
if (!CanCreateObject(bdi.declinfo2.thetype)) {
CError_Error(CErrorStr131);
bdi.xCD = 0;
}
if (bdi.declinfo2.x3E) {
CError_Error(CErrorStr131);
bdi.xCD = 0;
}
if (bdi.declinfo.x48)
CError_Error(CErrorStr121);
if (bdi.xCD) {
for (ivar = first; ivar; ivar = ivar->next) {
if (ivar->name == bdi.declinfo2.name)
break;
}
if (ivar || bdi.declinfo2.name == no_name_node) {
CError_Error(CErrorStr133, bdi.declinfo2.name->name);
} else {
ivar = galloc(sizeof(ObjMemberVar));
memclrw(ivar, sizeof(ObjMemberVar));
ivar->otype = OT_MEMBERVAR;
ivar->access = access;
ivar->type = bdi.declinfo2.thetype;
ivar->name = bdi.declinfo2.name;
ivar->qual = bdi.declinfo2.qual;
if ((scan = first)) {
while (scan->next)
scan = scan->next;
scan->next = ivar;
} else {
first = ivar;
}
if (!checkOnly)
CScope_AddObject(tclass->nspace, ivar->name, OBJ_BASE(ivar));
}
}
if (tk != ',')
break;
tk = lex();
}
}
if (tk != ';') {
CError_Error(CErrorStr123);
break;
}
}
if (checkOnly) {
if (!CObjC_IsSameMemberList(tclass->ivars, first))
CError_Error(CErrorStr323);
} else {
tclass->ivars = first;
}
}
static void CObjC_ParseInterfaceImplementation(void) {
TypeClass *tclass;
Boolean isInterface;
Boolean flag2;
ClassList *base;
TypeClass *tclassbase;
ObjCProtocolList *protlist;
ObjCMethod *meth;
BClassList *classdef;
isInterface = tk == TK_AT_INTERFACE;
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
return;
}
if (!(tclass = CObjC_NewObjCClass(tkidentifier)))
return;
if ((tk = lex()) == '(') {
if (isInterface)
CObjC_ParseCategoryInterface(tclass);
else
CObjC_ParseCategoryImplementation(tclass);
return;
}
flag2 = (tclass->flags & CLASS_FLAGS_2) ? 1 : 0;
if (flag2 && isInterface) {
CError_Error(CErrorStr132, tclass->classname->name);
return;
}
if (tk == ':') {
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
return;
}
if ((tclassbase = CObjC_FindObjCClass(tkidentifier, 1))) {
if (tclassbase->flags & CLASS_FLAGS_2) {
if (!flag2) {
base = galloc(sizeof(ClassList));
memclrw(base, sizeof(ClassList));
base->base = tclassbase;
base->access = ACCESSPUBLIC;
tclass->bases = base;
} else {
if (!tclass->bases || tclass->bases->base != tclassbase)
CError_Error(CErrorStr325);
}
} else {
CError_Error(CErrorStr136, tclassbase, 0);
}
}
tk = lex();
}
if (tk == '<') {
protlist = CObjC_ParserProtocolList();
if (flag2) {
if (!CObjC_IsSameProtocolList(protlist, tclass->objcinfo->protocols))
CError_Error(CErrorStr324);
} else {
tclass->objcinfo->protocols = protlist;
CObjC_AddProtocolMethods(tclass, &tclass->objcinfo->methods, tclass->objcinfo->protocols);
}
}
if (tk == '{')
CObjC_ParseInstanceVariables(tclass, flag2);
if (!flag2) {
DeclE decle;
memclrw(&decle, sizeof(decle));
CABI_LayoutClass(&decle, tclass);
}
cobjc_currentclass = tclass;
while (1) {
switch (tk) {
case '+':
case '-':
if (isInterface)
CObjC_AddMethod(tclass);
else
CObjC_DefineMethod(tclass, NULL, &tclass->objcinfo->methods);
continue;
case TK_AT_END:
break;
default:
CParser_ParseGlobalDeclaration();
continue;
}
break;
}
cobjc_currentclass = NULL;
if (!isInterface) {
for (meth = tclass->objcinfo->methods; meth; meth = meth->next) {
if (!meth->is_defined)
CError_Warning(CErrorStr299, meth);
}
CObjC_DefineClassObjects(tclass);
classdef = galloc(sizeof(BClassList));
classdef->next = cobjc_classdefs;
classdef->type = TYPE(tclass);
cobjc_classdefs = classdef;
}
}
void CObjC_ParseInterface(void) {
CObjC_ParseInterfaceImplementation();
}
void CObjC_ParseImplementation(void) {
CObjC_ParseInterfaceImplementation();
}
void CObjC_ParseProtocol(void) {
ObjCProtocol *protocol;
ObjCMethod *meth;
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
return;
}
if ((protocol = CObjC_FindProtocol(tkidentifier)))
CError_Error(CErrorStr308, protocol->name->name);
protocol = galloc(sizeof(ObjCProtocol));
memclrw(protocol, sizeof(ObjCProtocol));
protocol->name = tkidentifier;
if ((tk = lex()) == '<') {
protocol->protocols = CObjC_ParserProtocolList();
CObjC_AddProtocolMethods(NULL, &protocol->methods, protocol->protocols);
}
protocol->next = cobjc_protocols;
cobjc_protocols = protocol;
while (1) {
switch (tk) {
case '-':
case '+':
if ((meth = CObjC_ParseMethod(1))) {
if (!CObjC_FindMethod(protocol->methods, meth, 0, 1)) {
meth->next = protocol->methods;
protocol->methods = meth;
CObjC_MakeSelector(meth);
}
}
if (tk != ';')
CError_Error(CErrorStr123);
else
tk = lex();
continue;
case TK_AT_END:
break;
default:
CParser_ParseGlobalDeclaration();
continue;
}
break;
}
}
void CObjC_ParseClassDeclaration(void) {
while (1) {
if ((tk = lex()) != TK_IDENTIFIER) {
CError_Error(CErrorStr107);
break;
}
CObjC_NewObjCClass(tkidentifier);
if ((tk = lex()) != ',') {
if (tk != ';')
CError_Error(CErrorStr123);
break;
}
}
}
void *CObjC_ParseIdentifier() {
// ??? unused
return NULL;
}
static void CObjC_CoerceMethodArgs(ObjCMethod *meth, ObjCNamedArg *namedArgs, ENodeList *unnamedArgs) {
ObjCMethodArg *metharg;
ObjCNamedArg *arg;
if (namedArgs->expr) {
metharg = meth->selector_args;
arg = namedArgs;
while (1) {
arg->expr = argumentpromotion(arg->expr, metharg->type, metharg->qual, 1);
arg = arg->next;
if (!arg)
break;
metharg = metharg->next;
CError_ASSERT(3004, metharg);
}
}
while (unnamedArgs) {
unnamedArgs->node = CExpr_VarArgPromotion(unnamedArgs->node, 1);
unnamedArgs = unnamedArgs->next;
}
}
static Boolean CObjC_SelectorCompare(ObjCMethod *method, ObjCNamedArg *args, Boolean has_varargs) {
ObjCMethodArg *metharg;
if (has_varargs && !method->has_valist)
return 0;
metharg = method->selector_args;
do {
if (metharg->selector != args->name)
return 0;
if (!metharg->type && args->expr)
return 0;
if (metharg->type && !args->expr)
return 0;
args = args->next;
if (!args) {
if (!metharg->next)
return 1;
else
return 0;
}
} while ((metharg = metharg->next));
return 0;
}
ENode *CObjC_MakeSendMsgExpr(ENode *objexpr, TypeClass *tclass, ObjCNamedArg *namedArgs, ENodeList *unnamedArgs, UInt8 calltype, Boolean isSuper) {
ObjCMethod *meth;
ObjCSelector *sel;
ENode *callexpr;
ObjCMethodList *methlist;
TypeClass *scanclass;
Object *sendMsgFunc;
TypeFunc *methodtype;
ObjCNamedArg *namedArg;
ENodeList *arg;
ObjCCategory *cat;
ObjCProtocolList *protlist;
meth = NULL;
if (tclass) {
scanclass = tclass;
while (1) {
CError_ASSERT(3112, scanclass->objcinfo);
for (cat = scanclass->objcinfo->categories; cat; cat = cat->next) {
for (meth = cat->methods; meth; meth = meth->next) {
switch (calltype) {
case 0:
if (meth->is_class_method)
continue;
break;
case 1:
if (!meth->is_class_method)
continue;
break;
case 2:
break;
}
if (CObjC_SelectorCompare(meth, namedArgs, unnamedArgs != NULL)) {
CObjC_CoerceMethodArgs(meth, namedArgs, unnamedArgs);
sel = CObjC_MakeSelector(meth);
break;
}
}
if (meth)
break;
}
if (meth)
break;
for (meth = scanclass->objcinfo->methods; meth; meth = meth->next) {
if (CObjC_SelectorCompare(meth, namedArgs, unnamedArgs != NULL)) {
CObjC_CoerceMethodArgs(meth, namedArgs, unnamedArgs);
sel = CObjC_MakeSelector(meth);
break;
}
}
if (meth)
break;
if (!scanclass->bases) {
CError_Warning(CErrorStr304);
break;
}
scanclass = scanclass->bases->base;
}
}
if (!meth) {
if (IS_TYPE_POINTER_ONLY(objexpr->rtype) && (TPTR_QUAL(objexpr->rtype) & Q_100000)) {
for (protlist = TYPE_OBJC_ID(objexpr->rtype)->protocols; protlist; protlist = protlist->next) {
for (meth = protlist->protocol->methods; meth; meth = meth->next) {
if (CObjC_SelectorCompare(meth, namedArgs, unnamedArgs != NULL)) {
CObjC_CoerceMethodArgs(meth, namedArgs, unnamedArgs);
sel = CObjC_MakeSelector(meth);
break;
}
}
}
if (!meth)
CError_Warning(CErrorStr304);
}
if (!meth) {
if ((sel = CObjC_FindKeyArgSelector(namedArgs))) {
for (methlist = sel->methods; methlist; methlist = methlist->next) {
if (!methlist->method->is_class_method) {
if (meth)
break;
meth = methlist->method;
}
}
if (!meth) {
for (methlist = sel->methods; methlist; methlist = methlist->next) {
if (methlist->method->is_class_method) {
if (meth)
break;
meth = methlist->method;
}
}
}
if (meth) {
if (methlist)
CError_Warning(CErrorStr305, meth, methlist->method);
if (CObjC_SelectorCompare(meth, namedArgs, unnamedArgs != NULL)) {
CObjC_CoerceMethodArgs(meth, namedArgs, unnamedArgs);
} else {
CError_Warning(CErrorStr304);
}
} else {
CError_Error(CErrorStr306);
}
} else {
CError_Error(CErrorStr306);
}
}
}
if (meth) {
methodtype = CObjC_GetMethodFuncType(meth);
sendMsgFunc = CObjC_FindSendMessageRTFunc(isSuper, CMach_GetFunctionResultClass(methodtype) > 0);
if (isSuper) {
ENode *temp;
ENode *indirect;
ENode *ass;
ENode *tempCopy;
ENode *classObjRef;
temp = CExpr_NewETEMPNode(CDecl_NewStructType(8, 4), 1);
indirect = makemonadicnode(temp, EINDIRECT);
indirect->rtype = TYPE(&void_ptr);
objexpr = makediadicnode(indirect, objexpr, EASS);
tempCopy = lalloc(sizeof(ENode));
*tempCopy = *temp;
indirect = makediadicnode(tempCopy, intconstnode(TYPE(&stunsignedlong), 4), EADD);
indirect = makemonadicnode(indirect, EINDIRECT);
indirect->rtype = TYPE(&void_ptr);
classObjRef = create_objectrefnode(tclass->objcinfo->classobject);
classObjRef = makediadicnode(classObjRef, intconstnode(TYPE(&stunsignedlong), 4), EADD);
classObjRef = makemonadicnode(classObjRef, EINDIRECT);
ass = makediadicnode(indirect, classObjRef, EASS);
objexpr = makediadicnode(objexpr, ass, ECOMMA);
tempCopy = lalloc(sizeof(ENode));
*tempCopy = *temp;
objexpr = makediadicnode(objexpr, tempCopy, ECOMMA);
objexpr->rtype = temp->rtype;
}
callexpr = lalloc(sizeof(ENode));
callexpr->type = EFUNCCALL;
callexpr->cost = 200;
callexpr->rtype = meth->return_type;
callexpr->flags = meth->return_qual & ENODE_FLAG_QUALS;
callexpr->data.funccall.funcref = create_objectrefnode(sendMsgFunc);
callexpr->data.funccall.functype = methodtype;
CError_ASSERT(3286, IS_TYPE_FUNC(callexpr->data.funccall.functype));
arg = callexpr->data.funccall.args = lalloc(sizeof(ENodeList));
arg->node = objexpr;
arg = arg->next = lalloc(sizeof(ENodeList));
arg->node = create_objectnode(CObjC_GetSelectorObject(sel));
for (namedArg = namedArgs; namedArg; namedArg = namedArg->next) {
if (namedArg->expr) {
arg = arg->next = lalloc(sizeof(ENodeList));
arg->node = namedArg->expr;
}
}
arg->next = unnamedArgs;
return CExpr_AdjustFunctionCall(callexpr);
} else {
return nullnode();
}
}
ENode *CObjC_ParseMessageExpression(void) {
ENode *objexpr;
TypeClass *tclass;
Boolean isSuper;
ENodeList *unnamedArgs;
ObjCNamedArg *namedArgs;
ObjCNamedArg *lastNamedArg;
ENode *callexpr;
UInt8 calltype;
NameSpaceObjectList *list;
isSuper = 0;
tclass = NULL;
switch ((tk = lex())) {
case TK_IDENTIFIER:
if (!strcmp(tkidentifier->name, "super")) {
case TK_SUPER:
objexpr = CClass_CreateThisSelfExpr();
if (!objexpr || !cscope_currentclass->bases) {
CError_Error(CErrorStr302);
objexpr = nullnode();
} else {
tclass = cscope_currentclass;
isSuper = 1;
}
if (cscope_is_member_func)
calltype = 0;
else
calltype = 1;
tk = lex();
break;
}
if ((list = CScope_FindName(cscope_root, tkidentifier)) && list->object->otype == OT_TYPE) {
tclass = TYPE_CLASS(OBJ_TYPE(list->object)->type);
if (IS_TYPE_CLASS(tclass) && tclass->objcinfo) {
calltype = 1;
objexpr = create_objectnode(CObjC_GetClassRefObject(tclass));
objexpr->rtype = CDecl_NewPointerType(TYPE(tclass));
tk = lex();
break;
}
}
tclass = NULL;
default:
objexpr = expression();
if (CObjC_IsType_id(objexpr->rtype)) {
calltype = 2;
break;
}
if (!IS_TYPE_POINTER_ONLY(objexpr->rtype) || !IS_TYPE_OBJC_CLASS(TPTR_TARGET(objexpr->rtype))) {
CError_Error(CErrorStr303);
objexpr = nullnode();
calltype = 2;
break;
}
if (
cscope_currentclass == TYPE_CLASS(TPTR_TARGET(objexpr->rtype)) &&
!cscope_is_member_func &&
ENODE_IS_INDIRECT_TO(objexpr, EOBJREF) &&
objexpr->data.monadic->data.objref->name == self_name_node
)
calltype = 1;
else
calltype = 0;
tclass = TYPE_CLASS(TPTR_TARGET(objexpr->rtype));
}
lastNamedArg = lalloc(sizeof(ObjCNamedArg));
memclrw(lastNamedArg, sizeof(ObjCNamedArg));
namedArgs = lastNamedArg;
unnamedArgs = NULL;
while (1) {
CObjC_TranslateSelectorToken();
if (tk == TK_IDENTIFIER) {
lastNamedArg->name = tkidentifier;
if ((tk = lex()) == ']' && namedArgs == lastNamedArg)
break;
}
if (tk != ':') {
CError_Error(CErrorStr141);
return nullnode();
}
tk = lex();
lastNamedArg->expr = assignment_expression();
if (tk == ']')
break;
if (tk == ',') {
tk = lex();
unnamedArgs = CExpr_ScanExpressionList(0);
break;
}
lastNamedArg->next = lalloc(sizeof(ObjCNamedArg));
memclrw(lastNamedArg->next, sizeof(ObjCNamedArg));
lastNamedArg = lastNamedArg->next;
}
callexpr = CObjC_MakeSendMsgExpr(objexpr, tclass, namedArgs, unnamedArgs, calltype, isSuper);
tk = lex();
return callexpr;
}
ENode *CObjC_ParseEncodeExpression(void) {
ENode *expr;
char *str;
Type *type;
UInt32 qual;
if ((tk = lex()) != '(') {
CError_Error(CErrorStr114);
return nullnode();
}
CObjC_ParseTypeName(&type, &qual);
str = CObjC_EncodeTypeString(type, qual);
expr = lalloc(sizeof(ENode));
expr->type = ESTRINGCONST;
expr->cost = 0;
expr->flags = 0;
expr->rtype = CDecl_NewArrayType(TYPE(&stchar), strlen(str) + 1);
expr->data.string.size = expr->rtype->size;
expr->data.string.data = str;
expr->data.string.ispascal = 0;
expr = makemonadicnode(expr, EINDIRECT);
expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
return expr;
}
ENode *CObjC_ParseAtExpression(void) {
TypeClass *strclass;
OLinkList *refs;
OLinkList *ref;
Object *object;
ENode *expr;
NameSpaceObjectList *list;
UInt32 data[3];
char buf[16];
if ((tk = lex()) == TK_STRING) {
if ((strclass = CObjC_FindObjCClass(GetHashNameNodeExport("NSConstantString"), 1))) {
refs = NULL;
data[0] = CTool_EndianConvertWord32(0);
if ((list = CScope_GetLocalObject(cscope_root, GetHashNameNodeExport("_NSConstantStringClassReference")))) {
object = OBJECT(list->object);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = object;
ref->offset = 0;
ref->somevalue = 0;
} else {
CError_Error(CErrorStr140, "_NSConstantStringClassReference");
tk = lex();
return nullnode();
}
data[1] = CTool_EndianConvertWord32(0);
ref = lalloc(sizeof(OLinkList));
ref->next = refs;
refs = ref;
ref->obj = CInit_DeclareString(tkstring, tksize, 0, 0);
ref->offset = 4;
ref->somevalue = 0;
data[2] = CTool_EndianConvertWord32(tksize - 1);
sprintf(buf, "%" PRId32, cobjc_stringcount++);
object = CObjC_MakeObject("L_NSConstantString_", buf, sizeof(data));
object->type = TYPE(strclass);
object->sclass = TK_STATIC;
object->section = SECT_OBJC_CSTRING_OBJECT;
CInit_DeclareData(object, data, refs, object->type->size);
expr = create_objectrefnode(object);
} else {
expr = nullnode();
}
tk = lex();
} else {
CError_Error(CErrorStr101);
expr = nullnode();
}
return expr;
}
ENode *CObjC_ParseProtocolExpression(void) {
ObjCProtocol *protocol;
ENode *expr;
if ((tk = lex()) == '(') {
if ((tk = lex()) == TK_IDENTIFIER) {
if ((protocol = CObjC_FindProtocol(tkidentifier))) {
expr = create_objectrefnode(CObjC_GetProtocolObject(protocol));
if ((tk = lex()) != ')')
CError_Error(CErrorStr115);
else
tk = lex();
return expr;
}
} else {
CError_Error(CErrorStr107);
}
} else {
CError_Error(CErrorStr114);
}
return nullnode();
}
ENode *CObjC_ParseSelectorExpression(void) {
HashNameNode *name;
ObjCSelector *selector;
ENode *expr;
if ((tk = lex()) == '(') {
name_mangle_list.size = 0;
while (1) {
tk = lex();
if (tk == TK_IDENTIFIER) {
AppendGListName(&name_mangle_list, tkidentifier->name);
tk = lex();
}
if (tk == ')') {
if (name_mangle_list.size == 0)
CError_Error(CErrorStr107);
tk = lex();
break;
}
if (tk == ':') {
AppendGListByte(&name_mangle_list, ':');
} else {
CError_Error(CErrorStr115);
break;
}
}
AppendGListByte(&name_mangle_list, 0);
COS_LockHandle(name_mangle_list.data);
name = GetHashNameNodeExport(*name_mangle_list.data);
COS_UnlockHandle(name_mangle_list.data);
selector = CObjC_FindSelector(name);
if (!selector)
selector = CObjC_NewSelector(name);
expr = create_objectnode(CObjC_GetSelectorObject(selector));
expr->rtype = CObjC_FindObjCType_SEL();
return expr;
} else {
CError_Error(CErrorStr114);
return nullnode();
}
}