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 }