241 changes: 241 additions & 0 deletions src/objc.c
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);
}
59 changes: 59 additions & 0 deletions src/objc.di
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();
76 changes: 76 additions & 0 deletions src/objc.h
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 */
292 changes: 292 additions & 0 deletions src/objc_glue.c
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);
}
}
41 changes: 41 additions & 0 deletions src/objc_glue_stubs.c
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
}
119 changes: 119 additions & 0 deletions src/objc_stubs.c
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
}
96 changes: 96 additions & 0 deletions src/objc_stubs.d
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
}
19 changes: 18 additions & 1 deletion src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,13 +1319,30 @@ LINK Parser::parseLinkage(Identifiers **pidents)
}
}
}
else if (id == Id::Objective) // Looking for tokens "Objective-C"
{
if (token.value == TOKmin)
{
nextToken();
if (token.ident == Id::C)
{
link = LINKobjc;
nextToken();
}
else
goto LinvalidLinkage;
}
else
goto LinvalidLinkage;
}
else if (id == Id::System)
{
link = global.params.isWindows ? LINKwindows : LINKc;
}
else
{
error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
LinvalidLinkage:
error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
link = LINKd;
}
}
Expand Down
35 changes: 33 additions & 2 deletions src/posix.mak
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ GLUE_FLAGS := -I$(ROOT) -I$(TK) -I$(C)
BACK_FLAGS := -I$(ROOT) -I$(TK) -I$(C) -I. -DDMDV2=1
ROOT_FLAGS := -I$(ROOT)

ifeq ($(OS), osx)
ifeq ($(MODEL), 64)
D_OBJC := 1
endif
endif

DMD_OBJS = \
access.o attrib.o \
Expand All @@ -170,6 +175,12 @@ DMD_OBJS = \
intrange.o canthrow.o target.o nspace.o errors.o \
escape.o tokens.o globals.o

ifeq ($(D_OBJC),1)
DMD_OBJS += objc.o
else
DMD_OBJS += objc_stubs.o
endif

ROOT_OBJS = \
rmem.o port.o man.o stringtable.o response.o \
aav.o speller.o outbuffer.o object.o \
Expand All @@ -181,6 +192,13 @@ GLUE_OBJS = \
toobj.o toctype.o toelfdebug.o toir.o \
irstate.o typinf.o iasm.o


ifeq ($(D_OBJC),1)
GLUE_OBJS += objc_glue.o
else
GLUE_OBJS += objc_glue_stubs.o
endif

ifeq (osx,$(OS))
GLUE_OBJS += libmach.o scanmach.o
else
Expand Down Expand Up @@ -228,7 +246,7 @@ SRC = win32.mak posix.mak osmodel.mak \
intrange.h intrange.c canthrow.c target.c target.h \
scanmscoff.c scanomf.c ctfe.h ctfeexpr.c \
ctfe.h ctfeexpr.c visitor.h nspace.h nspace.c errors.h errors.c \
escape.c tokens.h tokens.c globals.h globals.c
escape.c tokens.h tokens.c globals.h globals.c objc.c objc.h objc_stubs.c

ROOT_SRC = $(ROOT)/root.h \
$(ROOT)/array.h \
Expand All @@ -249,7 +267,7 @@ GLUE_SRC = glue.c msc.c s2ir.c todt.c e2ir.c tocsym.c \
toobj.c toctype.c tocvdebug.c toir.h toir.c \
libmscoff.c scanmscoff.c irstate.h irstate.c typinf.c iasm.c \
toelfdebug.c libomf.c scanomf.c libelf.c scanelf.c libmach.c scanmach.c \
tk.c eh.c gluestub.c
tk.c eh.c gluestub.c objc_glue.c objc_glue_stubs.c

BACK_SRC = \
$C/cdef.h $C/cc.h $C/oper.h $C/ty.h $C/optabgen.c \
Expand Down Expand Up @@ -500,6 +518,13 @@ endif
gcov msc.c
gcov mtype.c
gcov nspace.c
ifeq ($(D_OBJC),1)
gcov objc.c
gcov objc_glue.c
else
gcov objc_stubs.c
gcov objc_glue_stubs.c
endif
gcov opover.c
gcov optimize.c
gcov parse.c
Expand Down Expand Up @@ -576,6 +601,12 @@ MANUALSRC= \
$(ROOT)/rootobject.d $(ROOT)/port.d \
$(ROOT)/rmem.d

ifeq ($(D_OBJC),1)
GENSRC += objc.d
else
MANUALSRC += objc.di objc_stubs.d
endif

mars.d : $(SRC) $(ROOT_SRC) magicport.json $(MAGICPORT) id.c impcnvtab.c
$(MAGICPORT) . .

Expand Down
1 change: 1 addition & 0 deletions src/tocsym.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ Symbol *toSymbol(Dsymbol *s)
break;

case LINKc:
case LINKobjc:
t->Tmangle = mTYman_c;
break;

Expand Down
4 changes: 4 additions & 0 deletions src/toobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "cgcv.h"
#include "outbuf.h"
#include "irstate.h"
#include "objc.h"

extern bool obj_includelib(const char *name);
void obj_startaddress(Symbol *s);
Expand All @@ -63,6 +64,8 @@ void toDebug(EnumDeclaration *ed);
void toDebug(StructDeclaration *sd);
void toDebug(ClassDeclaration *cd);

void objc_Module_genmoduleinfo_classes();

/* ================================================================== */

// Put out instance of ModuleInfo for this Module
Expand Down Expand Up @@ -198,6 +201,7 @@ void genModuleInfo(Module *m)
//printf("nameoffset = x%x\n", nameoffset);
}

objc_Module_genmoduleinfo_classes();
m->csym->Sdt = dt;
out_readonly(m->csym);
outdata(m->csym);
Expand Down
14 changes: 8 additions & 6 deletions src/win32.mak
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@ FRONTOBJ= enum.obj struct.obj dsymbol.obj import.obj id.obj \
builtin.obj clone.obj arrayop.obj \
json.obj unittests.obj imphint.obj argtypes.obj apply.obj sapply.obj \
sideeffect.obj intrange.obj canthrow.obj target.obj nspace.obj \
errors.obj escape.obj tokens.obj globals.obj
errors.obj escape.obj tokens.obj globals.obj objc_stubs.obj

# Glue layer
GLUEOBJ=glue.obj msc.obj s2ir.obj todt.obj e2ir.obj tocsym.obj \
toobj.obj toctype.obj tocvdebug.obj toir.obj \
libmscoff.obj scanmscoff.obj irstate.obj typinf.obj \
libomf.obj scanomf.obj iasm.obj
libomf.obj scanomf.obj iasm.obj objc_glue_stubs.obj

#GLUEOBJ=gluestub.obj

Expand Down Expand Up @@ -195,14 +195,14 @@ SRCS= mars.c enum.c struct.c dsymbol.c import.c idgen.d impcnvgen.c utf.h \
aliasthis.h aliasthis.c json.h json.c unittests.c imphint.c argtypes.c \
apply.c sapply.c sideeffect.c ctfe.h \
intrange.h intrange.c canthrow.c target.c target.h visitor.h \
tokens.h tokens.c globals.h globals.c
tokens.h tokens.c globals.h globals.c objc.h objc_stubs.c objc.c

# Glue layer
GLUESRC= glue.c msc.c s2ir.c todt.c e2ir.c tocsym.c \
toobj.c toctype.c tocvdebug.c toir.h toir.c \
libmscoff.c scanmscoff.c irstate.h irstate.c typinf.c iasm.c \
toelfdebug.c libomf.c scanomf.c libelf.c scanelf.c libmach.c scanmach.c \
tk.c eh.c gluestub.c
tk.c eh.c gluestub.c objc_glue_stubs.c objc_glue.c

# D back end
BACKSRC= $C\cdef.h $C\cc.h $C\oper.h $C\ty.h $C\optabgen.c \
Expand Down Expand Up @@ -351,7 +351,7 @@ GENSRC=access.d aggregate.d aliasthis.d apply.d \

MANUALSRC= \
intrange.d complex.d \
entity.d backend.d \
entity.d backend.d objc.di objc_stubs.d \
$(ROOT)\array.d $(ROOT)\longdouble.d \
$(ROOT)\rootobject.d $(ROOT)\port.d \
$(ROOT)\rmem.d
Expand Down Expand Up @@ -747,7 +747,7 @@ file.obj : $(ROOT)\file.c

# These rules were generated by makedep, but are not currently maintained

access.obj : $(TOTALH) enum.h aggregate.h init.h attrib.h access.c
access.obj : $(TOTALH) enum.h objc.h aggregate.h init.h attrib.h access.c
aliasthis.obj : $(TOTALH) aliasthis.h aliasthis.c
apply.obj : $(TOTALH) apply.c
argtypes.obj : $(TOTALH) mtype.h argtypes.c
Expand Down Expand Up @@ -788,6 +788,8 @@ link.obj : $(TOTALH) link.c
macro.obj : $(TOTALH) macro.h macro.c
mangle.obj : $(TOTALH) dsymbol.h declaration.h mangle.c
nspace.obj : $(TOTALH) nspace.c
objc_stubs.obj : $(TOTALH) objc.h objc_stubs.c
objc_glue_stubs.obj : $(TOTALH) objc.h objc_glue_stubs.c
opover.obj : $(TOTALH) expression.h opover.c
optimize.obj : $(TOTALH) expression.h optimize.c
parse.obj : $(TOTALH) attrib.h lexer.h parse.h parse.c
Expand Down
3 changes: 3 additions & 0 deletions test/compilable/objc_gfunc.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// EXTRA_OBJC_SOURCES

extern (Objective-C) void NSLog();
8 changes: 8 additions & 0 deletions test/compilable/objc_interface.d
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:::");
}
12 changes: 12 additions & 0 deletions test/fail_compilation/objc_interface1.d
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
}
13 changes: 13 additions & 0 deletions test/fail_compilation/objc_interface2.d
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
}
20 changes: 20 additions & 0 deletions test/fail_compilation/objc_interface3.d
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);
}
26 changes: 26 additions & 0 deletions test/runnable/objc_call.d
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();
}