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 }