1 /**
2 * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`.
3 *
4 * Copyright: Copyright (C) 1999-2022 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.mtype;
26 import dmd.common.outbuffer;
27 import dmd.root.rootobject;
28 import dmd.tokens;
29 import dmd.visitor;
30
31 enum NeedInterpret : int
32 {
33 INITnointerpret,
34 INITinterpret,
35 }
36
37 alias INITnointerpret = NeedInterpret.INITnointerpret;
38 alias INITinterpret = NeedInterpret.INITinterpret;
39
40 /***********************************************************
41 */
42 extern (C++) class Initializer : ASTNode
43 {
44 Loc loc;
45 InitKind kind;
46
dyncast()47 override DYNCAST dyncast() const nothrow pure
48 {
49 return DYNCAST.initializer;
50 }
51
52
this(const ref Loc loc,InitKind kind)53 extern (D) this(const ref Loc loc, InitKind kind)
54 {
55 this.loc = loc;
56 this.kind = kind;
57 }
58
toChars()59 override final const(char)* toChars() const
60 {
61 OutBuffer buf;
62 HdrGenState hgs;
63 .toCBuffer(this, &buf, &hgs);
64 return buf.extractChars();
65 }
66
inout(ErrorInitializer)67 final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
68 {
69 // Use void* cast to skip dynamic casting call
70 return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
71 }
72
inout(VoidInitializer)73 final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
74 {
75 return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
76 }
77
inout(StructInitializer)78 final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
79 {
80 return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
81 }
82
inout(ArrayInitializer)83 final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
84 {
85 return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
86 }
87
inout(ExpInitializer)88 final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
89 {
90 return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
91 }
92
inout(CInitializer)93 final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
94 {
95 return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
96 }
97
accept(Visitor v)98 override void accept(Visitor v)
99 {
100 v.visit(this);
101 }
102 }
103
104 /***********************************************************
105 */
106 extern (C++) final class VoidInitializer : Initializer
107 {
108 Type type; // type that this will initialize to
109
this(const ref Loc loc)110 extern (D) this(const ref Loc loc)
111 {
112 super(loc, InitKind.void_);
113 }
114
accept(Visitor v)115 override void accept(Visitor v)
116 {
117 v.visit(this);
118 }
119 }
120
121 /***********************************************************
122 */
123 extern (C++) final class ErrorInitializer : Initializer
124 {
this()125 extern (D) this()
126 {
127 super(Loc.initial, InitKind.error);
128 }
129
accept(Visitor v)130 override void accept(Visitor v)
131 {
132 v.visit(this);
133 }
134 }
135
136 /***********************************************************
137 */
138 extern (C++) final class StructInitializer : Initializer
139 {
140 Identifiers field; // of Identifier *'s
141 Initializers value; // parallel array of Initializer *'s
142
this(const ref Loc loc)143 extern (D) this(const ref Loc loc)
144 {
145 super(loc, InitKind.struct_);
146 }
147
addInit(Identifier field,Initializer value)148 extern (D) void addInit(Identifier field, Initializer value)
149 {
150 //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
151 this.field.push(field);
152 this.value.push(value);
153 }
154
accept(Visitor v)155 override void accept(Visitor v)
156 {
157 v.visit(this);
158 }
159 }
160
161 /***********************************************************
162 */
163 extern (C++) final class ArrayInitializer : Initializer
164 {
165 Expressions index; // indices
166 Initializers value; // of Initializer *'s
167 uint dim; // length of array being initialized
168 Type type; // type that array will be used to initialize
169 bool sem; // true if semantic() is run
170
this(const ref Loc loc)171 extern (D) this(const ref Loc loc)
172 {
173 super(loc, InitKind.array);
174 }
175
addInit(Expression index,Initializer value)176 extern (D) void addInit(Expression index, Initializer value)
177 {
178 this.index.push(index);
179 this.value.push(value);
180 dim = 0;
181 type = null;
182 }
183
isAssociativeArray()184 bool isAssociativeArray() const pure
185 {
186 foreach (idx; index)
187 {
188 if (idx)
189 return true;
190 }
191 return false;
192 }
193
accept(Visitor v)194 override void accept(Visitor v)
195 {
196 v.visit(this);
197 }
198 }
199
200 /***********************************************************
201 */
202 extern (C++) final class ExpInitializer : Initializer
203 {
204 bool expandTuples;
205 Expression exp;
206
this(const ref Loc loc,Expression exp)207 extern (D) this(const ref Loc loc, Expression exp)
208 {
209 super(loc, InitKind.exp);
210 this.exp = exp;
211 }
212
accept(Visitor v)213 override void accept(Visitor v)
214 {
215 v.visit(this);
216 }
217 }
218
219 /*********************************************
220 * Holds the `designator` for C initializers
221 */
222 struct Designator
223 {
224 Expression exp; /// [ constant-expression ]
225 Identifier ident; /// . identifier
226
thisDesignator227 this(Expression exp) { this.exp = exp; }
thisDesignator228 this(Identifier ident) { this.ident = ident; }
229 }
230
231 /*********************************************
232 * Holds the `designation (opt) initializer` for C initializers
233 */
234 struct DesigInit
235 {
236 Designators* designatorList; /// designation (opt)
237 Initializer initializer; /// initializer
238 }
239
240 /********************************
241 * C11 6.7.9 Initialization
242 * Represents the C initializer-list
243 */
244 extern (C++) final class CInitializer : Initializer
245 {
246 DesigInits initializerList; /// initializer-list
247 Type type; /// type that array will be used to initialize
248 bool sem; /// true if semantic() is run
249
this(const ref Loc loc)250 extern (D) this(const ref Loc loc)
251 {
252 super(loc, InitKind.C_);
253 }
254
accept(Visitor v)255 override void accept(Visitor v)
256 {
257 v.visit(this);
258 }
259 }
260
261 /****************************************
262 * Copy the AST for Initializer.
263 * Params:
264 * inx = Initializer AST to copy
265 * Returns:
266 * the copy
267 */
syntaxCopy(Initializer inx)268 Initializer syntaxCopy(Initializer inx)
269 {
270 static Initializer copyStruct(StructInitializer vi)
271 {
272 auto si = new StructInitializer(vi.loc);
273 assert(vi.field.dim == vi.value.dim);
274 si.field.setDim(vi.field.dim);
275 si.value.setDim(vi.value.dim);
276 foreach (const i; 0 .. vi.field.dim)
277 {
278 si.field[i] = vi.field[i];
279 si.value[i] = vi.value[i].syntaxCopy();
280 }
281 return si;
282 }
283
284 static Initializer copyArray(ArrayInitializer vi)
285 {
286 auto ai = new ArrayInitializer(vi.loc);
287 assert(vi.index.dim == vi.value.dim);
288 ai.index.setDim(vi.index.dim);
289 ai.value.setDim(vi.value.dim);
290 foreach (const i; 0 .. vi.value.dim)
291 {
292 ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null;
293 ai.value[i] = vi.value[i].syntaxCopy();
294 }
295 return ai;
296 }
297
298 static Initializer copyC(CInitializer vi)
299 {
300 auto ci = new CInitializer(vi.loc);
301 ci.initializerList.setDim(vi.initializerList.length);
302 foreach (const i; 0 .. vi.initializerList.length)
303 {
304 DesigInit* cdi = &ci.initializerList[i];
305 DesigInit* vdi = &ci.initializerList[i];
306 cdi.initializer = vdi.initializer.syntaxCopy();
307 if (vdi.designatorList)
308 {
309 cdi.designatorList = new Designators();
310 cdi.designatorList.setDim(vdi.designatorList.length);
311 foreach (const j; 0 .. vdi.designatorList.length)
312 {
313 Designator* cdid = &(*cdi.designatorList)[j];
314 Designator* vdid = &(*vdi.designatorList)[j];
315 cdid.exp = vdid.exp ? vdid.exp.syntaxCopy() : null;
316 cdid.ident = vdid.ident;
317 }
318 }
319 }
320 return ci;
321 }
322
323 final switch (inx.kind)
324 {
325 case InitKind.void_: return new VoidInitializer(inx.loc);
326 case InitKind.error: return inx;
327 case InitKind.struct_: return copyStruct(cast(StructInitializer)inx);
328 case InitKind.array: return copyArray(cast(ArrayInitializer)inx);
329 case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy());
330 case InitKind.C_: return copyC(cast(CInitializer)inx);
331 }
332 }
333