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