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