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.root.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) 55 { 56 this.loc = loc; 57 this.kind = kind; 58 } 59 60 override final const(char)* toChars() const 61 { 62 OutBuffer buf; 63 HdrGenState hgs; 64 .toCBuffer(this, &buf, &hgs); 65 return buf.extractChars(); 66 } 67 68 final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure 69 { 70 // Use void* cast to skip dynamic casting call 71 return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null; 72 } 73 74 final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure 75 { 76 return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; 77 } 78 79 final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure 80 { 81 return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; 82 } 83 84 final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure 85 { 86 return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null; 87 } 88 89 final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure 90 { 91 return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null; 92 } 93 94 final inout(CInitializer) isCInitializer() inout @nogc nothrow pure 95 { 96 return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null; 97 } 98 99 override void accept(Visitor v) 100 { 101 v.visit(this); 102 } 103 } 104 105 /*********************************************************** 106 */ 107 extern (C++) final class VoidInitializer : Initializer 108 { 109 Type type; // type that this will initialize to 110 111 extern (D) this(const ref Loc loc) 112 { 113 super(loc, InitKind.void_); 114 } 115 116 override void accept(Visitor v) 117 { 118 v.visit(this); 119 } 120 } 121 122 /*********************************************************** 123 */ 124 extern (C++) final class ErrorInitializer : Initializer 125 { 126 extern (D) this() 127 { 128 super(Loc.initial, InitKind.error); 129 } 130 131 override void accept(Visitor v) 132 { 133 v.visit(this); 134 } 135 } 136 137 /*********************************************************** 138 */ 139 extern (C++) final class StructInitializer : Initializer 140 { 141 Identifiers field; // of Identifier *'s 142 Initializers value; // parallel array of Initializer *'s 143 144 extern (D) this(const ref Loc loc) 145 { 146 super(loc, InitKind.struct_); 147 } 148 149 extern (D) void addInit(Identifier field, Initializer value) 150 { 151 //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); 152 this.field.push(field); 153 this.value.push(value); 154 } 155 156 override void accept(Visitor v) 157 { 158 v.visit(this); 159 } 160 } 161 162 /*********************************************************** 163 */ 164 extern (C++) final class ArrayInitializer : Initializer 165 { 166 Expressions index; // indices 167 Initializers value; // of Initializer *'s 168 uint dim; // length of array being initialized 169 Type type; // type that array will be used to initialize 170 bool sem; // true if semantic() is run 171 bool isCarray; // C array semantics 172 173 extern (D) this(const ref Loc loc) 174 { 175 super(loc, InitKind.array); 176 } 177 178 extern (D) void addInit(Expression index, Initializer value) 179 { 180 this.index.push(index); 181 this.value.push(value); 182 dim = 0; 183 type = null; 184 } 185 186 bool isAssociativeArray() const pure 187 { 188 foreach (idx; index) 189 { 190 if (idx) 191 return true; 192 } 193 return false; 194 } 195 196 override void accept(Visitor v) 197 { 198 v.visit(this); 199 } 200 } 201 202 /*********************************************************** 203 */ 204 extern (C++) final class ExpInitializer : Initializer 205 { 206 bool expandTuples; 207 Expression exp; 208 209 extern (D) this(const ref Loc loc, Expression exp) 210 { 211 super(loc, InitKind.exp); 212 this.exp = exp; 213 } 214 215 override void accept(Visitor v) 216 { 217 v.visit(this); 218 } 219 } 220 221 /********************************************* 222 * Holds the `designator` for C initializers 223 */ 224 struct Designator 225 { 226 Expression exp; /// [ constant-expression ] 227 Identifier ident; /// . identifier 228 229 this(Expression exp) { this.exp = exp; } 230 this(Identifier ident) { this.ident = ident; } 231 } 232 233 /********************************************* 234 * Holds the `designation (opt) initializer` for C initializers 235 */ 236 struct DesigInit 237 { 238 Designators* designatorList; /// designation (opt) 239 Initializer initializer; /// initializer 240 } 241 242 /******************************** 243 * C11 6.7.9 Initialization 244 * Represents the C initializer-list 245 */ 246 extern (C++) final class CInitializer : Initializer 247 { 248 DesigInits initializerList; /// initializer-list 249 Type type; /// type that array will be used to initialize 250 bool sem; /// true if semantic() is run 251 252 extern (D) this(const ref Loc loc) 253 { 254 super(loc, InitKind.C_); 255 } 256 257 override void accept(Visitor v) 258 { 259 v.visit(this); 260 } 261 } 262 263 /**************************************** 264 * Copy the AST for Initializer. 265 * Params: 266 * inx = Initializer AST to copy 267 * Returns: 268 * the copy 269 */ 270 Initializer syntaxCopy(Initializer inx) 271 { 272 static Initializer visitVoid(VoidInitializer vi) 273 { 274 return new VoidInitializer(vi.loc); 275 } 276 277 static Initializer visitError(ErrorInitializer vi) 278 { 279 return vi; 280 } 281 282 static Initializer visitExp(ExpInitializer vi) 283 { 284 return new ExpInitializer(vi.loc, vi.exp.syntaxCopy()); 285 } 286 287 static Initializer visitStruct(StructInitializer vi) 288 { 289 auto si = new StructInitializer(vi.loc); 290 assert(vi.field.length == vi.value.length); 291 si.field.setDim(vi.field.length); 292 si.value.setDim(vi.value.length); 293 foreach (const i; 0 .. vi.field.length) 294 { 295 si.field[i] = vi.field[i]; 296 si.value[i] = vi.value[i].syntaxCopy(); 297 } 298 return si; 299 } 300 301 static Initializer visitArray(ArrayInitializer vi) 302 { 303 auto ai = new ArrayInitializer(vi.loc); 304 assert(vi.index.length == vi.value.length); 305 ai.index.setDim(vi.index.length); 306 ai.value.setDim(vi.value.length); 307 foreach (const i; 0 .. vi.value.length) 308 { 309 ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null; 310 ai.value[i] = vi.value[i].syntaxCopy(); 311 } 312 return ai; 313 } 314 315 static Initializer visitC(CInitializer vi) 316 { 317 auto ci = new CInitializer(vi.loc); 318 ci.initializerList.setDim(vi.initializerList.length); 319 foreach (const i; 0 .. vi.initializerList.length) 320 { 321 DesigInit* cdi = &ci.initializerList[i]; 322 DesigInit* vdi = &ci.initializerList[i]; 323 cdi.initializer = vdi.initializer.syntaxCopy(); 324 if (vdi.designatorList) 325 { 326 cdi.designatorList = new Designators(); 327 cdi.designatorList.setDim(vdi.designatorList.length); 328 foreach (const j; 0 .. vdi.designatorList.length) 329 { 330 Designator* cdid = &(*cdi.designatorList)[j]; 331 Designator* vdid = &(*vdi.designatorList)[j]; 332 cdid.exp = vdid.exp ? vdid.exp.syntaxCopy() : null; 333 cdid.ident = vdid.ident; 334 } 335 } 336 } 337 return ci; 338 } 339 340 mixin VisitInitializer!Initializer visit; 341 return visit.VisitInitializer(inx); 342 } 343 344 /*********************************************************** 345 * Visit each Initializer in init. Call a function visit%s(init) for 346 * each node, where %s is the op of the node. Otherwise call visitDefault(init) 347 * for that node. If the visit function returns R.init, continue 348 * visiting each node, otherwise return the value of R. 349 * Params: 350 * Result = return type 351 * init = Initializer tree to traverse 352 * Returns: 353 * Result.init for continue, value of type Result for early exit 354 */ 355 356 mixin template VisitInitializer(Result) 357 { 358 Result VisitInitializer(Initializer init) 359 { 360 final switch (init.kind) 361 { 362 case InitKind.void_: mixin(visitCase("Void")); break; 363 case InitKind.error: mixin(visitCase("Error")); break; 364 case InitKind.struct_: mixin(visitCase("Struct")); break; 365 case InitKind.array: mixin(visitCase("Array")); break; 366 case InitKind.exp: mixin(visitCase("Exp")); break; 367 case InitKind.C_: mixin(visitCase("C")); break; 368 } 369 static if (is(Result == void)) { } else 370 return Result.init; 371 } 372 } 373 374 /**************************************** 375 * CTFE-only helper function for VisitInitializer. 376 * Params: 377 * handler = string for the name of the visit handler 378 * Returns: boilerplate code for a case 379 */ 380 pure string visitCase(string handler) 381 { 382 if (__ctfe) 383 { 384 return 385 " 386 auto ix = init.is"~handler~"Initializer(); 387 static if (is(Result == void)) 388 visit"~handler~"(ix); 389 else 390 { 391 Result r = visit"~handler~"(ix); 392 if (r !is Result.init) 393 return r; 394 } 395 "; 396 } 397 assert(0); 398 }