1 /**
2 Copyright: Copyright (c) 2016, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 */
10 module cpptooling.data.type;
11 
12 import std.traits : isSomeString;
13 import std.typecons : Flag;
14 
15 import my.sumtype;
16 
17 public import cpptooling.data.symbol.types : USRType;
18 import cpptooling.data.kind_type : TypeKind, TypeAttr, TypeKindAttr, TypeResult, toStringDecl;
19 
20 static import cpptooling.data.class_classification;
21 
22 /// Convert a namespace stack to a string separated by ::.
23 string toStringNs(T)(T ns) @safe if (is(Tx == CppNsStack) || is(Tx == CppNs[])) {
24     import std.algorithm : map;
25     import std.array : join;
26 
27     return (cast(CppNs[]) ns).map!(a => cast(string) a).join("::");
28 }
29 
30 /// Locaiton of a symbol.
31 struct Location {
32     import std.format : FormatSpec;
33 
34     ///
35     string file;
36     ///
37     uint line;
38     ///
39     uint column;
40 
41     /// Create a file with default line and column
42     this(string file) @safe {
43         this(file, 0, 0);
44     }
45 
46     ///
47     this(string file, uint line, uint column) @safe {
48         //TODO remove idup if it isn't needed
49         this.file = file;
50         this.line = line;
51         this.column = column;
52     }
53 
54     /// Location as File Line Column
55     string toString() @safe pure {
56         import std.exception : assumeUnique;
57         import std.format : FormatSpec;
58 
59         char[] buf;
60         buf.reserve(100);
61         auto fmt = FormatSpec!char("%s");
62         toString((const(char)[] s) { buf ~= s; }, fmt);
63         auto trustedUnique(T)(T t) @trusted {
64             return assumeUnique(t);
65         }
66 
67         return trustedUnique(buf);
68     }
69 
70     /// ditto
71     void toString(Writer, Char)(scope Writer w, FormatSpec!Char formatSpec) {
72         import std.format : formatValue;
73         import std.range.primitives : put;
74 
75         put(w, "File:");
76         formatValue(w, file, formatSpec);
77         put(w, " Line:");
78         formatValue(w, line, formatSpec);
79         put(w, " Column:");
80         formatValue(w, column, formatSpec);
81     }
82 
83     ///
84     T opCast(T : string)() @safe pure nothrow {
85         return toString();
86     }
87 }
88 
89 /** Represent a location.
90  *
91  * Either a:
92  *  - no location.
93  *  - location with data.
94  */
95 struct LocationTag {
96     import std.format : FormatSpec;
97 
98     enum Kind {
99         noloc,
100         loc
101     }
102 
103     /// Kind stored. Only use the payload when kind is "loc".
104     Kind kind;
105 
106     ///
107     Location payload;
108     alias payload this;
109 
110     /// Create either a noloc instance when passed null or a location.
111     this(T)(T t) @safe pure {
112         static if (is(T == typeof(null))) {
113             this.kind = Kind.noloc;
114         } else {
115             this.kind = Kind.loc;
116             this.payload = t;
117         }
118     }
119 
120     this(string file, uint line, uint column) {
121         this(Location(file, line, column));
122     }
123 
124     string toString() @safe pure {
125         import std.exception : assumeUnique;
126         import std.format : FormatSpec;
127 
128         char[] buf;
129         buf.reserve(100);
130         auto fmt = FormatSpec!char("%s");
131         toString((const(char)[] s) { buf ~= s; }, fmt);
132         auto trustedUnique(T)(T t) @trusted {
133             return assumeUnique(t);
134         }
135 
136         return trustedUnique(buf);
137     }
138 
139     void toString(Writer, Char)(scope Writer w, FormatSpec!Char formatSpec) {
140         import std.format : formatValue;
141         import std.range.primitives : put;
142 
143         final switch (kind) {
144         case Kind.noloc:
145             put(w, "noloc");
146             break;
147         case Kind.loc:
148             put(w, this.payload.toString);
149             break;
150         }
151     }
152 }
153 
154 auto toString(LocationTag data) @safe pure {
155     static import std.format;
156 
157     final switch (data.kind) {
158     case LocationTag.Kind.noloc:
159         return "noloc";
160     case LocationTag.Kind.loc:
161         return data.toString;
162     }
163 }
164 
165 // From this point onward only simple types thus mass apply of attributes.
166 @safe pure nothrow @nogc:
167 
168 /// Name of a C++ namespace.
169 struct CppNs {
170     string payload;
171     alias payload this;
172 }
173 
174 /** Stack of nested C++ namespaces.
175  *
176  * So A::B::C would be a range of [A, B, C].
177  */
178 struct CppNsStack {
179     CppNs[] payload;
180     alias payload this;
181 
182     this(CppNs[] fqn) @safe pure nothrow {
183         payload = fqn;
184     }
185 
186     this(CppNs[] reside_in_ns, CppNs name) @safe pure nothrow {
187         payload = reside_in_ns ~ name;
188     }
189 
190     void put()(CppNs n) {
191         payload ~= n;
192     }
193 
194     CppNs front() @safe pure nothrow {
195         assert(!empty, "Can't get front of an empty range");
196         return payload[$ - 1];
197     }
198 
199     void popFront() @safe pure nothrow {
200         assert(!empty, "Can't pop front of an empty range");
201         payload = payload[0 .. $ - 1];
202     }
203 
204     bool empty() @safe pure nothrow @nogc {
205         return payload.length == 0;
206     }
207 }
208 
209 /// Nesting of C++ namespaces as a string.
210 struct CppNsNesting {
211     string payload;
212     alias payload this;
213 }
214 
215 struct CppVariable {
216     string payload;
217     alias payload this;
218 }
219 
220 struct TypeKindVariable {
221     TypeKindAttr type;
222     CppVariable name;
223 }
224 
225 // Types for classes
226 struct CppClassName {
227     string payload;
228     alias payload this;
229 }
230 
231 ///TODO should be Optional type, either it has a nesting or it is "global".
232 /// Don't check the length and use that as an insidential "no nesting".
233 struct CppClassNesting {
234     string payload;
235     alias payload this;
236 }
237 
238 // Types for methods
239 struct CppMethodName {
240     string payload;
241     alias payload this;
242 }
243 
244 struct CppConstMethod {
245     bool payload;
246     alias payload this;
247 }
248 
249 struct CppVirtualMethod {
250     MemberVirtualType payload;
251     alias payload this;
252 }
253 
254 struct CppAccess {
255     AccessType payload;
256     alias payload this;
257 
258     T opCast(T)() if (isSomeString!T) {
259         import std.conv : to;
260 
261         return payload.to!T();
262     }
263 }
264 
265 // Types for free functions
266 struct CFunctionName {
267     string payload;
268     alias payload this;
269 }
270 
271 // Shared types between C and Cpp
272 alias VariadicType = Flag!"isVariadic";
273 alias CxParam = SumType!(TypeKindVariable, TypeKindAttr, VariadicType);
274 
275 struct CxReturnType {
276     TypeKindAttr payload;
277     alias payload this;
278 }
279 
280 //TODO change name to MethodVirtualType
281 enum MemberVirtualType {
282     Unknown,
283     Normal,
284     Virtual,
285     Pure
286 }
287 
288 enum AccessType {
289     Public,
290     Protected,
291     Private
292 }
293 
294 enum StorageClass {
295     None,
296     Extern,
297     Static
298 }
299 
300 /// The kind of language which influences name mangling.
301 enum Language {
302     unknown,
303     c,
304     cpp
305 }