1 /** 2 * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) 8 * Documentation: https://dlang.org/phobos/dmd_init.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d 10 */ 11 12 module dmd.init; 13 14 import core.stdc.stdio; 15 import core.checkedint; 16 17 import dmd.arraytypes; 18 import dmd.astenums; 19 import dmd.ast_node; 20 import dmd.dsymbol; 21 import dmd.expression; 22 import dmd.globals; 23 import dmd.hdrgen; 24 import dmd.identifier; 25 import dmd.location; 26 import dmd.mtype; 27 import dmd.common.outbuffer; 28 import dmd.rootobject; 29 import dmd.tokens; 30 import dmd.visitor; 31 32 enum NeedInterpret : int 33 { 34 INITnointerpret, 35 INITinterpret, 36 } 37 38 alias INITnointerpret = NeedInterpret.INITnointerpret; 39 alias INITinterpret = NeedInterpret.INITinterpret; 40 41 /*********************************************************** 42 */ 43 extern (C++) class Initializer : ASTNode 44 { 45 Loc loc; 46 InitKind kind; 47 48 override DYNCAST dyncast() const 49 { 50 return DYNCAST.initializer; 51 } 52 53 54 extern (D) this(const ref Loc loc, InitKind kind) @safe 55 { 56 this.loc = loc; 57 this.kind = kind; 58 } 59 60 final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure 61 { 62 // Use void* cast to skip dynamic casting call 63 return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null; 64 } 65 66 final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure 67 { 68 return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; 69 } 70 71 final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure 72 { 73 return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; 74 } 75 76 final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure 77 { 78 return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null; 79 } 80 81 final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure 82 { 83 return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null; 84 } 85 86 final inout(CInitializer) isCInitializer() inout @nogc nothrow pure 87 { 88 return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null; 89 } 90 91 override void accept(Visitor v) 92 { 93 v.visit(this); 94 } 95 } 96 97 /*********************************************************** 98 */ 99 extern (C++) final class VoidInitializer : Initializer 100 { 101 Type type; // type that this will initialize to 102 103 extern (D) this(const ref Loc loc) @safe 104 { 105 super(loc, InitKind.void_); 106 } 107 108 override void accept(Visitor v) 109 { 110 v.visit(this); 111 } 112 } 113 114 /*********************************************************** 115 */ 116 extern (C++) final class ErrorInitializer : Initializer 117 { 118 extern (D) this() @safe 119 { 120 super(Loc.initial, InitKind.error); 121 } 122 123 override void accept(Visitor v) 124 { 125 v.visit(this); 126 } 127 } 128 129 /*********************************************************** 130 */ 131 extern (C++) final class StructInitializer : Initializer 132 { 133 Identifiers field; // of Identifier *'s 134 Initializers value; // parallel array of Initializer *'s 135 136 extern (D) this(const ref Loc loc) 137 { 138 super(loc, InitKind.struct_); 139 } 140 141 extern (D) void addInit(Identifier field, Initializer value) 142 { 143 //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); 144 this.field.push(field); 145 this.value.push(value); 146 } 147 148 override void accept(Visitor v) 149 { 150 v.visit(this); 151 } 152 } 153 154 /*********************************************************** 155 */ 156 extern (C++) final class ArrayInitializer : Initializer 157 { 158 Expressions index; // indices 159 Initializers value; // of Initializer *'s 160 uint dim; // length of array being initialized 161 Type type; // type that array will be used to initialize 162 bool sem; // true if semantic() is run 163 bool isCarray; // C array semantics 164 165 extern (D) this(const ref Loc loc) 166 { 167 super(loc, InitKind.array); 168 } 169 170 extern (D) void addInit(Expression index, Initializer value) 171 { 172 this.index.push(index); 173 this.value.push(value); 174 dim = 0; 175 type = null; 176 } 177 178 bool isAssociativeArray() const pure 179 { 180 foreach (idx; index) 181 { 182 if (idx) 183 return true; 184 } 185 return false; 186 } 187 188 override void accept(Visitor v) 189 { 190 v.visit(this); 191 } 192 } 193 194 /*********************************************************** 195 */ 196 extern (C++) final class ExpInitializer : Initializer 197 { 198 bool expandTuples; 199 Expression exp; 200 201 extern (D) this(const ref Loc loc, Expression exp) @safe 202 { 203 super(loc, InitKind.exp); 204 this.exp = exp; 205 } 206 207 override void accept(Visitor v) 208 { 209 v.visit(this); 210 } 211 } 212 213 /********************************************* 214 * Holds the `designator` for C initializers 215 */ 216 struct Designator 217 { 218 Expression exp; /// [ constant-expression ] 219 Identifier ident; /// . identifier 220 221 this(Expression exp) @safe { this.exp = exp; } 222 this(Identifier ident) @safe { this.ident = ident; } 223 } 224 225 /********************************************* 226 * Holds the `designation (opt) initializer` for C initializers 227 */ 228 struct DesigInit 229 { 230 Designators* designatorList; /// designation (opt) 231 Initializer initializer; /// initializer 232 } 233 234 /******************************** 235 * C11 6.7.9 Initialization 236 * Represents the C initializer-list 237 */ 238 extern (C++) final class CInitializer : Initializer 239 { 240 DesigInits initializerList; /// initializer-list 241 Type type; /// type that array will be used to initialize 242 bool sem; /// true if semantic() is run 243 244 extern (D) this(const ref Loc loc) 245 { 246 super(loc, InitKind.C_); 247 } 248 249 override void accept(Visitor v) 250 { 251 v.visit(this); 252 } 253 } 254 255 /**************************************** 256 * Copy the AST for Initializer. 257 * Params: 258 * inx = Initializer AST to copy 259 * Returns: 260 * the copy 261 */ 262 Initializer syntaxCopy(Initializer inx) 263 { 264 static Initializer visitVoid(VoidInitializer vi) 265 { 266 return new VoidInitializer(vi.loc); 267 } 268 269 static Initializer visitError(ErrorInitializer vi) 270 { 271 return vi; 272 } 273 274 static Initializer visitExp(ExpInitializer vi) 275 { 276 return new ExpInitializer(vi.loc, vi.exp.syntaxCopy()); 277 } 278 279 static Initializer visitStruct(StructInitializer vi) 280 { 281 auto si = new StructInitializer(vi.loc); 282 assert(vi.field.length == vi.value.length); 283 si.field.setDim(vi.field.length); 284 si.value.setDim(vi.value.length); 285 foreach (const i; 0 .. vi.field.length) 286 { 287 si.field[i] = vi.field[i]; 288 si.value[i] = vi.value[i].syntaxCopy(); 289 } 290 return si; 291 } 292 293 static Initializer visitArray(ArrayInitializer vi) 294 { 295 auto ai = new ArrayInitializer(vi.loc); 296 assert(vi.index.length == vi.value.length); 297 ai.index.setDim(vi.index.length); 298 ai.value.setDim(vi.value.length); 299 foreach (const i; 0 .. vi.value.length) 300 { 301 ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null; 302 ai.value[i] = vi.value[i].syntaxCopy(); 303 } 304 return ai; 305 } 306 307 static Initializer visitC(CInitializer vi) 308 { 309 auto ci = new CInitializer(vi.loc); 310 ci.initializerList.setDim(vi.initializerList.length); 311 foreach (const i; 0 .. vi.initializerList.length) 312 { 313 DesigInit* cdi = &ci.initializerList[i]; 314 DesigInit* vdi = &ci.initializerList[i]; 315 cdi.initializer = vdi.initializer.syntaxCopy(); 316 if (vdi.designatorList) 317 { 318 cdi.designatorList = new Designators(); 319 cdi.designatorList.setDim(vdi.designatorList.length); 320 foreach (const j; 0 .. vdi.designatorList.length) 321 { 322 Designator* cdid = &(*cdi.designatorList)[j]; 323 Designator* vdid = &(*vdi.designatorList)[j]; 324 cdid.exp = vdid.exp ? vdid.exp.syntaxCopy() : null; 325 cdid.ident = vdid.ident; 326 } 327 } 328 } 329 return ci; 330 } 331 332 mixin VisitInitializer!Initializer visit; 333 return visit.VisitInitializer(inx); 334 } 335 336 /*********************************************************** 337 * Visit each Initializer in init. Call a function visit%s(init) for 338 * each node, where %s is the op of the node. Otherwise call visitDefault(init) 339 * for that node. If the visit function returns R.init, continue 340 * visiting each node, otherwise return the value of R. 341 * Params: 342 * Result = return type 343 * init = Initializer tree to traverse 344 * Returns: 345 * Result.init for continue, value of type Result for early exit 346 */ 347 348 mixin template VisitInitializer(Result) 349 { 350 Result VisitInitializer(Initializer init) 351 { 352 final switch (init.kind) 353 { 354 case InitKind.void_: mixin(visitCase("Void")); break; 355 case InitKind.error: mixin(visitCase("Error")); break; 356 case InitKind.struct_: mixin(visitCase("Struct")); break; 357 case InitKind.array: mixin(visitCase("Array")); break; 358 case InitKind.exp: mixin(visitCase("Exp")); break; 359 case InitKind.C_: mixin(visitCase("C")); break; 360 } 361 static if (is(Result == void)) { } else 362 return Result.init; 363 } 364 } 365 366 /**************************************** 367 * CTFE-only helper function for VisitInitializer. 368 * Params: 369 * handler = string for the name of the visit handler 370 * Returns: boilerplate code for a case 371 */ 372 string visitCase(string handler) pure @safe 373 { 374 if (__ctfe) 375 { 376 return 377 " 378 auto ix = init.is"~handler~"Initializer(); 379 static if (is(Result == void)) 380 visit"~handler~"(ix); 381 else 382 { 383 Result r = visit"~handler~"(ix); 384 if (r !is Result.init) 385 return r; 386 } 387 "; 388 } 389 assert(0); 390 }