1 
2 // This file is part of Visual D
3 //
4 // Visual D integrates the D programming language into Visual Studio
5 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved
6 //
7 // Distributed under the Boost Software License, Version 1.0.
8 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
9 
10 module vdc.util;
11 
12 import vdc.lexer;
13 
14 import std.conv;
15 import std.string;
16 import std.array;
17 
18 ////////////////////////////////////////////////////////////////
19 // use instead of assert() to be nicely breakable and avoid the bad
20 // semantics of assert(false)
21 void _assert(bool cond)
22 {
23     if(!cond)
24         assert(false);
25 }
26 
27 ////////////////////////////////////////////////////////////////
28 alias int TokenId;
29 enum NumTokens = TOK_end_Operators;
30 
31 struct TextPos
32 {
33     int index;
34     int line;
35 
36     int opCmp(ref const(TextPos) tp) const
37     {
38         if(line != tp.line)
39             return line - tp.line;
40         return index - tp.index;
41     }
42 }
43 
44 struct TextSpan
45 {
46     TextPos start;
47     TextPos end;
48 }
49 
50 // returns < 0 if adr1 < adr2
51 int compareTextSpanAddress(int line1, int index1, int line2, int index2)
52 {
53     int difflines = line1 - line2;
54     if(difflines != 0)
55         return difflines;
56     return index1 - index2;
57 }
58 
59 bool textSpanContains(ref const(TextSpan) span, int line, int index)
60 {
61     return compareTextSpanAddress(span.start.line, span.start.index, line, index) <= 0
62         && compareTextSpanAddress(span.end.line,   span.end.index,   line, index) > 0;
63 }
64 
65 
66 class Token
67 {
68     TokenId id; // terminals and non-terminals
69     string txt;
70     TextSpan span;
71 
72     void copy(const(Token) tok)
73     {
74         id = tok.id;
75         txt = tok.txt;
76         span = tok.span;
77     }
78 }
79 
80 ////////////////////////////////////////////////////////////////
81 string genFlagsEnum(string name, string prefix, string[] allMembers)
82 {
83     string s = "enum " ~ name ~ " { ";
84     foreach(i, c; allMembers)
85         s ~= prefix ~ c ~ " = 1 << " ~ to!string(i) ~ ", ";
86     s ~= "}";
87     return s;
88 }
89 
90 // Attribute also used for storage class
91 enum AttrBits
92 {
93     Extern,
94     Synchronized,
95     Static,
96     Final,
97     Abstract,
98     Const,
99     Auto,
100     Scope,
101     Ref,
102     Volatile,
103     Gshared,
104     Thread,
105     Shared,
106     Immutable,
107     Pure,
108     Nothrow,
109     Inout,
110     ExternC,
111     ExternCPP,
112     ExternD,
113     ExternWindows,
114     ExternSystem,
115     Export,
116     Align,
117     Align1,
118     Align2,
119     Align4,
120     Align8,
121     Align16,
122 }
123 
124 mixin(genFlagsEnum("", "Attr_", [__traits(allMembers,AttrBits)]));
125 
126 enum Attr_AlignMask  = Attr_Align | Attr_Align1 | Attr_Align2 | Attr_Align4 | Attr_Align8 | Attr_Align16;
127 enum Attr_CallMask   = Attr_ExternC | Attr_ExternCPP | Attr_ExternD | Attr_ExternWindows | Attr_ExternSystem;
128 enum Attr_ShareMask  = Attr_Shared | Attr_Gshared | Attr_Thread;
129 
130 alias uint Attribute;
131 
132 Attribute tokenToAttribute(TokenId tok)
133 {
134     switch(tok)
135     {
136         case TOK_extern:       return Attr_Extern;
137         case TOK_synchronized: return Attr_Synchronized;
138         case TOK_static:       return Attr_Static;
139         case TOK_final:        return Attr_Final;
140         case TOK_abstract:     return Attr_Abstract;
141         case TOK_const:        return Attr_Const;
142         case TOK_auto:         return Attr_Auto;
143         case TOK_scope:        return Attr_Scope;
144         case TOK_ref:          return Attr_Ref;
145         case TOK_volatile:     return Attr_Volatile;
146         case TOK___gshared:    return Attr_Gshared;
147         case TOK___thread:     return Attr_Thread;
148         case TOK_shared:       return Attr_Shared;
149         case TOK_immutable:    return Attr_Immutable;
150         case TOK_pure:         return Attr_Pure;
151         case TOK_nothrow:      return Attr_Nothrow;
152         case TOK_inout:        return Attr_Inout;
153         case TOK_export:       return Attr_Export;
154         case TOK_align:        return Attr_Align;
155         default: return 0;
156     }
157 }
158 
159 TokenId attributeToToken(Attribute attr)
160 {
161     switch(attr)
162     {
163         case Attr_Extern:       return TOK_extern;
164         case Attr_Synchronized: return TOK_synchronized;
165         case Attr_Static:       return TOK_static;
166         case Attr_Final:        return TOK_final;
167         case Attr_Abstract:     return TOK_abstract;
168         case Attr_Const:        return TOK_const;
169         case Attr_Auto:         return TOK_auto;
170         case Attr_Scope:        return TOK_scope;
171         case Attr_Ref:          return TOK_ref;
172         case Attr_Volatile:     return TOK_volatile;
173         case Attr_Gshared:      return TOK___gshared;
174         case Attr_Thread:       return TOK___thread;
175         case Attr_Shared:       return TOK_shared;
176         case Attr_Immutable:    return TOK_immutable;
177         case Attr_Pure:         return TOK_pure;
178         case Attr_Nothrow:      return TOK_nothrow;
179         case Attr_Inout:        return TOK_inout;
180         case Attr_Export:       return TOK_export;
181         case Attr_Align:        return TOK_align;
182         default: return -1;
183     }
184 }
185 
186 Attribute combineAttributes(Attribute attr, Attribute newAttr)
187 {
188     if(newAttr & Attr_AlignMask)
189         attr &= ~Attr_AlignMask;
190     if(newAttr & Attr_CallMask)
191         attr &= ~Attr_CallMask;
192     if(newAttr & Attr_ShareMask)
193         attr &= ~Attr_ShareMask;
194     return attr | newAttr;
195 }
196 
197 string attrToString(Attribute attr)
198 {
199     switch(attr)
200     {
201         case Attr_Extern:        return "extern";
202         case Attr_Synchronized:  return "synchronized";
203         case Attr_Static:        return "static";
204         case Attr_Final:         return "final";
205         case Attr_Abstract:      return "abstract";
206         case Attr_Const:         return "const";
207         case Attr_Auto:          return "auto";
208         case Attr_Scope:         return "scope";
209         case Attr_Ref:           return "ref";
210         case Attr_Volatile:      return "volatile";
211         case Attr_Gshared:       return "__gshared";
212         case Attr_Thread:        return "__thread";
213         case Attr_Shared:        return "shared";
214         case Attr_Immutable:     return "immutable";
215         case Attr_Pure:          return "pure";
216         case Attr_Nothrow:       return "nothrow";
217         case Attr_Inout:         return "inout";
218         case Attr_ExternC:       return "extern(C)";
219         case Attr_ExternCPP:     return "extern(C++)";
220         case Attr_ExternD:       return "extern(D)";
221         case Attr_ExternWindows: return "extern(Windows)";
222         case Attr_ExternSystem:  return "extern(System)";
223         case Attr_Export:        return "export";
224         case Attr_Align:         return "align";
225         case Attr_Align1:        return "align(1)";
226         case Attr_Align2:        return "align(2)";
227         case Attr_Align4:        return "align(4)";
228         case Attr_Align8:        return "align(8)";
229         case Attr_Align16:       return "align(16)";
230         default: assert(false);
231     }
232 }
233 
234 string attrToStringC(Attribute attr)
235 {
236     // Compiler-Specific
237     switch(attr)
238     {
239         case Attr_Extern:        return "extern";
240         case Attr_Synchronized:  return "";
241         case Attr_Static:        return "static";
242         case Attr_Final:         return "";
243         case Attr_Abstract:      return "";
244         case Attr_Const:         return "const";
245         case Attr_Auto:          return "auto";
246         case Attr_Scope:         return "scope";
247         case Attr_Ref:           return "ref";
248         case Attr_Volatile:      return "volatile";
249         case Attr_Gshared:       return "";
250         case Attr_Thread:        return "__declspec(thread)";
251         case Attr_Shared:        return "shared";
252         case Attr_Immutable:     return "const";
253         case Attr_Pure:          return "";
254         case Attr_Nothrow:       return "";
255         case Attr_Inout:         return "";
256         case Attr_ExternC:       return "extern \"C\"";
257         case Attr_ExternCPP:     return "";
258         case Attr_ExternD:       return "";
259         case Attr_ExternWindows: return "__stdcall";
260         case Attr_ExternSystem:  return "__stdcall";
261         case Attr_Export:        return "__declspec(dllexport)";
262         case Attr_Align:         return "__declspec(align(4))";
263         case Attr_Align1:        return "__declspec(align(1))";
264         case Attr_Align2:        return "__declspec(align(2))";
265         case Attr_Align4:        return "__declspec(align(4))";
266         case Attr_Align8:        return "__declspec(align(8))";
267         case Attr_Align16:       return "__declspec(align(16))";
268         default: assert(false);
269     }
270 }
271 
272 ////////////////////////////////////////////////////////////////
273 enum AnnotationBits
274 {
275     Deprecated,
276     Override,
277     Private,
278     Package,
279     Protected,
280     Nogc,
281     Public,
282     Export,
283     Disable,
284     Property,
285     Safe,
286     System,
287     Trusted,
288 }
289 
290 mixin(genFlagsEnum("", "Annotation_", [__traits(allMembers,AnnotationBits)]));
291 
292 alias uint Annotation;
293 
294 enum Annotation_ProtectionMask = Annotation_Private | Annotation_Protected | Annotation_Public | Annotation_Package;
295 enum Annotation_SafeMask       = Annotation_Safe | Annotation_System | Annotation_Trusted;
296 
297 Annotation tokenToAnnotation(TokenId tok)
298 {
299     switch(tok)
300     {
301         case TOK_deprecated: return Annotation_Deprecated;
302         case TOK_override:   return Annotation_Override;
303         case TOK_disable:    return Annotation_Disable;
304         case TOK_property:   return Annotation_Property;
305         case TOK_nogc:       return Annotation_Nogc;
306         case TOK_safe:       return Annotation_Safe;
307         case TOK_system:     return Annotation_System;
308         case TOK_trusted:    return Annotation_Trusted;
309         default:             return 0;
310     }
311 }
312 
313 Annotation tokenToProtection(TokenId tok)
314 {
315     switch(tok)
316     {
317         case TOK_private:   return Annotation_Private;
318         case TOK_package:   return Annotation_Package;
319         case TOK_protected: return Annotation_Protected;
320         case TOK_public:    return Annotation_Public;
321         case TOK_export:    return Annotation_Export;
322         default:            return 0;
323     }
324 }
325 
326 Annotation combineAnnotations(Annotation annot, Annotation newAnnot)
327 {
328     if(newAnnot & Annotation_ProtectionMask)
329         annot &= ~Annotation_ProtectionMask;
330     if(newAnnot & Annotation_SafeMask)
331         annot &= ~Annotation_SafeMask;
332     return annot | newAnnot;
333 }
334 
335 string annotationToString(Annotation annot)
336 {
337     switch(annot)
338     {
339         case Annotation_Deprecated:return "deprecated";
340         case Annotation_Override:  return "override";
341         case Annotation_Disable:   return "@disable";
342         case Annotation_Property:  return "@property";
343         case Annotation_Nogc:      return "@nogc";
344         case Annotation_Safe:      return "@safe";
345         case Annotation_System:    return "@system";
346         case Annotation_Trusted:   return "@trusted";
347         case Annotation_Private:   return "private";
348         case Annotation_Package:   return "package";
349         case Annotation_Protected: return "protected";
350         case Annotation_Public:    return "public";
351         case Annotation_Export:    return "export";
352         default: assert(false);
353     }
354 }
355 
356 ////////////////////////////////////////////////////////////////
357 string _mixinGetClasses(allMembers...)()
358 {
359     string s;
360     foreach(c; allMembers)
361         s ~= "if(is(" ~ c ~ " == class)) classes ~= `" ~ c ~ "`;";
362     return s;
363 }
364 
365 string[] getClasses(allMembers...)()
366 {
367     string[] classes;
368     mixin(_mixinGetClasses!(allMembers));
369     return classes;
370 }
371 
372 string genClassEnum(allMembers...)(string name, string prefix, int off)
373 {
374     string[] classes = getClasses!allMembers();
375 
376     string s = "enum " ~ name ~ " { ";
377     bool first = true;
378     foreach(c; classes)
379     {
380         if(first)
381             s ~= prefix ~ c ~ " = " ~ to!string(off) ~ ", ";
382         else
383             s ~= prefix ~ c ~ ", ";
384         first = false;
385     }
386     if(prefix.length > 0)
387         s ~= prefix ~ "end";
388     s ~= " }";
389     return s;
390 }
391 
392 version(none)
393 mixin(genClassEnum!(__traits(allMembers,vdc.parser.expr),
394                     __traits(allMembers,vdc.parser.decl),
395                     __traits(allMembers,vdc.parser.stmt),
396                     __traits(allMembers,vdc.parser.mod),
397                     __traits(allMembers,vdc.parser.aggr),
398                     __traits(allMembers,vdc.parser.misc))("", "NT_", TOK_end_Operators));