1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity low)
4 module dil.code.Methods;
5 
6 import dil.ast.Node,
7        dil.ast.Expressions;
8 import dil.semantic.Types;
9 import dil.code.NotAResult;
10 import dil.i18n.Messages;
11 import dil.Float,
12        dil.Complex,
13        dil.Diagnostics;
14 import common;
15 
16 /// A collection of methods that operate on Expression nodes.
17 class EMethods
18 {
19   Diagnostics diag; /// For error messages.
20 
21   alias NK = NodeKind;
22 
23   /// Constructs an EMethods object.
24   this(Diagnostics diag = null)
25   {
26     this.diag = diag;
27   }
28 
29   /// Issues an error.
30   void error(Node n, cstring msg, ...)
31   {
32     auto location = n.begin.getErrorLocation(/+filePath+/""); // FIXME
33     msg = Format(_arguments, _argptr, msg);
34     auto error = new SemanticError(location, msg);
35     if (diag !is null)
36       diag ~= error;
37   }
38 
39   /// Converts the expression to an integer. Reports an error if impossible.
40   long toInt(Expression e)
41   {
42     long i;
43     switch (e.kind)
44     {
45     // TODO:
46     case NK.IntExpr:
47       break;
48     default:
49       //error("expected integer constant, not ‘{}’", e.toText());
50     }
51     return i;
52   }
53 
54   /// ditto
55   ulong toUInt(Expression e)
56   {
57     return cast(ulong)toInt(e);
58   }
59 
60   /// Reports an error.
61   void errorExpectedIntOrFloat(Expression e)
62   {
63     error(e, "expected integer or float constant, not ‘{}’", e.toText());
64   }
65 
66   /// Returns Im(e).
67   Float toImag(Expression e)
68   {
69     Float r;
70     switch (e.kind)
71     {
72     case NK.ComplexExpr:
73       r = e.to!(ComplexExpr).number.im; break;
74     case NK.FloatExpr:
75       auto fe = e.to!(FloatExpr);
76       if (fe.type.flagsOf().isImaginary())
77         r = fe.number;
78       else
79         r = Float();
80       break;
81     case NK.IntExpr:
82       r = Float();
83       break;
84     default:
85       errorExpectedIntOrFloat(e);
86     }
87     return r;
88   }
89 
90   /// Returns Re(e).
91   Float toReal(Expression e)
92   {
93     Float r;
94     switch (e.kind)
95     {
96     case NK.ComplexExpr:
97       r = e.to!(ComplexExpr).number.re; break;
98     case NK.FloatExpr:
99       auto fe = e.to!(FloatExpr);
100       if (fe.type.flagsOf().isReal())
101         r = fe.number;
102       else
103         r = Float();
104       break;
105     case NK.IntExpr:
106       auto ie = e.to!(IntExpr);
107       if (ie.type.flagsOf().isSigned())
108         r = Float(cast(long)ie.number);
109       else
110         r = Float(ie.number);
111       break;
112     default:
113       errorExpectedIntOrFloat(e);
114     }
115     return r;
116   }
117 
118   /// Returns Re(e) + Im(e).
119   Complex toComplex(Expression e)
120   {
121     Complex z;
122     switch (e.kind)
123     {
124     case NK.ComplexExpr:
125       z = e.to!(ComplexExpr).number; break;
126     case NK.FloatExpr:
127       auto fe = e.to!(FloatExpr);
128       Float re, im;
129       if (fe.type.flagsOf().isReal())
130         re = fe.number;
131       else
132         im = fe.number;
133       z = Complex(re, im);
134       break;
135     case NK.IntExpr:
136       z = Complex(toReal(e)); break;
137     default:
138       errorExpectedIntOrFloat(e);
139     }
140     return z;
141   }
142 
143   /// Returns true if e is a constant expression.
144   static bool isConst(Expression e)
145   {
146     return e.kind.In(NK.IntExpr, NK.FloatExpr, NK.ComplexExpr, NK.CharExpr,
147       NK.BoolExpr, NK.StringExpr, NK.NullExpr);
148   }
149 
150   /// Checks if e has a boolean value.
151   /// Returns: -1 if not a bool, 0 if the value is false and 1 if true.
152   static int isBool(Expression e)
153   {
154     int r = void;
155   Lagain:
156     switch (e.kind)
157     {
158     case NK.IntExpr:
159       auto num = e.to!(IntExpr).number;
160       r = num != 0; break;
161     case NK.FloatExpr:
162       auto num = e.to!(FloatExpr).number;
163       r = num != 0; break;
164     case NK.ComplexExpr:
165       auto num = e.to!(ComplexExpr).number;
166       r = num != 0L; break;
167     case NK.CharExpr:
168       auto num = e.to!(CharExpr).value.number;
169       r = num != 0; break;
170     case NK.BoolExpr:
171       auto num = e.to!(BoolExpr).value.number;
172       r = num != 0; break;
173     case NK.CommaExpr:
174       e = e.to!(CommaExpr).rhs; goto Lagain;
175     case NK.ArrayLiteralExpr:
176       r = e.to!(ArrayLiteralExpr).values.length != 0; break;
177     case NK.AArrayLiteralExpr:
178       r = e.to!(AArrayLiteralExpr).values.length != 0; break;
179     case NK.StringExpr:
180       r = 1; break;
181     case NK.NullExpr:
182       r = 0; break;
183     default:
184       r = -1; // It has no boolean value.
185     }
186     return r;
187   }
188 
189   /// Returns true if e has a boolean value and if it is true.
190   static bool isTrue(Expression e)
191   {
192     return isBool(e) == 1;
193   }
194 
195   /// Returns true if e has a boolean value and if it is false.
196   static bool isFalse(Expression e)
197   {
198     return isBool(e) == 0;
199   }
200 
201   /// Returns a boolean IntExpr if e has a boolean value, otherwise NAR.
202   static Expression toBool(Expression e)
203   {
204     auto boolval = isBool(e);
205     Expression r = NAR;
206     if (boolval != -1)
207     {
208       r = new IntExpr(boolval, Types.Bool);
209       r.setLoc(e);
210     }
211     return r;
212   }
213 
214   /// Returns the Float value of e.
215   Float toRealOrImag(Expression e)
216   {
217     return e.type.flagsOf().isReal() ? toReal(e) : toImag(e);
218   }
219 
220   /// Returns the length of a string/array/assocarray.
221   static Expression arrayLength(Expression e)
222   {
223     size_t len;
224     if (auto se = e.Is!(StringExpr))
225       len = se.length();
226     else if (auto ae = e.Is!(ArrayLiteralExpr))
227       len = ae.values.length;
228     else if (auto aae = e.Is!(AArrayLiteralExpr))
229       len = aae.keys.length;
230     else
231       return NAR;
232     auto r = new IntExpr(len, e.type);
233     r.setLoc(e);
234     return r;
235   }
236 
237   /// Returns the lvalue of e.
238   Expression toLValue(Expression e)
239   {
240     switch (e.kind)
241     {
242     case NK.IdentifierExpr,
243          NK.ThisExpr,
244          NK.IndexExpr,
245          NK.StructInitExpr,
246          NK.VariablesDecl,
247          NK.DerefExpr,
248          NK.SliceExpr:
249       // Nothing to do.
250       break;
251     case NK.ArrayLiteralExpr:
252       // if (e.type && e.type.baseType().tid == TYP.Void)
253       //   error();
254       break;
255     case NK.CommaExpr:
256       e = toLValue(e.to!(CommaExpr).rhs); // (lhs, rhs)
257       break;
258     case NK.CondExpr:
259       break;
260     case NK.CallExpr:
261       if (e.type.baseType().isStruct())
262         break;
263       goto default;
264     default:
265       error(e, "‘{}’ is not an lvalue", e.toText());
266     }
267     return e;
268   }
269 
270   /// Returns the expression &e.
271   Expression addressOf(Expression e)
272   {
273     auto e2 = new AddressExpr(toLValue(e));
274     e2.setLoc(e);
275     e2.type = e.type.ptrTo();
276     return e2;
277   }
278 }