1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.compiler.mangle;
7 
8 import std.conv : to;
9 import std..string : indexOf;
10 import grimoire.compiler.type;
11 
12 /**
13     Mangle a signature of types.
14 
15     Example:
16     ---
17     [int, string, func(bool, float)]
18     ---
19     Will be mangled as `$i$s$f($b$f)()`
20 
21     The return type is not conserved in the mangled form as its not part of its signature.
22     But function. passed as parameters have theirs.
23 */
24 string grMangleSignature(GrType[] signature) {
25     string mangledName;
26     foreach (type; signature) {
27         mangledName ~= "$";
28         final switch (type.baseType) with (GrBaseType) {
29         case void_:
30             mangledName ~= "*";
31             break;
32         case null_:
33             mangledName ~= "0";
34             break;
35         case int_:
36             mangledName ~= "i";
37             break;
38         case float_:
39             mangledName ~= "r";
40             break;
41         case bool_:
42             mangledName ~= "b";
43             break;
44         case string_:
45             mangledName ~= "s";
46             break;
47         case array_:
48             mangledName ~= "n(" ~ type.mangledType ~ ")";
49             break;
50         case class_:
51             mangledName ~= "p(" ~ type.mangledType ~ ")";
52             break;
53         case enum_:
54             mangledName ~= "e(" ~ type.mangledType ~ ")";
55             break;
56         case foreign:
57             mangledName ~= "u(" ~ type.mangledType ~ ")";
58             break;
59         case function_:
60             mangledName ~= "f(" ~ type.mangledType ~ ")(" ~ type.mangledReturnType ~ ")";
61             break;
62         case task:
63             mangledName ~= "t(" ~ type.mangledType ~ ")";
64             break;
65         case chan:
66             mangledName ~= "c(" ~ type.mangledType ~ ")";
67             break;
68         case reference:
69             mangledName ~= "h(" ~ type.mangledType ~ ")";
70             break;
71         case internalTuple:
72             throw new Exception("Trying to mangle a tuple. Tuples should not exist here.");
73         }
74     }
75     return mangledName;
76 }
77 
78 /// Reverse the mangling operation for a signature.
79 GrType[] grUnmangleSignature(string mangledSignature) {
80     GrType[] unmangledSignature;
81 
82     int i;
83     while (i < mangledSignature.length) {
84         //Type separator
85         if (mangledSignature[i] != '$') {
86             throw new Exception("Invalid unmangle signature mangling format, missing $");
87         }
88         i++;
89 
90         //Value
91         GrType currentType = GrBaseType.void_;
92         switch (mangledSignature[i]) {
93         case '*':
94             currentType.baseType = GrBaseType.void_;
95             break;
96         case 'i':
97             currentType.baseType = GrBaseType.int_;
98             break;
99         case 'r':
100             currentType.baseType = GrBaseType.float_;
101             break;
102         case 'b':
103             currentType.baseType = GrBaseType.bool_;
104             break;
105         case 's':
106             currentType.baseType = GrBaseType.string_;
107             break;
108         case 'n':
109             i++;
110             currentType.baseType = GrBaseType.array_;
111             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
112             break;
113         case 'e':
114             currentType.baseType = GrBaseType.enum_;
115             string enumName;
116             if ((i + 2) >= mangledSignature.length)
117                 throw new Exception("Invalid mangling format");
118             i++;
119             if (mangledSignature[i] != '(')
120                 throw new Exception("Invalid mangling format");
121             i++;
122             while (mangledSignature[i] != ')') {
123                 enumName ~= mangledSignature[i];
124                 i++;
125                 if (i >= mangledSignature.length)
126                     throw new Exception("Invalid mangling format");
127             }
128             currentType.mangledType = enumName;
129             break;
130         case 'p':
131             currentType.baseType = GrBaseType.class_;
132             if ((i + 2) >= mangledSignature.length)
133                 throw new Exception("Invalid mangling format");
134             i++;
135             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
136             break;
137         case 'u':
138             currentType.baseType = GrBaseType.foreign;
139             if ((i + 2) >= mangledSignature.length)
140                 throw new Exception("Invalid mangling format");
141             i++;
142             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
143             break;
144         case 'f':
145             i++;
146             currentType.baseType = GrBaseType.function_;
147             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
148             i++;
149             currentType.mangledReturnType = grUnmangleBlock(mangledSignature, i);
150             break;
151         case 't':
152             i++;
153             currentType.baseType = GrBaseType.task;
154             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
155             break;
156         case 'c':
157             i++;
158             currentType.baseType = GrBaseType.chan;
159             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
160             break;
161         default:
162             break;
163         }
164         unmangledSignature ~= currentType;
165         i++;
166     }
167     return unmangledSignature;
168 }
169 
170 /**
171     Can be used to mangle a named function or a templated type.
172 
173     Example:
174     ---
175     func test(int i, string s, func(bool, float)) float {}
176     ---
177     Will be mangled as `test$i$s$f($b$f)()`
178 
179     The return type is not conserved in the mangled form as its not part of its signature.
180     But function. passed as parameters have theirs.
181 */
182 string grMangleComposite(string name, GrType[] signature) {
183     return name ~ grMangleSignature(signature);
184 }
185 
186 /// Reverses the grMangleComposite operation.
187 /// Returns a struct containing the name and the signature.
188 auto grUnmangleComposite(string mangledSignature) {
189     struct UnmangleCompositeResult {
190         string name;
191         GrType[] signature;
192     }
193 
194     UnmangleCompositeResult result;
195     size_t index = mangledSignature.indexOf('$');
196     if (index == -1) {
197         result.name = mangledSignature;
198         return result;
199     }
200     result.name = mangledSignature[0 .. index];
201     result.signature = grUnmangleSignature(mangledSignature[index .. $]);
202     return result;
203 }
204 
205 /// Reverse the mangling operation for a function passed as a parameter.
206 string grUnmangleBlock(string mangledSignature, ref int i) {
207     string subString;
208     int blockCount = 1;
209     if (i >= mangledSignature.length || mangledSignature[i] != '(')
210         throw new Exception("Invalid subType mangling format, missing (");
211     i++;
212 
213     for (; i < mangledSignature.length; i++) {
214         switch (mangledSignature[i]) {
215         case '(':
216             blockCount++;
217             break;
218         case ')':
219             blockCount--;
220             if (blockCount == 0) {
221                 return subString;
222             }
223             break;
224         default:
225             break;
226         }
227         subString ~= mangledSignature[i];
228     }
229     throw new Exception("Invalid subType mangling format, missing )");
230 }
231 
232 /// Reverse the mangling operation for a single type.
233 GrType grUnmangle(string mangledSignature) {
234     GrType currentType = GrBaseType.void_;
235 
236     int i;
237     if (i < mangledSignature.length) {
238         //Type separator
239         if (mangledSignature[i] != '$')
240             throw new Exception("Invalid unmangle mangling format, missing $");
241         i++;
242 
243         //Value
244         switch (mangledSignature[i]) {
245         case '*':
246             currentType.baseType = GrBaseType.void_;
247             break;
248         case 'i':
249             currentType.baseType = GrBaseType.int_;
250             break;
251         case 'r':
252             currentType.baseType = GrBaseType.float_;
253             break;
254         case 'b':
255             currentType.baseType = GrBaseType.bool_;
256             break;
257         case 's':
258             currentType.baseType = GrBaseType.string_;
259             break;
260         case 'n':
261             i++;
262             currentType.baseType = GrBaseType.array_;
263             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
264             i++;
265             break;
266         case 'e':
267             currentType.baseType = GrBaseType.enum_;
268             string enumName;
269             if ((i + 2) >= mangledSignature.length)
270                 throw new Exception("Invalid unmangle mangling format in struct");
271             i++;
272             if (mangledSignature[i] != '(')
273                 throw new Exception("Invalid unmangle mangling format in struct");
274             i++;
275             while (mangledSignature[i] != ')') {
276                 enumName ~= mangledSignature[i];
277                 i++;
278                 if (i >= mangledSignature.length)
279                     throw new Exception("Invalid unmangle mangling format in struct");
280             }
281             currentType.mangledType = enumName;
282             break;
283         case 'p':
284             currentType.baseType = GrBaseType.class_;
285             string structName;
286             if ((i + 2) >= mangledSignature.length)
287                 throw new Exception("Invalid unmangle mangling format in struct");
288             i++;
289             if (mangledSignature[i] != '(')
290                 throw new Exception("Invalid unmangle mangling format in struct");
291             i++;
292             while (mangledSignature[i] != ')') {
293                 structName ~= mangledSignature[i];
294                 i++;
295                 if (i >= mangledSignature.length)
296                     throw new Exception("Invalid unmangle mangling format in struct");
297             }
298             currentType.mangledType = structName;
299             break;
300         case 'u':
301             currentType.baseType = GrBaseType.foreign;
302             string foreignName;
303             if ((i + 2) >= mangledSignature.length)
304                 throw new Exception("Invalid unmangle mangling format in foreign");
305             i++;
306             if (mangledSignature[i] != '(')
307                 throw new Exception("Invalid unmangle mangling format in foreign");
308             i++;
309             while (mangledSignature[i] != ')') {
310                 foreignName ~= mangledSignature[i];
311                 i++;
312                 if (i >= mangledSignature.length)
313                     throw new Exception("Invalid unmangle mangling format in foreign");
314             }
315             currentType.mangledType = foreignName;
316             break;
317         case 'f':
318             i++;
319             currentType.baseType = GrBaseType.function_;
320             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
321             i++;
322             currentType.mangledReturnType = grUnmangleBlock(mangledSignature, i);
323             i++;
324             break;
325         case 't':
326             i++;
327             currentType.baseType = GrBaseType.task;
328             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
329             i++;
330             break;
331         case 'c':
332             i++;
333             currentType.baseType = GrBaseType.chan;
334             currentType.mangledType = grUnmangleBlock(mangledSignature, i);
335             i++;
336             break;
337         default:
338             break;
339         }
340     }
341 
342     return currentType;
343 }