mirror of https://git.wuffs.org/MWCC
3103 lines
87 KiB
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();
|
|
}
|
|
}
|