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 }