1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _objc.d) 9 */ 10 11 module ddmd.objc; 12 13 import ddmd.arraytypes; 14 import ddmd.cond; 15 import ddmd.dclass; 16 import ddmd.dmangle; 17 import ddmd.dmodule; 18 import ddmd.dscope; 19 import ddmd.dstruct; 20 import ddmd.expression; 21 import ddmd.func; 22 import ddmd.globals; 23 import ddmd.gluelayer; 24 import ddmd.id; 25 import ddmd.identifier; 26 import ddmd.mtype; 27 import ddmd.root.outbuffer; 28 import ddmd.root.stringtable; 29 30 struct ObjcSelector 31 { 32 // MARK: Selector 33 extern (C++) static __gshared StringTable stringtable; 34 extern (C++) static __gshared StringTable vTableDispatchSelectors; 35 extern (C++) static __gshared int incnum = 0; 36 const(char)* stringvalue; 37 size_t stringlen; 38 size_t paramCount; 39 40 extern (C++) static void _init() 41 { 42 stringtable._init(); 43 } 44 45 extern (D) this(const(char)* sv, size_t len, size_t pcount) 46 { 47 stringvalue = sv; 48 stringlen = len; 49 paramCount = pcount; 50 } 51 52 extern (C++) static ObjcSelector* lookup(const(char)* s) 53 { 54 size_t len = 0; 55 size_t pcount = 0; 56 const(char)* i = s; 57 while (*i != 0) 58 { 59 ++len; 60 if (*i == ':') 61 ++pcount; 62 ++i; 63 } 64 return lookup(s, len, pcount); 65 } 66 67 extern (C++) static ObjcSelector* lookup(const(char)* s, size_t len, size_t pcount) 68 { 69 StringValue* sv = stringtable.update(s, len); 70 ObjcSelector* sel = cast(ObjcSelector*)sv.ptrvalue; 71 if (!sel) 72 { 73 sel = new ObjcSelector(sv.toDchars(), len, pcount); 74 sv.ptrvalue = cast(char*)sel; 75 } 76 return sel; 77 } 78 79 extern (C++) static ObjcSelector* create(FuncDeclaration fdecl) 80 { 81 OutBuffer buf; 82 size_t pcount = 0; 83 TypeFunction ftype = cast(TypeFunction)fdecl.type; 84 const id = fdecl.ident.toString(); 85 // Special case: property setter 86 if (ftype.isproperty && ftype.parameters && ftype.parameters.dim == 1) 87 { 88 // rewrite "identifier" as "setIdentifier" 89 char firstChar = id[0]; 90 if (firstChar >= 'a' && firstChar <= 'z') 91 firstChar = cast(char)(firstChar - 'a' + 'A'); 92 buf.writestring("set"); 93 buf.writeByte(firstChar); 94 buf.write(id.ptr + 1, id.length - 1); 95 buf.writeByte(':'); 96 goto Lcomplete; 97 } 98 // write identifier in selector 99 buf.write(id.ptr, id.length); 100 // add mangled type and colon for each parameter 101 if (ftype.parameters && ftype.parameters.dim) 102 { 103 buf.writeByte('_'); 104 Parameters* arguments = ftype.parameters; 105 size_t dim = Parameter.dim(arguments); 106 for (size_t i = 0; i < dim; i++) 107 { 108 Parameter arg = Parameter.getNth(arguments, i); 109 mangleToBuffer(arg.type, &buf); 110 buf.writeByte(':'); 111 } 112 pcount = dim; 113 } 114 Lcomplete: 115 buf.writeByte('\0'); 116 return lookup(cast(const(char)*)buf.data, buf.size, pcount); 117 } 118 } 119 120 struct Objc_ClassDeclaration 121 { 122 // true if this is an Objective-C class/interface 123 bool objc; 124 125 // MARK: Objc_ClassDeclaration 126 extern (C++) bool isInterface() 127 { 128 return objc; 129 } 130 } 131 132 struct Objc_FuncDeclaration 133 { 134 FuncDeclaration fdecl; 135 // Objective-C method selector (member function only) 136 ObjcSelector* selector; 137 138 extern (D) this(FuncDeclaration fdecl) 139 { 140 this.fdecl = fdecl; 141 } 142 } 143 144 // MARK: semantic 145 extern (C++) void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration cd) 146 { 147 if (global.params.hasObjectiveC) 148 cd.objc.objc = true; 149 else 150 cd.error("Objective-C classes not supported"); 151 } 152 153 extern (C++) void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration id, Scope* sc) 154 { 155 if (sc.linkage == LINKobjc) 156 { 157 if (global.params.hasObjectiveC) 158 id.objc.objc = true; 159 else 160 id.error("Objective-C interfaces not supported"); 161 } 162 } 163 164 // MARK: semantic 165 extern (C++) void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration fd, Scope* sc) 166 { 167 import ddmd.tokens; 168 169 if (!fd.userAttribDecl) 170 return; 171 Expressions* udas = fd.userAttribDecl.getAttributes(); 172 arrayExpressionSemantic(udas, sc, true); 173 for (size_t i = 0; i < udas.dim; i++) 174 { 175 Expression uda = (*udas)[i]; 176 assert(uda); 177 if (uda.op != TOKtuple) 178 continue; 179 Expressions* exps = (cast(TupleExp)uda).exps; 180 for (size_t j = 0; j < exps.dim; j++) 181 { 182 Expression e = (*exps)[j]; 183 assert(e); 184 if (e.op != TOKstructliteral) 185 continue; 186 StructLiteralExp literal = cast(StructLiteralExp)e; 187 assert(literal.sd); 188 if (!objc_isUdaSelector(literal.sd)) 189 continue; 190 if (fd.objc.selector) 191 { 192 fd.error("can only have one Objective-C selector per method"); 193 return; 194 } 195 assert(literal.elements.dim == 1); 196 StringExp se = (*literal.elements)[0].toStringExp(); 197 assert(se); 198 fd.objc.selector = ObjcSelector.lookup(cast(const(char)*)se.toUTF8(sc).string); 199 } 200 } 201 } 202 203 extern (C++) bool objc_isUdaSelector(StructDeclaration sd) 204 { 205 if (sd.ident != Id.udaSelector || !sd.parent) 206 return false; 207 Module _module = sd.parent.isModule(); 208 return _module && _module.isCoreModule(Id.attribute); 209 } 210 211 extern (C++) void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration fd) 212 { 213 if (!fd.objc.selector) 214 return; 215 TypeFunction tf = cast(TypeFunction)fd.type; 216 if (fd.objc.selector.paramCount != tf.parameters.dim) 217 fd.error("number of colons in Objective-C selector must match number of parameters"); 218 if (fd.parent && fd.parent.isTemplateInstance()) 219 fd.error("template cannot have an Objective-C selector attached"); 220 } 221 222 extern (C++) void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration fd) 223 { 224 if (fd.linkage != LINKobjc && fd.objc.selector) 225 fd.error("must have Objective-C linkage to attach a selector"); 226 } 227 228 // MARK: init 229 extern (C++) void objc_tryMain_dObjc() 230 { 231 if (global.params.isOSX && global.params.is64bit) 232 { 233 global.params.hasObjectiveC = true; 234 VersionCondition.addPredefinedGlobalIdent("D_ObjectiveC"); 235 } 236 } 237 238 extern (C++) void objc_tryMain_init() 239 { 240 objc_initSymbols(); 241 ObjcSelector._init(); 242 }