1 /** 2 * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jan 29, 2012 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dstep.translator.objc.ObjcInterface; 8 9 import clang.c.Index; 10 import clang.Cursor; 11 import clang.Type; 12 import clang.Util; 13 import clang.Visitor; 14 15 import dstep.translator.Translator; 16 import dstep.translator.Declaration; 17 import dstep.translator.Output; 18 import dstep.translator.Type; 19 20 import std..string; 21 import std.exception : assumeUnique; 22 23 class ObjcInterface (Data) : Declaration 24 { 25 ClassData currentClass; 26 27 this (Cursor cursor, Cursor parent, Translator translator) 28 { 29 super(cursor, parent, translator); 30 } 31 32 override void translate (Output output) 33 { 34 auto cursor = cursor.objc; 35 36 writeClass(output, spelling, cursor.superClass.spelling, collectInterfaces(cursor.objc), { 37 foreach (cursor, parent ; cursor.declarations) 38 { 39 with (CXCursorKind) 40 switch (cursor.kind) 41 { 42 case objCInstanceMethodDecl: 43 translateMethod(cursor.func); 44 break; 45 46 case objCClassMethodDecl: 47 translateMethod(cursor.func, true); 48 break; 49 50 case objCPropertyDecl: 51 translateProperty(cursor); 52 break; 53 54 case objCIvarDecl: 55 translateInstanceVariable(cursor); 56 break; 57 58 default: 59 break; 60 } 61 } 62 }); 63 64 output.output(currentClass.data()); 65 } 66 67 protected string[] collectInterfaces (ObjcCursor cursor) 68 { 69 string[] interfaces; 70 71 foreach (cursor , parent ; cursor.protocols) 72 interfaces ~= translateIdentifier(cursor.spelling); 73 74 return interfaces; 75 } 76 77 private: 78 79 void writeClass ( 80 Output output, 81 string name, 82 string superClassName, 83 string[] interfaces, 84 void delegate () dg) 85 { 86 currentClass = new Data(translator.context); 87 currentClass.name = translateIdentifier(name); 88 currentClass.interfaces = interfaces; 89 90 if (superClassName.length) 91 currentClass.superclass ~= translateIdentifier(superClassName); 92 93 dg(); 94 } 95 96 void translateMethod ( 97 FunctionCursor func, 98 bool classMethod = false, 99 string name = null) 100 { 101 import std.format : format; 102 103 auto cls = currentClass; 104 105 if (cls.propertyList.contains(func.spelling)) 106 return; 107 108 name = cls.getMethodName(func, name, false); 109 110 if (isGetter(func, name)) 111 translateGetter(func, func.resultType, name, cls, classMethod); 112 113 else if (isSetter(func, name)) 114 { 115 auto param = func.parameters.first; 116 name = toDSetterName(name); 117 translateSetter(param, param.type, name, cls, classMethod, param.spelling); 118 } 119 120 else 121 { 122 Output output = new Output(); 123 124 output.adaptiveSourceNode(translateFunction(translator.context, func, name, classMethod)); 125 output.append(" "); 126 writeSelector(output, func.spelling); 127 output.append(";"); 128 129 cls.members ~= output; 130 } 131 } 132 133 void translateProperty (Cursor cursor) 134 { 135 auto cls = currentClass; 136 auto name = cls.getMethodName(cursor.func, "", false); 137 138 translateGetter(cursor, cursor.type, name, cls, false); 139 translateSetter(cursor, cursor.type, name, cls, false); 140 } 141 142 void translateInstanceVariable (Cursor cursor) 143 { 144 Output output = new Output(); 145 translator.variable(output, cursor); 146 currentClass.instanceVariables ~= output; 147 } 148 149 void translateGetter (Cursor cursor, Type type, string name, ClassData cls, bool classMethod) 150 { 151 import std.format : format; 152 153 auto dName = name == "class" ? name : translateIdentifier(name); 154 155 Output output = new Output(); 156 157 output.singleLine( 158 "@property %s%s %s () ", 159 classMethod ? "static " : "", 160 translateType(translator.context, cursor, type).makeString(), 161 dName); 162 163 writeSelector(output, name); 164 output.append(";"); 165 166 cls.members ~= output; 167 cls.propertyList.add(name); 168 } 169 170 void translateSetter (Cursor cursor, Type type, string name, ClassData cls, bool classMethod, string parameterName = "") 171 { 172 import std.format : format; 173 174 auto selector = toObjcSetterName(name) ~ ':'; 175 176 Output output = new Output(); 177 178 output.singleLine( 179 "@property %svoid %s (%s", 180 classMethod ? "static " : "", 181 translateIdentifier(name), 182 translateType(translator.context, cursor, type).makeString()); 183 184 if (parameterName.length) 185 output.append(" %s", parameterName); 186 187 output.append(") "); 188 writeSelector(output, selector); 189 output.append(";"); 190 191 cls.members ~= output; 192 cls.propertyList.add(selector); 193 } 194 195 string toDSetterName (string name) 196 { 197 assert(isSetter(name)); 198 name = name[3 .. $]; 199 auto firstLetter = name[0 .. 1]; 200 auto r = firstLetter.toLower ~ name[1 .. $]; 201 return r.assumeUnique; 202 } 203 204 string toObjcSetterName (string name) 205 { 206 auto r = "set" ~ name[0 .. 1].toUpper ~ name[1 .. $]; 207 return r.assumeUnique; 208 } 209 210 bool isGetter (FunctionCursor cursor, string name) 211 { 212 return cursor.resultType.kind != CXTypeKind.void_ && cursor.parameters.isEmpty; 213 } 214 215 bool isSetter (string name) 216 { 217 import std.ascii; 218 219 if (name.length > 3 && name.startsWith("set")) 220 { 221 auto firstLetter = name[3 .. $][0]; 222 return firstLetter.isUpper; 223 } 224 225 return false; 226 } 227 228 bool isSetter (FunctionCursor cursor, string name) 229 { 230 return isSetter(name) && 231 cursor.resultType.kind == CXTypeKind.void_ && 232 cursor.parameters.length == 1; 233 } 234 235 void writeSelector (Output output, string selector) 236 { 237 import std.format : format; 238 output.append(`@selector("%s")`, selector); 239 } 240 }