1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _identifier.d)
9  */
10 
11 module ddmd.identifier;
12 
13 import core.stdc.ctype;
14 import core.stdc.stdio;
15 import core.stdc..string;
16 import ddmd.globals;
17 import ddmd.id;
18 import ddmd.root.outbuffer;
19 import ddmd.root.rootobject;
20 import ddmd.root.stringtable;
21 import ddmd.tokens;
22 import ddmd.utf;
23 
24 /***********************************************************
25  */
26 extern (C++) final class Identifier : RootObject
27 {
28 private:
29     const int value;
30     const char* string;
31     const size_t len;
32 
33 public:
34 
35     extern (D) this(const(char)* string, size_t length, int value)
36     {
37         //printf("Identifier('%s', %d)\n", string, value);
38         this.string = string;
39         this.value = value;
40         this.len = length;
41     }
42 
43     extern (D) this(const(char)* string)
44     {
45         //printf("Identifier('%s', %d)\n", string, value);
46         this(string, strlen(string), TOKidentifier);
47     }
48 
49     static Identifier create(const(char)* string)
50     {
51         return new Identifier(string);
52     }
53 
54     override bool equals(RootObject o) const
55     {
56         return this == o || strncmp(string, o.toChars(), len + 1) == 0;
57     }
58 
59     override int compare(RootObject o) const
60     {
61         return strncmp(string, o.toChars(), len + 1);
62     }
63 
64     override void print() const
65     {
66         fprintf(stderr, "%s", string);
67     }
68 
69     override const(char)* toChars() const
70     {
71         return string;
72     }
73 
74     extern (D) final const(char)[] toString() const
75     {
76         return string[0 .. len];
77     }
78 
79     final int getValue() const
80     {
81         return value;
82     }
83 
84     const(char)* toHChars2() const
85     {
86         const(char)* p = null;
87         if (this == Id.ctor)
88             p = "this";
89         else if (this == Id.dtor)
90             p = "~this";
91         else if (this == Id.unitTest)
92             p = "unittest";
93         else if (this == Id.dollar)
94             p = "$";
95         else if (this == Id.withSym)
96             p = "with";
97         else if (this == Id.result)
98             p = "result";
99         else if (this == Id.returnLabel)
100             p = "return";
101         else
102         {
103             p = toChars();
104             if (*p == '_')
105             {
106                 if (strncmp(p, "_staticCtor", 11) == 0)
107                     p = "static this";
108                 else if (strncmp(p, "_staticDtor", 11) == 0)
109                     p = "static ~this";
110                 else if (strncmp(p, "__invariant", 11) == 0)
111                     p = "invariant";
112             }
113         }
114         return p;
115     }
116 
117     override int dyncast() const
118     {
119         return DYNCAST_IDENTIFIER;
120     }
121 
122     extern (C++) static __gshared StringTable stringtable;
123 
124     static Identifier generateId(const(char)* prefix)
125     {
126         static __gshared size_t i;
127         return generateId(prefix, ++i);
128     }
129 
130     static Identifier generateId(const(char)* prefix, size_t i)
131     {
132         OutBuffer buf;
133         buf.writestring(prefix);
134         buf.printf("%llu", cast(ulong)i);
135         return idPool(buf.peekSlice());
136     }
137 
138     /********************************************
139      * Create an identifier in the string table.
140      */
141     extern (D) static Identifier idPool(const(char)[] s)
142     {
143         return idPool(s.ptr, s.length);
144     }
145 
146     static Identifier idPool(const(char)* s, size_t len)
147     {
148         StringValue* sv = stringtable.update(s, len);
149         Identifier id = cast(Identifier)sv.ptrvalue;
150         if (!id)
151         {
152             id = new Identifier(sv.toDchars(), len, TOKidentifier);
153             sv.ptrvalue = cast(char*)id;
154         }
155         return id;
156     }
157 
158     extern (D) static Identifier idPool(const(char)* s, size_t len, int value)
159     {
160         auto sv = stringtable.insert(s, len, null);
161         assert(sv);
162         auto id = new Identifier(sv.toDchars(), len, value);
163         sv.ptrvalue = cast(char*)id;
164         return id;
165     }
166 
167     /**********************************
168      * Determine if string is a valid Identifier.
169      * Returns:
170      *      0       invalid
171      */
172     static bool isValidIdentifier(const(char)* p)
173     {
174         size_t len;
175         size_t idx;
176         if (!p || !*p)
177             goto Linvalid;
178         if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars
179             goto Linvalid;
180         len = strlen(p);
181         idx = 0;
182         while (p[idx])
183         {
184             dchar dc;
185             const q = utf_decodeChar(p, len, idx, dc);
186             if (q)
187                 goto Linvalid;
188             if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
189                 goto Linvalid;
190         }
191         return true;
192     Linvalid:
193         return false;
194     }
195 
196     static Identifier lookup(const(char)* s, size_t len)
197     {
198         auto sv = stringtable.lookup(s, len);
199         if (!sv)
200             return null;
201         return cast(Identifier)sv.ptrvalue;
202     }
203 
204     static void initTable()
205     {
206         stringtable._init(28000);
207     }
208 }