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 }