1 module d.ast.expression; 2 3 import d.ast.declaration; 4 import d.ast.identifier; 5 import d.ast.statement; 6 import d.ast.type; 7 8 import d.common.node; 9 10 import source.context; 11 import source.name; 12 13 abstract class AstExpression : Node { 14 this(Location location) { 15 super(location); 16 } 17 18 string toString(const Context) const { 19 assert(0, "toString not implement for " ~ typeid(this).toString()); 20 } 21 } 22 23 final: 24 /** 25 * Conditional expression of type ?: 26 */ 27 class TernaryExpression(E) : E if (is(E : AstExpression)) { 28 E condition; 29 E lhs; 30 E rhs; 31 32 this(U...)(Location location, U args, E condition, E lhs, E rhs) { 33 super(location, args); 34 35 this.condition = condition; 36 this.lhs = lhs; 37 this.rhs = rhs; 38 } 39 40 override string toString(const Context c) const { 41 return condition.toString(c) ~ " ? " ~ lhs.toString(c) ~ " : " 42 ~ rhs.toString(c); 43 } 44 } 45 46 alias AstTernaryExpression = TernaryExpression!AstExpression; 47 48 /** 49 * Binary Expressions. 50 */ 51 enum AstBinaryOp { 52 Comma, 53 Assign, 54 Add, 55 Sub, 56 Mul, 57 Pow, 58 Div, 59 Rem, 60 Or, 61 And, 62 Xor, 63 LeftShift, 64 UnsignedRightShift, 65 SignedRightShift, 66 LogicalOr, 67 LogicalAnd, 68 Concat, 69 AddAssign, 70 SubAssign, 71 MulAssign, 72 PowAssign, 73 DivAssign, 74 RemAssign, 75 OrAssign, 76 AndAssign, 77 XorAssign, 78 LeftShiftAssign, 79 UnsignedRightShiftAssign, 80 SignedRightShiftAssign, 81 LogicalOrAssign, 82 LogicalAndAssign, 83 ConcatAssign, 84 Equal, 85 NotEqual, 86 Identical, 87 NotIdentical, 88 In, 89 NotIn, 90 Greater, 91 GreaterEqual, 92 Less, 93 LessEqual, 94 95 // Weird float operators 96 LessGreater, 97 LessEqualGreater, 98 UnorderedLess, 99 UnorderedLessEqual, 100 UnorderedGreater, 101 UnorderedGreaterEqual, 102 Unordered, 103 UnorderedEqual, 104 } 105 106 bool isAssign(AstBinaryOp op) { 107 return op >= AstBinaryOp.AddAssign && op <= AstBinaryOp.ConcatAssign; 108 } 109 110 unittest { 111 enum Assign = "Assign"; 112 bool isAssignStupid(AstBinaryOp op) { 113 import std.conv; 114 auto s = op.to!string(); 115 if (s.length <= Assign.length) { 116 return false; 117 } 118 119 return s[$ - Assign.length .. $] == Assign; 120 } 121 122 import std.traits; 123 foreach (op; EnumMembers!AstBinaryOp) { 124 import std.conv; 125 assert(op.isAssign() == isAssignStupid(op), op.to!string()); 126 } 127 } 128 129 AstBinaryOp getBaseOp(AstBinaryOp op) in { 130 assert(isAssign(op)); 131 } do { 132 return op + AstBinaryOp.Add - AstBinaryOp.AddAssign; 133 } 134 135 unittest { 136 enum Assign = "Assign"; 137 138 import std.traits; 139 foreach (op; EnumMembers!AstBinaryOp) { 140 if (!op.isAssign()) { 141 continue; 142 } 143 144 import std.conv; 145 auto b0 = op.to!string()[0 .. $ - Assign.length]; 146 auto b1 = op.getBaseOp().to!string(); 147 assert(b0 == b1); 148 } 149 } 150 151 class AstBinaryExpression : AstExpression { 152 AstBinaryOp op; 153 154 AstExpression lhs; 155 AstExpression rhs; 156 157 this(Location location, AstBinaryOp op, AstExpression lhs, 158 AstExpression rhs) { 159 super(location); 160 161 this.op = op; 162 this.lhs = lhs; 163 this.rhs = rhs; 164 } 165 166 override string toString(const Context c) const { 167 import std.conv; 168 return lhs.toString(c) ~ " " ~ to!string(op) ~ " " ~ rhs.toString(c); 169 } 170 } 171 172 /** 173 * Unary Expression types. 174 */ 175 enum UnaryOp { 176 AddressOf, 177 Dereference, 178 PreInc, 179 PreDec, 180 PostInc, 181 PostDec, 182 Plus, 183 Minus, 184 Complement, 185 Not, 186 } 187 188 string unarizeString(string s, UnaryOp op) { 189 final switch (op) with (UnaryOp) { 190 case AddressOf: 191 return "&" ~ s; 192 193 case Dereference: 194 return "*" ~ s; 195 196 case PreInc: 197 return "++" ~ s; 198 199 case PreDec: 200 return "--" ~ s; 201 202 case PostInc: 203 return s ~ "++"; 204 205 case PostDec: 206 return s ~ "--"; 207 208 case Plus: 209 return "+" ~ s; 210 211 case Minus: 212 return "-" ~ s; 213 214 case Not: 215 return "!" ~ s; 216 217 case Complement: 218 return "~" ~ s; 219 } 220 } 221 222 class AstUnaryExpression : AstExpression { 223 AstExpression expr; 224 UnaryOp op; 225 226 this(Location location, UnaryOp op, AstExpression expr) { 227 super(location); 228 229 this.expr = expr; 230 this.op = op; 231 } 232 233 invariant() { 234 assert(expr); 235 } 236 237 override string toString(const Context c) const { 238 return unarizeString(expr.toString(c), op); 239 } 240 } 241 242 class AstCastExpression : AstExpression { 243 AstType type; 244 AstExpression expr; 245 246 this(Location location, AstType type, AstExpression expr) { 247 super(location); 248 249 this.type = type; 250 this.expr = expr; 251 } 252 253 override string toString(const Context c) const { 254 return "cast(" ~ type.toString(c) ~ ") " ~ expr.toString(c); 255 } 256 } 257 258 /** 259 * Function call 260 */ 261 class AstCallExpression : AstExpression { 262 AstExpression callee; 263 AstExpression[] args; 264 265 this(Location location, AstExpression callee, AstExpression[] args) { 266 super(location); 267 268 this.callee = callee; 269 this.args = args; 270 } 271 272 override string toString(const Context c) const { 273 import std.algorithm, std.range; 274 auto aa = args.map!(a => a.toString(c)).join(", "); 275 return callee.toString(c) ~ "(" ~ aa ~ ")"; 276 } 277 } 278 279 /** 280 * Indetifier calls. 281 */ 282 class IdentifierCallExpression : AstExpression { 283 Identifier callee; 284 AstExpression[] args; 285 286 this(Location location, Identifier callee, AstExpression[] args) { 287 super(location); 288 289 this.callee = callee; 290 this.args = args; 291 } 292 293 override string toString(const Context c) const { 294 import std.algorithm, std.range; 295 auto aa = args.map!(a => a.toString(c)).join(", "); 296 return callee.toString(c) ~ "(" ~ aa ~ ")"; 297 } 298 } 299 300 /** 301 * Contructor for builtin types. 302 */ 303 class TypeCallExpression : AstExpression { 304 AstType type; 305 AstExpression[] args; 306 307 this(Location location, AstType type, AstExpression[] args) { 308 super(location); 309 310 this.type = type; 311 this.args = args; 312 } 313 314 override string toString(const Context c) const { 315 import std.algorithm, std.range; 316 auto aa = args.map!(a => a.toString(c)).join(", "); 317 return type.toString(c) ~ "(" ~ aa ~ ")"; 318 } 319 } 320 321 /** 322 * Index expression : indexed[arguments] 323 */ 324 class AstIndexExpression : AstExpression { 325 AstExpression indexed; 326 AstExpression[] arguments; 327 328 this(Location location, AstExpression indexed, AstExpression[] arguments) { 329 super(location); 330 331 this.indexed = indexed; 332 this.arguments = arguments; 333 } 334 } 335 336 /** 337 * Slice expression : [first .. second] 338 */ 339 class AstSliceExpression : AstExpression { 340 AstExpression sliced; 341 342 AstExpression[] first; 343 AstExpression[] second; 344 345 this(Location location, AstExpression sliced, AstExpression[] first, 346 AstExpression[] second) { 347 super(location); 348 349 this.sliced = sliced; 350 this.first = first; 351 this.second = second; 352 } 353 } 354 355 /** 356 * Parenthese expression. 357 */ 358 class ParenExpression : AstExpression { 359 AstExpression expr; 360 361 this(Location location, AstExpression expr) { 362 super(location); 363 364 this.expr = expr; 365 } 366 } 367 368 /** 369 * Identifier expression 370 */ 371 class IdentifierExpression : AstExpression { 372 Identifier identifier; 373 374 this(Identifier identifier) { 375 super(identifier.location); 376 377 this.identifier = identifier; 378 } 379 380 override string toString(const Context c) const { 381 return identifier.toString(c); 382 } 383 } 384 385 /** 386 * new 387 */ 388 class AstNewExpression : AstExpression { 389 AstType type; 390 AstExpression[] args; 391 392 this(Location location, AstType type, AstExpression[] args) { 393 super(location); 394 395 this.type = type; 396 this.args = args; 397 } 398 399 override string toString(const Context c) const { 400 import std.algorithm, std.range; 401 auto aa = args.map!(a => a.toString(c)).join(", "); 402 return "new " ~ type.toString(c) ~ "(" ~ aa ~ ")"; 403 } 404 } 405 406 /** 407 * This 408 */ 409 class ThisExpression : AstExpression { 410 this(Location location) { 411 super(location); 412 } 413 414 override string toString(const Context) const { 415 return "this"; 416 } 417 } 418 419 /** 420 * Array literal 421 */ 422 class ArrayLiteral(T) : T if (is(T : AstExpression)) { 423 T[] values; 424 425 this(U...)(Location location, U args, T[] values) { 426 super(location, args); 427 this.values = values; 428 } 429 430 override string toString(const Context c) const { 431 import std.algorithm, std.range; 432 return "[" ~ values.map!(v => v.toString(c)).join(", ") ~ "]"; 433 } 434 } 435 436 alias AstArrayLiteral = ArrayLiteral!AstExpression; 437 438 /** 439 * __FILE__ literal 440 */ 441 class __File__Literal : AstExpression { 442 this(Location location) { 443 super(location); 444 } 445 } 446 447 /** 448 * __LINE__ literal 449 */ 450 class __Line__Literal : AstExpression { 451 this(Location location) { 452 super(location); 453 } 454 } 455 456 /** 457 * Delegate literal 458 */ 459 class DelegateLiteral : AstExpression { 460 ParamDecl[] params; 461 bool isVariadic; 462 BlockStatement fbody; 463 464 this(Location location, ParamDecl[] params, bool isVariadic, 465 BlockStatement fbody) { 466 super(location); 467 468 this.params = params; 469 this.isVariadic = isVariadic; 470 this.fbody = fbody; 471 } 472 473 this(BlockStatement fbody) { 474 this(fbody.location, [], false, fbody); 475 } 476 } 477 478 /** 479 * Lambda expressions 480 */ 481 class Lambda : AstExpression { 482 ParamDecl[] params; 483 AstExpression value; 484 485 this(Location location, ParamDecl[] params, AstExpression value) { 486 super(location); 487 488 this.params = params; 489 this.value = value; 490 } 491 } 492 493 /** 494 * $ 495 */ 496 class DollarExpression : AstExpression { 497 this(Location location) { 498 super(location); 499 } 500 } 501 502 /** 503 * is expression. 504 */ 505 class IsExpression : AstExpression { 506 AstType tested; 507 508 this(Location location, AstType tested) { 509 super(location); 510 511 this.tested = tested; 512 } 513 } 514 515 /** 516 * typeid(expression) expression. 517 */ 518 class AstTypeidExpression : AstExpression { 519 AstExpression argument; 520 521 this(Location location, AstExpression argument) { 522 super(location); 523 524 this.argument = argument; 525 } 526 } 527 528 /** 529 * typeid(type) expression. 530 */ 531 class StaticTypeidExpression(T, E) : E if (is(E : AstExpression)) { 532 T argument; 533 534 this(U...)(Location location, U args, T argument) { 535 super(location, args); 536 537 this.argument = argument; 538 } 539 540 override string toString(const Context c) const { 541 return "typeid(" ~ argument.toString(c) ~ ")"; 542 } 543 } 544 545 alias AstStaticTypeidExpression = 546 StaticTypeidExpression!(AstType, AstExpression); 547 548 /** 549 * ambiguous typeid expression. 550 */ 551 class IdentifierTypeidExpression : AstExpression { 552 Identifier argument; 553 554 this(Location location, Identifier argument) { 555 super(location); 556 557 this.argument = argument; 558 } 559 } 560 561 /** 562 * Used for type identifier = void; 563 */ 564 class AstVoidInitializer : AstExpression { 565 this(Location location) { 566 super(location); 567 } 568 569 override string toString(const Context) const { 570 return "void"; 571 } 572 }