1
/**
2
 * Defines an identifier, which is the name of a `Dsymbol`.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_identifier.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/identifier.d
10
 */
11

12
module dmd.identifier;
13

14
import core.stdc.ctype;
15
import core.stdc.stdio;
16
import core.stdc.string;
17
import dmd.globals;
18
import dmd.id;
19
import dmd.root.outbuffer;
20
import dmd.root.rootobject;
21
import dmd.root.string;
22
import dmd.root.stringtable;
23
import dmd.tokens;
24
import dmd.utf;
25

26

27
/***********************************************************
28
 */
29
extern (C++) final class Identifier : RootObject
30
{
31
    private const int value;
32
    private const char[] name;
33

34
nothrow:
35

36
    /// Construct an identifier from the given name.
37 1
    extern (D) this(const(char)* name)
38
    {
39
        //printf("Identifier('%s', %d)\n", name, value);
40 1
        this(name.toDString(), TOK.identifier);
41
    }
42

43
    /**
44
       Construct an identifier from the given name.
45

46
       Params:
47
         name = the identifier name. There must be `'\0'` at `name[length]`.
48
         length = the length of `name`, excluding the terminating `'\0'`
49
         value = Identifier value (e.g. `Id.unitTest`) or `TOK.identifier`
50
     */
51 0
    extern (D) this(const(char)* name, size_t length, int value)
52
    in
53
    {
54 0
        assert(name[length] == '\0');
55
    }
56
    do
57
    {
58
        //printf("Identifier('%s', %d)\n", name, value);
59 0
        this(name[0 .. length], value);
60
    }
61

62
    /// ditto
63 1
    extern (D) this(const(char)[] name, int value)
64
    {
65
        //printf("Identifier('%.*s', %d)\n", cast(int)name.length, name.ptr, value);
66 1
        this.name = name;
67 1
        this.value = value;
68
    }
69

70
    /// Sentinel for an anonymous identifier.
71
    static Identifier anonymous()
72
    {
73 1
        __gshared Identifier anonymous;
74

75 1
        if (anonymous)
76 1
            return anonymous;
77

78 1
        return anonymous = new Identifier("__anonymous", TOK.identifier);
79
    }
80

81
    static Identifier create(const(char)* name)
82
    {
83 1
        return new Identifier(name);
84
    }
85

86
    override const(char)* toChars() const pure
87
    {
88 1
        return name.ptr;
89
    }
90

91
    extern (D) override const(char)[] toString() const pure
92
    {
93 1
        return name;
94
    }
95

96
    int getValue() const pure
97
    {
98 1
        return value;
99
    }
100

101
    const(char)* toHChars2() const
102
    {
103 1
        const(char)* p = null;
104 1
        if (this == Id.ctor)
105 1
            p = "this";
106 1
        else if (this == Id.dtor)
107 0
            p = "~this";
108 1
        else if (this == Id.unitTest)
109 0
            p = "unittest";
110 1
        else if (this == Id.dollar)
111 1
            p = "$";
112 1
        else if (this == Id.withSym)
113 0
            p = "with";
114 1
        else if (this == Id.result)
115 0
            p = "result";
116 1
        else if (this == Id.returnLabel)
117 0
            p = "return";
118
        else
119
        {
120 1
            p = toChars();
121 1
            if (*p == '_')
122
            {
123 1
                if (strncmp(p, "_staticCtor", 11) == 0)
124 0
                    p = "static this";
125 1
                else if (strncmp(p, "_staticDtor", 11) == 0)
126 0
                    p = "static ~this";
127 1
                else if (strncmp(p, "__invariant", 11) == 0)
128 0
                    p = "invariant";
129
            }
130
        }
131 1
        return p;
132
    }
133

134
    override DYNCAST dyncast() const
135
    {
136 1
        return DYNCAST.identifier;
137
    }
138

139
    private extern (D) __gshared StringTable!Identifier stringtable;
140

141
    extern(D) static Identifier generateId(const(char)[] prefix)
142
    {
143 1
        __gshared size_t i;
144 1
        return generateId(prefix, ++i);
145
    }
146

147
    extern(D) static Identifier generateId(const(char)[] prefix, size_t i)
148
    {
149 1
        OutBuffer buf;
150 1
        buf.write(prefix);
151 1
        buf.print(i);
152 1
        return idPool(buf[]);
153
    }
154

155
    /***************************************
156
     * Generate deterministic named identifier based on a source location,
157
     * such that the name is consistent across multiple compilations.
158
     * A new unique name is generated. If the prefix+location is already in
159
     * the stringtable, an extra suffix is added (starting the count at "_1").
160
     *
161
     * Params:
162
     *      prefix      = first part of the identifier name.
163
     *      loc         = source location to use in the identifier name.
164
     * Returns:
165
     *      Identifier (inside Identifier.idPool) with deterministic name based
166
     *      on the source location.
167
     */
168
    extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc)
169
    {
170
        // generate `<prefix>_L<line>_C<col>`
171 1
        OutBuffer idBuf;
172 1
        idBuf.writestring(prefix);
173 1
        idBuf.writestring("_L");
174 1
        idBuf.print(loc.linnum);
175 1
        idBuf.writestring("_C");
176 1
        idBuf.print(loc.charnum);
177

178
        /**
179
         * Make sure the identifiers are unique per filename, i.e., per module/mixin
180
         * (`path/to/foo.d` and `path/to/foo.d-mixin-<line>`). See issues
181
         * https://issues.dlang.org/show_bug.cgi?id=16995
182
         * https://issues.dlang.org/show_bug.cgi?id=18097
183
         * https://issues.dlang.org/show_bug.cgi?id=18111
184
         * https://issues.dlang.org/show_bug.cgi?id=18880
185
         * https://issues.dlang.org/show_bug.cgi?id=18868
186
         * https://issues.dlang.org/show_bug.cgi?id=19058
187
         */
188
        static struct Key { Loc loc; string prefix; }
189 1
        __gshared uint[Key] counters;
190

191
        static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u)))
192
        {
193
            // 2.082+
194 1
            counters.update(Key(loc, prefix),
195 1
                () => 1u,          // insertion
196
                (ref uint counter) // update
197
                {
198 1
                    idBuf.writestring("_");
199 1
                    idBuf.print(counter);
200 1
                    return counter + 1;
201
                }
202
            );
203
        }
204
        else
205
        {
206
            const key = Key(loc, prefix);
207
            if (auto pCounter = key in counters)
208
            {
209
                idBuf.writestring("_");
210
                idBuf.print((*pCounter)++);
211
            }
212
            else
213
                counters[key] = 1;
214
        }
215

216 1
        return idPool(idBuf[]);
217
    }
218

219
    /********************************************
220
     * Create an identifier in the string table.
221
     */
222
    static Identifier idPool(const(char)* s, uint len)
223
    {
224 1
        return idPool(s[0 .. len]);
225
    }
226

227
    extern (D) static Identifier idPool(const(char)[] s)
228
    {
229 1
        auto sv = stringtable.update(s);
230 1
        auto id = sv.value;
231 1
        if (!id)
232
        {
233 1
            id = new Identifier(sv.toString(), TOK.identifier);
234 1
            sv.value = id;
235
        }
236 1
        return id;
237
    }
238

239
    extern (D) static Identifier idPool(const(char)* s, size_t len, int value)
240
    {
241 1
        return idPool(s[0 .. len], value);
242
    }
243

244
    extern (D) static Identifier idPool(const(char)[] s, int value)
245
    {
246 1
        auto sv = stringtable.insert(s, null);
247 1
        assert(sv);
248 1
        auto id = new Identifier(sv.toString(), value);
249 1
        sv.value = id;
250 1
        return id;
251
    }
252

253
    /**********************************
254
     * Determine if string is a valid Identifier.
255
     * Params:
256
     *      str = string to check
257
     * Returns:
258
     *      false for invalid
259
     */
260
    static bool isValidIdentifier(const(char)* str)
261
    {
262 1
        return str && isValidIdentifier(str.toDString);
263
    }
264

265
    /**********************************
266
     * ditto
267
     */
268
    extern (D) static bool isValidIdentifier(const(char)[] str)
269
    {
270 1
        if (str.length == 0 ||
271 1
            (str[0] >= '0' && str[0] <= '9')) // beware of isdigit() on signed chars
272
        {
273 1
            return false;
274
        }
275

276 1
        size_t idx = 0;
277 1
        while (idx < str.length)
278
        {
279 1
            dchar dc;
280 1
            const s = utf_decodeChar(str, idx, dc);
281 1
            if (s ||
282 1
                !((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
283
            {
284 1
                return false;
285
            }
286
        }
287 1
        return true;
288
    }
289

290
    extern (D) static Identifier lookup(const(char)* s, size_t len)
291
    {
292 1
        return lookup(s[0 .. len]);
293
    }
294

295
    extern (D) static Identifier lookup(const(char)[] s)
296
    {
297 1
        auto sv = stringtable.lookup(s);
298 1
        if (!sv)
299 1
            return null;
300 1
        return sv.value;
301
    }
302

303
    extern (D) static void initTable()
304
    {
305 1
        stringtable._init(28_000);
306
    }
307
}

Read our documentation on viewing source code .

Loading