1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity low)
4 module dil.semantic.Mangler;
5 
6 import dil.ast.Visitor,
7        dil.ast.Node,
8        dil.ast.Expressions;
9 import dil.semantic.TypesEnum;
10 import dil.i18n.Messages;
11 import dil.Float,
12        dil.Unicode,
13        dil.String,
14        dil.Diagnostics;
15 import common;
16 
17 /// Mangles expressions used as template arguments.
18 class TArgMangler : Visitor2
19 {
20   char[] text; /// The mangled text.
21   Diagnostics diag;
22   string filePath;
23 
24   void mangleFloat(Float f)
25   {
26     if (f.isNaN())
27       text ~= "NAN";
28     // FIXME:
29     // Replace('-', 'N')
30     // Ignore('+', 'X', '.')
31     // Ignore leading 0. E.g.: "0X123" -> "123"
32 
33     // Converting from Float to long double is probably inaccurate.
34     // Matching the mangled strings of DMD will be difficult.
35     // Just use Float.toString() for now.
36     text ~= f.toString();
37   }
38 
39   /// Issues an error message.
40   void error(Token* tok, MID mid, ...)
41   {
42     auto location = tok.getErrorLocation(filePath);
43     auto msg = diag.formatMsg(mid, _arguments, _argptr);
44     auto error = new SemanticError(location, msg);
45     diag ~= error;
46   }
47 
48   void utf16Error(Token* tok, cwstring s, size_t i)
49   {
50     auto e = dil.Unicode.utf16Error(s, i);
51     ushort arg1 = s[i-1], arg2 = arg1;
52     MID mid = MID.InvalidUTF16Sequence;
53     if (e == UTF16Error.Invalid)
54       arg1 = s[i-2];
55     else if (e == UTF16Error.LoSurrogate)
56       mid = MID.MissingLowSurrogate;
57     else if (e == UTF16Error.HiSurrogate)
58       mid = MID.MissingHighSurrogate;
59     else
60       assert(0);
61     error(tok, mid, arg1, arg2);
62   }
63 
64 override:
65   alias visit = super.visit;
66 
67   void unhandled(Node n)
68   {
69     error(n.begin, MID.InvalidTemplateArgument, n.toText());
70   }
71 
72   void visit(IntExpr e)
73   {
74     if (cast(long)e.number < 0)
75       text ~= 'N' ~ itoa(-e.number);
76     else
77       text ~= 'i' ~ itoa(e.number);
78   }
79 
80   void visit(FloatExpr e)
81   {
82     text ~= 'e';
83     mangleFloat(e.number);
84   }
85 
86   void visit(ComplexExpr e)
87   {
88     text ~= 'c';
89     mangleFloat(e.re);
90     text ~= 'c';
91     mangleFloat(e.im);
92   }
93 
94   void visit(NullExpr e)
95   {
96     text ~= 'n';
97   }
98 
99   void visit(StringExpr e)
100   { // := MangleChar UTF8StringLength "_" UTF8StringInHex
101     char mc; // Mangle character.
102     cstring utf8str;
103     char[] tmp;
104     switch (e.charType.tid)
105     {
106     case TYP.Char:
107       mc = 'a';
108       utf8str = e.getString();
109       break;
110     case TYP.WChar:
111       mc = 'w';
112       auto str = e.getWString();
113       for (size_t i; i < str.length;)
114       {
115         auto c = decode(str, i);
116         if (c == ERROR_CHAR) {
117           utf16Error(e.begin, str, i);
118           break;
119         }
120         else
121           encode(tmp, c);
122       }
123       utf8str = tmp;
124       break;
125     case TYP.DChar:
126       mc = 'd';
127       auto str = e.getDString();
128       foreach (dchar c; str)
129         if (!isValidChar(c)) {
130           error(e.begin, MID.InvalidUTF32Character, c+0);
131           break;
132         }
133         else
134           encode(tmp, c);
135       utf8str = tmp;
136       break;
137     default: assert(0);
138     }
139     auto s = String(utf8str);
140     // Finally append the mangled string.
141     text ~= mc ~ itoa(s.len) ~ "_" ~ s.tohex()[];
142   }
143 
144   void visit(ArrayLiteralExpr e)
145   {
146     text ~= 'A' ~ itoa(e.values.length);
147     foreach (val; e.values)
148       visitN(val);
149   }
150 
151   void visit(AArrayLiteralExpr e)
152   {
153     text ~= 'A' ~ itoa(e.values.length);
154     foreach (i, key; e.keys)
155       visitN(key), visitN(e.values[i]);
156   }
157 
158   void visit(StructInitExpr e)
159   {
160     text ~= 'S' ~ itoa(e.values.length);
161     foreach (val; e.values)
162       if (val.kind == NodeKind.VoidInitExpr)
163         text ~= 'v';
164       else
165         visitN(val);
166   }
167 }