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