1 module source.name;
2 
3 import source.context;
4 
5 struct Name {
6 private:
7 	uint id;
8 	
9 	this(uint id) {
10 		this.id = id;
11 	}
12 	
13 public:
14 	@property
15 	bool isEmpty() const {
16 		return this == BuiltinName!"";
17 	}
18 	
19 	@property
20 	bool isReserved() const {
21 		return id < (Names.length - Prefill.length);
22 	}
23 	
24 	@property
25 	bool isDefined() const {
26 		return id != 0;
27 	}
28 	
29 	auto getFullName(const Context c) const {
30 		return FullName(this, c);
31 	}
32 	
33 	string toString(const Context c) const {
34 		return getFullName(c).toString();
35 	}
36 	
37 	immutable(char)* toStringz(const Context c) const {
38 		return getFullName(c).toStringz();
39 	}
40 }
41 
42 template BuiltinName(string name) {
43 	private enum id = Lookups.get(name, uint.max);
44 	static assert(id < uint.max, name ~ " is not a builtin name.");
45 	enum BuiltinName = Name(id);
46 }
47 
48 struct FullName {
49 private:
50 	Name _name;
51 	const Context context;
52 	
53 	this(Name name, const Context context) {
54 		this._name = name;
55 		this.context = context;
56 	}
57 	
58 	@property
59 	ref nameManager() const {
60 		return context.nameManager;
61 	}
62 	
63 public:
64 	alias name this;
65 	@property name() const {
66 		return _name;
67 	}
68 	
69 	string toString() const {
70 		return nameManager.names[id];
71 	}
72 	
73 	immutable(char)* toStringz() const {
74 		auto s = toString();
75 		assert(s.ptr[s.length] == '\0', "Expected a zero terminated string");
76 		return s.ptr;
77 	}
78 }
79 
80 struct NameManager {
81 private:
82 	string[] names;
83 	uint[string] lookups;
84 
85 	// Make it non copyable.
86 	@disable this(this);
87 
88 package:
89 	static get() {
90 		return NameManager(Names, Lookups);
91 	}
92 
93 public:
94 	auto getName(const(char)[] str) {
95 		if (auto id = str in lookups) {
96 			return Name(*id);
97 		}
98 		
99 		// As we are cloning, make sure it is 0 terminated as to pass to C.
100 		import std.string;
101 		auto s = str.toStringz()[0 .. str.length];
102 		
103 		// Make sure we do not keep around slice of potentially large input.
104 		scope(exit) assert(str.ptr !is s.ptr, s);
105 		
106 		auto id = lookups[s] = cast(uint) names.length;
107 		names ~= s;
108 		
109 		return Name(id);
110 	}
111 	
112 	void dump() {
113 		foreach(s; names) {
114 			import std.stdio;
115 			writeln(lookups[s], "\t=> ", s);
116 		}
117 	}
118 }
119 
120 private:
121 
122 enum Reserved = ["__ctor", "__dtor", "__postblit", "__vtbl"];
123 
124 enum Prefill = [
125 	// Linkages
126 	"C", "D", "C++", "Windows", "System", "Pascal", "Java",
127 	// Version
128 	"SDC", "D_LP64", "X86_64", "linux", "OSX", "FreeBSD", "Posix",
129 	// Generated
130 	"init", "length", "max", "min", "ptr", "sizeof", "alignof",
131 	// Scope
132 	"exit", "success", "failure",
133 	// Main
134 	"main", "_Dmain",
135 	// Defined in object
136 	"object", "size_t", "ptrdiff_t", "string",
137 	"Object",
138 	"TypeInfo", "ClassInfo",
139 	"Throwable", "Exception", "Error",
140 	// Attribute
141 	"property", "safe", "trusted", "system", "nogc",
142 	// Runtime
143 	"__sd_assert_fail",
144 	"__sd_assert_fail_msg",
145 	"__sd_class_downcast",
146 	"__sd_eh_throw",
147 	"__sd_eh_personality",
148 	"__sd_array_concat",
149 	"__sd_array_outofbounds",
150 	"__sd_gc_tl_malloc",
151 	// Generated symbols
152 	"__ctx",
153 	"__dg",
154 	"__lambda",
155 	"__unittest",
156 	// Used to make IR more comprehensible.
157 	"entry", "then", "unwind", "resume", "destroy", "cleanup",
158 	"assert.fail", "assert.success", "scope.entry",
159 	"endif", "endswitch", "endcatch", "unreachable",
160 	"loop.continue", "loop.test", "loop.body", "loop.exit",
161 	// Intrinsics
162 	"3sdc10intrinsics", "expect", "cas", "casWeak", "popCount",
163 	"countLeadingZeros", "countTrailingZeros", "bswap",
164 ];
165 
166 auto getNames() {
167 	import source.dlexer;
168 	
169 	auto identifiers = [""];
170 	foreach(k, _; getOperatorsMap()) {
171 		identifiers ~= k;
172 	}
173 	
174 	foreach(k, _; getKeywordsMap()) {
175 		identifiers ~= k;
176 	}
177 	
178 	return identifiers ~ Reserved ~ Prefill;
179 }
180 
181 enum Names = getNames();
182 
183 static assert(Names[0] == "");
184 
185 auto getLookups() {
186 	// XXX: DMD zero terminate here, but I'd like to not rely on it :/
187 	uint[string] lookups;
188 	foreach(i, id; Names) {
189 		lookups[id] = cast(uint) i;
190 	}
191 	
192 	return lookups;
193 }
194 
195 enum Lookups = getLookups();