1 /**
2  * Defines a `Dsymbol` for `version = identifier` and `debug = identifier` statements.
3  *
4  * Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification),
5  *                $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification).
6  *
7  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
8  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
9  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
10  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d)
11  * Documentation:  https://dlang.org/phobos/dmd_dversion.html
12  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dversion.d
13  */
14 
15 module dmd.dversion;
16 
17 import dmd.arraytypes;
18 import dmd.cond;
19 import dmd.dmodule;
20 import dmd.dscope;
21 import dmd.dsymbol;
22 import dmd.dsymbolsem;
23 import dmd.globals;
24 import dmd.identifier;
25 import dmd.root.outbuffer;
26 import dmd.visitor;
27 
28 /***********************************************************
29  * DebugSymbol's happen for statements like:
30  *      debug = identifier;
31  *      debug = integer;
32  */
33 extern (C++) final class DebugSymbol : Dsymbol
34 {
35     uint level;
36 
37     extern (D) this(const ref Loc loc, Identifier ident)
38     {
39         super(loc, ident);
40     }
41 
42     extern (D) this(const ref Loc loc, uint level)
43     {
44         super(loc, null);
45         this.level = level;
46     }
47 
48     override DebugSymbol syntaxCopy(Dsymbol s)
49     {
50         assert(!s);
51         auto ds = new DebugSymbol(loc, ident);
52         ds.comment = comment;
53         ds.level = level;
54         return ds;
55     }
56 
57     override const(char)* toChars() const nothrow
58     {
59         if (ident)
60             return ident.toChars();
61         else
62         {
63             OutBuffer buf;
64             buf.print(level);
65             return buf.extractChars();
66         }
67     }
68 
69     override void addMember(Scope* sc, ScopeDsymbol sds)
70     {
71         //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
72         Module m = sds.isModule();
73         // Do not add the member to the symbol table,
74         // just make sure subsequent debug declarations work.
75         if (ident)
76         {
77             if (!m)
78             {
79                 error("declaration must be at module level");
80                 errors = true;
81             }
82             else
83             {
84                 if (findCondition(m.debugidsNot, ident))
85                 {
86                     error("defined after use");
87                     errors = true;
88                 }
89                 if (!m.debugids)
90                     m.debugids = new Identifiers();
91                 m.debugids.push(ident);
92             }
93         }
94         else
95         {
96             if (!m)
97             {
98                 error("level declaration must be at module level");
99                 errors = true;
100             }
101             else
102                 m.debuglevel = level;
103         }
104     }
105 
106     override const(char)* kind() const nothrow
107     {
108         return "debug";
109     }
110 
111     override inout(DebugSymbol) isDebugSymbol() inout
112     {
113         return this;
114     }
115 
116     override void accept(Visitor v)
117     {
118         v.visit(this);
119     }
120 }
121 
122 /***********************************************************
123  * VersionSymbol's happen for statements like:
124  *      version = identifier;
125  *      version = integer;
126  */
127 extern (C++) final class VersionSymbol : Dsymbol
128 {
129     uint level;
130 
131     extern (D) this(const ref Loc loc, Identifier ident)
132     {
133         super(loc, ident);
134     }
135 
136     extern (D) this(const ref Loc loc, uint level)
137     {
138         super(loc, null);
139         this.level = level;
140     }
141 
142     override VersionSymbol syntaxCopy(Dsymbol s)
143     {
144         assert(!s);
145         auto ds = ident ? new VersionSymbol(loc, ident)
146                         : new VersionSymbol(loc, level);
147         ds.comment = comment;
148         return ds;
149     }
150 
151     override const(char)* toChars() const nothrow
152     {
153         if (ident)
154             return ident.toChars();
155         else
156         {
157             OutBuffer buf;
158             buf.print(level);
159             return buf.extractChars();
160         }
161     }
162 
163     override void addMember(Scope* sc, ScopeDsymbol sds)
164     {
165         //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
166         Module m = sds.isModule();
167         // Do not add the member to the symbol table,
168         // just make sure subsequent debug declarations work.
169         if (ident)
170         {
171             VersionCondition.checkReserved(loc, ident.toString());
172             if (!m)
173             {
174                 error("declaration must be at module level");
175                 errors = true;
176             }
177             else
178             {
179                 if (findCondition(m.versionidsNot, ident))
180                 {
181                     error("defined after use");
182                     errors = true;
183                 }
184                 if (!m.versionids)
185                     m.versionids = new Identifiers();
186                 m.versionids.push(ident);
187             }
188         }
189         else
190         {
191             if (!m)
192             {
193                 error("level declaration must be at module level");
194                 errors = true;
195             }
196             else
197                 m.versionlevel = level;
198         }
199     }
200 
201     override const(char)* kind() const nothrow
202     {
203         return "version";
204     }
205 
206     override inout(VersionSymbol) isVersionSymbol() inout
207     {
208         return this;
209     }
210 
211     override void accept(Visitor v)
212     {
213         v.visit(this);
214     }
215 }