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-2020 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 Dsymbol 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 void accept(Visitor v)
112     {
113         v.visit(this);
114     }
115 }
116 
117 /***********************************************************
118  * VersionSymbol's happen for statements like:
119  *      version = identifier;
120  *      version = integer;
121  */
122 extern (C++) final class VersionSymbol : Dsymbol
123 {
124     uint level;
125 
126     extern (D) this(const ref Loc loc, Identifier ident)
127     {
128         super(loc, ident);
129     }
130 
131     extern (D) this(const ref Loc loc, uint level)
132     {
133         super(loc, null);
134         this.level = level;
135     }
136 
137     override Dsymbol syntaxCopy(Dsymbol s)
138     {
139         assert(!s);
140         auto ds = ident ? new VersionSymbol(loc, ident)
141                         : new VersionSymbol(loc, level);
142         ds.comment = comment;
143         return ds;
144     }
145 
146     override const(char)* toChars() const nothrow
147     {
148         if (ident)
149             return ident.toChars();
150         else
151         {
152             OutBuffer buf;
153             buf.print(level);
154             return buf.extractChars();
155         }
156     }
157 
158     override void addMember(Scope* sc, ScopeDsymbol sds)
159     {
160         //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
161         Module m = sds.isModule();
162         // Do not add the member to the symbol table,
163         // just make sure subsequent debug declarations work.
164         if (ident)
165         {
166             VersionCondition.checkReserved(loc, ident.toString());
167             if (!m)
168             {
169                 error("declaration must be at module level");
170                 errors = true;
171             }
172             else
173             {
174                 if (findCondition(m.versionidsNot, ident))
175                 {
176                     error("defined after use");
177                     errors = true;
178                 }
179                 if (!m.versionids)
180                     m.versionids = new Identifiers();
181                 m.versionids.push(ident);
182             }
183         }
184         else
185         {
186             if (!m)
187             {
188                 error("level declaration must be at module level");
189                 errors = true;
190             }
191             else
192                 m.versionlevel = level;
193         }
194     }
195 
196     override const(char)* kind() const nothrow
197     {
198         return "version";
199     }
200 
201     override void accept(Visitor v)
202     {
203         v.visit(this);
204     }
205 }