2 * Defines the bulk of the classes which represent the AST at the expression level.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
10 * Documentation: https://dlang.org/phobos/dmd_expression.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
14 module dmd
.expression
;
16 import core
.stdc
.stdarg
;
17 import core
.stdc
.stdio
;
18 import core
.stdc
.string
;
21 import dmd
.arraytypes
;
25 import dmd
.declaration
;
37 import dmd
.identifier
;
41 import dmd
.root
.complex
;
42 import dmd
.root
.ctfloat
;
43 import dmd
.common
.outbuffer
;
44 import dmd
.root
.optional
;
46 import dmd
.rootobject
;
47 import dmd
.root
.string
;
53 enum LOGSEMANTIC
= false;
55 /// Return value for `checkModifiable`
60 /// Modifiable (the type is mutable)
62 /// Modifiable because it is initialization
66 * Specifies how the checkModify deals with certain situations
70 /// Issue error messages on invalid modifications of the variable
72 /// No errors are emitted for invalid modifications
74 /// The modification occurs for a subfield of the current variable
78 /****************************************
79 * Find the last non-comma expression.
81 * e = Expressions connected by commas
83 * right-most non-comma expression
86 inout(Expression
) lastComma(inout Expression e
)
88 Expression ex
= cast()e
;
89 while (ex
.op
== EXP
.comma
)
90 ex
= (cast(CommaExp
)ex
).e2
;
95 /****************************************
96 * Expand tuples in-place.
99 * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is:
100 * `exps = [10, (20, 30), 40]`
101 * `names = [null, "pair", "single"]`
102 * The arrays will be modified to:
103 * `exps = [10, 20, 30, 40]`
104 * `names = [null, "pair", null, "single"]`
107 * exps = array of Expressions
108 * names = optional array of names corresponding to Expressions
110 extern (C
++) void expandTuples(Expressions
* exps
, Identifiers
* names
= null)
112 //printf("expandTuples()\n");
118 if (exps
.length
!= names
.length
)
120 printf("exps.length = %d, names.length = %d\n", cast(int) exps
.length
, cast(int) names
.length
);
121 printf("exps = %s, names = %s\n", exps
.toChars(), names
.toChars());
123 printf("%s\n", (*exps
)[0].loc
.toChars());
128 // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`.
129 void expandNames(size_t index
, size_t length
)
138 foreach (i
; 1 .. length
)
140 names
.insert(index
+ i
, cast(Identifier
) null);
145 for (size_t i
= 0; i
< exps
.length
; i
++)
147 Expression arg
= (*exps
)[i
];
151 // Look for tuple with 0 members
152 if (auto e
= arg
.isTypeExp())
154 if (auto tt
= e
.type
.toBasetype().isTypeTuple())
156 if (!tt
.arguments || tt
.arguments
.length
== 0)
160 if (i
== exps
.length
)
163 else // Expand a TypeTuple
166 auto texps
= new Expressions(tt
.arguments
.length
);
167 foreach (j
, a
; *tt
.arguments
)
168 (*texps
)[j
] = new TypeExp(e
.loc
, a
.type
);
169 exps
.insert(i
, texps
);
170 expandNames(i
, texps
.length
);
177 // Inline expand all the tuples
178 while (arg
.op
== EXP
.tuple
)
180 TupleExp te
= cast(TupleExp
)arg
;
181 exps
.remove(i
); // remove arg
182 exps
.insert(i
, te
.exps
); // replace with tuple contents
183 expandNames(i
, te
.exps
.length
);
184 if (i
== exps
.length
)
185 return; // empty tuple, no more arguments
186 (*exps
)[i
] = Expression
.combine(te
.e0
, (*exps
)[i
]);
192 /****************************************
193 * If `s` is a function template, i.e. the only member of a template
194 * and that member is a function, return that template.
196 * s = symbol that might be a function template
198 * template for that function, otherwise null
200 TemplateDeclaration
getFuncTemplateDecl(Dsymbol s
) @safe
202 FuncDeclaration f
= s
.isFuncDeclaration();
205 if (auto ti
= f
.parent
.isTemplateInstance())
207 if (!ti
.isTemplateMixin() && ti
.tempdecl
)
209 auto td
= ti
.tempdecl
.isTemplateDeclaration();
210 if (td
.onemember
&& td
.ident
== f
.ident
)
220 /************************ TypeDotIdExp ************************************/
227 DotIdExp
typeDotIdExp(const ref Loc loc
, Type type
, Identifier ident
) @safe
229 return new DotIdExp(loc
, new TypeExp(loc
, type
), ident
);
232 /***************************************************
233 * Given an Expression, find the variable it really is.
235 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
237 * e = Expression to look at
239 * variable if there is one, null if not
241 VarDeclaration
expToVariable(Expression e
)
248 return (cast(VarExp
)e
).var
.isVarDeclaration();
250 case EXP
.dotVariable
:
251 e
= (cast(DotVarExp
)e
).e1
;
256 IndexExp ei
= cast(IndexExp
)e
;
258 Type ti
= e
.type
.toBasetype();
259 if (ti
.ty
== Tsarray
)
266 SliceExp ei
= cast(SliceExp
)e
;
268 Type ti
= e
.type
.toBasetype();
269 if (ti
.ty
== Tsarray
)
276 return (cast(ThisExp
)e
).var
.isVarDeclaration();
278 // Temporaries for rvalues that need destruction
279 // are of form: (T s = rvalue, s). For these cases
280 // we can just return var declaration of `s`. However,
281 // this is intentionally not calling `Expression.extractLast`
282 // because at this point we cannot infer the var declaration
283 // of more complex generated comma expressions such as the
284 // one for the array append hook.
287 if (auto ve
= e
.isCommaExp().e2
.isVarExp())
288 return ve
.var
.isVarDeclaration();
300 code
, // normal code expression in AST
301 ctfe
, // value expression for CTFE
302 cache
, // constant value cached for CTFE
305 enum WANTvalue
= 0; // default
306 enum WANTexpand
= 1; // expand const/immutable variables if possible
308 /***********************************************************
309 * https://dlang.org/spec/expression.html#expression
311 extern (C
++) abstract class Expression
: ASTNode
313 Type type
; // !=null means that semantic() has been run
314 Loc loc
; // file location
315 const EXP op
; // to minimize use of dynamic_cast
317 extern (D
) this(const ref Loc loc
, EXP op
) scope @safe
319 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
324 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
325 final size_t
size() nothrow @nogc pure @safe const { return expSize
[op
]; }
329 CTFEExp
.cantexp
= new CTFEExp(EXP
.cantExpression
);
330 CTFEExp
.voidexp
= new CTFEExp(EXP
.voidExpression
);
331 CTFEExp
.breakexp
= new CTFEExp(EXP
.break_
);
332 CTFEExp
.continueexp
= new CTFEExp(EXP
.continue_
);
333 CTFEExp
.gotoexp
= new CTFEExp(EXP
.goto_
);
334 CTFEExp
.showcontext
= new CTFEExp(EXP
.showCtfeContext
);
338 * Deinitializes the global state of the compiler.
340 * This can be used to restore the state set by `_init` to its original
343 static void deinitialize()
345 CTFEExp
.cantexp
= CTFEExp
.cantexp
.init
;
346 CTFEExp
.voidexp
= CTFEExp
.voidexp
.init
;
347 CTFEExp
.breakexp
= CTFEExp
.breakexp
.init
;
348 CTFEExp
.continueexp
= CTFEExp
.continueexp
.init
;
349 CTFEExp
.gotoexp
= CTFEExp
.gotoexp
.init
;
350 CTFEExp
.showcontext
= CTFEExp
.showcontext
.init
;
353 /*********************************
354 * Does *not* do a deep copy.
356 extern (D
) final Expression
copy()
363 fprintf(stderr
, "No expression copy for: %s\n", toChars());
364 printf("op = %d\n", op
);
369 // memory never freed, so can use the faster bump-pointer-allocation
370 e
= cast(Expression
)allocmemory(size
);
371 //printf("Expression::copy(op = %d) e = %p\n", op, e);
372 return cast(Expression
)memcpy(cast(void*)e
, cast(void*)this, size
);
375 Expression
syntaxCopy()
377 //printf("Expression::syntaxCopy()\n");
382 // kludge for template.isExpression()
383 override final DYNCAST
dyncast() const
385 return DYNCAST
.expression
;
388 override const(char)* toChars() const
390 return .toChars(this);
393 /**********************************
394 * Combine e1 and e2 by CommaExp if both are not NULL.
396 extern (D
) static Expression
combine(Expression e1
, Expression e2
) @safe
402 e1
= new CommaExp(e1
.loc
, e1
, e2
);
411 extern (D
) static Expression
combine(Expression e1
, Expression e2
, Expression e3
) @safe
413 return combine(combine(e1
, e2
), e3
);
416 extern (D
) static Expression
combine(Expression e1
, Expression e2
, Expression e3
, Expression e4
) @safe
418 return combine(combine(e1
, e2
), combine(e3
, e4
));
421 /**********************************
422 * If 'e' is a tree of commas, returns the rightmost expression
423 * by stripping off it from the tree. The remained part of the tree
424 * is returned via e0.
425 * Otherwise 'e' is directly returned and e0 is set to NULL.
427 extern (D
) static Expression
extractLast(Expression e
, out Expression e0
) @safe
429 if (e
.op
!= EXP
.comma
)
434 CommaExp ce
= cast(CommaExp
)e
;
435 if (ce
.e2
.op
!= EXP
.comma
)
444 Expression
* pce
= &ce
.e2
;
445 while ((cast(CommaExp
)(*pce
)).e2
.op
== EXP
.comma
)
447 pce
= &(cast(CommaExp
)(*pce
)).e2
;
449 assert((*pce
).op
== EXP
.comma
);
450 ce
= cast(CommaExp
)(*pce
);
457 extern (D
) static Expressions
* arraySyntaxCopy(Expressions
* exps
)
459 Expressions
* a
= null;
462 a
= new Expressions(exps
.length
);
463 foreach (i
, e
; *exps
)
465 (*a
)[i
] = e ? e
.syntaxCopy() : null;
471 dinteger_t
toInteger()
473 //printf("Expression %s\n", EXPtoString(op).ptr);
474 if (!type
.isTypeError())
475 error(loc
, "integer constant expression expected instead of `%s`", toChars());
479 uinteger_t
toUInteger()
481 //printf("Expression %s\n", EXPtoString(op).ptr);
482 return cast(uinteger_t
)toInteger();
487 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
493 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
497 complex_t
toComplex()
499 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
500 return complex_t(CTFloat
.zero
);
503 StringExp
toStringExp()
508 /***************************************
509 * Return !=0 if expression is an lvalue.
516 /****************************************
517 * Check that the expression has a valid type.
518 * If not, generates an error "... has no type".
520 * true if the expression is not valid.
522 * When this function returns true, `checkValue()` should also return true.
529 /****************************************
530 * Check that the expression has a valid value.
531 * If not, generates an error "... has no value".
533 * true if the expression is not valid or has void type.
537 if (type
&& type
.toBasetype().ty
== Tvoid
)
539 error(loc
, "expression `%s` is `void` and has no value", toChars());
540 //print(); assert(0);
548 extern (D
) final bool checkScalar()
552 if (type
.toBasetype().ty
== Terror
)
554 if (!type
.isscalar())
556 error(loc
, "`%s` is not a scalar, it is a `%s`", toChars(), type
.toChars());
562 extern (D
) final bool checkNoBool()
566 if (type
.toBasetype().ty
== Terror
)
568 if (type
.toBasetype().ty
== Tbool
)
570 error(loc
, "operation not allowed on `bool` `%s`", toChars());
576 extern (D
) final bool checkIntegral()
580 if (type
.toBasetype().ty
== Terror
)
582 if (!type
.isintegral())
584 error(loc
, "`%s` is not of integral type, it is a `%s`", toChars(), type
.toChars());
590 extern (D
) final bool checkArithmetic(EXP op
)
594 if (type
.toBasetype().ty
== Terror
)
596 if (!type
.isintegral() && !type
.isfloating())
598 // unary aggregate ops error here
599 const char* msg
= type
.isAggregate() ?
600 "operator `%s` is not defined for `%s` of type `%s`" :
601 "illegal operator `%s` for `%s` of type `%s`";
602 error(loc
, msg
, EXPtoString(op
).ptr
, toChars(), type
.toChars());
608 /*******************************
609 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
610 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
611 * Returns true if error occurs.
613 extern (D
) final bool checkReadModifyWrite(EXP rmwOp
, Expression ex
= null)
615 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
616 if (!type ||
!type
.isShared() || type
.isTypeStruct() || type
.isTypeClass())
619 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
623 case EXP
.prePlusPlus
:
624 rmwOp
= EXP
.addAssign
;
627 case EXP
.preMinusMinus
:
628 rmwOp
= EXP
.minAssign
;
634 error(loc
, "read-modify-write operations are not allowed for `shared` variables");
635 errorSupplemental(loc
, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
636 EXPtoString(rmwOp
).ptr
, toChars(), ex ? ex
.toChars() : "1");
640 /******************************
641 * Take address of expression.
643 final Expression
addressOf()
645 //printf("Expression::addressOf()\n");
648 assert(op
== EXP
.error ||
isLvalue());
650 Expression e
= new AddrExp(loc
, this, type
.pointerTo());
654 /******************************
655 * If this is a reference, dereference it.
657 final Expression
deref()
659 //printf("Expression::deref()\n");
660 // type could be null if forward referencing an 'auto' variable
662 if (auto tr
= type
.isTypeReference())
664 Expression e
= new PtrExp(loc
, this, tr
.next
);
672 //printf("Expression::isConst(): %s\n", e.toChars());
681 case EXP
.symbolOffset
:
690 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
692 bool isIdentical(const Expression e
) const
698 /// Statically evaluate this expression to a `bool` if possible
699 /// Returns: an optional thath either contains the value or is empty
700 Optional
!bool toBool()
702 return typeof(return)();
710 final pure inout nothrow @nogc @safe
712 inout(IntegerExp
) isIntegerExp() { return op
== EXP
.int64 ?
cast(typeof(return))this : null; }
713 inout(ErrorExp
) isErrorExp() { return op
== EXP
.error ?
cast(typeof(return))this : null; }
714 inout(VoidInitExp
) isVoidInitExp() { return op
== EXP
.void_ ?
cast(typeof(return))this : null; }
715 inout(RealExp
) isRealExp() { return op
== EXP
.float64 ?
cast(typeof(return))this : null; }
716 inout(ComplexExp
) isComplexExp() { return op
== EXP
.complex80 ?
cast(typeof(return))this : null; }
717 inout(IdentifierExp
) isIdentifierExp() { return op
== EXP
.identifier ?
cast(typeof(return))this : null; }
718 inout(DollarExp
) isDollarExp() { return op
== EXP
.dollar ?
cast(typeof(return))this : null; }
719 inout(DsymbolExp
) isDsymbolExp() { return op
== EXP
.dSymbol ?
cast(typeof(return))this : null; }
720 inout(ThisExp
) isThisExp() { return op
== EXP
.this_ ?
cast(typeof(return))this : null; }
721 inout(SuperExp
) isSuperExp() { return op
== EXP
.super_ ?
cast(typeof(return))this : null; }
722 inout(NullExp
) isNullExp() { return op
== EXP
.null_ ?
cast(typeof(return))this : null; }
723 inout(StringExp
) isStringExp() { return op
== EXP
.string_ ?
cast(typeof(return))this : null; }
724 inout(InterpExp
) isInterpExp() { return op
== EXP
.interpolated ?
cast(typeof(return))this : null; }
725 inout(TupleExp
) isTupleExp() { return op
== EXP
.tuple ?
cast(typeof(return))this : null; }
726 inout(ArrayLiteralExp
) isArrayLiteralExp() { return op
== EXP
.arrayLiteral ?
cast(typeof(return))this : null; }
727 inout(AssocArrayLiteralExp
) isAssocArrayLiteralExp() { return op
== EXP
.assocArrayLiteral ?
cast(typeof(return))this : null; }
728 inout(StructLiteralExp
) isStructLiteralExp() { return op
== EXP
.structLiteral ?
cast(typeof(return))this : null; }
729 inout(CompoundLiteralExp
) isCompoundLiteralExp() { return op
== EXP
.compoundLiteral ?
cast(typeof(return))this : null; }
730 inout(TypeExp
) isTypeExp() { return op
== EXP
.type ?
cast(typeof(return))this : null; }
731 inout(ScopeExp
) isScopeExp() { return op
== EXP
.scope_ ?
cast(typeof(return))this : null; }
732 inout(TemplateExp
) isTemplateExp() { return op
== EXP
.template_ ?
cast(typeof(return))this : null; }
733 inout(NewExp
) isNewExp() { return op
== EXP
.new_ ?
cast(typeof(return))this : null; }
734 inout(NewAnonClassExp
) isNewAnonClassExp() { return op
== EXP
.newAnonymousClass ?
cast(typeof(return))this : null; }
735 inout(SymOffExp
) isSymOffExp() { return op
== EXP
.symbolOffset ?
cast(typeof(return))this : null; }
736 inout(VarExp
) isVarExp() { return op
== EXP
.variable ?
cast(typeof(return))this : null; }
737 inout(OverExp
) isOverExp() { return op
== EXP
.overloadSet ?
cast(typeof(return))this : null; }
738 inout(FuncExp
) isFuncExp() { return op
== EXP
.function_ ?
cast(typeof(return))this : null; }
739 inout(DeclarationExp
) isDeclarationExp() { return op
== EXP
.declaration ?
cast(typeof(return))this : null; }
740 inout(TypeidExp
) isTypeidExp() { return op
== EXP
.typeid_ ?
cast(typeof(return))this : null; }
741 inout(TraitsExp
) isTraitsExp() { return op
== EXP
.traits ?
cast(typeof(return))this : null; }
742 inout(HaltExp
) isHaltExp() { return op
== EXP
.halt ?
cast(typeof(return))this : null; }
743 inout(IsExp
) isExp() { return op
== EXP
.is_ ?
cast(typeof(return))this : null; }
744 inout(MixinExp
) isMixinExp() { return op
== EXP
.mixin_ ?
cast(typeof(return))this : null; }
745 inout(ImportExp
) isImportExp() { return op
== EXP
.import_ ?
cast(typeof(return))this : null; }
746 inout(AssertExp
) isAssertExp() { return op
== EXP
.assert_ ?
cast(typeof(return))this : null; }
747 inout(ThrowExp
) isThrowExp() { return op
== EXP
.throw_ ?
cast(typeof(return))this : null; }
748 inout(DotIdExp
) isDotIdExp() { return op
== EXP
.dotIdentifier ?
cast(typeof(return))this : null; }
749 inout(DotTemplateExp
) isDotTemplateExp() { return op
== EXP
.dotTemplateDeclaration ?
cast(typeof(return))this : null; }
750 inout(DotVarExp
) isDotVarExp() { return op
== EXP
.dotVariable ?
cast(typeof(return))this : null; }
751 inout(DotTemplateInstanceExp
) isDotTemplateInstanceExp() { return op
== EXP
.dotTemplateInstance ?
cast(typeof(return))this : null; }
752 inout(DelegateExp
) isDelegateExp() { return op
== EXP
.delegate_ ?
cast(typeof(return))this : null; }
753 inout(DotTypeExp
) isDotTypeExp() { return op
== EXP
.dotType ?
cast(typeof(return))this : null; }
754 inout(CallExp
) isCallExp() { return op
== EXP
.call ?
cast(typeof(return))this : null; }
755 inout(AddrExp
) isAddrExp() { return op
== EXP
.address ?
cast(typeof(return))this : null; }
756 inout(PtrExp
) isPtrExp() { return op
== EXP
.star ?
cast(typeof(return))this : null; }
757 inout(NegExp
) isNegExp() { return op
== EXP
.negate ?
cast(typeof(return))this : null; }
758 inout(UAddExp
) isUAddExp() { return op
== EXP
.uadd ?
cast(typeof(return))this : null; }
759 inout(ComExp
) isComExp() { return op
== EXP
.tilde ?
cast(typeof(return))this : null; }
760 inout(NotExp
) isNotExp() { return op
== EXP
.not ?
cast(typeof(return))this : null; }
761 inout(DeleteExp
) isDeleteExp() { return op
== EXP
.delete_ ?
cast(typeof(return))this : null; }
762 inout(CastExp
) isCastExp() { return op
== EXP
.cast_ ?
cast(typeof(return))this : null; }
763 inout(VectorExp
) isVectorExp() { return op
== EXP
.vector ?
cast(typeof(return))this : null; }
764 inout(VectorArrayExp
) isVectorArrayExp() { return op
== EXP
.vectorArray ?
cast(typeof(return))this : null; }
765 inout(SliceExp
) isSliceExp() { return op
== EXP
.slice ?
cast(typeof(return))this : null; }
766 inout(ArrayLengthExp
) isArrayLengthExp() { return op
== EXP
.arrayLength ?
cast(typeof(return))this : null; }
767 inout(ArrayExp
) isArrayExp() { return op
== EXP
.array ?
cast(typeof(return))this : null; }
768 inout(DotExp
) isDotExp() { return op
== EXP
.dot ?
cast(typeof(return))this : null; }
769 inout(CommaExp
) isCommaExp() { return op
== EXP
.comma ?
cast(typeof(return))this : null; }
770 inout(IntervalExp
) isIntervalExp() { return op
== EXP
.interval ?
cast(typeof(return))this : null; }
771 inout(DelegatePtrExp
) isDelegatePtrExp() { return op
== EXP
.delegatePointer ?
cast(typeof(return))this : null; }
772 inout(DelegateFuncptrExp
) isDelegateFuncptrExp() { return op
== EXP
.delegateFunctionPointer ?
cast(typeof(return))this : null; }
773 inout(IndexExp
) isIndexExp() { return op
== EXP
.index ?
cast(typeof(return))this : null; }
774 inout(PostExp
) isPostExp() { return (op
== EXP
.plusPlus || op
== EXP
.minusMinus
) ?
cast(typeof(return))this : null; }
775 inout(PreExp
) isPreExp() { return (op
== EXP
.prePlusPlus || op
== EXP
.preMinusMinus
) ?
cast(typeof(return))this : null; }
776 inout(AssignExp
) isAssignExp() { return op
== EXP
.assign ?
cast(typeof(return))this : null; }
777 inout(LoweredAssignExp
) isLoweredAssignExp() { return op
== EXP
.loweredAssignExp ?
cast(typeof(return))this : null; }
778 inout(ConstructExp
) isConstructExp() { return op
== EXP
.construct ?
cast(typeof(return))this : null; }
779 inout(BlitExp
) isBlitExp() { return op
== EXP
.blit ?
cast(typeof(return))this : null; }
780 inout(AddAssignExp
) isAddAssignExp() { return op
== EXP
.addAssign ?
cast(typeof(return))this : null; }
781 inout(MinAssignExp
) isMinAssignExp() { return op
== EXP
.minAssign ?
cast(typeof(return))this : null; }
782 inout(MulAssignExp
) isMulAssignExp() { return op
== EXP
.mulAssign ?
cast(typeof(return))this : null; }
784 inout(DivAssignExp
) isDivAssignExp() { return op
== EXP
.divAssign ?
cast(typeof(return))this : null; }
785 inout(ModAssignExp
) isModAssignExp() { return op
== EXP
.modAssign ?
cast(typeof(return))this : null; }
786 inout(AndAssignExp
) isAndAssignExp() { return op
== EXP
.andAssign ?
cast(typeof(return))this : null; }
787 inout(OrAssignExp
) isOrAssignExp() { return op
== EXP
.orAssign ?
cast(typeof(return))this : null; }
788 inout(XorAssignExp
) isXorAssignExp() { return op
== EXP
.xorAssign ?
cast(typeof(return))this : null; }
789 inout(PowAssignExp
) isPowAssignExp() { return op
== EXP
.powAssign ?
cast(typeof(return))this : null; }
791 inout(ShlAssignExp
) isShlAssignExp() { return op
== EXP
.leftShiftAssign ?
cast(typeof(return))this : null; }
792 inout(ShrAssignExp
) isShrAssignExp() { return op
== EXP
.rightShiftAssign ?
cast(typeof(return))this : null; }
793 inout(UshrAssignExp
) isUshrAssignExp() { return op
== EXP
.unsignedRightShiftAssign ?
cast(typeof(return))this : null; }
795 inout(CatAssignExp
) isCatAssignExp() { return op
== EXP
.concatenateAssign
796 ?
cast(typeof(return))this
799 inout(CatElemAssignExp
) isCatElemAssignExp() { return op
== EXP
.concatenateElemAssign
800 ?
cast(typeof(return))this
803 inout(CatDcharAssignExp
) isCatDcharAssignExp() { return op
== EXP
.concatenateDcharAssign
804 ?
cast(typeof(return))this
807 inout(AddExp
) isAddExp() { return op
== EXP
.add ?
cast(typeof(return))this : null; }
808 inout(MinExp
) isMinExp() { return op
== EXP
.min ?
cast(typeof(return))this : null; }
809 inout(CatExp
) isCatExp() { return op
== EXP
.concatenate ?
cast(typeof(return))this : null; }
810 inout(MulExp
) isMulExp() { return op
== EXP
.mul ?
cast(typeof(return))this : null; }
811 inout(DivExp
) isDivExp() { return op
== EXP
.div ?
cast(typeof(return))this : null; }
812 inout(ModExp
) isModExp() { return op
== EXP
.mod ?
cast(typeof(return))this : null; }
813 inout(PowExp
) isPowExp() { return op
== EXP
.pow ?
cast(typeof(return))this : null; }
814 inout(ShlExp
) isShlExp() { return op
== EXP
.leftShift ?
cast(typeof(return))this : null; }
815 inout(ShrExp
) isShrExp() { return op
== EXP
.rightShift ?
cast(typeof(return))this : null; }
816 inout(UshrExp
) isUshrExp() { return op
== EXP
.unsignedRightShift ?
cast(typeof(return))this : null; }
817 inout(AndExp
) isAndExp() { return op
== EXP
.and ?
cast(typeof(return))this : null; }
818 inout(OrExp
) isOrExp() { return op
== EXP
.or ?
cast(typeof(return))this : null; }
819 inout(XorExp
) isXorExp() { return op
== EXP
.xor ?
cast(typeof(return))this : null; }
820 inout(LogicalExp
) isLogicalExp() { return (op
== EXP
.andAnd || op
== EXP
.orOr
) ?
cast(typeof(return))this : null; }
821 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
822 inout(InExp
) isInExp() { return op
== EXP
.in_ ?
cast(typeof(return))this : null; }
823 inout(RemoveExp
) isRemoveExp() { return op
== EXP
.remove ?
cast(typeof(return))this : null; }
824 inout(EqualExp
) isEqualExp() { return (op
== EXP
.equal || op
== EXP
.notEqual
) ?
cast(typeof(return))this : null; }
825 inout(IdentityExp
) isIdentityExp() { return (op
== EXP
.identity || op
== EXP
.notIdentity
) ?
cast(typeof(return))this : null; }
826 inout(CondExp
) isCondExp() { return op
== EXP
.question ?
cast(typeof(return))this : null; }
827 inout(GenericExp
) isGenericExp() { return op
== EXP
._Generic ?
cast(typeof(return))this : null; }
828 inout(DefaultInitExp
) isDefaultInitExp() { return
829 (op
== EXP
.prettyFunction || op
== EXP
.functionString ||
830 op
== EXP
.line || op
== EXP
.moduleString ||
831 op
== EXP
.file || op
== EXP
.fileFullPath
) ?
cast(typeof(return))this : null; }
832 inout(FileInitExp
) isFileInitExp() { return (op
== EXP
.file || op
== EXP
.fileFullPath
) ?
cast(typeof(return))this : null; }
833 inout(LineInitExp
) isLineInitExp() { return op
== EXP
.line ?
cast(typeof(return))this : null; }
834 inout(ModuleInitExp
) isModuleInitExp() { return op
== EXP
.moduleString ?
cast(typeof(return))this : null; }
835 inout(FuncInitExp
) isFuncInitExp() { return op
== EXP
.functionString ?
cast(typeof(return))this : null; }
836 inout(PrettyFuncInitExp
) isPrettyFuncInitExp() { return op
== EXP
.prettyFunction ?
cast(typeof(return))this : null; }
837 inout(ObjcClassReferenceExp
) isObjcClassReferenceExp() { return op
== EXP
.objcClassReference ?
cast(typeof(return))this : null; }
838 inout(ClassReferenceExp
) isClassReferenceExp() { return op
== EXP
.classReference ?
cast(typeof(return))this : null; }
839 inout(ThrownExceptionExp
) isThrownExceptionExp() { return op
== EXP
.thrownException ?
cast(typeof(return))this : null; }
841 inout(UnaExp
) isUnaExp() pure inout nothrow @nogc
843 return exptab
[op
] & EXPFLAGS
.unary ?
cast(typeof(return))this : null;
846 inout(BinExp
) isBinExp() pure inout nothrow @nogc
848 return exptab
[op
] & EXPFLAGS
.binary ?
cast(typeof(return))this : null;
851 inout(BinAssignExp
) isBinAssignExp() pure inout nothrow @nogc
853 return exptab
[op
] & EXPFLAGS
.binaryAssign ?
cast(typeof(return))this : null;
857 override void accept(Visitor v
)
863 /***********************************************************
864 * A compile-time known integer value
866 extern (C
++) final class IntegerExp
: Expression
868 private dinteger_t value
;
870 extern (D
) this(const ref Loc loc
, dinteger_t value
, Type type
)
872 super(loc
, EXP
.int64
);
873 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
875 if (!type
.isscalar())
877 //printf("%s, loc = %d\n", toChars(), loc.linnum);
878 if (type
.ty
!= Terror
)
879 error(loc
, "integral constant must be scalar type, not `%s`", type
.toChars());
883 this.value
= normalize(type
.toBasetype().ty
, value
);
886 extern (D
) this(dinteger_t value
)
888 super(Loc
.initial
, EXP
.int64
);
889 this.type
= Type
.tint32
;
890 this.value
= cast(int)value
;
893 static IntegerExp
create(const ref Loc loc
, dinteger_t value
, Type type
)
895 return new IntegerExp(loc
, value
, type
);
898 override bool equals(const RootObject o
) const
902 if (auto ne
= (cast(Expression
)o
).isIntegerExp())
904 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && value
== ne
.value
)
912 override dinteger_t
toInteger()
914 // normalize() is necessary until we fix all the paints of 'type'
915 return value
= normalize(type
.toBasetype().ty
, value
);
918 override real_t
toReal()
920 // normalize() is necessary until we fix all the paints of 'type'
921 const ty
= type
.toBasetype().ty
;
922 const val
= normalize(ty
, value
);
924 return (ty
== Tuns64
)
925 ?
real_t(cast(ulong)val
)
926 : real_t(cast(long)val
);
929 override real_t
toImaginary()
934 override complex_t
toComplex()
936 return complex_t(toReal());
939 override Optional
!bool toBool()
941 bool r
= toInteger() != 0;
942 return typeof(return)(r
);
945 override void accept(Visitor v
)
950 dinteger_t
getInteger()
955 extern (D
) void setInteger(dinteger_t value
)
957 this.value
= normalize(type
.toBasetype().ty
, value
);
960 extern (D
) static dinteger_t
normalize(TY ty
, dinteger_t value
)
962 /* 'Normalize' the value of the integer to be in range of the type
968 result
= (value
!= 0);
972 result
= cast(byte)value
;
977 result
= cast(ubyte)value
;
981 result
= cast(short)value
;
986 result
= cast(ushort)value
;
990 result
= cast(int)value
;
995 result
= cast(uint)value
;
999 result
= cast(long)value
;
1003 result
= cast(ulong)value
;
1007 if (target
.ptrsize
== 8)
1009 if (target
.ptrsize
== 4)
1011 if (target
.ptrsize
== 2)
1021 override IntegerExp
syntaxCopy()
1027 * Use this instead of creating new instances for commonly used literals
1031 * v = The value of the expression
1033 * A static instance of the expression, typed as `Tint32`.
1035 static IntegerExp
literal(int v
)()
1037 __gshared IntegerExp theConstant
;
1039 theConstant
= new IntegerExp(v
);
1044 * Use this instead of creating new instances for commonly used bools.
1047 * b = The value of the expression
1049 * A static instance of the expression, typed as `Type.tbool`.
1051 static IntegerExp
createBool(bool b
)
1053 __gshared IntegerExp trueExp
, falseExp
;
1056 trueExp
= new IntegerExp(Loc
.initial
, 1, Type
.tbool
);
1057 falseExp
= new IntegerExp(Loc
.initial
, 0, Type
.tbool
);
1059 return b ? trueExp
: falseExp
;
1063 /***********************************************************
1064 * Use this expression for error recovery.
1066 * It should behave as a 'sink' to prevent further cascaded error messages.
1068 extern (C
++) final class ErrorExp
: Expression
1072 super(Loc
.initial
, EXP
.error
);
1076 static ErrorExp
get ()
1078 if (errorexp
is null)
1079 errorexp
= new ErrorExp();
1081 if (global
.errors
== 0 && global
.gaggedErrors
== 0)
1083 /* Unfortunately, errors can still leak out of gagged errors,
1084 * and we need to set the error count to prevent bogus code
1085 * generation. At least give a message.
1087 .error(Loc
.initial
, "unknown, please file report on issues.dlang.org");
1093 override void accept(Visitor v
)
1098 extern (C
++) __gshared ErrorExp errorexp
; // handy shared value
1102 /***********************************************************
1103 * An uninitialized value,
1104 * generated from void initializers.
1106 * https://dlang.org/spec/declaration.html#void_init
1108 extern (C
++) final class VoidInitExp
: Expression
1110 VarDeclaration var
; /// the variable from where the void value came from, null if not known
1111 /// Useful for error messages
1113 extern (D
) this(VarDeclaration var
) @safe
1115 super(var
.loc
, EXP
.void_
);
1117 this.type
= var
.type
;
1120 override void accept(Visitor v
)
1127 /***********************************************************
1128 * A compile-time known floating point number
1130 extern (C
++) final class RealExp
: Expression
1134 extern (D
) this(const ref Loc loc
, real_t value
, Type type
) @safe
1136 super(loc
, EXP
.float64
);
1137 //printf("RealExp::RealExp(%Lg)\n", value);
1142 static RealExp
create(const ref Loc loc
, real_t value
, Type type
) @safe
1144 return new RealExp(loc
, value
, type
);
1147 /********************************
1148 * Test to see if two reals are the same.
1149 * Regard NaN's as equivalent.
1150 * Regard +0 and -0 as different.
1152 * x1 = first operand
1153 * x2 = second operand
1158 private static bool RealIdentical(real_t x1
, real_t x2
) @safe
1160 return (CTFloat
.isNaN(x1
) && CTFloat
.isNaN(x2
)) || CTFloat
.isIdentical(x1
, x2
);
1162 override bool equals(const RootObject o
) const
1166 if (auto ne
= (cast(Expression
)o
).isRealExp())
1168 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && RealIdentical(value
, ne
.value
))
1176 override bool isIdentical(const Expression e
) const
1180 return CTFloat
.isIdentical(value
, e
.isRealExp().value
);
1183 override dinteger_t
toInteger()
1185 return cast(sinteger_t
)toReal();
1188 override uinteger_t
toUInteger()
1190 return cast(uinteger_t
)toReal();
1193 override real_t
toReal()
1195 return type
.isreal() ? value
: CTFloat
.zero
;
1198 override real_t
toImaginary()
1200 return type
.isreal() ? CTFloat
.zero
: value
;
1203 override complex_t
toComplex()
1205 return complex_t(toReal(), toImaginary());
1208 override Optional
!bool toBool()
1210 return typeof(return)(!!value
);
1213 override void accept(Visitor v
)
1219 /***********************************************************
1220 * A compile-time complex number (deprecated)
1222 extern (C
++) final class ComplexExp
: Expression
1226 extern (D
) this(const ref Loc loc
, complex_t value
, Type type
) @safe
1228 super(loc
, EXP
.complex80
);
1231 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
1234 static ComplexExp
create(const ref Loc loc
, complex_t value
, Type type
) @safe
1236 return new ComplexExp(loc
, value
, type
);
1239 override bool equals(const RootObject o
) const
1243 if (auto ne
= (cast(Expression
)o
).isComplexExp())
1245 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) &&
1246 RealExp
.RealIdentical(creall(value
), creall(ne
.value
)) &&
1247 RealExp
.RealIdentical(cimagl(value
), cimagl(ne
.value
)))
1255 override bool isIdentical(const Expression e
) const
1259 // equals() regards different NaN values as 'equals'
1260 auto c
= e
.isComplexExp();
1261 return CTFloat
.isIdentical(creall(value
), creall(c
.value
)) &&
1262 CTFloat
.isIdentical(cimagl(value
), cimagl(c
.value
));
1265 override dinteger_t
toInteger()
1267 return cast(sinteger_t
)toReal();
1270 override uinteger_t
toUInteger()
1272 return cast(uinteger_t
)toReal();
1275 override real_t
toReal()
1277 return creall(value
);
1280 override real_t
toImaginary()
1282 return cimagl(value
);
1285 override complex_t
toComplex()
1290 override Optional
!bool toBool()
1292 return typeof(return)(!!value
);
1295 override void accept(Visitor v
)
1301 /***********************************************************
1302 * An identifier in the context of an expression (as opposed to a declaration)
1305 * int x; // VarDeclaration with Identifier
1306 * x++; // PostExp with IdentifierExp
1309 extern (C
++) class IdentifierExp
: Expression
1312 bool parens
; // if it appears as (identifier)
1314 extern (D
) this(const ref Loc loc
, Identifier ident
) scope @safe
1316 super(loc
, EXP
.identifier
);
1320 static IdentifierExp
create(const ref Loc loc
, Identifier ident
) @safe
1322 return new IdentifierExp(loc
, ident
);
1325 override final bool isLvalue()
1330 override void accept(Visitor v
)
1336 /***********************************************************
1337 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
1339 * https://dlang.org/spec/arrays.html#array-length
1341 extern (C
++) final class DollarExp
: IdentifierExp
1343 extern (D
) this(const ref Loc loc
)
1345 super(loc
, Id
.dollar
);
1348 override void accept(Visitor v
)
1354 /***********************************************************
1355 * Won't be generated by parser.
1357 extern (C
++) final class DsymbolExp
: Expression
1362 extern (D
) this(const ref Loc loc
, Dsymbol s
, bool hasOverloads
= true) @safe
1364 super(loc
, EXP
.dSymbol
);
1366 this.hasOverloads
= hasOverloads
;
1369 override bool isLvalue()
1374 override void accept(Visitor v
)
1380 /***********************************************************
1381 * https://dlang.org/spec/expression.html#this
1383 extern (C
++) class ThisExp
: Expression
1387 extern (D
) this(const ref Loc loc
) @safe
1389 super(loc
, EXP
.this_
);
1390 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1393 this(const ref Loc loc
, const EXP tok
) @safe
1396 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1399 override ThisExp
syntaxCopy()
1401 auto r
= cast(ThisExp
) super.syntaxCopy();
1402 // require new semantic (possibly new `var` etc.)
1408 override Optional
!bool toBool()
1410 // `this` is never null (what about structs?)
1411 return typeof(return)(true);
1414 override final bool isLvalue()
1416 // Class `this` should be an rvalue; struct `this` should be an lvalue.
1417 return type
.toBasetype().ty
!= Tclass
;
1420 override void accept(Visitor v
)
1426 /***********************************************************
1427 * https://dlang.org/spec/expression.html#super
1429 extern (C
++) final class SuperExp
: ThisExp
1431 extern (D
) this(const ref Loc loc
) @safe
1433 super(loc
, EXP
.super_
);
1436 override void accept(Visitor v
)
1442 /***********************************************************
1443 * A compile-time known `null` value
1445 * https://dlang.org/spec/expression.html#null
1447 extern (C
++) final class NullExp
: Expression
1449 extern (D
) this(const ref Loc loc
, Type type
= null) scope @safe
1451 super(loc
, EXP
.null_
);
1455 override bool equals(const RootObject o
) const
1457 if (auto e
= o
.isExpression())
1459 if (e
.op
== EXP
.null_
&& type
.equals(e
.type
))
1467 override Optional
!bool toBool()
1469 // null in any type is false
1470 return typeof(return)(false);
1473 override StringExp
toStringExp()
1475 if (this.type
.implicitConvTo(Type
.tstring
))
1477 auto se
= new StringExp(loc
, (cast(char*)mem
.xcalloc(1, 1))[0 .. 0]);
1478 se
.type
= Type
.tstring
;
1485 override void accept(Visitor v
)
1491 /***********************************************************
1492 * https://dlang.org/spec/expression.html#string_literals
1494 extern (C
++) final class StringExp
: Expression
1496 char postfix
= NoPostfix
; // 'c', 'w', 'd'
1497 OwnedBy ownedByCtfe
= OwnedBy
.code
;
1500 char* string
; // if sz == 1
1501 wchar* wstring
; // if sz == 2
1502 dchar* dstring
; // if sz == 4
1503 ulong* lstring
; // if sz == 8
1504 } // (const if ownedByCtfe == OwnedBy.code)
1505 size_t len
; // number of code units
1506 ubyte sz
= 1; // 1: char, 2: wchar, 4: dchar
1509 * Whether the string literal's type is fixed
1512 * wstring x = "abc"; // OK, string literal is flexible
1513 * wstring y = cast(string) "abc"; // Error: type was committed after cast
1518 /// If the string is parsed from a hex string literal
1519 bool hexString
= false;
1521 enum char NoPostfix
= 0;
1523 extern (D
) this(const ref Loc loc
, const(void)[] string
) scope
1525 super(loc
, EXP
.string_
);
1526 this.string
= cast(char*)string
.ptr
; // note that this.string should be const
1527 this.len
= string
.length
;
1528 this.sz
= 1; // work around LDC bug #1286
1531 extern (D
) this(const ref Loc loc
, const(void)[] string
, size_t len
, ubyte sz
, char postfix
= NoPostfix
) scope
1533 super(loc
, EXP
.string_
);
1534 this.string
= cast(char*)string
.ptr
; // note that this.string should be const
1537 this.postfix
= postfix
;
1540 static StringExp
create(const ref Loc loc
, const(char)* s
)
1542 return new StringExp(loc
, s
.toDString());
1545 static StringExp
create(const ref Loc loc
, const(void)* string
, size_t len
)
1547 return new StringExp(loc
, string
[0 .. len
]);
1550 override bool equals(const RootObject o
) const
1552 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
1553 if (auto e
= o
.isExpression())
1555 if (auto se
= e
.isStringExp())
1557 return compare(se
) == 0;
1563 /**********************************
1564 * Return the number of code units the string would be if it were re-encoded
1567 * tynto = code unit type of the target encoding
1569 * number of code units
1571 size_t
numberOfCodeUnits(int tynto
= 0) const
1577 case Tchar
: encSize
= 1; break;
1578 case Twchar
: encSize
= 2; break;
1579 case Tdchar
: encSize
= 4; break;
1592 for (size_t u
= 0; u
< len
;)
1594 if (const s
= utf_decodeChar(string
[0 .. len
], u
, c
))
1596 error(loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1599 result
+= utf_codeLength(encSize
, c
);
1604 for (size_t u
= 0; u
< len
;)
1606 if (const s
= utf_decodeWchar(wstring
[0 .. len
], u
, c
))
1608 error(loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1611 result
+= utf_codeLength(encSize
, c
);
1616 foreach (u
; 0 .. len
)
1618 result
+= utf_codeLength(encSize
, dstring
[u
]);
1628 /**********************************************
1629 * Write the contents of the string to dest.
1630 * Use numberOfCodeUnits() to determine size of result.
1632 * dest = destination
1633 * tyto = encoding type of the result
1634 * zero = add terminating 0
1636 void writeTo(void* dest
, bool zero
, int tyto
= 0) const
1641 case 0: encSize
= sz
; break;
1642 case Tchar
: encSize
= 1; break;
1643 case Twchar
: encSize
= 2; break;
1644 case Tdchar
: encSize
= 4; break;
1650 memcpy(dest
, string
, len
* sz
);
1652 memset(dest
+ len
* sz
, 0, sz
);
1658 /*********************************************
1659 * Get the code unit at index i
1663 * code unit at index i
1665 dchar getCodeUnit(size_t i
) const pure
1667 assert(this.sz
<= dchar.sizeof
);
1668 return cast(dchar) getIndex(i
);
1671 /// Returns: integer at index `i`
1672 dinteger_t
getIndex(size_t i
) const pure
1688 /*********************************************
1689 * Set the code unit at index i to c
1692 * c = code unit to set it to
1694 extern (D
) void setCodeUnit(size_t i
, dchar c
)
1696 return setIndex(i
, c
);
1699 extern (D
) void setIndex(size_t i
, long c
)
1705 string
[i
] = cast(char)c
;
1708 wstring
[i
] = cast(wchar)c
;
1711 dstring
[i
] = cast(dchar) c
;
1719 override StringExp
toStringExp()
1726 * Compare two `StringExp` by length, then value
1728 * The comparison is not the usual C-style comparison as seen with
1729 * `strcmp` or `memcmp`, but instead first compare based on the length.
1730 * This allows both faster lookup and sorting when comparing sparse data.
1732 * This ordering scheme is relied on by the string-switching feature.
1733 * Code in Druntime's `core.internal.switch_` relies on this ordering
1734 * when doing a binary search among case statements.
1736 * Both `StringExp` should be of the same encoding.
1739 * se2 = String expression to compare `this` to
1742 * `0` when `this` is equal to se2, a value greater than `0` if
1743 * `this` should be considered greater than `se2`,
1744 * and a value less than `0` if `this` is lesser than `se2`.
1746 int compare(const StringExp se2
) const nothrow pure @nogc
1748 //printf("StringExp::compare()\n");
1750 const len2
= se2
.len
;
1752 assert(this.sz
== se2
.sz
, "Comparing string expressions of different sizes");
1753 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
1759 return memcmp(string
, se2
.string
, len1
);
1763 wchar* s1
= cast(wchar*)string
;
1764 wchar* s2
= cast(wchar*)se2
.string
;
1765 foreach (u
; 0 .. len
)
1768 return s1
[u
] - s2
[u
];
1774 dchar* s1
= cast(dchar*)string
;
1775 dchar* s2
= cast(dchar*)se2
.string
;
1776 foreach (u
; 0 .. len
)
1779 return s1
[u
] - s2
[u
];
1787 return cast(int)(len1
- len2
);
1790 override Optional
!bool toBool()
1792 // Keep the old behaviour for this refactoring
1793 // Should probably match language spec instead and check for length
1794 return typeof(return)(true);
1797 override bool isLvalue()
1799 /* string literal is rvalue in default, but
1800 * conversion to reference of static array is only allowed.
1802 return (type
&& type
.toBasetype().ty
== Tsarray
);
1805 /********************************
1806 * Convert string contents to a 0 terminated string,
1807 * allocated by mem.xmalloc().
1809 extern (D
) const(char)[] toStringz() const
1811 auto nbytes
= len
* sz
;
1812 char* s
= cast(char*)mem
.xmalloc(nbytes
+ sz
);
1814 return s
[0 .. nbytes
];
1817 extern (D
) const(char)[] peekString() const
1820 return this.string
[0 .. len
];
1823 extern (D
) const(wchar)[] peekWstring() const
1826 return this.wstring
[0 .. len
];
1829 extern (D
) const(dchar)[] peekDstring() const
1832 return this.dstring
[0 .. len
];
1835 /*******************
1836 * Get a slice of the data.
1838 extern (D
) const(ubyte)[] peekData() const
1840 return cast(const(ubyte)[])this.string
[0 .. len
* sz
];
1843 /*******************
1844 * Borrow a slice of the data, so the caller can modify
1847 extern (D
) ubyte[] borrowData()
1849 return cast(ubyte[])this.string
[0 .. len
* sz
];
1852 /***********************
1853 * Set new string data.
1854 * `this` becomes the new owner of the data.
1856 extern (D
) void setData(void* s
, size_t len
, ubyte sz
)
1858 this.string
= cast(char*)s
;
1863 override void accept(Visitor v
)
1869 extern (C
++) final class InterpExp
: Expression
1871 char postfix
= NoPostfix
; // 'c', 'w', 'd'
1872 OwnedBy ownedByCtfe
= OwnedBy
.code
;
1873 InterpolatedSet
* interpolatedSet
;
1875 enum char NoPostfix
= 0;
1877 extern (D
) this(const ref Loc loc
, InterpolatedSet
* set
, char postfix
= NoPostfix
) scope
1879 super(loc
, EXP
.interpolated
);
1880 this.interpolatedSet
= set
;
1881 this.postfix
= postfix
;
1884 override void accept(Visitor v
)
1891 /***********************************************************
1892 * A sequence of expressions
1895 * alias AliasSeq(T...) = T;
1896 * alias Tup = AliasSeq!(3, int, "abc");
1899 extern (C
++) final class TupleExp
: Expression
1901 /* Tuple-field access may need to take out its side effect part.
1905 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
1906 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
1912 extern (D
) this(const ref Loc loc
, Expression e0
, Expressions
* exps
) @safe
1914 super(loc
, EXP
.tuple
);
1915 //printf("TupleExp(this = %p)\n", this);
1920 extern (D
) this(const ref Loc loc
, Expressions
* exps
) @safe
1922 super(loc
, EXP
.tuple
);
1923 //printf("TupleExp(this = %p)\n", this);
1927 extern (D
) this(const ref Loc loc
, TupleDeclaration tup
)
1929 super(loc
, EXP
.tuple
);
1930 this.exps
= new Expressions();
1932 this.exps
.reserve(tup
.objects
.length
);
1933 foreach (o
; *tup
.objects
)
1935 if (Dsymbol s
= getDsymbol(o
))
1937 /* If tuple element represents a symbol, translate to DsymbolExp
1938 * to supply implicit 'this' if needed later.
1940 Expression e
= new DsymbolExp(loc
, s
);
1943 else if (auto eo
= o
.isExpression())
1946 e
.loc
= loc
; // https://issues.dlang.org/show_bug.cgi?id=15669
1949 else if (auto t
= o
.isType())
1951 Expression e
= new TypeExp(loc
, t
);
1956 error(loc
, "`%s` is not an expression", o
.toChars());
1961 static TupleExp
create(const ref Loc loc
, Expressions
* exps
) @safe
1963 return new TupleExp(loc
, exps
);
1966 override TupleExp
syntaxCopy()
1968 return new TupleExp(loc
, e0 ? e0
.syntaxCopy() : null, arraySyntaxCopy(exps
));
1971 override bool equals(const RootObject o
) const
1975 if (auto e
= o
.isExpression())
1976 if (auto te
= e
.isTupleExp())
1978 if (exps
.length
!= te
.exps
.length
)
1980 if (e0
&& !e0
.equals(te
.e0
) ||
!e0
&& te
.e0
)
1982 foreach (i
, e1
; *exps
)
1984 auto e2
= (*te
.exps
)[i
];
1993 override void accept(Visitor v
)
1999 /***********************************************************
2000 * [ e1, e2, e3, ... ]
2002 * https://dlang.org/spec/expression.html#array_literals
2004 extern (C
++) final class ArrayLiteralExp
: Expression
2006 OwnedBy ownedByCtfe
= OwnedBy
.code
;
2007 bool onstack
= false;
2009 /** If !is null, elements[] can be sparse and basis is used for the
2010 * "default" element value. In other words, non-null elements[i] overrides
2011 * this 'basis' value.
2015 Expressions
* elements
;
2017 extern (D
) this(const ref Loc loc
, Type type
, Expressions
* elements
) @safe
2019 super(loc
, EXP
.arrayLiteral
);
2021 this.elements
= elements
;
2024 extern (D
) this(const ref Loc loc
, Type type
, Expression e
)
2026 super(loc
, EXP
.arrayLiteral
);
2028 elements
= new Expressions();
2032 extern (D
) this(const ref Loc loc
, Type type
, Expression basis
, Expressions
* elements
) @safe
2034 super(loc
, EXP
.arrayLiteral
);
2037 this.elements
= elements
;
2040 static ArrayLiteralExp
create(const ref Loc loc
, Expressions
* elements
) @safe
2042 return new ArrayLiteralExp(loc
, null, elements
);
2045 override ArrayLiteralExp
syntaxCopy()
2047 return new ArrayLiteralExp(loc
,
2049 basis ? basis
.syntaxCopy() : null,
2050 arraySyntaxCopy(elements
));
2053 override bool equals(const RootObject o
) const
2057 auto e
= o
.isExpression();
2060 if (auto ae
= e
.isArrayLiteralExp())
2062 if (elements
.length
!= ae
.elements
.length
)
2064 if (elements
.length
== 0 && !type
.equals(ae
.type
))
2069 foreach (i
, e1
; *elements
)
2071 auto e2
= (*ae
.elements
)[i
];
2072 auto e1x
= e1 ? e1
: basis
;
2073 auto e2x
= e2 ? e2
: ae
.basis
;
2075 if (e1x
!= e2x
&& (!e1x ||
!e2x ||
!e1x
.equals(e2x
)))
2083 Expression
getElement(size_t i
) // use opIndex instead
2088 extern (D
) Expression
opIndex(size_t i
)
2090 auto el
= (*elements
)[i
];
2091 return el ? el
: basis
;
2094 override Optional
!bool toBool()
2096 size_t dim
= elements ? elements
.length
: 0;
2097 return typeof(return)(dim
!= 0);
2100 override StringExp
toStringExp()
2102 TY telem
= type
.nextOf().toBasetype().ty
;
2103 if (telem
.isSomeChar ||
(telem
== Tvoid
&& (!elements || elements
.length
== 0)))
2106 if (telem
== Twchar
)
2108 else if (telem
== Tdchar
)
2114 foreach (i
; 0 .. elements
.length
)
2117 if (ch
.op
!= EXP
.int64
)
2120 buf
.writeByte(cast(uint)ch
.toInteger());
2122 buf
.writeword(cast(uint)ch
.toInteger());
2124 buf
.write4(cast(uint)ch
.toInteger());
2144 const size_t len
= buf
.length
/ sz
- 1;
2145 auto se
= new StringExp(loc
, buf
.extractSlice()[0 .. len
* sz
], len
, sz
, prefix
);
2153 override void accept(Visitor v
)
2159 /***********************************************************
2160 * [ key0 : value0, key1 : value1, ... ]
2162 * https://dlang.org/spec/expression.html#associative_array_literals
2164 extern (C
++) final class AssocArrayLiteralExp
: Expression
2166 OwnedBy ownedByCtfe
= OwnedBy
.code
;
2169 Expressions
* values
;
2170 /// Lower to core.internal.newaa for static initializaton
2171 Expression lowering
;
2173 extern (D
) this(const ref Loc loc
, Expressions
* keys
, Expressions
* values
) @safe
2175 super(loc
, EXP
.assocArrayLiteral
);
2176 assert(keys
.length
== values
.length
);
2178 this.values
= values
;
2181 override bool equals(const RootObject o
) const
2185 auto e
= o
.isExpression();
2188 if (auto ae
= e
.isAssocArrayLiteralExp())
2190 if (keys
.length
!= ae
.keys
.length
)
2193 foreach (i
, key
; *keys
)
2195 foreach (j
, akey
; *ae
.keys
)
2197 if (key
.equals(akey
))
2199 if (!(*values
)[i
].equals((*ae
.values
)[j
]))
2205 return count
== keys
.length
;
2210 override AssocArrayLiteralExp
syntaxCopy()
2212 return new AssocArrayLiteralExp(loc
, arraySyntaxCopy(keys
), arraySyntaxCopy(values
));
2215 override Optional
!bool toBool()
2217 size_t dim
= keys
.length
;
2218 return typeof(return)(dim
!= 0);
2221 override void accept(Visitor v
)
2227 enum stageScrub
= 0x1; /// scrubReturnValue is running
2228 enum stageSearchPointers
= 0x2; /// hasNonConstPointers is running
2229 enum stageOptimize
= 0x4; /// optimize is running
2230 enum stageApply
= 0x8; /// apply is running
2231 enum stageInlineScan
= 0x10; /// inlineScan is running
2232 enum stageToCBuffer
= 0x20; /// toCBuffer is running
2234 /***********************************************************
2235 * sd( e1, e2, e3, ... )
2237 extern (C
++) final class StructLiteralExp
: Expression
2239 StructDeclaration sd
; /// which aggregate this is for
2240 Expressions
* elements
; /// parallels sd.fields[] with null entries for fields to skip
2241 Type stype
; /// final type of result (can be different from sd's type)
2243 // `inlineCopy` is only used temporarily in the `inline.d` pass,
2244 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
2247 void* sym
; /// back end symbol to initialize with literal (used as a Symbol*)
2249 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
2250 StructLiteralExp inlinecopy
;
2253 /** pointer to the origin instance of the expression.
2254 * once a new expression is created, origin is set to 'this'.
2255 * anytime when an expression copy is created, 'origin' pointer is set to
2256 * 'origin' pointer value of the original expression.
2258 StructLiteralExp origin
;
2261 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
2262 * current stage and unmarks before return from this function.
2263 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
2264 * (with infinite recursion) of this expression.
2268 bool useStaticInit
; /// if this is true, use the StructDeclaration's init symbol
2269 bool isOriginal
= false; /// used when moving instances to indicate `this is this.origin`
2270 OwnedBy ownedByCtfe
= OwnedBy
.code
;
2272 extern (D
) this(const ref Loc loc
, StructDeclaration sd
, Expressions
* elements
, Type stype
= null) @safe
2274 super(loc
, EXP
.structLiteral
);
2277 elements
= new Expressions();
2278 this.elements
= elements
;
2281 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
2284 static StructLiteralExp
create(const ref Loc loc
, StructDeclaration sd
, void* elements
, Type stype
= null)
2286 return new StructLiteralExp(loc
, sd
, cast(Expressions
*)elements
, stype
);
2289 override bool equals(const RootObject o
) const
2293 auto e
= o
.isExpression();
2296 if (auto se
= e
.isStructLiteralExp())
2298 if (!type
.equals(se
.type
))
2300 if (elements
.length
!= se
.elements
.length
)
2302 foreach (i
, e1
; *elements
)
2304 auto e2
= (*se
.elements
)[i
];
2305 if (e1
!= e2
&& (!e1 ||
!e2 ||
!e1
.equals(e2
)))
2313 override StructLiteralExp
syntaxCopy()
2315 auto exp
= new StructLiteralExp(loc
, sd
, arraySyntaxCopy(elements
), type ? type
: stype
);
2320 /**************************************
2321 * Gets expression at offset of type.
2322 * Returns NULL if not found.
2324 extern (D
) Expression
getField(Type type
, uint offset
)
2326 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
2327 // /*toChars()*/"", type.toChars(), offset);
2328 Expression e
= null;
2329 int i
= getFieldIndex(type
, offset
);
2333 //printf("\ti = %d\n", i);
2334 if (i
>= sd
.nonHiddenFields())
2337 assert(i
< elements
.length
);
2341 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
2343 /* If type is a static array, and e is an initializer for that array,
2344 * then the field initializer should be an array literal of e.
2346 auto tsa
= type
.isTypeSArray();
2347 if (tsa
&& e
.type
.castMod(0) != type
.castMod(0))
2349 const length
= cast(size_t
)tsa
.dim
.toInteger();
2350 auto z
= new Expressions(length
);
2353 e
= new ArrayLiteralExp(loc
, type
, z
);
2360 if (useStaticInit
&& e
.type
.needsNested())
2361 if (auto se
= e
.isStructLiteralExp())
2363 se
.useStaticInit
= true;
2370 /************************************
2371 * Get index of field.
2372 * Returns -1 if not found.
2374 extern (D
) int getFieldIndex(Type type
, uint offset
)
2376 /* Find which field offset is by looking at the field offsets
2378 if (elements
.length
)
2380 const sz
= type
.size();
2381 if (sz
== SIZE_INVALID
)
2383 foreach (i
, v
; sd
.fields
)
2385 if (offset
== v
.offset
&& sz
== v
.type
.size())
2387 /* context fields might not be filled. */
2388 if (i
>= sd
.nonHiddenFields())
2390 if (auto e
= (*elements
)[i
])
2401 override void accept(Visitor v
)
2407 /***********************************************************
2409 * ( type-name ) { initializer-list }
2411 extern (C
++) final class CompoundLiteralExp
: Expression
2413 Initializer initializer
; /// initializer-list
2415 extern (D
) this(const ref Loc loc
, Type type_name
, Initializer initializer
) @safe
2417 super(loc
, EXP
.compoundLiteral
);
2418 super.type
= type_name
;
2419 this.initializer
= initializer
;
2420 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
2423 override void accept(Visitor v
)
2429 /***********************************************************
2430 * Mainly just a placeholder
2432 extern (C
++) final class TypeExp
: Expression
2434 bool parens
; // if this is a parenthesized expression
2436 extern (D
) this(const ref Loc loc
, Type type
) @safe
2438 super(loc
, EXP
.type
);
2439 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
2443 override TypeExp
syntaxCopy()
2445 return new TypeExp(loc
, type
.syntaxCopy());
2448 override bool checkType()
2450 error(loc
, "type `%s` is not an expression", toChars());
2454 override bool checkValue()
2456 error(loc
, "type `%s` has no value", toChars());
2460 override void accept(Visitor v
)
2466 /***********************************************************
2467 * Mainly just a placeholder of
2468 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
2470 * A template instance that requires IFTI:
2471 * foo!tiargs(fargs) // foo!tiargs
2472 * is left until CallExp::semantic() or resolveProperties()
2474 extern (C
++) final class ScopeExp
: Expression
2478 extern (D
) this(const ref Loc loc
, ScopeDsymbol sds
) @safe
2480 super(loc
, EXP
.scope_
);
2481 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
2482 //static int count; if (++count == 38) *(char*)0=0;
2484 assert(!sds
.isTemplateDeclaration()); // instead, you should use TemplateExp
2487 override ScopeExp
syntaxCopy()
2489 return new ScopeExp(loc
, sds
.syntaxCopy(null));
2492 override bool checkType()
2494 if (sds
.isPackage())
2496 error(loc
, "%s `%s` has no type", sds
.kind(), sds
.toChars());
2499 if (auto ti
= sds
.isTemplateInstance())
2501 //assert(ti.needsTypeInference(sc));
2503 ti
.semantictiargsdone
&&
2504 ti
.semanticRun
== PASS
.initial
)
2506 error(loc
, "partial %s `%s` has no type", sds
.kind(), toChars());
2513 override bool checkValue()
2515 error(loc
, "%s `%s` has no value", sds
.kind(), sds
.toChars());
2519 override void accept(Visitor v
)
2525 /***********************************************************
2526 * Mainly just a placeholder
2528 extern (C
++) final class TemplateExp
: Expression
2530 TemplateDeclaration td
;
2533 extern (D
) this(const ref Loc loc
, TemplateDeclaration td
, FuncDeclaration fd
= null) @safe
2535 super(loc
, EXP
.template_
);
2536 //printf("TemplateExp(): %s\n", td.toChars());
2541 override bool isLvalue()
2546 override bool checkType()
2548 error(loc
, "%s `%s` has no type", td
.kind(), toChars());
2552 override bool checkValue()
2554 error(loc
, "%s `%s` has no value", td
.kind(), toChars());
2558 override void accept(Visitor v
)
2564 /***********************************************************
2565 * newtype(arguments)
2567 extern (C
++) final class NewExp
: Expression
2569 Expression thisexp
; // if !=null, 'this' for class being allocated
2571 Expressions
* arguments
; // Array of Expression's
2572 Identifiers
* names
; // Array of names corresponding to expressions
2574 Expression argprefix
; // expression to be evaluated just before arguments[]
2575 CtorDeclaration member
; // constructor function
2576 bool onstack
; // allocate on stack
2577 bool thrownew
; // this NewExp is the expression of a ThrowStatement
2579 Expression lowering
; // lowered druntime hook: `_d_new{class,itemT}`
2581 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
2582 /// The fields are still separate for backwards compatibility
2583 extern (D
) ArgumentList
argumentList() { return ArgumentList(arguments
, names
); }
2585 extern (D
) this(const ref Loc loc
, Expression thisexp
, Type newtype
, Expressions
* arguments
, Identifiers
* names
= null) @safe
2587 super(loc
, EXP
.new_
);
2588 this.thisexp
= thisexp
;
2589 this.newtype
= newtype
;
2590 this.arguments
= arguments
;
2594 static NewExp
create(const ref Loc loc
, Expression thisexp
, Type newtype
, Expressions
* arguments
) @safe
2596 return new NewExp(loc
, thisexp
, newtype
, arguments
);
2599 override NewExp
syntaxCopy()
2601 return new NewExp(loc
,
2602 thisexp ? thisexp
.syntaxCopy() : null,
2603 newtype
.syntaxCopy(),
2604 arraySyntaxCopy(arguments
),
2605 names ? names
.copy() : null);
2608 override void accept(Visitor v
)
2614 /***********************************************************
2615 * class baseclasses { } (arguments)
2617 extern (C
++) final class NewAnonClassExp
: Expression
2619 Expression thisexp
; // if !=null, 'this' for class being allocated
2620 ClassDeclaration cd
; // class being instantiated
2621 Expressions
* arguments
; // Array of Expression's to call class constructor
2623 extern (D
) this(const ref Loc loc
, Expression thisexp
, ClassDeclaration cd
, Expressions
* arguments
) @safe
2625 super(loc
, EXP
.newAnonymousClass
);
2626 this.thisexp
= thisexp
;
2628 this.arguments
= arguments
;
2631 override NewAnonClassExp
syntaxCopy()
2633 return new NewAnonClassExp(loc
, thisexp ? thisexp
.syntaxCopy() : null, cd
.syntaxCopy(null), arraySyntaxCopy(arguments
));
2636 override void accept(Visitor v
)
2642 /***********************************************************
2644 extern (C
++) class SymbolExp
: Expression
2647 Dsymbol originalScope
; // original scope before inlining
2650 extern (D
) this(const ref Loc loc
, EXP op
, Declaration var
, bool hasOverloads
) @safe
2655 this.hasOverloads
= hasOverloads
;
2658 override void accept(Visitor v
)
2664 /***********************************************************
2665 * Offset from symbol
2667 extern (C
++) final class SymOffExp
: SymbolExp
2671 extern (D
) this(const ref Loc loc
, Declaration var
, dinteger_t offset
, bool hasOverloads
= true)
2673 if (auto v
= var
.isVarDeclaration())
2675 // FIXME: This error report will never be handled anyone.
2676 // It should be done before the SymOffExp construction.
2679 auto t
= v
.isThis();
2681 .error(loc
, "taking the address of non-static variable `%s` requires an instance of `%s`", v
.toChars(), t
.toChars());
2683 hasOverloads
= false;
2685 super(loc
, EXP
.symbolOffset
, var
, hasOverloads
);
2686 this.offset
= offset
;
2689 override Optional
!bool toBool()
2691 return typeof(return)(true);
2694 override void accept(Visitor v
)
2700 /***********************************************************
2703 extern (C
++) final class VarExp
: SymbolExp
2705 bool delegateWasExtracted
;
2706 extern (D
) this(const ref Loc loc
, Declaration var
, bool hasOverloads
= true) @safe
2708 if (var
.isVarDeclaration())
2709 hasOverloads
= false;
2711 super(loc
, EXP
.variable
, var
, hasOverloads
);
2712 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
2713 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
2714 this.type
= var
.type
;
2717 static VarExp
create(const ref Loc loc
, Declaration var
, bool hasOverloads
= true) @safe
2719 return new VarExp(loc
, var
, hasOverloads
);
2722 override bool equals(const RootObject o
) const
2726 if (auto ne
= o
.isExpression().isVarExp())
2728 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && var
== ne
.var
)
2736 override bool isLvalue()
2738 if (var
.storage_class
& (STC
.lazy_ | STC
.rvalue | STC
.manifest
))
2743 override void accept(Visitor v
)
2749 /***********************************************************
2752 extern (C
++) final class OverExp
: Expression
2756 extern (D
) this(const ref Loc loc
, OverloadSet s
)
2758 super(loc
, EXP
.overloadSet
);
2759 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
2764 override bool isLvalue()
2769 override void accept(Visitor v
)
2775 /***********************************************************
2776 * Function/Delegate literal
2779 extern (C
++) final class FuncExp
: Expression
2781 FuncLiteralDeclaration fd
;
2782 TemplateDeclaration td
;
2783 TOK tok
; // TOK.reserved, TOK.delegate_, TOK.function_
2785 extern (D
) this(const ref Loc loc
, Dsymbol s
)
2787 super(loc
, EXP
.function_
);
2788 this.td
= s
.isTemplateDeclaration();
2789 this.fd
= s
.isFuncLiteralDeclaration();
2793 assert(td
.members
&& td
.members
.length
== 1);
2794 fd
= (*td
.members
)[0].isFuncLiteralDeclaration();
2796 tok
= fd
.tok
; // save original kind of function/delegate/(infer)
2800 override bool equals(const RootObject o
) const
2804 auto e
= o
.isExpression();
2807 if (auto fe
= e
.isFuncExp())
2814 override FuncExp
syntaxCopy()
2817 return new FuncExp(loc
, td
.syntaxCopy(null));
2818 else if (fd
.semanticRun
== PASS
.initial
)
2819 return new FuncExp(loc
, fd
.syntaxCopy(null));
2820 else // https://issues.dlang.org/show_bug.cgi?id=13481
2821 // Prevent multiple semantic analysis of lambda body.
2822 return new FuncExp(loc
, fd
);
2825 override const(char)* toChars() const
2827 return fd
.toChars();
2830 override bool checkType()
2834 error(loc
, "template lambda has no type");
2840 override bool checkValue()
2844 error(loc
, "template lambda has no value");
2850 override void accept(Visitor v
)
2856 /***********************************************************
2857 * Declaration of a symbol
2859 * D grammar allows declarations only as statements. However in AST representation
2860 * it can be part of any expression. This is used, for example, during internal
2861 * syntax re-writes to inject hidden symbols.
2863 extern (C
++) final class DeclarationExp
: Expression
2865 Dsymbol declaration
;
2867 extern (D
) this(const ref Loc loc
, Dsymbol declaration
) @safe
2869 super(loc
, EXP
.declaration
);
2870 this.declaration
= declaration
;
2873 override DeclarationExp
syntaxCopy()
2875 return new DeclarationExp(loc
, declaration
.syntaxCopy(null));
2878 override bool hasCode()
2880 if (auto vd
= declaration
.isVarDeclaration())
2882 return !(vd
.storage_class
& (STC
.manifest | STC
.static_
));
2887 override void accept(Visitor v
)
2893 /***********************************************************
2896 extern (C
++) final class TypeidExp
: Expression
2900 extern (D
) this(const ref Loc loc
, RootObject o
) @safe
2902 super(loc
, EXP
.typeid_
);
2906 override TypeidExp
syntaxCopy()
2908 return new TypeidExp(loc
, objectSyntaxCopy(obj
));
2911 override void accept(Visitor v
)
2917 /***********************************************************
2918 * __traits(identifier, args...)
2920 extern (C
++) final class TraitsExp
: Expression
2925 extern (D
) this(const ref Loc loc
, Identifier ident
, Objects
* args
) @safe
2927 super(loc
, EXP
.traits
);
2932 override TraitsExp
syntaxCopy()
2934 return new TraitsExp(loc
, ident
, TemplateInstance
.arraySyntaxCopy(args
));
2937 override void accept(Visitor v
)
2943 /***********************************************************
2944 * Generates a halt instruction
2946 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
2948 extern (C
++) final class HaltExp
: Expression
2950 extern (D
) this(const ref Loc loc
) @safe
2952 super(loc
, EXP
.halt
);
2955 override void accept(Visitor v
)
2961 /***********************************************************
2962 * is(targ id tok tspec)
2963 * is(targ id == tok2)
2965 extern (C
++) final class IsExp
: Expression
2968 Identifier id
; // can be null
2969 Type tspec
; // can be null
2970 TemplateParameters
* parameters
;
2971 TOK tok
; // ':' or '=='
2972 TOK tok2
; // 'struct', 'union', etc.
2974 extern (D
) this(const ref Loc loc
, Type targ
, Identifier id
, TOK tok
, Type tspec
, TOK tok2
, TemplateParameters
* parameters
) scope @safe
2976 super(loc
, EXP
.is_
);
2982 this.parameters
= parameters
;
2985 override IsExp
syntaxCopy()
2987 // This section is identical to that in TemplateDeclaration::syntaxCopy()
2988 TemplateParameters
* p
= null;
2991 p
= new TemplateParameters(parameters
.length
);
2992 foreach (i
, el
; *parameters
)
2993 (*p
)[i
] = el
.syntaxCopy();
2995 return new IsExp(loc
, targ
.syntaxCopy(), id
, tok
, tspec ? tspec
.syntaxCopy() : null, tok2
, p
);
2998 override void accept(Visitor v
)
3004 /***********************************************************
3005 * Base class for unary operators
3007 * https://dlang.org/spec/expression.html#unary-expression
3009 extern (C
++) abstract class UnaExp
: Expression
3013 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
) scope @safe
3019 override UnaExp
syntaxCopy()
3021 UnaExp e
= cast(UnaExp
)copy();
3023 e
.e1
= e
.e1
.syntaxCopy();
3027 /********************************
3028 * The type for a unary expression is incompatible.
3029 * Print error message.
3033 extern (D
) final Expression
incompatibleTypes()
3035 if (e1
.type
.toBasetype() == Type
.terror
)
3038 if (e1
.op
== EXP
.type
)
3040 error(loc
, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op
).ptr
, e1
.toChars(), EXPtoString(op
).ptr
);
3044 error(loc
, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op
).ptr
, e1
.toChars(), e1
.type
.toChars());
3046 return ErrorExp
.get();
3049 /*********************
3050 * Mark the operand as will never be dereferenced,
3051 * which is useful info for @safe checks.
3052 * Do before semantic() on operands rewrites them.
3054 final void setNoderefOperand()
3056 if (auto edi
= e1
.isDotIdExp())
3061 override void accept(Visitor v
)
3067 /***********************************************************
3068 * Base class for binary operators
3070 extern (C
++) abstract class BinExp
: Expression
3074 Type att1
; // Save alias this type to detect recursion
3075 Type att2
; // Save alias this type to detect recursion
3077 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) scope @safe
3084 override BinExp
syntaxCopy()
3086 BinExp e
= cast(BinExp
)copy();
3088 e
.e1
= e
.e1
.syntaxCopy();
3089 e
.e2
= e
.e2
.syntaxCopy();
3093 /********************************
3094 * The types for a binary expression are incompatible.
3095 * Print error message.
3099 extern (D
) final Expression
incompatibleTypes()
3101 if (e1
.type
.toBasetype() == Type
.terror
)
3103 if (e2
.type
.toBasetype() == Type
.terror
)
3106 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
3107 const(char)* thisOp
= (op
== EXP
.question
) ?
":" : EXPtoString(op
).ptr
;
3108 if (e1
.op
== EXP
.type || e2
.op
== EXP
.type
)
3110 error(loc
, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
3111 e1
.toChars(), thisOp
, e2
.toChars(), EXPtoString(op
).ptr
);
3113 else if (e1
.type
.equals(e2
.type
))
3115 error(loc
, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
3116 e1
.toChars(), thisOp
, e2
.toChars(), e1
.type
.toChars());
3120 auto ts
= toAutoQualChars(e1
.type
, e2
.type
);
3121 error(loc
, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
3122 e1
.toChars(), thisOp
, e2
.toChars(), ts
[0], ts
[1]);
3124 return ErrorExp
.get();
3127 extern (D
) final bool checkIntegralBin()
3129 bool r1
= e1
.checkIntegral();
3130 bool r2
= e2
.checkIntegral();
3134 extern (D
) final bool checkArithmeticBin()
3136 bool r1
= e1
.checkArithmetic(this.op
);
3137 bool r2
= e2
.checkArithmetic(this.op
);
3141 /*********************
3142 * Mark the operands as will never be dereferenced,
3143 * which is useful info for @safe checks.
3144 * Do before semantic() on operands rewrites them.
3146 final void setNoderefOperands()
3148 if (auto edi
= e1
.isDotIdExp())
3150 if (auto edi
= e2
.isDotIdExp())
3155 override void accept(Visitor v
)
3161 /***********************************************************
3162 * Binary operator assignment, `+=` `-=` `*=` etc.
3164 extern (C
++) class BinAssignExp
: BinExp
3166 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) scope @safe
3168 super(loc
, op
, e1
, e2
);
3171 override final bool isLvalue()
3176 override void accept(Visitor v
)
3182 /***********************************************************
3183 * A string mixin, `mixin("x")`
3185 * https://dlang.org/spec/expression.html#mixin_expressions
3187 extern (C
++) final class MixinExp
: Expression
3191 extern (D
) this(const ref Loc loc
, Expressions
* exps
) @safe
3193 super(loc
, EXP
.mixin_
);
3197 override MixinExp
syntaxCopy()
3199 return new MixinExp(loc
, arraySyntaxCopy(exps
));
3202 override bool equals(const RootObject o
) const
3206 auto e
= o
.isExpression();
3209 if (auto ce
= e
.isMixinExp())
3211 if (exps
.length
!= ce
.exps
.length
)
3213 foreach (i
, e1
; *exps
)
3215 auto e2
= (*ce
.exps
)[i
];
3216 if (e1
!= e2
&& (!e1 ||
!e2 ||
!e1
.equals(e2
)))
3224 override void accept(Visitor v
)
3230 /***********************************************************
3231 * An import expression, `import("file.txt")`
3233 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
3235 * https://dlang.org/spec/expression.html#import_expressions
3237 extern (C
++) final class ImportExp
: UnaExp
3239 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3241 super(loc
, EXP
.import_
, e
);
3244 override void accept(Visitor v
)
3250 /***********************************************************
3251 * An assert expression, `assert(x == y)`
3253 * https://dlang.org/spec/expression.html#assert_expressions
3255 extern (C
++) final class AssertExp
: UnaExp
3259 extern (D
) this(const ref Loc loc
, Expression e
, Expression msg
= null) @safe
3261 super(loc
, EXP
.assert_
, e
);
3265 override AssertExp
syntaxCopy()
3267 return new AssertExp(loc
, e1
.syntaxCopy(), msg ? msg
.syntaxCopy() : null);
3270 override void accept(Visitor v
)
3276 /***********************************************************
3277 * `throw <e1>` as proposed by DIP 1034.
3279 * Replacement for the deprecated `ThrowStatement` that can be nested
3280 * in other expression.
3282 extern (C
++) final class ThrowExp
: UnaExp
3284 extern (D
) this(const ref Loc loc
, Expression e
)
3286 super(loc
, EXP
.throw_
, e
);
3287 this.type
= Type
.tnoreturn
;
3290 override ThrowExp
syntaxCopy()
3292 return new ThrowExp(loc
, e1
.syntaxCopy());
3295 override void accept(Visitor v
)
3301 /***********************************************************
3303 extern (C
++) final class DotIdExp
: UnaExp
3306 bool noderef
; // true if the result of the expression will never be dereferenced
3307 bool wantsym
; // do not replace Symbol with its initializer during semantic()
3308 bool arrow
; // ImportC: if -> instead of .
3310 extern (D
) this(const ref Loc loc
, Expression e
, Identifier ident
) @safe
3312 super(loc
, EXP
.dotIdentifier
, e
);
3316 static DotIdExp
create(const ref Loc loc
, Expression e
, Identifier ident
) @safe
3318 return new DotIdExp(loc
, e
, ident
);
3321 override void accept(Visitor v
)
3327 /***********************************************************
3328 * Mainly just a placeholder
3330 extern (C
++) final class DotTemplateExp
: UnaExp
3332 TemplateDeclaration td
;
3334 extern (D
) this(const ref Loc loc
, Expression e
, TemplateDeclaration td
) @safe
3336 super(loc
, EXP
.dotTemplateDeclaration
, e
);
3340 override bool checkType()
3342 error(loc
, "%s `%s` has no type", td
.kind(), toChars());
3346 override bool checkValue()
3348 error(loc
, "%s `%s` has no value", td
.kind(), toChars());
3352 override void accept(Visitor v
)
3358 /***********************************************************
3360 extern (C
++) final class DotVarExp
: UnaExp
3365 extern (D
) this(const ref Loc loc
, Expression e
, Declaration var
, bool hasOverloads
= true) @safe
3367 if (var
.isVarDeclaration())
3368 hasOverloads
= false;
3370 super(loc
, EXP
.dotVariable
, e
);
3371 //printf("DotVarExp()\n");
3373 this.hasOverloads
= hasOverloads
;
3376 override bool isLvalue()
3378 if (e1
.op
!= EXP
.structLiteral
)
3380 auto vd
= var
.isVarDeclaration();
3381 return !(vd
&& vd
.isField());
3384 override void accept(Visitor v
)
3390 /***********************************************************
3393 extern (C
++) final class DotTemplateInstanceExp
: UnaExp
3395 TemplateInstance ti
;
3397 extern (D
) this(const ref Loc loc
, Expression e
, Identifier name
, Objects
* tiargs
)
3399 super(loc
, EXP
.dotTemplateInstance
, e
);
3400 //printf("DotTemplateInstanceExp()\n");
3401 this.ti
= new TemplateInstance(loc
, name
, tiargs
);
3404 extern (D
) this(const ref Loc loc
, Expression e
, TemplateInstance ti
) @safe
3406 super(loc
, EXP
.dotTemplateInstance
, e
);
3410 override DotTemplateInstanceExp
syntaxCopy()
3412 return new DotTemplateInstanceExp(loc
, e1
.syntaxCopy(), ti
.name
, TemplateInstance
.arraySyntaxCopy(ti
.tiargs
));
3415 override bool checkType()
3417 // Same logic as ScopeExp.checkType()
3419 ti
.semantictiargsdone
&&
3420 ti
.semanticRun
== PASS
.initial
)
3422 error(loc
, "partial %s `%s` has no type", ti
.kind(), toChars());
3428 override bool checkValue()
3431 ti
.semantictiargsdone
&&
3432 ti
.semanticRun
== PASS
.initial
)
3434 error(loc
, "partial %s `%s` has no value", ti
.kind(), toChars());
3436 error(loc
, "%s `%s` has no value", ti
.kind(), ti
.toChars());
3440 override void accept(Visitor v
)
3446 /***********************************************************
3448 extern (C
++) final class DelegateExp
: UnaExp
3450 FuncDeclaration func
;
3452 VarDeclaration vthis2
; // container for multi-context
3454 extern (D
) this(const ref Loc loc
, Expression e
, FuncDeclaration f
, bool hasOverloads
= true, VarDeclaration vthis2
= null) @safe
3456 super(loc
, EXP
.delegate_
, e
);
3458 this.hasOverloads
= hasOverloads
;
3459 this.vthis2
= vthis2
;
3462 override void accept(Visitor v
)
3468 /***********************************************************
3470 extern (C
++) final class DotTypeExp
: UnaExp
3472 Dsymbol sym
; // symbol that represents a type
3474 extern (D
) this(const ref Loc loc
, Expression e
, Dsymbol s
) @safe
3476 super(loc
, EXP
.dotType
, e
);
3480 override void accept(Visitor v
)
3487 * The arguments of a function call
3489 * Contains a list of expressions. If it is a named argument, the `names`
3490 * list has a non-null entry at the same index.
3494 Expressions
* arguments
; // function arguments
3495 Identifiers
* names
; // named argument identifiers
3497 size_t
length() const @nogc nothrow pure @safe { return arguments ? arguments
.length
: 0; }
3499 /// Returns: whether this argument list contains any named arguments
3500 bool hasNames() const @nogc nothrow pure @safe
3504 foreach (name
; *names
)
3512 /***********************************************************
3514 extern (C
++) final class CallExp
: UnaExp
3516 Expressions
* arguments
; // function arguments
3517 Identifiers
* names
; // named argument identifiers
3518 FuncDeclaration f
; // symbol to call
3519 bool directcall
; // true if a virtual call is devirtualized
3520 bool inDebugStatement
; /// true if this was in a debug statement
3521 bool ignoreAttributes
; /// don't enforce attributes (e.g. call @gc function in @nogc code)
3522 bool isUfcsRewrite
; /// the first argument was pushed in here by a UFCS rewrite
3523 VarDeclaration vthis2
; // container for multi-context
3525 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3526 /// The fields are still separate for backwards compatibility
3527 extern (D
) ArgumentList
argumentList() { return ArgumentList(arguments
, names
); }
3529 extern (D
) this(const ref Loc loc
, Expression e
, Expressions
* exps
, Identifiers
* names
= null) @safe
3531 super(loc
, EXP
.call, e
);
3532 this.arguments
= exps
;
3536 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3538 super(loc
, EXP
.call, e
);
3541 extern (D
) this(const ref Loc loc
, Expression e
, Expression earg1
)
3543 super(loc
, EXP
.call, e
);
3544 this.arguments
= new Expressions();
3546 this.arguments
.push(earg1
);
3549 extern (D
) this(const ref Loc loc
, Expression e
, Expression earg1
, Expression earg2
)
3551 super(loc
, EXP
.call, e
);
3552 auto arguments
= new Expressions(2);
3553 (*arguments
)[0] = earg1
;
3554 (*arguments
)[1] = earg2
;
3555 this.arguments
= arguments
;
3558 /***********************************************************
3559 * Instatiates a new function call expression
3562 * fd = the declaration of the function to call
3563 * earg1 = the function argument
3565 extern(D
) this(const ref Loc loc
, FuncDeclaration fd
, Expression earg1
)
3567 this(loc
, new VarExp(loc
, fd
, false), earg1
);
3571 static CallExp
create(const ref Loc loc
, Expression e
, Expressions
* exps
) @safe
3573 return new CallExp(loc
, e
, exps
);
3576 static CallExp
create(const ref Loc loc
, Expression e
) @safe
3578 return new CallExp(loc
, e
);
3581 static CallExp
create(const ref Loc loc
, Expression e
, Expression earg1
)
3583 return new CallExp(loc
, e
, earg1
);
3586 /***********************************************************
3587 * Creates a new function call expression
3590 * fd = the declaration of the function to call
3591 * earg1 = the function argument
3593 static CallExp
create(const ref Loc loc
, FuncDeclaration fd
, Expression earg1
)
3595 return new CallExp(loc
, fd
, earg1
);
3598 override CallExp
syntaxCopy()
3600 return new CallExp(loc
, e1
.syntaxCopy(), arraySyntaxCopy(arguments
), names ? names
.copy() : null);
3603 override bool isLvalue()
3605 Type tb
= e1
.type
.toBasetype();
3606 if (tb
.ty
== Tdelegate || tb
.ty
== Tpointer
)
3608 auto tf
= tb
.isTypeFunction();
3611 if (auto dve
= e1
.isDotVarExp())
3612 if (dve
.var
.isCtorDeclaration())
3614 return true; // function returns a reference
3619 override void accept(Visitor v
)
3626 * Get the called function type from a call expression
3628 * ce = function call expression. Must have had semantic analysis done.
3629 * Returns: called function type, or `null` if error / no semantic analysis done
3631 TypeFunction
calledFunctionType(CallExp ce
)
3633 Type t
= ce
.e1
.type
;
3637 if (auto tf
= t
.isTypeFunction())
3639 else if (auto td
= t
.isTypeDelegate())
3640 return td
.nextOf().isTypeFunction();
3645 FuncDeclaration
isFuncAddress(Expression e
, bool* hasOverloads
= null) @safe
3647 if (auto ae
= e
.isAddrExp())
3650 if (auto ve
= ae1
.isVarExp())
3653 *hasOverloads
= ve
.hasOverloads
;
3654 return ve
.var
.isFuncDeclaration();
3656 if (auto dve
= ae1
.isDotVarExp())
3659 *hasOverloads
= dve
.hasOverloads
;
3660 return dve
.var
.isFuncDeclaration();
3665 if (auto soe
= e
.isSymOffExp())
3668 *hasOverloads
= soe
.hasOverloads
;
3669 return soe
.var
.isFuncDeclaration();
3671 if (auto dge
= e
.isDelegateExp())
3674 *hasOverloads
= dge
.hasOverloads
;
3675 return dge
.func
.isFuncDeclaration();
3681 /***********************************************************
3682 * The 'address of' operator, `&p`
3684 extern (C
++) final class AddrExp
: UnaExp
3686 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3688 super(loc
, EXP
.address
, e
);
3691 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3697 override void accept(Visitor v
)
3703 /***********************************************************
3704 * The pointer dereference operator, `*p`
3706 extern (C
++) final class PtrExp
: UnaExp
3708 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3710 super(loc
, EXP
.star
, e
);
3712 // type = ((TypePointer *)e.type).next;
3715 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3717 super(loc
, EXP
.star
, e
);
3721 override bool isLvalue()
3726 override void accept(Visitor v
)
3732 /***********************************************************
3733 * The negation operator, `-x`
3735 extern (C
++) final class NegExp
: UnaExp
3737 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3739 super(loc
, EXP
.negate
, e
);
3742 override void accept(Visitor v
)
3748 /***********************************************************
3749 * The unary add operator, `+x`
3751 extern (C
++) final class UAddExp
: UnaExp
3753 extern (D
) this(const ref Loc loc
, Expression e
) scope @safe
3755 super(loc
, EXP
.uadd
, e
);
3758 override void accept(Visitor v
)
3764 /***********************************************************
3765 * The bitwise complement operator, `~x`
3767 extern (C
++) final class ComExp
: UnaExp
3769 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3771 super(loc
, EXP
.tilde
, e
);
3774 override void accept(Visitor v
)
3780 /***********************************************************
3781 * The logical not operator, `!x`
3783 extern (C
++) final class NotExp
: UnaExp
3785 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3787 super(loc
, EXP
.not, e
);
3790 override void accept(Visitor v
)
3796 /***********************************************************
3797 * The delete operator, `delete x` (deprecated)
3799 * https://dlang.org/spec/expression.html#delete_expressions
3801 extern (C
++) final class DeleteExp
: UnaExp
3803 bool isRAII
; // true if called automatically as a result of scoped destruction
3805 extern (D
) this(const ref Loc loc
, Expression e
, bool isRAII
) @safe
3807 super(loc
, EXP
.delete_
, e
);
3808 this.isRAII
= isRAII
;
3811 override void accept(Visitor v
)
3817 /***********************************************************
3818 * The type cast operator, `cast(T) x`
3820 * It's possible to cast to one type while painting to another type
3822 * https://dlang.org/spec/expression.html#cast_expressions
3824 extern (C
++) final class CastExp
: UnaExp
3826 Type to
; // type to cast to
3827 ubyte mod
= cast(ubyte)~0; // MODxxxxx
3829 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3831 super(loc
, EXP
.cast_
, e
);
3835 /* For cast(const) and cast(immutable)
3837 extern (D
) this(const ref Loc loc
, Expression e
, ubyte mod
) @safe
3839 super(loc
, EXP
.cast_
, e
);
3843 override CastExp
syntaxCopy()
3845 return to ?
new CastExp(loc
, e1
.syntaxCopy(), to
.syntaxCopy()) : new CastExp(loc
, e1
.syntaxCopy(), mod
);
3848 override bool isLvalue()
3850 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
3853 return (to
.ty
== Tsarray
&& (e1
.type
.ty
== Tvector || e1
.type
.ty
== Tsarray
)) ||
3854 e1
.type
.mutableOf().unSharedOf().equals(to
.mutableOf().unSharedOf());
3857 override void accept(Visitor v
)
3863 /***********************************************************
3865 extern (C
++) final class VectorExp
: UnaExp
3867 TypeVector to
; // the target vector type before semantic()
3868 uint dim
= ~0; // number of elements in the vector
3869 OwnedBy ownedByCtfe
= OwnedBy
.code
;
3871 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3873 super(loc
, EXP
.vector
, e
);
3874 assert(t
.ty
== Tvector
);
3875 to
= cast(TypeVector
)t
;
3878 static VectorExp
create(const ref Loc loc
, Expression e
, Type t
) @safe
3880 return new VectorExp(loc
, e
, t
);
3883 override VectorExp
syntaxCopy()
3885 return new VectorExp(loc
, e1
.syntaxCopy(), to
.syntaxCopy());
3888 override void accept(Visitor v
)
3894 /***********************************************************
3895 * e1.array property for vectors.
3897 * https://dlang.org/spec/simd.html#properties
3899 extern (C
++) final class VectorArrayExp
: UnaExp
3901 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
3903 super(loc
, EXP
.vectorArray
, e1
);
3906 override bool isLvalue()
3908 return e1
.isLvalue();
3911 override void accept(Visitor v
)
3917 /***********************************************************
3920 * https://dlang.org/spec/expression.html#slice_expressions
3922 extern (C
++) final class SliceExp
: UnaExp
3924 Expression upr
; // null if implicit 0
3925 Expression lwr
; // null if implicit [length - 1]
3927 VarDeclaration lengthVar
;
3929 private extern(D
) static struct BitFields
3931 bool upperIsInBounds
; // true if upr <= e1.length
3932 bool lowerIsLessThanUpper
; // true if lwr <= upr
3933 bool arrayop
; // an array operation, rather than a slice
3935 import dmd
.common
.bitfields
: generateBitFields
;
3936 mixin(generateBitFields
!(BitFields
, ubyte));
3938 /************************************************************/
3939 extern (D
) this(const ref Loc loc
, Expression e1
, IntervalExp ie
) @safe
3941 super(loc
, EXP
.slice
, e1
);
3942 this.upr
= ie ? ie
.upr
: null;
3943 this.lwr
= ie ? ie
.lwr
: null;
3946 extern (D
) this(const ref Loc loc
, Expression e1
, Expression lwr
, Expression upr
) @safe
3948 super(loc
, EXP
.slice
, e1
);
3953 override SliceExp
syntaxCopy()
3955 auto se
= new SliceExp(loc
, e1
.syntaxCopy(), lwr ? lwr
.syntaxCopy() : null, upr ? upr
.syntaxCopy() : null);
3956 se
.lengthVar
= this.lengthVar
; // bug7871
3960 override bool isLvalue()
3962 /* slice expression is rvalue in default, but
3963 * conversion to reference of static array is only allowed.
3965 return (type
&& type
.toBasetype().ty
== Tsarray
);
3968 override Optional
!bool toBool()
3973 override void accept(Visitor v
)
3979 /***********************************************************
3980 * The `.length` property of an array
3982 extern (C
++) final class ArrayLengthExp
: UnaExp
3984 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
3986 super(loc
, EXP
.arrayLength
, e1
);
3989 override void accept(Visitor v
)
3995 /***********************************************************
3996 * e1 [ a0, a1, a2, a3 ,... ]
3998 * https://dlang.org/spec/expression.html#index_expressions
4000 extern (C
++) final class ArrayExp
: UnaExp
4002 Expressions
* arguments
; // Array of Expression's a0..an
4004 size_t currentDimension
; // for opDollar
4005 VarDeclaration lengthVar
;
4007 extern (D
) this(const ref Loc loc
, Expression e1
, Expression index
= null)
4009 super(loc
, EXP
.array
, e1
);
4010 arguments
= new Expressions();
4012 arguments
.push(index
);
4015 extern (D
) this(const ref Loc loc
, Expression e1
, Expressions
* args
) @safe
4017 super(loc
, EXP
.array
, e1
);
4021 override ArrayExp
syntaxCopy()
4023 auto ae
= new ArrayExp(loc
, e1
.syntaxCopy(), arraySyntaxCopy(arguments
));
4024 ae
.lengthVar
= this.lengthVar
; // bug7871
4028 override bool isLvalue()
4030 if (type
&& type
.toBasetype().ty
== Tvoid
)
4035 override void accept(Visitor v
)
4041 /***********************************************************
4043 extern (C
++) final class DotExp
: BinExp
4045 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4047 super(loc
, EXP
.dot
, e1
, e2
);
4050 override void accept(Visitor v
)
4056 /***********************************************************
4058 extern (C
++) final class CommaExp
: BinExp
4060 /// This is needed because AssignExp rewrites CommaExp, hence it needs
4061 /// to trigger the deprecation.
4062 const bool isGenerated
;
4064 /// Temporary variable to enable / disable deprecation of comma expression
4065 /// depending on the context.
4066 /// Since most constructor calls are rewritting, the only place where
4067 /// false will be passed will be from the parser.
4071 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
, bool generated
= true) @safe
4073 super(loc
, EXP
.comma
, e1
, e2
);
4074 allowCommaExp
= isGenerated
= generated
;
4077 override bool isLvalue()
4079 return e2
.isLvalue();
4082 override Optional
!bool toBool()
4087 override void accept(Visitor v
)
4093 * If the argument is a CommaExp, set a flag to prevent deprecation messages
4095 * It's impossible to know from CommaExp.semantic if the result will
4096 * be used, hence when there is a result (type != void), a deprecation
4097 * message is always emitted.
4098 * However, some construct can produce a result but won't use it
4099 * (ExpStatement and for loop increment). Those should call this function
4100 * to prevent unwanted deprecations to be emitted.
4103 * exp = An expression that discards its result.
4104 * If the argument is null or not a CommaExp, nothing happens.
4106 static void allow(Expression exp
) @safe
4109 if (auto ce
= exp
.isCommaExp())
4110 ce
.allowCommaExp
= true;
4114 /***********************************************************
4115 * Mainly just a placeholder
4117 extern (C
++) final class IntervalExp
: Expression
4122 extern (D
) this(const ref Loc loc
, Expression lwr
, Expression upr
) @safe
4124 super(loc
, EXP
.interval
);
4129 override Expression
syntaxCopy()
4131 return new IntervalExp(loc
, lwr
.syntaxCopy(), upr
.syntaxCopy());
4134 override void accept(Visitor v
)
4140 /***********************************************************
4141 * The `dg.ptr` property, pointing to the delegate's 'context'
4143 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
4145 extern (C
++) final class DelegatePtrExp
: UnaExp
4147 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
4149 super(loc
, EXP
.delegatePointer
, e1
);
4152 override bool isLvalue()
4154 return e1
.isLvalue();
4157 override void accept(Visitor v
)
4163 /***********************************************************
4164 * The `dg.funcptr` property, pointing to the delegate's function
4166 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
4168 extern (C
++) final class DelegateFuncptrExp
: UnaExp
4170 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
4172 super(loc
, EXP
.delegateFunctionPointer
, e1
);
4175 override bool isLvalue()
4177 return e1
.isLvalue();
4180 override void accept(Visitor v
)
4186 /***********************************************************
4189 extern (C
++) final class IndexExp
: BinExp
4191 VarDeclaration lengthVar
;
4192 bool modifiable
= false; // assume it is an rvalue
4193 bool indexIsInBounds
; // true if 0 <= e2 && e2 <= e1.length - 1
4195 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4197 super(loc
, EXP
.index
, e1
, e2
);
4198 //printf("IndexExp::IndexExp('%s')\n", toChars());
4201 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
, bool indexIsInBounds
) @safe
4203 super(loc
, EXP
.index
, e1
, e2
);
4204 this.indexIsInBounds
= indexIsInBounds
;
4205 //printf("IndexExp::IndexExp('%s')\n", toChars());
4208 override IndexExp
syntaxCopy()
4210 auto ie
= new IndexExp(loc
, e1
.syntaxCopy(), e2
.syntaxCopy());
4211 ie
.lengthVar
= this.lengthVar
; // bug7871
4215 override bool isLvalue()
4217 if (e1
.op
== EXP
.assocArrayLiteral
)
4219 if (e1
.type
.ty
== Tsarray ||
4220 (e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
))
4222 return e1
.isLvalue();
4227 extern (D
) Expression
markSettingAAElem()
4229 if (e1
.type
.toBasetype().ty
== Taarray
)
4231 Type t2b
= e2
.type
.toBasetype();
4232 if (t2b
.ty
== Tarray
&& t2b
.nextOf().isMutable())
4234 error(loc
, "associative arrays can only be assigned values with immutable keys, not `%s`", e2
.type
.toChars());
4235 return ErrorExp
.get();
4239 if (auto ie
= e1
.isIndexExp())
4241 Expression ex
= ie
.markSettingAAElem();
4242 if (ex
.op
== EXP
.error
)
4250 override void accept(Visitor v
)
4256 /***********************************************************
4257 * The postfix increment/decrement operator, `i++` / `i--`
4259 extern (C
++) final class PostExp
: BinExp
4261 extern (D
) this(EXP op
, const ref Loc loc
, Expression e
)
4263 super(loc
, op
, e
, IntegerExp
.literal
!1);
4264 assert(op
== EXP
.minusMinus || op
== EXP
.plusPlus
);
4267 override void accept(Visitor v
)
4273 /***********************************************************
4274 * The prefix increment/decrement operator, `++i` / `--i`
4276 extern (C
++) final class PreExp
: UnaExp
4278 extern (D
) this(EXP op
, const ref Loc loc
, Expression e
) @safe
4281 assert(op
== EXP
.preMinusMinus || op
== EXP
.prePlusPlus
);
4284 override void accept(Visitor v
)
4292 none
= 0, // simple assignment
4293 blockAssign
= 1, // setting the contents of an array
4294 referenceInit
= 2, // setting the reference of STC.ref_ variable
4297 /***********************************************************
4298 * The assignment / initialization operator, `=`
4300 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
4302 extern (C
++) class AssignExp
: BinExp
4306 /************************************************************/
4307 /* op can be EXP.assign, EXP.construct, or EXP.blit */
4308 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4310 super(loc
, EXP
.assign
, e1
, e2
);
4313 this(const ref Loc loc
, EXP tok
, Expression e1
, Expression e2
) @safe
4315 super(loc
, tok
, e1
, e2
);
4318 override final bool isLvalue()
4320 // Array-op 'x[] = y[]' should make an rvalue.
4321 // Setting array length 'x.length = v' should make an rvalue.
4322 if (e1
.op
== EXP
.slice || e1
.op
== EXP
.arrayLength
)
4329 override void accept(Visitor v
)
4335 /***********************************************************
4336 * When an assignment expression is lowered to a druntime call
4337 * this class is used to store the lowering.
4338 * It essentially behaves the same as an AssignExp, but it is
4339 * used to not waste space for other AssignExp that are not
4340 * lowered to anything.
4342 extern (C
++) final class LoweredAssignExp
: AssignExp
4344 Expression lowering
;
4345 extern (D
) this(AssignExp exp
, Expression lowering
) @safe
4347 super(exp
.loc
, EXP
.loweredAssignExp
, exp
.e1
, exp
.e2
);
4348 this.lowering
= lowering
;
4351 override const(char)* toChars() const
4353 return lowering
.toChars();
4355 override void accept(Visitor v
)
4361 /***********************************************************
4363 extern (C
++) final class ConstructExp
: AssignExp
4365 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4367 super(loc
, EXP
.construct
, e1
, e2
);
4370 // Internal use only. If `v` is a reference variable, the assignment
4371 // will become a reference initialization automatically.
4372 extern (D
) this(const ref Loc loc
, VarDeclaration v
, Expression e2
) @safe
4374 auto ve
= new VarExp(loc
, v
);
4375 assert(v
.type
&& ve
.type
);
4377 super(loc
, EXP
.construct
, ve
, e2
);
4379 if (v
.isReference())
4380 memset
= MemorySet
.referenceInit
;
4383 override void accept(Visitor v
)
4389 /***********************************************************
4390 * A bit-for-bit copy from `e2` to `e1`
4392 extern (C
++) final class BlitExp
: AssignExp
4394 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4396 super(loc
, EXP
.blit
, e1
, e2
);
4399 // Internal use only. If `v` is a reference variable, the assinment
4400 // will become a reference rebinding automatically.
4401 extern (D
) this(const ref Loc loc
, VarDeclaration v
, Expression e2
) @safe
4403 auto ve
= new VarExp(loc
, v
);
4404 assert(v
.type
&& ve
.type
);
4406 super(loc
, EXP
.blit
, ve
, e2
);
4408 if (v
.isReference())
4409 memset
= MemorySet
.referenceInit
;
4412 override void accept(Visitor v
)
4418 /***********************************************************
4421 extern (C
++) final class AddAssignExp
: BinAssignExp
4423 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4425 super(loc
, EXP
.addAssign
, e1
, e2
);
4428 override void accept(Visitor v
)
4434 /***********************************************************
4437 extern (C
++) final class MinAssignExp
: BinAssignExp
4439 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4441 super(loc
, EXP
.minAssign
, e1
, e2
);
4444 override void accept(Visitor v
)
4450 /***********************************************************
4453 extern (C
++) final class MulAssignExp
: BinAssignExp
4455 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4457 super(loc
, EXP
.mulAssign
, e1
, e2
);
4460 override void accept(Visitor v
)
4466 /***********************************************************
4469 extern (C
++) final class DivAssignExp
: BinAssignExp
4471 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4473 super(loc
, EXP
.divAssign
, e1
, e2
);
4476 override void accept(Visitor v
)
4482 /***********************************************************
4485 extern (C
++) final class ModAssignExp
: BinAssignExp
4487 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4489 super(loc
, EXP
.modAssign
, e1
, e2
);
4492 override void accept(Visitor v
)
4498 /***********************************************************
4501 extern (C
++) final class AndAssignExp
: BinAssignExp
4503 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4505 super(loc
, EXP
.andAssign
, e1
, e2
);
4508 override void accept(Visitor v
)
4514 /***********************************************************
4517 extern (C
++) final class OrAssignExp
: BinAssignExp
4519 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4521 super(loc
, EXP
.orAssign
, e1
, e2
);
4524 override void accept(Visitor v
)
4530 /***********************************************************
4533 extern (C
++) final class XorAssignExp
: BinAssignExp
4535 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4537 super(loc
, EXP
.xorAssign
, e1
, e2
);
4540 override void accept(Visitor v
)
4546 /***********************************************************
4549 extern (C
++) final class PowAssignExp
: BinAssignExp
4551 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4553 super(loc
, EXP
.powAssign
, e1
, e2
);
4556 override void accept(Visitor v
)
4562 /***********************************************************
4565 extern (C
++) final class ShlAssignExp
: BinAssignExp
4567 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4569 super(loc
, EXP
.leftShiftAssign
, e1
, e2
);
4572 override void accept(Visitor v
)
4578 /***********************************************************
4581 extern (C
++) final class ShrAssignExp
: BinAssignExp
4583 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4585 super(loc
, EXP
.rightShiftAssign
, e1
, e2
);
4588 override void accept(Visitor v
)
4594 /***********************************************************
4597 extern (C
++) final class UshrAssignExp
: BinAssignExp
4599 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4601 super(loc
, EXP
.unsignedRightShiftAssign
, e1
, e2
);
4604 override void accept(Visitor v
)
4610 /***********************************************************
4611 * The `~=` operator.
4613 * It can have one of the following operators:
4615 * EXP.concatenateAssign - appending T[] to T[]
4616 * EXP.concatenateElemAssign - appending T to T[]
4617 * EXP.concatenateDcharAssign - appending dchar to T[]
4619 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
4620 * of the three it will be set to.
4622 extern (C
++) class CatAssignExp
: BinAssignExp
4624 Expression lowering
; // lowered druntime hook `_d_arrayappend{cTX,T}`
4626 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
)
4628 super(loc
, EXP
.concatenateAssign
, e1
, e2
);
4631 extern (D
) this(const ref Loc loc
, EXP tok
, Expression e1
, Expression e2
) @safe
4633 super(loc
, tok
, e1
, e2
);
4636 override void accept(Visitor v
)
4642 /***********************************************************
4643 * The `~=` operator when appending a single element
4645 extern (C
++) final class CatElemAssignExp
: CatAssignExp
4647 extern (D
) this(const ref Loc loc
, Type type
, Expression e1
, Expression e2
) @safe
4649 super(loc
, EXP
.concatenateElemAssign
, e1
, e2
);
4653 override void accept(Visitor v
)
4659 /***********************************************************
4660 * The `~=` operator when appending a single `dchar`
4662 extern (C
++) final class CatDcharAssignExp
: CatAssignExp
4664 extern (D
) this(const ref Loc loc
, Type type
, Expression e1
, Expression e2
) @safe
4666 super(loc
, EXP
.concatenateDcharAssign
, e1
, e2
);
4670 override void accept(Visitor v
)
4676 /***********************************************************
4677 * The addition operator, `x + y`
4679 * https://dlang.org/spec/expression.html#add_expressions
4681 extern (C
++) final class AddExp
: BinExp
4683 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4685 super(loc
, EXP
.add, e1
, e2
);
4688 override void accept(Visitor v
)
4694 /***********************************************************
4695 * The minus operator, `x - y`
4697 * https://dlang.org/spec/expression.html#add_expressions
4699 extern (C
++) final class MinExp
: BinExp
4701 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4703 super(loc
, EXP
.min
, e1
, e2
);
4706 override void accept(Visitor v
)
4712 /***********************************************************
4713 * The concatenation operator, `x ~ y`
4715 * https://dlang.org/spec/expression.html#cat_expressions
4717 extern (C
++) final class CatExp
: BinExp
4719 Expression lowering
; // call to druntime hook `_d_arraycatnTX`
4721 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) scope @safe
4723 super(loc
, EXP
.concatenate
, e1
, e2
);
4726 override void accept(Visitor v
)
4732 /***********************************************************
4733 * The multiplication operator, `x * y`
4735 * https://dlang.org/spec/expression.html#mul_expressions
4737 extern (C
++) final class MulExp
: BinExp
4739 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4741 super(loc
, EXP
.mul, e1
, e2
);
4744 override void accept(Visitor v
)
4750 /***********************************************************
4751 * The division operator, `x / y`
4753 * https://dlang.org/spec/expression.html#mul_expressions
4755 extern (C
++) final class DivExp
: BinExp
4757 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4759 super(loc
, EXP
.div, e1
, e2
);
4762 override void accept(Visitor v
)
4768 /***********************************************************
4769 * The modulo operator, `x % y`
4771 * https://dlang.org/spec/expression.html#mul_expressions
4773 extern (C
++) final class ModExp
: BinExp
4775 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4777 super(loc
, EXP
.mod
, e1
, e2
);
4780 override void accept(Visitor v
)
4786 /***********************************************************
4787 * The 'power' operator, `x ^^ y`
4789 * https://dlang.org/spec/expression.html#pow_expressions
4791 extern (C
++) final class PowExp
: BinExp
4793 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4795 super(loc
, EXP
.pow
, e1
, e2
);
4798 override void accept(Visitor v
)
4804 /***********************************************************
4805 * The 'shift left' operator, `x << y`
4807 * https://dlang.org/spec/expression.html#shift_expressions
4809 extern (C
++) final class ShlExp
: BinExp
4811 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4813 super(loc
, EXP
.leftShift
, e1
, e2
);
4816 override void accept(Visitor v
)
4822 /***********************************************************
4823 * The 'shift right' operator, `x >> y`
4825 * https://dlang.org/spec/expression.html#shift_expressions
4827 extern (C
++) final class ShrExp
: BinExp
4829 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4831 super(loc
, EXP
.rightShift
, e1
, e2
);
4834 override void accept(Visitor v
)
4840 /***********************************************************
4841 * The 'unsigned shift right' operator, `x >>> y`
4843 * https://dlang.org/spec/expression.html#shift_expressions
4845 extern (C
++) final class UshrExp
: BinExp
4847 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4849 super(loc
, EXP
.unsignedRightShift
, e1
, e2
);
4852 override void accept(Visitor v
)
4858 /***********************************************************
4859 * The bitwise 'and' operator, `x & y`
4861 * https://dlang.org/spec/expression.html#and_expressions
4863 extern (C
++) final class AndExp
: BinExp
4865 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4867 super(loc
, EXP
.and, e1
, e2
);
4870 override void accept(Visitor v
)
4876 /***********************************************************
4877 * The bitwise 'or' operator, `x | y`
4879 * https://dlang.org/spec/expression.html#or_expressions
4881 extern (C
++) final class OrExp
: BinExp
4883 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4885 super(loc
, EXP
.or, e1
, e2
);
4888 override void accept(Visitor v
)
4894 /***********************************************************
4895 * The bitwise 'xor' operator, `x ^ y`
4897 * https://dlang.org/spec/expression.html#xor_expressions
4899 extern (C
++) final class XorExp
: BinExp
4901 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4903 super(loc
, EXP
.xor, e1
, e2
);
4906 override void accept(Visitor v
)
4912 /***********************************************************
4913 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
4915 * https://dlang.org/spec/expression.html#andand_expressions
4916 * https://dlang.org/spec/expression.html#oror_expressions
4918 extern (C
++) final class LogicalExp
: BinExp
4920 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) @safe
4922 super(loc
, op
, e1
, e2
);
4923 assert(op
== EXP
.andAnd || op
== EXP
.orOr
);
4926 override void accept(Visitor v
)
4932 /***********************************************************
4933 * A comparison operator, `<` `<=` `>` `>=`
4936 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
4938 * https://dlang.org/spec/expression.html#relation_expressions
4940 extern (C
++) final class CmpExp
: BinExp
4942 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
4944 super(loc
, op
, e1
, e2
);
4945 assert(op
== EXP
.lessThan || op
== EXP
.lessOrEqual || op
== EXP
.greaterThan || op
== EXP
.greaterOrEqual
);
4948 override void accept(Visitor v
)
4954 /***********************************************************
4955 * The `in` operator, `"a" in ["a": 1]`
4957 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
4959 * https://dlang.org/spec/expression.html#in_expressions
4961 extern (C
++) final class InExp
: BinExp
4963 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4965 super(loc
, EXP
.in_
, e1
, e2
);
4968 override void accept(Visitor v
)
4974 /***********************************************************
4975 * Associative array removal, `aa.remove(arg)`
4977 * This deletes the key e1 from the associative array e2
4979 extern (C
++) final class RemoveExp
: BinExp
4981 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
)
4983 super(loc
, EXP
.remove
, e1
, e2
);
4987 override void accept(Visitor v
)
4993 /***********************************************************
4996 * EXP.equal and EXP.notEqual
4998 * https://dlang.org/spec/expression.html#equality_expressions
5000 extern (C
++) final class EqualExp
: BinExp
5002 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
5004 super(loc
, op
, e1
, e2
);
5005 assert(op
== EXP
.equal || op
== EXP
.notEqual
);
5008 override void accept(Visitor v
)
5014 /***********************************************************
5017 * EXP.identity and EXP.notIdentity
5019 * https://dlang.org/spec/expression.html#identity_expressions
5021 extern (C
++) final class IdentityExp
: BinExp
5023 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
5025 super(loc
, op
, e1
, e2
);
5026 assert(op
== EXP
.identity || op
== EXP
.notIdentity
);
5029 override void accept(Visitor v
)
5035 /***********************************************************
5036 * The ternary operator, `econd ? e1 : e2`
5038 * https://dlang.org/spec/expression.html#conditional_expressions
5040 extern (C
++) final class CondExp
: BinExp
5044 extern (D
) this(const ref Loc loc
, Expression econd
, Expression e1
, Expression e2
) scope @safe
5046 super(loc
, EXP
.question
, e1
, e2
);
5050 override CondExp
syntaxCopy()
5052 return new CondExp(loc
, econd
.syntaxCopy(), e1
.syntaxCopy(), e2
.syntaxCopy());
5055 override bool isLvalue()
5057 return e1
.isLvalue() && e2
.isLvalue();
5060 override void accept(Visitor v
)
5066 /***********************************************************
5067 * A special keyword when used as a function's default argument
5069 * When possible, special keywords are resolved in the parser, but when
5070 * appearing as a default argument, they result in an expression deriving
5071 * from this base class that is resolved for each function call.
5074 * const x = __LINE__; // resolved in the parser
5075 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
5078 * https://dlang.org/spec/expression.html#specialkeywords
5080 extern (C
++) class DefaultInitExp
: Expression
5082 /*************************
5085 * op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
5086 * EXP.line, EXP.file, EXP.fileFullPath
5088 extern (D
) this(const ref Loc loc
, EXP op
) @safe
5093 override void accept(Visitor v
)
5099 /***********************************************************
5100 * The `__FILE__` token as a default argument
5102 extern (C
++) final class FileInitExp
: DefaultInitExp
5104 extern (D
) this(const ref Loc loc
, EXP tok
) @safe
5109 override void accept(Visitor v
)
5115 /***********************************************************
5116 * The `__LINE__` token as a default argument
5118 extern (C
++) final class LineInitExp
: DefaultInitExp
5120 extern (D
) this(const ref Loc loc
) @safe
5122 super(loc
, EXP
.line
);
5125 override void accept(Visitor v
)
5131 /***********************************************************
5132 * The `__MODULE__` token as a default argument
5134 extern (C
++) final class ModuleInitExp
: DefaultInitExp
5136 extern (D
) this(const ref Loc loc
) @safe
5138 super(loc
, EXP
.moduleString
);
5141 override void accept(Visitor v
)
5147 /***********************************************************
5148 * The `__FUNCTION__` token as a default argument
5150 extern (C
++) final class FuncInitExp
: DefaultInitExp
5152 extern (D
) this(const ref Loc loc
) @safe
5154 super(loc
, EXP
.functionString
);
5157 override void accept(Visitor v
)
5163 /***********************************************************
5164 * The `__PRETTY_FUNCTION__` token as a default argument
5166 extern (C
++) final class PrettyFuncInitExp
: DefaultInitExp
5168 extern (D
) this(const ref Loc loc
) @safe
5170 super(loc
, EXP
.prettyFunction
);
5173 override void accept(Visitor v
)
5179 /***********************************************************
5180 * A reference to a class, or an interface. We need this when we
5181 * point to a base class (we must record what the type is).
5183 extern (C
++) final class ClassReferenceExp
: Expression
5185 StructLiteralExp value
;
5187 extern (D
) this(const ref Loc loc
, StructLiteralExp lit
, Type type
) @safe
5189 super(loc
, EXP
.classReference
);
5190 assert(lit
&& lit
.sd
&& lit
.sd
.isClassDeclaration());
5195 ClassDeclaration
originalClass()
5197 return value
.sd
.isClassDeclaration();
5200 // Return index of the field, or -1 if not found
5201 int getFieldIndex(Type fieldtype
, uint fieldoffset
)
5203 ClassDeclaration cd
= originalClass();
5204 uint fieldsSoFar
= 0;
5205 for (size_t j
= 0; j
< value
.elements
.length
; j
++)
5207 while (j
- fieldsSoFar
>= cd
.fields
.length
)
5209 fieldsSoFar
+= cd
.fields
.length
;
5212 VarDeclaration v2
= cd
.fields
[j
- fieldsSoFar
];
5213 if (fieldoffset
== v2
.offset
&& fieldtype
.size() == v2
.type
.size())
5215 return cast(int)(value
.elements
.length
- fieldsSoFar
- cd
.fields
.length
+ (j
- fieldsSoFar
));
5221 // Return index of the field, or -1 if not found
5222 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
5223 int findFieldIndexByName(VarDeclaration v
)
5225 ClassDeclaration cd
= originalClass();
5226 size_t fieldsSoFar
= 0;
5227 for (size_t j
= 0; j
< value
.elements
.length
; j
++)
5229 while (j
- fieldsSoFar
>= cd
.fields
.length
)
5231 fieldsSoFar
+= cd
.fields
.length
;
5234 VarDeclaration v2
= cd
.fields
[j
- fieldsSoFar
];
5237 return cast(int)(value
.elements
.length
- fieldsSoFar
- cd
.fields
.length
+ (j
- fieldsSoFar
));
5243 override void accept(Visitor v
)
5249 /***********************************************************
5250 * This type is only used by the interpreter.
5252 extern (C
++) final class CTFEExp
: Expression
5254 extern (D
) this(EXP tok
)
5256 super(Loc
.initial
, tok
);
5260 override const(char)* toChars() const
5264 case EXP
.cantExpression
:
5266 case EXP
.voidExpression
:
5267 return "cast(void)0";
5268 case EXP
.showCtfeContext
:
5273 return "<continue>";
5281 extern (D
) __gshared CTFEExp cantexp
;
5282 extern (D
) __gshared CTFEExp voidexp
;
5283 extern (D
) __gshared CTFEExp breakexp
;
5284 extern (D
) __gshared CTFEExp continueexp
;
5285 extern (D
) __gshared CTFEExp gotoexp
;
5286 /* Used when additional information is needed regarding
5289 extern (D
) __gshared CTFEExp showcontext
;
5291 extern (D
) static bool isCantExp(const Expression e
) @safe
5293 return e
&& e
.op
== EXP
.cantExpression
;
5296 extern (D
) static bool isGotoExp(const Expression e
) @safe
5298 return e
&& e
.op
== EXP
.goto_
;
5302 /***********************************************************
5303 * Fake class which holds the thrown exception.
5304 * Used for implementing exception handling.
5306 extern (C
++) final class ThrownExceptionExp
: Expression
5308 ClassReferenceExp thrown
; // the thing being tossed
5310 extern (D
) this(const ref Loc loc
, ClassReferenceExp victim
) @safe
5312 super(loc
, EXP
.thrownException
);
5313 this.thrown
= victim
;
5314 this.type
= victim
.type
;
5317 override const(char)* toChars() const
5319 return "CTFE ThrownException";
5322 override void accept(Visitor v
)
5329 * Objective-C class reference expression.
5331 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
5333 extern (C
++) final class ObjcClassReferenceExp
: Expression
5335 ClassDeclaration classDeclaration
;
5337 extern (D
) this(const ref Loc loc
, ClassDeclaration classDeclaration
)
5339 super(loc
, EXP
.objcClassReference
);
5340 this.classDeclaration
= classDeclaration
;
5343 override void accept(Visitor v
)
5349 /*******************
5350 * C11 6.5.1.1 Generic Selection
5353 extern (C
++) final class GenericExp
: Expression
5355 Expression cntlExp
; /// controlling expression of a generic selection (not evaluated)
5356 Types
* types
; /// type-names for generic associations (null entry for `default`)
5357 Expressions
* exps
; /// 1:1 mapping of typeNames to exps
5359 extern (D
) this(const ref Loc loc
, Expression cntlExp
, Types
* types
, Expressions
* exps
) @safe
5361 super(loc
, EXP
._Generic
);
5362 this.cntlExp
= cntlExp
;
5365 assert(types
.length
== exps
.length
); // must be the same and >=1
5368 override GenericExp
syntaxCopy()
5370 return new GenericExp(loc
, cntlExp
.syntaxCopy(), Type
.arraySyntaxCopy(types
), Expression
.arraySyntaxCopy(exps
));
5373 override void accept(Visitor v
)
5380 * Verify if the given identifier is _d_array{,set}ctor.
5383 * id = the identifier to verify
5386 * `true` if the identifier corresponds to a construction runtime hook,
5387 * `false` otherwise.
5389 bool isArrayConstruction(const Identifier id
)
5393 return id
== Id
._d_arrayctor || id
== Id
._d_arraysetctor
;
5396 /******************************
5397 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
5399 private immutable ubyte[EXP
.max
+ 1] exptab
=
5401 ubyte[EXP
.max
+ 1] tab
;
5404 foreach (i
; Eunary
) { tab
[i
] |
= unary
; }
5405 foreach (i
; Ebinary
) { tab
[i
] |
= unary | binary
; }
5406 foreach (i
; EbinaryAssign
) { tab
[i
] |
= unary | binary | binaryAssign
; }
5411 private enum EXPFLAGS
: ubyte
5418 private enum Eunary
=
5420 EXP
.import_
, EXP
.assert_
, EXP
.throw_
, EXP
.dotIdentifier
, EXP
.dotTemplateDeclaration
,
5421 EXP
.dotVariable
, EXP
.dotTemplateInstance
, EXP
.delegate_
, EXP
.dotType
, EXP
.call,
5422 EXP
.address
, EXP
.star
, EXP
.negate
, EXP
.uadd
, EXP
.tilde
, EXP
.not, EXP
.delete_
, EXP
.cast_
,
5423 EXP
.vector
, EXP
.vectorArray
, EXP
.slice
, EXP
.arrayLength
, EXP
.array
, EXP
.delegatePointer
,
5424 EXP
.delegateFunctionPointer
, EXP
.preMinusMinus
, EXP
.prePlusPlus
,
5427 private enum Ebinary
=
5429 EXP
.dot
, EXP
.comma
, EXP
.index
, EXP
.minusMinus
, EXP
.plusPlus
, EXP
.assign
,
5430 EXP
.add, EXP
.min
, EXP
.concatenate
, EXP
.mul, EXP
.div, EXP
.mod
, EXP
.pow
, EXP
.leftShift
,
5431 EXP
.rightShift
, EXP
.unsignedRightShift
, EXP
.and, EXP
.or, EXP
.xor, EXP
.andAnd
, EXP
.orOr
,
5432 EXP
.lessThan
, EXP
.lessOrEqual
, EXP
.greaterThan
, EXP
.greaterOrEqual
,
5433 EXP
.in_
, EXP
.remove
, EXP
.equal
, EXP
.notEqual
, EXP
.identity
, EXP
.notIdentity
,
5435 EXP
.construct
, EXP
.blit
,
5438 private enum EbinaryAssign
=
5440 EXP
.addAssign
, EXP
.minAssign
, EXP
.mulAssign
, EXP
.divAssign
, EXP
.modAssign
,
5441 EXP
.andAssign
, EXP
.orAssign
, EXP
.xorAssign
, EXP
.powAssign
,
5442 EXP
.leftShiftAssign
, EXP
.rightShiftAssign
, EXP
.unsignedRightShiftAssign
,
5443 EXP
.concatenateAssign
, EXP
.concatenateElemAssign
, EXP
.concatenateDcharAssign
,
5446 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
5447 /// Needed because the classes are `extern(C++)`
5448 private immutable ubyte[EXP
.max
+1] expSize
= [
5450 EXP
.negate
: __traits(classInstanceSize
, NegExp
),
5451 EXP
.cast_
: __traits(classInstanceSize
, CastExp
),
5452 EXP
.null_
: __traits(classInstanceSize
, NullExp
),
5453 EXP
.assert_
: __traits(classInstanceSize
, AssertExp
),
5454 EXP
.array
: __traits(classInstanceSize
, ArrayExp
),
5455 EXP
.call: __traits(classInstanceSize
, CallExp
),
5456 EXP
.address
: __traits(classInstanceSize
, AddrExp
),
5457 EXP
.type
: __traits(classInstanceSize
, TypeExp
),
5458 EXP
.throw_
: __traits(classInstanceSize
, ThrowExp
),
5459 EXP
.new_
: __traits(classInstanceSize
, NewExp
),
5460 EXP
.delete_
: __traits(classInstanceSize
, DeleteExp
),
5461 EXP
.star
: __traits(classInstanceSize
, PtrExp
),
5462 EXP
.symbolOffset
: __traits(classInstanceSize
, SymOffExp
),
5463 EXP
.variable
: __traits(classInstanceSize
, VarExp
),
5464 EXP
.dotVariable
: __traits(classInstanceSize
, DotVarExp
),
5465 EXP
.dotIdentifier
: __traits(classInstanceSize
, DotIdExp
),
5466 EXP
.dotTemplateInstance
: __traits(classInstanceSize
, DotTemplateInstanceExp
),
5467 EXP
.dotType
: __traits(classInstanceSize
, DotTypeExp
),
5468 EXP
.slice
: __traits(classInstanceSize
, SliceExp
),
5469 EXP
.arrayLength
: __traits(classInstanceSize
, ArrayLengthExp
),
5470 EXP
.dollar
: __traits(classInstanceSize
, DollarExp
),
5471 EXP
.template_
: __traits(classInstanceSize
, TemplateExp
),
5472 EXP
.dotTemplateDeclaration
: __traits(classInstanceSize
, DotTemplateExp
),
5473 EXP
.declaration
: __traits(classInstanceSize
, DeclarationExp
),
5474 EXP
.dSymbol
: __traits(classInstanceSize
, DsymbolExp
),
5475 EXP
.typeid_
: __traits(classInstanceSize
, TypeidExp
),
5476 EXP
.uadd
: __traits(classInstanceSize
, UAddExp
),
5477 EXP
.remove
: __traits(classInstanceSize
, RemoveExp
),
5478 EXP
.newAnonymousClass
: __traits(classInstanceSize
, NewAnonClassExp
),
5479 EXP
.arrayLiteral
: __traits(classInstanceSize
, ArrayLiteralExp
),
5480 EXP
.assocArrayLiteral
: __traits(classInstanceSize
, AssocArrayLiteralExp
),
5481 EXP
.structLiteral
: __traits(classInstanceSize
, StructLiteralExp
),
5482 EXP
.classReference
: __traits(classInstanceSize
, ClassReferenceExp
),
5483 EXP
.thrownException
: __traits(classInstanceSize
, ThrownExceptionExp
),
5484 EXP
.delegatePointer
: __traits(classInstanceSize
, DelegatePtrExp
),
5485 EXP
.delegateFunctionPointer
: __traits(classInstanceSize
, DelegateFuncptrExp
),
5486 EXP
.lessThan
: __traits(classInstanceSize
, CmpExp
),
5487 EXP
.greaterThan
: __traits(classInstanceSize
, CmpExp
),
5488 EXP
.lessOrEqual
: __traits(classInstanceSize
, CmpExp
),
5489 EXP
.greaterOrEqual
: __traits(classInstanceSize
, CmpExp
),
5490 EXP
.equal
: __traits(classInstanceSize
, EqualExp
),
5491 EXP
.notEqual
: __traits(classInstanceSize
, EqualExp
),
5492 EXP
.identity
: __traits(classInstanceSize
, IdentityExp
),
5493 EXP
.notIdentity
: __traits(classInstanceSize
, IdentityExp
),
5494 EXP
.index
: __traits(classInstanceSize
, IndexExp
),
5495 EXP
.is_
: __traits(classInstanceSize
, IsExp
),
5496 EXP
.leftShift
: __traits(classInstanceSize
, ShlExp
),
5497 EXP
.rightShift
: __traits(classInstanceSize
, ShrExp
),
5498 EXP
.leftShiftAssign
: __traits(classInstanceSize
, ShlAssignExp
),
5499 EXP
.rightShiftAssign
: __traits(classInstanceSize
, ShrAssignExp
),
5500 EXP
.unsignedRightShift
: __traits(classInstanceSize
, UshrExp
),
5501 EXP
.unsignedRightShiftAssign
: __traits(classInstanceSize
, UshrAssignExp
),
5502 EXP
.concatenate
: __traits(classInstanceSize
, CatExp
),
5503 EXP
.concatenateAssign
: __traits(classInstanceSize
, CatAssignExp
),
5504 EXP
.concatenateElemAssign
: __traits(classInstanceSize
, CatElemAssignExp
),
5505 EXP
.concatenateDcharAssign
: __traits(classInstanceSize
, CatDcharAssignExp
),
5506 EXP
.add: __traits(classInstanceSize
, AddExp
),
5507 EXP
.min
: __traits(classInstanceSize
, MinExp
),
5508 EXP
.addAssign
: __traits(classInstanceSize
, AddAssignExp
),
5509 EXP
.minAssign
: __traits(classInstanceSize
, MinAssignExp
),
5510 EXP
.mul: __traits(classInstanceSize
, MulExp
),
5511 EXP
.div: __traits(classInstanceSize
, DivExp
),
5512 EXP
.mod
: __traits(classInstanceSize
, ModExp
),
5513 EXP
.mulAssign
: __traits(classInstanceSize
, MulAssignExp
),
5514 EXP
.divAssign
: __traits(classInstanceSize
, DivAssignExp
),
5515 EXP
.modAssign
: __traits(classInstanceSize
, ModAssignExp
),
5516 EXP
.and: __traits(classInstanceSize
, AndExp
),
5517 EXP
.or: __traits(classInstanceSize
, OrExp
),
5518 EXP
.xor: __traits(classInstanceSize
, XorExp
),
5519 EXP
.andAssign
: __traits(classInstanceSize
, AndAssignExp
),
5520 EXP
.orAssign
: __traits(classInstanceSize
, OrAssignExp
),
5521 EXP
.xorAssign
: __traits(classInstanceSize
, XorAssignExp
),
5522 EXP
.assign
: __traits(classInstanceSize
, AssignExp
),
5523 EXP
.not: __traits(classInstanceSize
, NotExp
),
5524 EXP
.tilde
: __traits(classInstanceSize
, ComExp
),
5525 EXP
.plusPlus
: __traits(classInstanceSize
, PostExp
),
5526 EXP
.minusMinus
: __traits(classInstanceSize
, PostExp
),
5527 EXP
.construct
: __traits(classInstanceSize
, ConstructExp
),
5528 EXP
.blit
: __traits(classInstanceSize
, BlitExp
),
5529 EXP
.dot
: __traits(classInstanceSize
, DotExp
),
5530 EXP
.comma
: __traits(classInstanceSize
, CommaExp
),
5531 EXP
.question
: __traits(classInstanceSize
, CondExp
),
5532 EXP
.andAnd
: __traits(classInstanceSize
, LogicalExp
),
5533 EXP
.orOr
: __traits(classInstanceSize
, LogicalExp
),
5534 EXP
.prePlusPlus
: __traits(classInstanceSize
, PreExp
),
5535 EXP
.preMinusMinus
: __traits(classInstanceSize
, PreExp
),
5536 EXP
.identifier
: __traits(classInstanceSize
, IdentifierExp
),
5537 EXP
.string_
: __traits(classInstanceSize
, StringExp
),
5538 EXP
.interpolated
: __traits(classInstanceSize
, InterpExp
),
5539 EXP
.this_
: __traits(classInstanceSize
, ThisExp
),
5540 EXP
.super_
: __traits(classInstanceSize
, SuperExp
),
5541 EXP
.halt
: __traits(classInstanceSize
, HaltExp
),
5542 EXP
.tuple
: __traits(classInstanceSize
, TupleExp
),
5543 EXP
.error
: __traits(classInstanceSize
, ErrorExp
),
5544 EXP
.void_
: __traits(classInstanceSize
, VoidInitExp
),
5545 EXP
.int64
: __traits(classInstanceSize
, IntegerExp
),
5546 EXP
.float64
: __traits(classInstanceSize
, RealExp
),
5547 EXP
.complex80
: __traits(classInstanceSize
, ComplexExp
),
5548 EXP
.import_
: __traits(classInstanceSize
, ImportExp
),
5549 EXP
.delegate_
: __traits(classInstanceSize
, DelegateExp
),
5550 EXP
.function_
: __traits(classInstanceSize
, FuncExp
),
5551 EXP
.mixin_
: __traits(classInstanceSize
, MixinExp
),
5552 EXP
.in_
: __traits(classInstanceSize
, InExp
),
5553 EXP
.break_
: __traits(classInstanceSize
, CTFEExp
),
5554 EXP
.continue_
: __traits(classInstanceSize
, CTFEExp
),
5555 EXP
.goto_
: __traits(classInstanceSize
, CTFEExp
),
5556 EXP
.scope_
: __traits(classInstanceSize
, ScopeExp
),
5557 EXP
.traits
: __traits(classInstanceSize
, TraitsExp
),
5558 EXP
.overloadSet
: __traits(classInstanceSize
, OverExp
),
5559 EXP
.line
: __traits(classInstanceSize
, LineInitExp
),
5560 EXP
.file
: __traits(classInstanceSize
, FileInitExp
),
5561 EXP
.fileFullPath
: __traits(classInstanceSize
, FileInitExp
),
5562 EXP
.moduleString
: __traits(classInstanceSize
, ModuleInitExp
),
5563 EXP
.functionString
: __traits(classInstanceSize
, FuncInitExp
),
5564 EXP
.prettyFunction
: __traits(classInstanceSize
, PrettyFuncInitExp
),
5565 EXP
.pow
: __traits(classInstanceSize
, PowExp
),
5566 EXP
.powAssign
: __traits(classInstanceSize
, PowAssignExp
),
5567 EXP
.vector
: __traits(classInstanceSize
, VectorExp
),
5568 EXP
.voidExpression
: __traits(classInstanceSize
, CTFEExp
),
5569 EXP
.cantExpression
: __traits(classInstanceSize
, CTFEExp
),
5570 EXP
.showCtfeContext
: __traits(classInstanceSize
, CTFEExp
),
5571 EXP
.objcClassReference
: __traits(classInstanceSize
, ObjcClassReferenceExp
),
5572 EXP
.vectorArray
: __traits(classInstanceSize
, VectorArrayExp
),
5573 EXP
.compoundLiteral
: __traits(classInstanceSize
, CompoundLiteralExp
),
5574 EXP
._Generic
: __traits(classInstanceSize
, GenericExp
),
5575 EXP
.interval
: __traits(classInstanceSize
, IntervalExp
),
5576 EXP
.loweredAssignExp
: __traits(classInstanceSize
, LoweredAssignExp
),