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 }