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