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