| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
|
|
||
| /* Compiler implementation of the D programming language | ||
| * Copyright (c) 2015 by Digital Mars | ||
| * All Rights Reserved | ||
| * written by Michel Fortin | ||
| * http://www.digitalmars.com | ||
| * Distributed under the Boost Software License, Version 1.0. | ||
| * http://www.boost.org/LICENSE_1_0.txt | ||
| * https://github.com/D-Programming-Language/dmd/blob/master/src/objc.c | ||
| */ | ||
|
|
||
| #include "aggregate.h" | ||
| #include "arraytypes.h" | ||
| #include "attrib.h" | ||
| #include "cond.h" | ||
| #include "declaration.h" | ||
| #include "id.h" | ||
| #include "init.h" | ||
| #include "mars.h" | ||
| #include "module.h" | ||
| #include "mtype.h" | ||
| #include "objc.h" | ||
| #include "outbuffer.h" | ||
| #include "scope.h" | ||
| #include "statement.h" | ||
| #include "visitor.h" | ||
|
|
||
| void mangleToBuffer(Type *t, OutBuffer *buf); | ||
| void objc_initSymbols(); | ||
|
|
||
| // MARK: Objc_ClassDeclaration | ||
|
|
||
| bool Objc_ClassDeclaration::isInterface() | ||
| { | ||
| return objc; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
|
|
||
| void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration *cd) | ||
| { | ||
| cd->objc.objc = true; | ||
| } | ||
|
|
||
| void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration *id, Scope *sc) | ||
| { | ||
| if (sc->linkage == LINKobjc) | ||
| id->objc.objc = true; | ||
| } | ||
|
|
||
| // MARK: Objc_FuncDeclaration | ||
|
|
||
| Objc_FuncDeclaration::Objc_FuncDeclaration() | ||
| { | ||
| this->fdecl = NULL; | ||
| selector = NULL; | ||
| } | ||
|
|
||
| Objc_FuncDeclaration::Objc_FuncDeclaration(FuncDeclaration* fdecl) | ||
| { | ||
| this->fdecl = fdecl; | ||
| selector = NULL; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
|
|
||
| void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration *fd, Scope *sc) | ||
| { | ||
| if (!fd->userAttribDecl) | ||
| return; | ||
|
|
||
| Expressions *udas = fd->userAttribDecl->getAttributes(); | ||
| arrayExpressionSemantic(udas, sc, true); | ||
|
|
||
| for (size_t i = 0; i < udas->dim; i++) | ||
| { | ||
| Expression *uda = (*udas)[i]; | ||
| assert(uda->type); | ||
|
|
||
| if (uda->type->ty != Ttuple) | ||
| continue; | ||
|
|
||
| Expressions *exps = ((TupleExp *)uda)->exps; | ||
|
|
||
| for (size_t j = 0; j < exps->dim; j++) | ||
| { | ||
| Expression *e = (*exps)[j]; | ||
| assert(e->type); | ||
|
|
||
| if (e->type->ty != Tstruct) | ||
| continue; | ||
|
|
||
| StructLiteralExp *literal = (StructLiteralExp *)e; | ||
| assert(literal->sd); | ||
|
|
||
| if (!objc_isUdaSelector(literal->sd)) | ||
| continue; | ||
|
|
||
| if (fd->objc.selector) | ||
| { | ||
| fd->error("can only have one Objective-C selector per method"); | ||
| return; | ||
| } | ||
|
|
||
| assert(literal->elements->dim == 1); | ||
| StringExp *se = (*literal->elements)[0]->toStringExp(); | ||
| assert(se); | ||
|
|
||
| fd->objc.selector = ObjcSelector::lookup((const char *)se->toUTF8(sc)->string); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| bool objc_isUdaSelector(StructDeclaration *sd) | ||
| { | ||
| if (sd->ident != Id::udaSelector || !sd->parent) | ||
| return false; | ||
|
|
||
| Module* module = sd->parent->isModule(); | ||
| return module && module->isCoreModule(Id::attribute); | ||
| } | ||
|
|
||
| void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration *fd) | ||
| { | ||
| if (!fd->objc.selector) | ||
| return; | ||
|
|
||
| TypeFunction *tf = (TypeFunction *)fd->type; | ||
|
|
||
| if (fd->objc.selector->paramCount != tf->parameters->dim) | ||
| fd->error("number of colons in Objective-C selector must match number of parameters"); | ||
|
|
||
| if (fd->parent && fd->parent->isTemplateInstance()) | ||
| fd->error("template cannot have an Objective-C selector attached"); | ||
| } | ||
|
|
||
| void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration *fd) | ||
| { | ||
| if (fd->linkage != LINKobjc && fd->objc.selector) | ||
| fd->error("must have Objective-C linkage to attach a selector"); | ||
| } | ||
|
|
||
| // MARK: init | ||
|
|
||
| void objc_tryMain_dObjc() | ||
| { | ||
| VersionCondition::addPredefinedGlobalIdent("D_ObjectiveC"); | ||
| } | ||
|
|
||
| void objc_tryMain_init() | ||
| { | ||
| objc_initSymbols(); | ||
| ObjcSelector::init(); | ||
| } | ||
|
|
||
| // MARK: Selector | ||
|
|
||
| StringTable ObjcSelector::stringtable; | ||
| int ObjcSelector::incnum = 0; | ||
|
|
||
| void ObjcSelector::init() | ||
| { | ||
| stringtable._init(); | ||
| } | ||
|
|
||
| ObjcSelector::ObjcSelector(const char *sv, size_t len, size_t pcount) | ||
| { | ||
| stringvalue = sv; | ||
| stringlen = len; | ||
| paramCount = pcount; | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::lookup(const char *s) | ||
| { | ||
| size_t len = 0; | ||
| size_t pcount = 0; | ||
| const char *i = s; | ||
| while (*i != 0) | ||
| { | ||
| ++len; | ||
| if (*i == ':') ++pcount; | ||
| ++i; | ||
| } | ||
| return lookup(s, len, pcount); | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::lookup(const char *s, size_t len, size_t pcount) | ||
| { | ||
| StringValue *sv = stringtable.update(s, len); | ||
| ObjcSelector *sel = (ObjcSelector *) sv->ptrvalue; | ||
| if (!sel) | ||
| { | ||
| sel = new ObjcSelector(sv->toDchars(), len, pcount); | ||
| sv->ptrvalue = (char *)sel; | ||
| } | ||
| return sel; | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::create(FuncDeclaration *fdecl) | ||
| { | ||
| OutBuffer buf; | ||
| size_t pcount = 0; | ||
| TypeFunction *ftype = (TypeFunction *)fdecl->type; | ||
|
|
||
| // Special case: property setter | ||
| if (ftype->isproperty && ftype->parameters && ftype->parameters->dim == 1) | ||
| { | ||
| // rewrite "identifier" as "setIdentifier" | ||
| char firstChar = fdecl->ident->string[0]; | ||
| if (firstChar >= 'a' && firstChar <= 'z') | ||
| firstChar = (char)(firstChar - 'a' + 'A'); | ||
|
|
||
| buf.writestring("set"); | ||
| buf.writeByte(firstChar); | ||
| buf.write(fdecl->ident->string+1, fdecl->ident->len-1); | ||
| buf.writeByte(':'); | ||
| goto Lcomplete; | ||
| } | ||
|
|
||
| // write identifier in selector | ||
| buf.write(fdecl->ident->string, fdecl->ident->len); | ||
|
|
||
| // add mangled type and colon for each parameter | ||
| if (ftype->parameters && ftype->parameters->dim) | ||
| { | ||
| buf.writeByte('_'); | ||
| Parameters *arguments = ftype->parameters; | ||
| size_t dim = Parameter::dim(arguments); | ||
| for (size_t i = 0; i < dim; i++) | ||
| { | ||
| Parameter *arg = Parameter::getNth(arguments, i); | ||
| mangleToBuffer(arg->type, &buf); | ||
| buf.writeByte(':'); | ||
| } | ||
| pcount = dim; | ||
| } | ||
| Lcomplete: | ||
| buf.writeByte('\0'); | ||
|
|
||
| return lookup((const char *)buf.data, buf.size, pcount); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.objc; | ||
|
|
||
| import core.stdc.stdio; | ||
| import ddmd.dclass, ddmd.dscope, ddmd.dstruct, ddmd.func, ddmd.globals, ddmd.id, ddmd.root.stringtable; | ||
|
|
||
| class ObjcSelector | ||
| { | ||
| public: | ||
| extern (C++) static __gshared StringTable stringtable; | ||
| extern (C++) static __gshared StringTable vTableDispatchSelectors; | ||
| extern (C++) static __gshared int incnum; | ||
| const(char)* stringvalue; | ||
| size_t stringlen; | ||
| size_t paramCount; | ||
|
|
||
| static void _init(); | ||
|
|
||
| // MARK: ObjcSelector | ||
| extern (D) this(const(char)* sv, size_t len, size_t pcount); | ||
| static ObjcSelector lookup(const(char)* s); | ||
| static ObjcSelector lookup(const(char)* s, size_t len, size_t pcount); | ||
| static ObjcSelector create(FuncDeclaration fdecl); | ||
| } | ||
|
|
||
| struct Objc_ClassDeclaration | ||
| { | ||
| // true if this is an Objective-C class/interface | ||
| bool objc; | ||
|
|
||
| // MARK: Objc_ClassDeclaration | ||
| extern (C++) bool isInterface(); | ||
| } | ||
|
|
||
| struct Objc_FuncDeclaration | ||
| { | ||
| FuncDeclaration fdecl; | ||
| // Objective-C method selector (member function only) | ||
| ObjcSelector selector; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
| extern (C++) void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration cd); | ||
| extern (C++) void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration id, Scope* sc); | ||
|
|
||
| // MARK: semantic | ||
| extern (C++) void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration fd, Scope* sc); | ||
| extern (C++) bool objc_isUdaSelector(StructDeclaration sd); | ||
| extern (C++) void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration fd); | ||
| extern (C++) void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration fd); | ||
| extern (C++) void objc_tryMain_dObjc(); | ||
| extern (C++) void objc_tryMain_init(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
|
|
||
| /* Compiler implementation of the D programming language | ||
| * Copyright (c) 2015 by Digital Mars | ||
| * All Rights Reserved | ||
| * written by Michel Fortin | ||
| * http://www.digitalmars.com | ||
| * Distributed under the Boost Software License, Version 1.0. | ||
| * http://www.boost.org/LICENSE_1_0.txt | ||
| * https://github.com/D-Programming-Language/dmd/blob/master/src/objc.h | ||
| */ | ||
|
|
||
| #ifndef DMD_OBJC_H | ||
| #define DMD_OBJC_H | ||
|
|
||
| #include "root.h" | ||
| #include "stringtable.h" | ||
|
|
||
| class Identifier; | ||
| class FuncDeclaration; | ||
| class ClassDeclaration; | ||
| class InterfaceDeclaration; | ||
| class ObjcSelector; | ||
|
|
||
| class ObjcSelector | ||
| { | ||
| public: | ||
| static StringTable stringtable; | ||
| static StringTable vTableDispatchSelectors; | ||
| static int incnum; | ||
|
|
||
| const char *stringvalue; | ||
| size_t stringlen; | ||
| size_t paramCount; | ||
|
|
||
| static void init(); | ||
|
|
||
| ObjcSelector(const char *sv, size_t len, size_t pcount); | ||
|
|
||
| static ObjcSelector *lookup(const char *s); | ||
| static ObjcSelector *lookup(const char *s, size_t len, size_t pcount); | ||
|
|
||
| static ObjcSelector *create(FuncDeclaration *fdecl); | ||
| }; | ||
|
|
||
| struct Objc_ClassDeclaration | ||
| { | ||
| // true if this is an Objective-C class/interface | ||
| bool objc; | ||
|
|
||
| bool isInterface(); | ||
| }; | ||
|
|
||
| struct Objc_FuncDeclaration | ||
| { | ||
| FuncDeclaration* fdecl; | ||
|
|
||
| // Objective-C method selector (member function only) | ||
| ObjcSelector *selector; | ||
|
|
||
| Objc_FuncDeclaration(); | ||
| Objc_FuncDeclaration(FuncDeclaration* fdecl); | ||
| }; | ||
|
|
||
| void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration *cd); | ||
|
|
||
| void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration *id, Scope *sc); | ||
|
|
||
| void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration *fd, Scope *sc); | ||
| bool objc_isUdaSelector(StructDeclaration *sd); | ||
| void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration *fd); | ||
| void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration *fd); | ||
|
|
||
| void objc_tryMain_dObjc(); | ||
| void objc_tryMain_init(); | ||
|
|
||
| #endif /* DMD_OBJC_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,292 @@ | ||
|
|
||
| /* Compiler implementation of the D programming language | ||
| * Copyright (c) 2015 by Digital Mars | ||
| * All Rights Reserved | ||
| * written by Michel Fortin | ||
| * http://www.digitalmars.com | ||
| * Distributed under the Boost Software License, Version 1.0. | ||
| * http://www.boost.org/LICENSE_1_0.txt | ||
| * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_glue.c | ||
| */ | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #include "aggregate.h" | ||
| #include "declaration.h" | ||
| #include "dt.h" | ||
| #include "cc.h" | ||
| #include "el.h" | ||
| #include "global.h" | ||
| #include "mars.h" | ||
| #include "module.h" | ||
| #include "mtype.h" | ||
| #include "objc.h" | ||
| #include "oper.h" | ||
| #include "outbuf.h" | ||
| #include "type.h" | ||
|
|
||
| #include "mach.h" | ||
| #include "obj.h" | ||
|
|
||
| enum ObjcSegment | ||
| { | ||
| SEGcstring, | ||
| SEGimage_info, | ||
| SEGmethname, | ||
| SEGmodule_info, | ||
| SEGselrefs, | ||
| SEG_MAX | ||
| }; | ||
|
|
||
| elem *addressElem(elem *e, Type *t, bool alwaysCopy = false); | ||
|
|
||
| int objc_segList[SEG_MAX] = {0}; | ||
|
|
||
| int objc_getSegment(ObjcSegment segid) | ||
| { | ||
| int *seg = objc_segList; | ||
| if (seg[segid] != 0) | ||
| return seg[segid]; | ||
|
|
||
| // initialize | ||
| int align = 3; | ||
|
|
||
| seg[SEGcstring] = MachObj::getsegment("__cstring", "__TEXT", align, S_CSTRING_LITERALS); | ||
| seg[SEGimage_info] = MachObj::getsegment("__objc_imageinfo", "__DATA", align, S_REGULAR | S_ATTR_NO_DEAD_STRIP); | ||
| seg[SEGmethname] = MachObj::getsegment("__objc_methname", "__TEXT", align, S_CSTRING_LITERALS); | ||
| seg[SEGmodule_info] = MachObj::getsegment("__objc_classlist", "__DATA", align, S_REGULAR | S_ATTR_NO_DEAD_STRIP); | ||
| seg[SEGselrefs] = MachObj::getsegment("__objc_selrefs", "__DATA", align, S_ATTR_NO_DEAD_STRIP | S_LITERAL_POINTERS); | ||
|
|
||
| return seg[segid]; | ||
| } | ||
|
|
||
| // MARK: ObjcSymbols | ||
|
|
||
| bool objc_hasSymbols = false; | ||
|
|
||
| Symbol *objc_smsgSend = NULL; | ||
| Symbol *objc_smsgSend_stret = NULL; | ||
| Symbol *objc_smsgSend_fpret = NULL; | ||
| Symbol *objc_smsgSend_fp2ret = NULL; | ||
|
|
||
| Symbol *objc_simageInfo = NULL; | ||
| Symbol *objc_smoduleInfo = NULL; | ||
|
|
||
| StringTable *objc_smethVarNameTable = NULL; | ||
| StringTable *objc_smethVarRefTable = NULL; | ||
|
|
||
| static StringTable *initStringTable(StringTable *stringtable) | ||
| { | ||
| stringtable = new StringTable(); | ||
| stringtable->_init(); | ||
|
|
||
| return stringtable; | ||
| } | ||
|
|
||
| extern int objc_segList[SEG_MAX]; | ||
|
|
||
| void objc_initSymbols() | ||
| { | ||
| objc_hasSymbols = false; | ||
|
|
||
| objc_smsgSend = NULL; | ||
| objc_smsgSend_stret = NULL; | ||
| objc_smsgSend_fpret = NULL; | ||
| objc_smsgSend_fp2ret = NULL; | ||
|
|
||
| objc_simageInfo = NULL; | ||
| objc_smoduleInfo = NULL; | ||
|
|
||
| // clear tables | ||
| objc_smethVarNameTable = initStringTable(objc_smethVarNameTable); | ||
| objc_smethVarRefTable = initStringTable(objc_smethVarRefTable); | ||
|
|
||
| // also wipe out segment numbers | ||
| for (int s = 0; s < SEG_MAX; ++s) | ||
| objc_segList[s] = 0; | ||
| } | ||
|
|
||
| Symbol *objc_getCString(const char *str, size_t len, const char *symbolName, ObjcSegment segment) | ||
| { | ||
| objc_hasSymbols = true; | ||
|
|
||
| // create data | ||
| dt_t *dt = NULL; | ||
| dtnbytes(&dt, len + 1, str); | ||
|
|
||
| // find segment | ||
| int seg = objc_getSegment(segment); | ||
|
|
||
| // create symbol | ||
| Symbol *s; | ||
| s = symbol_name(symbolName, SCstatic, type_allocn(TYarray, tschar)); | ||
| s->Sdt = dt; | ||
| s->Sseg = seg; | ||
| return s; | ||
| } | ||
|
|
||
| Symbol *objc_getMethVarName(const char *s, size_t len) | ||
| { | ||
| objc_hasSymbols = true; | ||
|
|
||
| StringValue *sv = objc_smethVarNameTable->update(s, len); | ||
| Symbol *sy = (Symbol *) sv->ptrvalue; | ||
| if (!sy) | ||
| { | ||
| static size_t classnamecount = 0; | ||
| char namestr[42]; | ||
| sprintf(namestr, "L_OBJC_METH_VAR_NAME_%lu", classnamecount++); | ||
| sy = objc_getCString(s, len, namestr, SEGmethname); | ||
| sv->ptrvalue = sy; | ||
| } | ||
| return sy; | ||
| } | ||
|
|
||
| Symbol *objc_getMethVarName(Identifier *ident) | ||
| { | ||
| return objc_getMethVarName(ident->string, ident->len); | ||
| } | ||
|
|
||
| Symbol *objc_getMsgSend(Type *ret, bool hasHiddenArg) | ||
| { | ||
| if (hasHiddenArg) | ||
| { | ||
| if (!objc_smsgSend_stret) | ||
| objc_smsgSend_stret = symbol_name("_objc_msgSend_stret", SCglobal, type_fake(TYhfunc)); | ||
| return objc_smsgSend_stret; | ||
| } | ||
| // not sure if DMD can handle this | ||
| else if (ret->ty == Tcomplex80) | ||
| { | ||
| if (!objc_smsgSend_fp2ret) | ||
| objc_smsgSend_fp2ret = symbol_name("_objc_msgSend_fp2ret", SCglobal, type_fake(TYnfunc)); | ||
| return objc_smsgSend_fp2ret; | ||
| } | ||
| else if (ret->ty == Tfloat80) | ||
| { | ||
| if (!objc_smsgSend_fpret) | ||
| objc_smsgSend_fpret = symbol_name("_objc_msgSend_fpret", SCglobal, type_fake(TYnfunc)); | ||
| return objc_smsgSend_fpret; | ||
| } | ||
| else | ||
| { | ||
| if (!objc_smsgSend) | ||
| objc_smsgSend = symbol_name("_objc_msgSend", SCglobal, type_fake(TYnfunc)); | ||
| return objc_smsgSend; | ||
| } | ||
| assert(0); | ||
| return NULL; | ||
| } | ||
|
|
||
| Symbol *objc_getImageInfo() | ||
| { | ||
| assert(!objc_simageInfo); // only allow once per object file | ||
| objc_hasSymbols = true; | ||
|
|
||
| dt_t *dt = NULL; | ||
| dtdword(&dt, 0); // version | ||
| dtdword(&dt, 0); // flags | ||
|
|
||
| objc_simageInfo = symbol_name("L_OBJC_IMAGE_INFO", SCstatic, type_allocn(TYarray, tschar)); | ||
| objc_simageInfo->Sdt = dt; | ||
| objc_simageInfo->Sseg = objc_getSegment(SEGimage_info); | ||
| outdata(objc_simageInfo); | ||
|
|
||
| return objc_simageInfo; | ||
| } | ||
|
|
||
| Symbol *objc_getModuleInfo() | ||
| { | ||
| assert(!objc_smoduleInfo); // only allow once per object file | ||
| objc_hasSymbols = true; | ||
|
|
||
| dt_t *dt = NULL; | ||
|
|
||
| Symbol* symbol = symbol_name("L_OBJC_LABEL_CLASS_$", SCstatic, type_allocn(TYarray, tschar)); | ||
| symbol->Sdt = dt; | ||
| symbol->Sseg = objc_getSegment(SEGmodule_info); | ||
| outdata(symbol); | ||
|
|
||
| objc_getImageInfo(); // make sure we also generate image info | ||
|
|
||
| return objc_smoduleInfo; | ||
| } | ||
|
|
||
| // MARK: Module::genmoduleinfo | ||
|
|
||
| void objc_Module_genmoduleinfo_classes() | ||
| { | ||
| if (objc_hasSymbols) | ||
| objc_getModuleInfo(); | ||
| } | ||
|
|
||
| // MARK: ObjcSelector | ||
|
|
||
| Symbol *objc_getMethVarRef(const char *s, size_t len) | ||
| { | ||
| objc_hasSymbols = true; | ||
|
|
||
| StringValue *sv = objc_smethVarRefTable->update(s, len); | ||
| Symbol *refsymbol = (Symbol *) sv->ptrvalue; | ||
| if (refsymbol == NULL) | ||
| { | ||
| // create data | ||
| dt_t *dt = NULL; | ||
| Symbol *sselname = objc_getMethVarName(s, len); | ||
| dtxoff(&dt, sselname, 0, TYnptr); | ||
|
|
||
| // find segment | ||
| int seg = objc_getSegment(SEGselrefs); | ||
|
|
||
| // create symbol | ||
| static size_t selcount = 0; | ||
| char namestr[42]; | ||
| sprintf(namestr, "L_OBJC_SELECTOR_REFERENCES_%lu", selcount); | ||
| refsymbol = symbol_name(namestr, SCstatic, type_fake(TYnptr)); | ||
|
|
||
| refsymbol->Sdt = dt; | ||
| refsymbol->Sseg = seg; | ||
| outdata(refsymbol); | ||
| sv->ptrvalue = refsymbol; | ||
|
|
||
| ++selcount; | ||
| } | ||
| return refsymbol; | ||
| } | ||
|
|
||
| Symbol *objc_getMethVarRef(Identifier *ident) | ||
| { | ||
| return objc_getMethVarRef(ident->string, ident->len); | ||
| } | ||
|
|
||
| // MARK: callfunc | ||
|
|
||
| void objc_callfunc_setupMethodSelector(Type *tret, FuncDeclaration *fd, Type *t, elem *ehidden, elem **esel) | ||
| { | ||
| if (fd && fd->objc.selector && !*esel) | ||
| { | ||
| *esel = el_var(objc_getMethVarRef(fd->objc.selector->stringvalue, fd->objc.selector->stringlen)); | ||
| } | ||
| } | ||
|
|
||
| void objc_callfunc_setupMethodCall(elem **ec, elem *ehidden, elem *ethis, TypeFunction *tf) | ||
| { | ||
| // make objc-style "virtual" call using dispatch function | ||
| assert(ethis); | ||
| Type *tret = tf->next; | ||
| *ec = el_var(objc_getMsgSend(tret, ehidden != 0)); | ||
| } | ||
|
|
||
| void objc_callfunc_setupEp(elem *esel, elem **ep, int reverse) | ||
| { | ||
| if (esel) | ||
| { | ||
| // using objc-style "virtual" call | ||
| // add hidden argument (second to 'this') for selector used by dispatch function | ||
| if (reverse) | ||
| *ep = el_param(esel,*ep); | ||
| else | ||
| *ep = el_param(*ep,esel); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
|
|
||
| /* Compiler implementation of the D programming language | ||
| * Copyright (c) 2015 by Digital Mars | ||
| * All Rights Reserved | ||
| * written by Michel Fortin | ||
| * http://www.digitalmars.com | ||
| * Distributed under the Boost Software License, Version 1.0. | ||
| * http://www.boost.org/LICENSE_1_0.txt | ||
| * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_glue_stubs.c | ||
| */ | ||
|
|
||
| #include <assert.h> | ||
| #include <stdio.h> | ||
|
|
||
| class FuncDeclaration; | ||
| class Type; | ||
| class TypeFunction; | ||
| struct elem; | ||
|
|
||
| void objc_callfunc_setupEp(elem *esel, elem **ep, int reverse) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_callfunc_setupMethodSelector(Type *tret, FuncDeclaration *fd, Type *t, elem *ehidden, elem **esel) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_callfunc_setupMethodCall(elem **ec, elem *ehidden, elem *ethis, TypeFunction *tf) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| } | ||
|
|
||
| // MARK: Module::genmoduleinfo | ||
|
|
||
| void objc_Module_genmoduleinfo_classes() | ||
| { | ||
| // noop | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
|
|
||
| /* Compiler implementation of the D programming language | ||
| * Copyright (c) 2015 by Digital Mars | ||
| * All Rights Reserved | ||
| * written by Michel Fortin | ||
| * http://www.digitalmars.com | ||
| * Distributed under the Boost Software License, Version 1.0. | ||
| * http://www.boost.org/LICENSE_1_0.txt | ||
| * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_stubs.c | ||
| */ | ||
|
|
||
| #include "arraytypes.h" | ||
| #include "class.c" | ||
| #include "mars.h" | ||
| #include "objc.h" | ||
| #include "outbuffer.h" | ||
| #include "parse.h" | ||
|
|
||
| class ClassDeclaration; | ||
| class FuncDeclaration; | ||
| class Identifier; | ||
| class InterfaceDeclaration; | ||
|
|
||
| // MARK: ObjcSelector | ||
|
|
||
| ObjcSelector::ObjcSelector(const char *sv, size_t len, size_t pcount) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::lookup(const char *s) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return NULL; | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::lookup(const char *s, size_t len, size_t pcount) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return NULL; | ||
| } | ||
|
|
||
| ObjcSelector *ObjcSelector::create(FuncDeclaration *fdecl) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return NULL; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
|
|
||
| void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration *cd) | ||
| { | ||
| cd->error("Objective-C classes not supported"); | ||
| } | ||
|
|
||
| void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration *id, Scope *sc) | ||
| { | ||
| if (sc->linkage == LINKobjc) | ||
| id->error("Objective-C interfaces not supported"); | ||
| } | ||
|
|
||
| // MARK: Objc_ClassDeclaration | ||
|
|
||
| bool Objc_ClassDeclaration::isInterface() | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // MARK: Objc_FuncDeclaration | ||
|
|
||
| Objc_FuncDeclaration::Objc_FuncDeclaration() | ||
| { | ||
| this->fdecl = fdecl; | ||
| selector = NULL; | ||
| } | ||
|
|
||
| Objc_FuncDeclaration::Objc_FuncDeclaration(FuncDeclaration* fdecl) | ||
| { | ||
| this->fdecl = fdecl; | ||
| selector = NULL; | ||
| } | ||
|
|
||
| bool objc_isUdaSelector (StructDeclaration *sd) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return false; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
|
|
||
| void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration *fd, Scope *sc) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_FuncDeclaration_semantic_validateSelector (FuncDeclaration *fd) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration *fd) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_tryMain_dObjc() | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| void objc_tryMain_init() | ||
| { | ||
| // noop | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.objc_stubs; | ||
|
|
||
| import core.stdc.stdio; | ||
| import ddmd.dclass, ddmd.dscope, ddmd.dstruct, ddmd.func, ddmd.globals, ddmd.id, ddmd.root.stringtable; | ||
|
|
||
| class ObjcSelector | ||
| { | ||
| // MARK: ObjcSelector | ||
| extern (D) this(const(char)* sv, size_t len, size_t pcount) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| } | ||
|
|
||
| static ObjcSelector lookup(const(char)* s) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return null; | ||
| } | ||
|
|
||
| static ObjcSelector lookup(const(char)* s, size_t len, size_t pcount) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return null; | ||
| } | ||
|
|
||
| static ObjcSelector create(FuncDeclaration fdecl) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| struct Objc_ClassDeclaration | ||
| { | ||
| // MARK: Objc_ClassDeclaration | ||
| extern (C++) bool isInterface() | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| extern (C++) void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration cd) | ||
| { | ||
| cd.error("Objective-C classes not supported"); | ||
| } | ||
|
|
||
| extern (C++) void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration id, Scope* sc) | ||
| { | ||
| if (sc.linkage == LINKobjc) | ||
| id.error("Objective-C interfaces not supported"); | ||
| } | ||
|
|
||
| // MARK: semantic | ||
| extern (C++) void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration fd, Scope* sc) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| extern (C++) bool objc_isUdaSelector(StructDeclaration sd) | ||
| { | ||
| printf("Should never be called when D_OBJC is false\n"); | ||
| assert(0); | ||
| return false; | ||
| } | ||
|
|
||
| extern (C++) void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration fd) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| extern (C++) void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration fd) | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| extern (C++) void objc_tryMain_dObjc() | ||
| { | ||
| // noop | ||
| } | ||
|
|
||
| extern (C++) void objc_tryMain_init() | ||
| { | ||
| // noop | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -330,6 +330,7 @@ Symbol *toSymbol(Dsymbol *s) | |
| break; | ||
|
|
||
| case LINKc: | ||
| case LINKobjc: | ||
| t->Tmangle = mTYman_c; | ||
| break; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
|
|
||
| extern (Objective-C) void NSLog(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
|
|
||
| extern (Objective-C) | ||
| interface A | ||
| { | ||
| void oneTwo(int a, int b) pure @selector("one:two:"); | ||
| void test(int a, int b, int c) @selector("test:::"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
| /* | ||
| TEST_OUTPUT: | ||
| --- | ||
| fail_compilation/objc_interface1.d(11): Error: function objc_interface1.A.oneTwo must have Objective-C linkage to attach a selector | ||
| --- | ||
| */ | ||
|
|
||
| interface A | ||
| { | ||
| void oneTwo(int a, int b) @selector("one:two:"); // selector attached in non-Objective-C interface | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
| /* | ||
| TEST_OUTPUT: | ||
| --- | ||
| fail_compilation/objc_interface2.d(12): Error: function objc_interface2.A.test number of colons in Objective-C selector must match number of parameters | ||
| --- | ||
| */ | ||
|
|
||
| extern (Objective-C) | ||
| interface A | ||
| { | ||
| void test(int a, int b, int c) @selector("test:"); // non-matching number of colon | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
| /* | ||
| TEST_OUTPUT: | ||
| --- | ||
| fail_compilation/objc_interface3.d(13): Error: function objc_interface3.A.test!int.test template cannot have an Objective-C selector attached | ||
| fail_compilation/objc_interface3.d(19): Error: template instance objc_interface3.A.test!int error instantiating | ||
| --- | ||
| */ | ||
|
|
||
| extern (Objective-C) | ||
| interface A | ||
| { | ||
| void test(T)(T a) @selector("test:"); // selector defined for template | ||
| } | ||
|
|
||
| void test() | ||
| { | ||
| A a; | ||
| a.test(3); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #import <Foundation/Foundation.h> | ||
|
|
||
| typedef struct | ||
| { | ||
| int a, b, c, d, e; | ||
| } Struct; | ||
|
|
||
| @interface stret : NSObject | ||
| -(Struct) getValue; | ||
| @end | ||
|
|
||
| @implementation stret | ||
| -(Struct) getValue | ||
| { | ||
| Struct s = { 3, 3, 3, 3, 3 }; | ||
| return s; | ||
| } | ||
| @end | ||
|
|
||
| @interface fp2ret : NSObject | ||
| -(_Complex long double) getValue; | ||
| @end | ||
|
|
||
| @implementation fp2ret | ||
| -(_Complex long double) getValue | ||
| { | ||
| return 1+3i; | ||
| } | ||
| @end | ||
|
|
||
| @interface fpret : NSObject | ||
| -(long double) getValue; | ||
| @end | ||
|
|
||
| @implementation fpret | ||
| -(long double) getValue | ||
| { | ||
| return 0.000000000000000002L; | ||
| } | ||
| @end | ||
|
|
||
| @interface float32 : NSObject | ||
| -(float) getValue; | ||
| @end | ||
|
|
||
| @implementation float32 | ||
| -(float) getValue | ||
| { | ||
| return 0.2f; | ||
| } | ||
| @end | ||
|
|
||
| @interface double64 : NSObject | ||
| -(double) getValue; | ||
| @end | ||
|
|
||
| @implementation double64 | ||
| -(double) getValue | ||
| { | ||
| return 0.2; | ||
| } | ||
| @end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // EXTRA_OBJC_SOURCES | ||
| // REQUIRED_ARGS: -L-framework -LFoundation | ||
|
|
||
| extern (Objective-C) | ||
| interface Class | ||
| { | ||
| NSObject alloc() @selector("alloc"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface NSObject | ||
| { | ||
| NSObject initWithUTF8String(in char* str) @selector("initWithUTF8String:"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| extern (C) void NSLog(NSObject, ...); | ||
| extern (C) Class objc_lookUpClass(in char* name); | ||
|
|
||
| void main() | ||
| { | ||
| auto c = objc_lookUpClass("NSString"); | ||
| auto o = c.alloc().initWithUTF8String("hello"); | ||
| NSLog(o); | ||
| o.release(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // EXTRA_OBJC_SOURCES: objc_objc_msgSend.m | ||
| // REQUIRED_ARGS: -L-framework -LFoundation | ||
|
|
||
| extern (C) Class objc_lookUpClass(in char* name); | ||
|
|
||
| struct Struct | ||
| { | ||
| int a, b, c, d, e; | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface Class | ||
| { | ||
| stret alloc_stret() @selector("alloc"); | ||
| fp2ret alloc_fp2ret() @selector("alloc"); | ||
| fpret alloc_fpret() @selector("alloc"); | ||
| float32 alloc_float32() @selector("alloc"); | ||
| double64 alloc_double64() @selector("alloc"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface stret | ||
| { | ||
| stret init() @selector("init"); | ||
| Struct getValue() @selector("getValue"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface fp2ret | ||
| { | ||
| fp2ret init() @selector("init"); | ||
| creal getValue() @selector("getValue"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface fpret | ||
| { | ||
| fpret init() @selector("init"); | ||
| real getValue() @selector("getValue"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface float32 | ||
| { | ||
| float32 init() @selector("init"); | ||
| float getValue() @selector("getValue"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| extern (Objective-C) | ||
| interface double64 | ||
| { | ||
| double64 init() @selector("init"); | ||
| double getValue() @selector("getValue"); | ||
| void release() @selector("release"); | ||
| } | ||
|
|
||
| void test_stret() | ||
| { | ||
| auto c = objc_lookUpClass("stret"); | ||
| auto o = c.alloc_stret().init(); | ||
| assert(o.getValue() == Struct(3, 3, 3, 3, 3)); | ||
| o.release(); | ||
| } | ||
|
|
||
| void test_fp2ret() | ||
| { | ||
| auto c = objc_lookUpClass("fp2ret"); | ||
| auto o = c.alloc_fp2ret().init(); | ||
| assert(o.getValue() == 1+3i); | ||
| o.release(); | ||
| } | ||
|
|
||
| void test_fpret() | ||
| { | ||
| auto c = objc_lookUpClass("fpret"); | ||
| auto o = c.alloc_fpret().init(); | ||
| assert(o.getValue() == 0.000000000000000002L); | ||
| o.release(); | ||
| } | ||
|
|
||
| void test_float32() | ||
| { | ||
| auto c = objc_lookUpClass("float32"); | ||
| auto o = c.alloc_float32.init(); | ||
| assert(o.getValue == 0.2f); | ||
| o.release(); | ||
| } | ||
|
|
||
| void test_double64() | ||
| { | ||
| auto c = objc_lookUpClass("double64"); | ||
| auto o = c.alloc_double64.init(); | ||
| assert(o.getValue == 0.2); | ||
| o.release(); | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| // test_stret(); | ||
| // test_fp2ret(); | ||
| test_fpret(); | ||
| test_float32(); | ||
| test_double64(); | ||
| } |