1 module d.ast.type; 2 3 public import d.common.builtintype; 4 public import d.common.qualifier; 5 6 import source.context; 7 import d.common.type; 8 9 enum AstTypeKind : ubyte { 10 Builtin, 11 Identifier, 12 13 // Type constructors 14 Pointer, 15 Slice, 16 Array, 17 Map, 18 Bracket, 19 Function, 20 21 // typeof 22 TypeOf, 23 } 24 25 struct AstType { 26 private: 27 mixin TypeMixin!(AstTypeKind, Payload); 28 29 this(Desc d, inout Payload p = Payload.init) inout { 30 desc = d; 31 payload = p; 32 } 33 34 import util.fastcast; 35 this(Desc d, inout Identifier i) inout { 36 this(d, fastCast!(inout Payload)(i)); 37 } 38 39 this(Desc d, inout AstExpression e) inout { 40 this(d, fastCast!(inout Payload)(e)); 41 } 42 43 this(Desc d, inout ArrayPayload* a) inout { 44 this(d, fastCast!(inout Payload)(a)); 45 } 46 47 this(Desc d, inout MapPayload* m) inout { 48 this(d, fastCast!(inout Payload)(m)); 49 } 50 51 this(Desc d, inout BracketPayload* b) inout { 52 this(d, fastCast!(inout Payload)(b)); 53 } 54 55 this(Desc d, inout AstType* t) inout { 56 this(d, fastCast!(inout Payload)(t)); 57 } 58 59 AstType getConstructedType(this T)(AstTypeKind k, TypeQualifier q) in { 60 assert(!isAuto, "Cannot build on top of auto type."); 61 } do { 62 return getConstructedMixin(k, q); 63 } 64 65 auto acceptImpl(T)(T t) { 66 final switch (kind) with (AstTypeKind) { 67 case Builtin: 68 return t.visit(builtin); 69 70 case Identifier: 71 return t.visit(identifier); 72 73 case Pointer: 74 return t.visitPointerOf(element); 75 76 case Slice: 77 return t.visitSliceOf(element); 78 79 case Array: 80 return t.visitArrayOf(size, element); 81 82 case Map: 83 return t.visitMapOf(key, element); 84 85 case Bracket: 86 return t.visitBracketOf(ikey, element); 87 88 case Function: 89 return t.visit(asFunctionType()); 90 91 case TypeOf: 92 return desc.data ? t.visitTypeOfReturn() : t.visit(expression); 93 } 94 } 95 96 public: 97 auto accept(T)(ref T t) if (is(T == struct)) { 98 return acceptImpl(&t); 99 } 100 101 auto accept(T)(T t) if (is(T == class)) { 102 return acceptImpl(t); 103 } 104 105 AstType qualify(TypeQualifier q) { 106 auto d = desc; 107 d.qualifier = q.add(qualifier); 108 return AstType(d, payload); 109 } 110 111 AstType unqual() { 112 auto d = desc; 113 d.qualifier = TypeQualifier.Mutable; 114 return AstType(d, payload); 115 } 116 117 @property 118 BuiltinType builtin() inout in { 119 assert(kind == AstTypeKind.Builtin); 120 } do { 121 return cast(BuiltinType) desc.data; 122 } 123 124 @property 125 bool isAuto() inout { 126 return payload.next is null && kind == AstTypeKind.Builtin 127 && builtin == BuiltinType.None; 128 } 129 130 @property 131 auto identifier() inout in { 132 assert(kind == AstTypeKind.Identifier); 133 } do { 134 return payload.identifier; 135 } 136 137 AstType getPointer(TypeQualifier q = TypeQualifier.Mutable) { 138 return getConstructedType(AstTypeKind.Pointer, q); 139 } 140 141 AstType getSlice(TypeQualifier q = TypeQualifier.Mutable) { 142 return getConstructedType(AstTypeKind.Slice, q); 143 } 144 145 AstType getArray(AstExpression size, 146 TypeQualifier q = TypeQualifier.Mutable) in { 147 assert(!isAuto, "Cannot build on top of auto type."); 148 } do { 149 return (payload.next is null && isPackable()) 150 ? AstType(Desc(AstTypeKind.Array, q, raw_desc), size) 151 : AstType(Desc(AstTypeKind.Array, q), new ArrayPayload(size, this)); 152 } 153 154 AstType getMap(AstType key, TypeQualifier q = TypeQualifier.Mutable) in { 155 assert(!isAuto, "Cannot build on top of auto type."); 156 } do { 157 return AstType(Desc(AstTypeKind.Map, q), new MapPayload(key, this)); 158 } 159 160 AstType getBracket(Identifier ikey, 161 TypeQualifier q = TypeQualifier.Mutable) in { 162 assert(!isAuto, "Cannot build on top of auto type."); 163 } do { 164 return (payload.next is null && isPackable()) 165 ? AstType(Desc(AstTypeKind.Bracket, q, raw_desc), ikey) 166 : AstType(Desc(AstTypeKind.Bracket, q), 167 new BracketPayload(ikey, this)); 168 } 169 170 bool hasElement() const { 171 return (kind >= AstTypeKind.Pointer) && (kind <= AstTypeKind.Bracket); 172 } 173 174 @property 175 auto element() inout in { 176 assert(hasElement, "element called on a type with no element."); 177 } do { 178 if (kind < AstTypeKind.Array) { 179 return getElementMixin(); 180 } 181 182 switch (kind) with (AstTypeKind) { 183 case Array: 184 return desc.data 185 ? inout(AstType)(getElementMixin().desc) 186 : payload.array.type; 187 188 case Map: 189 return payload.map.type; 190 191 case Bracket: 192 return desc.data 193 ? inout(AstType)(getElementMixin().desc) 194 : payload.bracket.type; 195 196 default: 197 assert(0); 198 } 199 } 200 201 @property 202 auto size() inout in { 203 assert(kind == AstTypeKind.Array, "Only array have size."); 204 } do { 205 return desc.data ? payload.expr : payload.array.size; 206 } 207 208 @property 209 auto key() inout in { 210 assert(kind == AstTypeKind.Map, "Only maps have key."); 211 } do { 212 return payload.map.key; 213 } 214 215 @property 216 auto ikey() inout in { 217 assert(kind == AstTypeKind.Bracket, 218 "Only bracket[identifier] have ikey."); 219 } do { 220 return desc.data ? payload.identifier : payload.bracket.key; 221 } 222 223 @property 224 auto expression() inout in { 225 assert(kind == AstTypeKind.TypeOf && desc.data == 0); 226 } do { 227 return payload.expr; 228 } 229 230 @property 231 bool isTypeOfReturn() inout { 232 return kind == AstTypeKind.TypeOf && desc.data != 0; 233 } 234 235 string toString(const Context c) const { 236 auto s = toUnqualString(c); 237 238 final switch (qualifier) with (TypeQualifier) { 239 case Mutable: 240 return s; 241 242 case Inout: 243 return "inout(" ~ s ~ ")"; 244 245 case Const: 246 return "const(" ~ s ~ ")"; 247 248 case Shared: 249 return "shared(" ~ s ~ ")"; 250 251 case ConstShared: 252 assert(0, "const shared isn't supported"); 253 254 case Immutable: 255 return "immutable(" ~ s ~ ")"; 256 } 257 } 258 259 string toUnqualString(const Context c) const { 260 final switch (kind) with (AstTypeKind) { 261 case Builtin: 262 import d.common.builtintype : toString; 263 return toString(builtin); 264 265 case Identifier: 266 return identifier.toString(c); 267 268 case Pointer: 269 return element.toString(c) ~ "*"; 270 271 case Slice: 272 return element.toString(c) ~ "[]"; 273 274 case Array: 275 return element.toString(c) ~ "[" ~ size.toString(c) ~ "]"; 276 277 case Map: 278 return element.toString(c) ~ "[" ~ key.toString(c) ~ "]"; 279 280 case Bracket: 281 return element.toString(c) ~ "[" ~ ikey.toString(c) ~ "]"; 282 283 case Function: 284 auto f = asFunctionType(); 285 auto ret = f.returnType.toString(c); 286 auto base = f.contexts.length ? " delegate(" : " function("; 287 import std.algorithm, std.range; 288 auto args = f.parameters.map!(p => p.toString(c)).join(", "); 289 return ret ~ base ~ args ~ (f.isVariadic ? ", ...)" : ")"); 290 291 case TypeOf: 292 return desc.data 293 ? "typeof(return)" 294 : "typeof(" ~ expression.toString(c) ~ ")"; 295 } 296 } 297 298 static: 299 AstType get(BuiltinType bt, TypeQualifier q = TypeQualifier.Mutable) { 300 Payload p; // Needed because of lolbug in inout 301 return AstType(Desc(AstTypeKind.Builtin, q, bt), p); 302 } 303 304 AstType getAuto(TypeQualifier q = TypeQualifier.Mutable) { 305 return get(BuiltinType.None, q); 306 } 307 308 AstType get(Identifier i, TypeQualifier q = TypeQualifier.Mutable) { 309 return AstType(Desc(AstTypeKind.Identifier, q), i); 310 } 311 312 AstType getTypeOf(AstExpression e, 313 TypeQualifier q = TypeQualifier.Mutable) { 314 return AstType(Desc(AstTypeKind.TypeOf, q), e); 315 } 316 317 AstType getTypeOfReturn(TypeQualifier q = TypeQualifier.Mutable) { 318 Payload p; // Needed because of lolbug in inout 319 return AstType(Desc(AstTypeKind.TypeOf, q, 1), p); 320 } 321 } 322 323 unittest { 324 AstType t; 325 assert(t.isAuto); 326 assert(t.qualifier == TypeQualifier.Mutable); 327 328 t = t.qualify(TypeQualifier.Immutable); 329 assert(t.isAuto); 330 assert(t.qualifier == TypeQualifier.Immutable); 331 332 t = AstType.getAuto(TypeQualifier.Const); 333 assert(t.isAuto); 334 assert(t.qualifier == TypeQualifier.Const); 335 336 auto l = AstType.get(BuiltinType.Long); 337 auto p = l.getPointer(); 338 assert(p.element == l); 339 340 import source.location; 341 auto s1 = new DollarExpression(Location.init); 342 auto a1 = l.getArray(s1); 343 assert(a1.size is s1); 344 assert(a1.element == l); 345 346 auto s2 = new DollarExpression(Location.init); 347 auto a2 = a1.getArray(s2); 348 assert(a2.size is s2); 349 assert(a2.element == a1); 350 351 auto f = AstType.get(BuiltinType.Float); 352 auto m = l.getMap(f); 353 assert(m.key == f); 354 assert(m.element == l); 355 356 import source.name; 357 auto i = new BasicIdentifier(Location.init, BuiltinName!""); 358 t = AstType.get(i, TypeQualifier.Shared); 359 assert(t.identifier is i); 360 assert(t.qualifier is TypeQualifier.Shared); 361 362 auto b1 = l.getBracket(i); 363 assert(b1.ikey is i); 364 assert(b1.element == l); 365 366 auto b2 = b1.getBracket(i); 367 assert(b2.ikey is i); 368 assert(b2.element == b1); 369 370 auto e = new DollarExpression(Location.init); 371 t = AstType.getTypeOf(e); 372 assert(t.expression is e); 373 374 t = AstType.getTypeOfReturn(); 375 376 import source.context; 377 Context c; 378 assert(t.toString(c) == "typeof(return)"); 379 } 380 381 alias ParamAstType = AstType.ParamType; 382 383 string toString(const ParamAstType t, const Context c) { 384 string s; 385 final switch (t.paramKind) with (ParamKind) { 386 case Regular: 387 s = ""; 388 break; 389 390 case Final: 391 s = "final "; 392 break; 393 394 case Ref: 395 s = "ref "; 396 break; 397 } 398 399 return s ~ t.getType().toString(c); 400 } 401 402 inout(ParamAstType) getParamType(inout ParamAstType t, ParamKind kind) { 403 return t.getType().getParamType(kind); 404 } 405 406 alias FunctionAstType = AstType.FunctionType; 407 408 private: 409 410 // XXX: we put it as a UFCS property to avoid forward reference. 411 @property 412 inout(ParamAstType)* params(inout Payload p) { 413 import util.fastcast; 414 return cast(inout ParamAstType*) p.next; 415 } 416 417 import d.ast.expression; 418 import d.ast.identifier; 419 420 union Payload { 421 AstType* next; 422 423 Identifier identifier; 424 425 ArrayPayload* array; 426 MapPayload* map; 427 BracketPayload* bracket; 428 429 AstExpression expr; 430 } 431 432 struct ArrayPayload { 433 AstExpression size; 434 AstType type; 435 } 436 437 struct MapPayload { 438 AstType key; 439 AstType type; 440 } 441 442 struct BracketPayload { 443 Identifier key; 444 AstType type; 445 }