1 1.1 mrg /** 2 1.1 mrg * Defines an identifier, which is the name of a `Dsymbol`. 3 1.1 mrg * 4 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 5 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d) 8 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_identifier.html 9 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/identifier.d 10 1.1 mrg */ 11 1.1 mrg 12 1.1 mrg module dmd.identifier; 13 1.1 mrg 14 1.1 mrg import core.stdc.ctype; 15 1.1 mrg import core.stdc.stdio; 16 1.1 mrg import core.stdc.string; 17 1.1 mrg import dmd.globals; 18 1.1 mrg import dmd.id; 19 1.1 mrg import dmd.common.outbuffer; 20 1.1 mrg import dmd.root.rootobject; 21 1.1 mrg import dmd.root.string; 22 1.1 mrg import dmd.root.stringtable; 23 1.1 mrg import dmd.root.utf; 24 1.1 mrg import dmd.tokens; 25 1.1 mrg 26 1.1 mrg 27 1.1 mrg /*********************************************************** 28 1.1 mrg */ 29 1.1 mrg extern (C++) final class Identifier : RootObject 30 1.1 mrg { 31 1.1 mrg private const int value; 32 1.1 mrg 33 1.1 mrg // Indicates if this is an identifier used for an anonymous symbol. 34 1.1 mrg private const bool isAnonymous_ = false; 35 1.1 mrg 36 1.1 mrg private const char[] name; 37 1.1 mrg 38 1.1 mrg nothrow: 39 1.1 mrg 40 1.1 mrg /// Construct an identifier from the given name. 41 1.1 mrg extern (D) this(const(char)* name) 42 1.1 mrg { 43 1.1 mrg //printf("Identifier('%s', %d)\n", name, value); 44 1.1 mrg this(name.toDString(), TOK.identifier); 45 1.1 mrg } 46 1.1 mrg 47 1.1 mrg /** 48 1.1 mrg Construct an identifier from the given name. 49 1.1 mrg 50 1.1 mrg Params: 51 1.1 mrg name = the identifier name. There must be `'\0'` at `name[length]`. 52 1.1 mrg length = the length of `name`, excluding the terminating `'\0'` 53 1.1 mrg value = Identifier value (e.g. `Id.unitTest`) or `TOK.identifier` 54 1.1 mrg */ 55 1.1 mrg extern (D) this(const(char)* name, size_t length, int value) 56 1.1 mrg in 57 1.1 mrg { 58 1.1 mrg assert(name[length] == '\0'); 59 1.1 mrg } 60 1.1 mrg do 61 1.1 mrg { 62 1.1 mrg //printf("Identifier('%s', %d)\n", name, value); 63 1.1 mrg this(name[0 .. length], value); 64 1.1 mrg } 65 1.1 mrg 66 1.1 mrg /// ditto 67 1.1 mrg extern (D) this(const(char)[] name, int value) 68 1.1 mrg { 69 1.1 mrg //printf("Identifier('%.*s', %d)\n", cast(int)name.length, name.ptr, value); 70 1.1 mrg this(name, value, false); 71 1.1 mrg } 72 1.1 mrg 73 1.1 mrg extern (D) private this(const(char)[] name, int value, bool isAnonymous) 74 1.1 mrg { 75 1.1 mrg //printf("Identifier('%.*s', %d, %d)\n", cast(int)name.length, name.ptr, value, isAnonymous); 76 1.1 mrg this.name = name; 77 1.1 mrg this.value = value; 78 1.1 mrg isAnonymous_ = isAnonymous; 79 1.1 mrg } 80 1.1 mrg 81 1.1 mrg static Identifier create(const(char)* name) 82 1.1 mrg { 83 1.1 mrg return new Identifier(name); 84 1.1 mrg } 85 1.1 mrg 86 1.1 mrg override const(char)* toChars() const pure 87 1.1 mrg { 88 1.1 mrg return name.ptr; 89 1.1 mrg } 90 1.1 mrg 91 1.1 mrg extern (D) override const(char)[] toString() const pure 92 1.1 mrg { 93 1.1 mrg return name; 94 1.1 mrg } 95 1.1 mrg 96 1.1 mrg int getValue() const pure 97 1.1 mrg { 98 1.1 mrg return value; 99 1.1 mrg } 100 1.1 mrg 101 1.1 mrg bool isAnonymous() const pure @nogc @safe 102 1.1 mrg { 103 1.1 mrg return isAnonymous_; 104 1.1 mrg } 105 1.1 mrg 106 1.1 mrg const(char)* toHChars2() const 107 1.1 mrg { 108 1.1 mrg const(char)* p = null; 109 1.1 mrg if (this == Id.ctor) 110 1.1 mrg p = "this"; 111 1.1 mrg else if (this == Id.dtor) 112 1.1 mrg p = "~this"; 113 1.1 mrg else if (this == Id.unitTest) 114 1.1 mrg p = "unittest"; 115 1.1 mrg else if (this == Id.dollar) 116 1.1 mrg p = "$"; 117 1.1 mrg else if (this == Id.withSym) 118 1.1 mrg p = "with"; 119 1.1 mrg else if (this == Id.result) 120 1.1 mrg p = "result"; 121 1.1 mrg else if (this == Id.returnLabel) 122 1.1 mrg p = "return"; 123 1.1 mrg else 124 1.1 mrg { 125 1.1 mrg p = toChars(); 126 1.1 mrg if (*p == '_') 127 1.1 mrg { 128 1.1 mrg if (strncmp(p, "_staticCtor", 11) == 0) 129 1.1 mrg p = "static this"; 130 1.1 mrg else if (strncmp(p, "_staticDtor", 11) == 0) 131 1.1 mrg p = "static ~this"; 132 1.1 mrg else if (strncmp(p, "__invariant", 11) == 0) 133 1.1 mrg p = "invariant"; 134 1.1 mrg } 135 1.1 mrg } 136 1.1 mrg return p; 137 1.1 mrg } 138 1.1 mrg 139 1.1 mrg override DYNCAST dyncast() const 140 1.1 mrg { 141 1.1 mrg return DYNCAST.identifier; 142 1.1 mrg } 143 1.1 mrg 144 1.1 mrg private extern (D) __gshared StringTable!Identifier stringtable; 145 1.1 mrg 146 1.1 mrg /** 147 1.1 mrg * Generates a new identifier. 148 1.1 mrg * 149 1.1 mrg * Params: 150 1.1 mrg * prefix = this will be the prefix of the name of the identifier. For debugging 151 1.1 mrg * purpose. 152 1.1 mrg */ 153 1.1 mrg extern(D) static Identifier generateId(const(char)[] prefix) 154 1.1 mrg { 155 1.1 mrg return generateId(prefix, newSuffix, false); 156 1.1 mrg } 157 1.1 mrg 158 1.1 mrg /** 159 1.1 mrg * Generates a new anonymous identifier. 160 1.1 mrg * 161 1.1 mrg * Params: 162 1.1 mrg * name = this will be part of the name of the identifier. For debugging 163 1.1 mrg * purpose. 164 1.1 mrg */ 165 1.1 mrg extern(D) static Identifier generateAnonymousId(const(char)[] name) 166 1.1 mrg { 167 1.1 mrg return generateId("__anon" ~ name, newSuffix, true); 168 1.1 mrg } 169 1.1 mrg 170 1.1 mrg /** 171 1.1 mrg * Generates a new identifier. 172 1.1 mrg * 173 1.1 mrg * Params: 174 1.1 mrg * prefix = this will be the prefix of the name of the identifier. For debugging 175 1.1 mrg * purpose. 176 1.1 mrg * suffix = this will be the suffix of the name of the identifier. This is 177 1.1 mrg * what makes the identifier unique 178 1.1 mrg */ 179 1.1 mrg extern(D) static Identifier generateId(const(char)[] prefix, size_t suffix) 180 1.1 mrg { 181 1.1 mrg return generateId(prefix, suffix, false); 182 1.1 mrg } 183 1.1 mrg 184 1.1 mrg /// ditto 185 1.1 mrg static Identifier generateId(const(char)* prefix, size_t length, size_t suffix) 186 1.1 mrg { 187 1.1 mrg return generateId(prefix[0 .. length], suffix); 188 1.1 mrg } 189 1.1 mrg 190 1.1 mrg // Generates a new, unique, suffix for an identifier. 191 1.1 mrg extern (D) private static size_t newSuffix() 192 1.1 mrg { 193 1.1 mrg __gshared size_t i; 194 1.1 mrg return ++i; 195 1.1 mrg } 196 1.1 mrg 197 1.1 mrg extern(D) private static Identifier generateId(const(char)[] prefix, size_t suffix, bool isAnonymous) 198 1.1 mrg { 199 1.1 mrg OutBuffer buf; 200 1.1 mrg buf.write(prefix); 201 1.1 mrg buf.print(suffix); 202 1.1 mrg return idPool(buf[], isAnonymous); 203 1.1 mrg } 204 1.1 mrg 205 1.1 mrg /*************************************** 206 1.1 mrg * Generate deterministic named identifier based on a source location, 207 1.1 mrg * such that the name is consistent across multiple compilations. 208 1.1 mrg * A new unique name is generated. If the prefix+location is already in 209 1.1 mrg * the stringtable, an extra suffix is added (starting the count at "_1"). 210 1.1 mrg * 211 1.1 mrg * Params: 212 1.1 mrg * prefix = first part of the identifier name. 213 1.1 mrg * loc = source location to use in the identifier name. 214 1.1 mrg * Returns: 215 1.1 mrg * Identifier (inside Identifier.idPool) with deterministic name based 216 1.1 mrg * on the source location. 217 1.1 mrg */ 218 1.1 mrg extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc) 219 1.1 mrg { 220 1.1 mrg // generate `<prefix>_L<line>_C<col>` 221 1.1 mrg OutBuffer idBuf; 222 1.1 mrg idBuf.writestring(prefix); 223 1.1 mrg idBuf.writestring("_L"); 224 1.1 mrg idBuf.print(loc.linnum); 225 1.1 mrg idBuf.writestring("_C"); 226 1.1 mrg idBuf.print(loc.charnum); 227 1.1 mrg 228 1.1 mrg /** 229 1.1 mrg * Make sure the identifiers are unique per filename, i.e., per module/mixin 230 1.1 mrg * (`path/to/foo.d` and `path/to/foo.d-mixin-<line>`). See issues 231 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=16995 232 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=18097 233 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=18111 234 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=18880 235 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=18868 236 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=19058 237 1.1 mrg */ 238 1.1 mrg static struct Key { Loc loc; string prefix; } 239 1.1 mrg __gshared uint[Key] counters; 240 1.1 mrg 241 1.1 mrg static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u))) 242 1.1 mrg { 243 1.1 mrg // 2.082+ 244 1.1 mrg counters.update(Key(loc, prefix), 245 1.1 mrg () => 1u, // insertion 246 1.1 mrg (ref uint counter) // update 247 1.1 mrg { 248 1.1 mrg idBuf.writestring("_"); 249 1.1 mrg idBuf.print(counter); 250 1.1 mrg return counter + 1; 251 1.1 mrg } 252 1.1 mrg ); 253 1.1 mrg } 254 1.1 mrg else 255 1.1 mrg { 256 1.1 mrg const key = Key(loc, prefix); 257 1.1 mrg if (auto pCounter = key in counters) 258 1.1 mrg { 259 1.1 mrg idBuf.writestring("_"); 260 1.1 mrg idBuf.print((*pCounter)++); 261 1.1 mrg } 262 1.1 mrg else 263 1.1 mrg counters[key] = 1; 264 1.1 mrg } 265 1.1 mrg 266 1.1 mrg return idPool(idBuf[]); 267 1.1 mrg } 268 1.1 mrg 269 1.1 mrg /******************************************** 270 1.1 mrg * Create an identifier in the string table. 271 1.1 mrg */ 272 1.1 mrg static Identifier idPool(const(char)* s, uint len) 273 1.1 mrg { 274 1.1 mrg return idPool(s[0 .. len]); 275 1.1 mrg } 276 1.1 mrg 277 1.1 mrg extern (D) static Identifier idPool(const(char)[] s) 278 1.1 mrg { 279 1.1 mrg return idPool(s, false); 280 1.1 mrg } 281 1.1 mrg 282 1.1 mrg extern (D) private static Identifier idPool(const(char)[] s, bool isAnonymous) 283 1.1 mrg { 284 1.1 mrg auto sv = stringtable.update(s); 285 1.1 mrg auto id = sv.value; 286 1.1 mrg if (!id) 287 1.1 mrg { 288 1.1 mrg id = new Identifier(sv.toString(), TOK.identifier, isAnonymous); 289 1.1 mrg sv.value = id; 290 1.1 mrg } 291 1.1 mrg return id; 292 1.1 mrg } 293 1.1 mrg 294 1.1 mrg extern (D) static Identifier idPool(const(char)* s, size_t len, int value) 295 1.1 mrg { 296 1.1 mrg return idPool(s[0 .. len], value); 297 1.1 mrg } 298 1.1 mrg 299 1.1 mrg extern (D) static Identifier idPool(const(char)[] s, int value) 300 1.1 mrg { 301 1.1 mrg auto sv = stringtable.insert(s, null); 302 1.1 mrg assert(sv); 303 1.1 mrg auto id = new Identifier(sv.toString(), value); 304 1.1 mrg sv.value = id; 305 1.1 mrg return id; 306 1.1 mrg } 307 1.1 mrg 308 1.1 mrg /********************************** 309 1.1 mrg * Determine if string is a valid Identifier. 310 1.1 mrg * Params: 311 1.1 mrg * str = string to check 312 1.1 mrg * Returns: 313 1.1 mrg * false for invalid 314 1.1 mrg */ 315 1.1 mrg static bool isValidIdentifier(const(char)* str) 316 1.1 mrg { 317 1.1 mrg return str && isValidIdentifier(str.toDString); 318 1.1 mrg } 319 1.1 mrg 320 1.1 mrg /********************************** 321 1.1 mrg * ditto 322 1.1 mrg */ 323 1.1 mrg extern (D) static bool isValidIdentifier(const(char)[] str) 324 1.1 mrg { 325 1.1 mrg if (str.length == 0 || 326 1.1 mrg (str[0] >= '0' && str[0] <= '9')) // beware of isdigit() on signed chars 327 1.1 mrg { 328 1.1 mrg return false; 329 1.1 mrg } 330 1.1 mrg 331 1.1 mrg size_t idx = 0; 332 1.1 mrg while (idx < str.length) 333 1.1 mrg { 334 1.1 mrg dchar dc; 335 1.1 mrg const s = utf_decodeChar(str, idx, dc); 336 1.1 mrg if (s || 337 1.1 mrg !((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) 338 1.1 mrg { 339 1.1 mrg return false; 340 1.1 mrg } 341 1.1 mrg } 342 1.1 mrg return true; 343 1.1 mrg } 344 1.1 mrg 345 1.1 mrg extern (D) static Identifier lookup(const(char)* s, size_t len) 346 1.1 mrg { 347 1.1 mrg return lookup(s[0 .. len]); 348 1.1 mrg } 349 1.1 mrg 350 1.1 mrg extern (D) static Identifier lookup(const(char)[] s) 351 1.1 mrg { 352 1.1 mrg auto sv = stringtable.lookup(s); 353 1.1 mrg if (!sv) 354 1.1 mrg return null; 355 1.1 mrg return sv.value; 356 1.1 mrg } 357 1.1 mrg 358 1.1 mrg extern (D) static void initTable() 359 1.1 mrg { 360 1.1 mrg stringtable._init(28_000); 361 1.1 mrg } 362 1.1 mrg } 363