Home | History | Annotate | Line # | Download | only in dmd
      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