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 * Expand alias this tuples.
195 TupleDeclaration
isAliasThisTuple(Expression e
)
200 Type t
= e
.type
.toBasetype();
203 if (Dsymbol s
= t
.toDsymbol(null))
205 if (auto ad
= s
.isAggregateDeclaration())
207 s
= ad
.aliasthis ? ad
.aliasthis
.sym
: null;
208 if (s
&& s
.isVarDeclaration())
210 TupleDeclaration td
= s
.isVarDeclaration().toAlias().isTupleDeclaration();
214 if (Type att
= t
.aliasthisOf())
225 /****************************************
226 * If `s` is a function template, i.e. the only member of a template
227 * and that member is a function, return that template.
229 * s = symbol that might be a function template
231 * template for that function, otherwise null
233 TemplateDeclaration
getFuncTemplateDecl(Dsymbol s
) @safe
235 FuncDeclaration f
= s
.isFuncDeclaration();
238 if (auto ti
= f
.parent
.isTemplateInstance())
240 if (!ti
.isTemplateMixin() && ti
.tempdecl
)
242 auto td
= ti
.tempdecl
.isTemplateDeclaration();
243 if (td
.onemember
&& td
.ident
== f
.ident
)
253 /************************ TypeDotIdExp ************************************/
260 DotIdExp
typeDotIdExp(const ref Loc loc
, Type type
, Identifier ident
) @safe
262 return new DotIdExp(loc
, new TypeExp(loc
, type
), ident
);
265 /***************************************************
266 * Given an Expression, find the variable it really is.
268 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
270 * e = Expression to look at
272 * variable if there is one, null if not
274 VarDeclaration
expToVariable(Expression e
)
281 return (cast(VarExp
)e
).var
.isVarDeclaration();
283 case EXP
.dotVariable
:
284 e
= (cast(DotVarExp
)e
).e1
;
289 IndexExp ei
= cast(IndexExp
)e
;
291 Type ti
= e
.type
.toBasetype();
292 if (ti
.ty
== Tsarray
)
299 SliceExp ei
= cast(SliceExp
)e
;
301 Type ti
= e
.type
.toBasetype();
302 if (ti
.ty
== Tsarray
)
309 return (cast(ThisExp
)e
).var
.isVarDeclaration();
311 // Temporaries for rvalues that need destruction
312 // are of form: (T s = rvalue, s). For these cases
313 // we can just return var declaration of `s`. However,
314 // this is intentionally not calling `Expression.extractLast`
315 // because at this point we cannot infer the var declaration
316 // of more complex generated comma expressions such as the
317 // one for the array append hook.
320 if (auto ve
= e
.isCommaExp().e2
.isVarExp())
321 return ve
.var
.isVarDeclaration();
333 code
, // normal code expression in AST
334 ctfe
, // value expression for CTFE
335 cache
, // constant value cached for CTFE
338 enum WANTvalue
= 0; // default
339 enum WANTexpand
= 1; // expand const/immutable variables if possible
341 /***********************************************************
342 * https://dlang.org/spec/expression.html#expression
344 extern (C
++) abstract class Expression
: ASTNode
346 Type type
; // !=null means that semantic() has been run
347 Loc loc
; // file location
348 const EXP op
; // to minimize use of dynamic_cast
350 extern (D
) this(const ref Loc loc
, EXP op
) scope @safe
352 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
357 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
358 final size_t
size() nothrow @nogc pure @safe const { return expSize
[op
]; }
362 CTFEExp
.cantexp
= new CTFEExp(EXP
.cantExpression
);
363 CTFEExp
.voidexp
= new CTFEExp(EXP
.voidExpression
);
364 CTFEExp
.breakexp
= new CTFEExp(EXP
.break_
);
365 CTFEExp
.continueexp
= new CTFEExp(EXP
.continue_
);
366 CTFEExp
.gotoexp
= new CTFEExp(EXP
.goto_
);
367 CTFEExp
.showcontext
= new CTFEExp(EXP
.showCtfeContext
);
371 * Deinitializes the global state of the compiler.
373 * This can be used to restore the state set by `_init` to its original
376 static void deinitialize()
378 CTFEExp
.cantexp
= CTFEExp
.cantexp
.init
;
379 CTFEExp
.voidexp
= CTFEExp
.voidexp
.init
;
380 CTFEExp
.breakexp
= CTFEExp
.breakexp
.init
;
381 CTFEExp
.continueexp
= CTFEExp
.continueexp
.init
;
382 CTFEExp
.gotoexp
= CTFEExp
.gotoexp
.init
;
383 CTFEExp
.showcontext
= CTFEExp
.showcontext
.init
;
386 /*********************************
387 * Does *not* do a deep copy.
389 extern (D
) final Expression
copy()
396 fprintf(stderr
, "No expression copy for: %s\n", toChars());
397 printf("op = %d\n", op
);
402 // memory never freed, so can use the faster bump-pointer-allocation
403 e
= cast(Expression
)allocmemory(size
);
404 //printf("Expression::copy(op = %d) e = %p\n", op, e);
405 return cast(Expression
)memcpy(cast(void*)e
, cast(void*)this, size
);
408 Expression
syntaxCopy()
410 //printf("Expression::syntaxCopy()\n");
415 // kludge for template.isExpression()
416 override final DYNCAST
dyncast() const
418 return DYNCAST
.expression
;
421 override const(char)* toChars() const
423 return .toChars(this);
426 /**********************************
427 * Combine e1 and e2 by CommaExp if both are not NULL.
429 extern (D
) static Expression
combine(Expression e1
, Expression e2
) @safe
435 e1
= new CommaExp(e1
.loc
, e1
, e2
);
444 extern (D
) static Expression
combine(Expression e1
, Expression e2
, Expression e3
) @safe
446 return combine(combine(e1
, e2
), e3
);
449 extern (D
) static Expression
combine(Expression e1
, Expression e2
, Expression e3
, Expression e4
) @safe
451 return combine(combine(e1
, e2
), combine(e3
, e4
));
454 /**********************************
455 * If 'e' is a tree of commas, returns the rightmost expression
456 * by stripping off it from the tree. The remained part of the tree
457 * is returned via e0.
458 * Otherwise 'e' is directly returned and e0 is set to NULL.
460 extern (D
) static Expression
extractLast(Expression e
, out Expression e0
) @safe
462 if (e
.op
!= EXP
.comma
)
467 CommaExp ce
= cast(CommaExp
)e
;
468 if (ce
.e2
.op
!= EXP
.comma
)
477 Expression
* pce
= &ce
.e2
;
478 while ((cast(CommaExp
)(*pce
)).e2
.op
== EXP
.comma
)
480 pce
= &(cast(CommaExp
)(*pce
)).e2
;
482 assert((*pce
).op
== EXP
.comma
);
483 ce
= cast(CommaExp
)(*pce
);
490 extern (D
) static Expressions
* arraySyntaxCopy(Expressions
* exps
)
492 Expressions
* a
= null;
495 a
= new Expressions(exps
.length
);
496 foreach (i
, e
; *exps
)
498 (*a
)[i
] = e ? e
.syntaxCopy() : null;
504 dinteger_t
toInteger()
506 //printf("Expression %s\n", EXPtoString(op).ptr);
507 if (!type
.isTypeError())
508 error(loc
, "integer constant expression expected instead of `%s`", toChars());
512 uinteger_t
toUInteger()
514 //printf("Expression %s\n", EXPtoString(op).ptr);
515 return cast(uinteger_t
)toInteger();
520 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
526 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
530 complex_t
toComplex()
532 error(loc
, "floating point constant expression expected instead of `%s`", toChars());
533 return complex_t(CTFloat
.zero
);
536 StringExp
toStringExp()
541 /***************************************
542 * Return !=0 if expression is an lvalue.
549 /****************************************
550 * Check that the expression has a valid type.
551 * If not, generates an error "... has no type".
553 * true if the expression is not valid.
555 * When this function returns true, `checkValue()` should also return true.
562 /****************************************
563 * Check that the expression has a valid value.
564 * If not, generates an error "... has no value".
566 * true if the expression is not valid or has void type.
570 if (type
&& type
.toBasetype().ty
== Tvoid
)
572 error(loc
, "expression `%s` is `void` and has no value", toChars());
573 //print(); assert(0);
581 extern (D
) final bool checkScalar()
585 if (type
.toBasetype().ty
== Terror
)
587 if (!type
.isscalar())
589 error(loc
, "`%s` is not a scalar, it is a `%s`", toChars(), type
.toChars());
595 extern (D
) final bool checkNoBool()
599 if (type
.toBasetype().ty
== Terror
)
601 if (type
.toBasetype().ty
== Tbool
)
603 error(loc
, "operation not allowed on `bool` `%s`", toChars());
609 extern (D
) final bool checkIntegral()
613 if (type
.toBasetype().ty
== Terror
)
615 if (!type
.isintegral())
617 error(loc
, "`%s` is not of integral type, it is a `%s`", toChars(), type
.toChars());
623 extern (D
) final bool checkArithmetic(EXP op
)
627 if (type
.toBasetype().ty
== Terror
)
629 if (!type
.isintegral() && !type
.isfloating())
631 // unary aggregate ops error here
632 const char* msg
= type
.isAggregate() ?
633 "operator `%s` is not defined for `%s` of type `%s`" :
634 "illegal operator `%s` for `%s` of type `%s`";
635 error(loc
, msg
, EXPtoString(op
).ptr
, toChars(), type
.toChars());
641 /*******************************
642 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
643 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
644 * Returns true if error occurs.
646 extern (D
) final bool checkReadModifyWrite(EXP rmwOp
, Expression ex
= null)
648 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
649 if (!type ||
!type
.isShared() || type
.isTypeStruct() || type
.isTypeClass())
652 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
656 case EXP
.prePlusPlus
:
657 rmwOp
= EXP
.addAssign
;
660 case EXP
.preMinusMinus
:
661 rmwOp
= EXP
.minAssign
;
667 error(loc
, "read-modify-write operations are not allowed for `shared` variables");
668 errorSupplemental(loc
, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
669 EXPtoString(rmwOp
).ptr
, toChars(), ex ? ex
.toChars() : "1");
673 /******************************
674 * Take address of expression.
676 final Expression
addressOf()
678 //printf("Expression::addressOf()\n");
681 assert(op
== EXP
.error ||
isLvalue());
683 Expression e
= new AddrExp(loc
, this, type
.pointerTo());
687 /******************************
688 * If this is a reference, dereference it.
690 final Expression
deref()
692 //printf("Expression::deref()\n");
693 // type could be null if forward referencing an 'auto' variable
695 if (auto tr
= type
.isTypeReference())
697 Expression e
= new PtrExp(loc
, this, tr
.next
);
705 //printf("Expression::isConst(): %s\n", e.toChars());
714 case EXP
.symbolOffset
:
723 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
725 bool isIdentical(const Expression e
) const
731 /// Statically evaluate this expression to a `bool` if possible
732 /// Returns: an optional thath either contains the value or is empty
733 Optional
!bool toBool()
735 return typeof(return)();
743 final pure inout nothrow @nogc @safe
745 inout(IntegerExp
) isIntegerExp() { return op
== EXP
.int64 ?
cast(typeof(return))this : null; }
746 inout(ErrorExp
) isErrorExp() { return op
== EXP
.error ?
cast(typeof(return))this : null; }
747 inout(VoidInitExp
) isVoidInitExp() { return op
== EXP
.void_ ?
cast(typeof(return))this : null; }
748 inout(RealExp
) isRealExp() { return op
== EXP
.float64 ?
cast(typeof(return))this : null; }
749 inout(ComplexExp
) isComplexExp() { return op
== EXP
.complex80 ?
cast(typeof(return))this : null; }
750 inout(IdentifierExp
) isIdentifierExp() { return op
== EXP
.identifier ?
cast(typeof(return))this : null; }
751 inout(DollarExp
) isDollarExp() { return op
== EXP
.dollar ?
cast(typeof(return))this : null; }
752 inout(DsymbolExp
) isDsymbolExp() { return op
== EXP
.dSymbol ?
cast(typeof(return))this : null; }
753 inout(ThisExp
) isThisExp() { return op
== EXP
.this_ ?
cast(typeof(return))this : null; }
754 inout(SuperExp
) isSuperExp() { return op
== EXP
.super_ ?
cast(typeof(return))this : null; }
755 inout(NullExp
) isNullExp() { return op
== EXP
.null_ ?
cast(typeof(return))this : null; }
756 inout(StringExp
) isStringExp() { return op
== EXP
.string_ ?
cast(typeof(return))this : null; }
757 inout(TupleExp
) isTupleExp() { return op
== EXP
.tuple ?
cast(typeof(return))this : null; }
758 inout(ArrayLiteralExp
) isArrayLiteralExp() { return op
== EXP
.arrayLiteral ?
cast(typeof(return))this : null; }
759 inout(AssocArrayLiteralExp
) isAssocArrayLiteralExp() { return op
== EXP
.assocArrayLiteral ?
cast(typeof(return))this : null; }
760 inout(StructLiteralExp
) isStructLiteralExp() { return op
== EXP
.structLiteral ?
cast(typeof(return))this : null; }
761 inout(CompoundLiteralExp
) isCompoundLiteralExp() { return op
== EXP
.compoundLiteral ?
cast(typeof(return))this : null; }
762 inout(TypeExp
) isTypeExp() { return op
== EXP
.type ?
cast(typeof(return))this : null; }
763 inout(ScopeExp
) isScopeExp() { return op
== EXP
.scope_ ?
cast(typeof(return))this : null; }
764 inout(TemplateExp
) isTemplateExp() { return op
== EXP
.template_ ?
cast(typeof(return))this : null; }
765 inout(NewExp
) isNewExp() { return op
== EXP
.new_ ?
cast(typeof(return))this : null; }
766 inout(NewAnonClassExp
) isNewAnonClassExp() { return op
== EXP
.newAnonymousClass ?
cast(typeof(return))this : null; }
767 inout(SymOffExp
) isSymOffExp() { return op
== EXP
.symbolOffset ?
cast(typeof(return))this : null; }
768 inout(VarExp
) isVarExp() { return op
== EXP
.variable ?
cast(typeof(return))this : null; }
769 inout(OverExp
) isOverExp() { return op
== EXP
.overloadSet ?
cast(typeof(return))this : null; }
770 inout(FuncExp
) isFuncExp() { return op
== EXP
.function_ ?
cast(typeof(return))this : null; }
771 inout(DeclarationExp
) isDeclarationExp() { return op
== EXP
.declaration ?
cast(typeof(return))this : null; }
772 inout(TypeidExp
) isTypeidExp() { return op
== EXP
.typeid_ ?
cast(typeof(return))this : null; }
773 inout(TraitsExp
) isTraitsExp() { return op
== EXP
.traits ?
cast(typeof(return))this : null; }
774 inout(HaltExp
) isHaltExp() { return op
== EXP
.halt ?
cast(typeof(return))this : null; }
775 inout(IsExp
) isExp() { return op
== EXP
.is_ ?
cast(typeof(return))this : null; }
776 inout(MixinExp
) isMixinExp() { return op
== EXP
.mixin_ ?
cast(typeof(return))this : null; }
777 inout(ImportExp
) isImportExp() { return op
== EXP
.import_ ?
cast(typeof(return))this : null; }
778 inout(AssertExp
) isAssertExp() { return op
== EXP
.assert_ ?
cast(typeof(return))this : null; }
779 inout(ThrowExp
) isThrowExp() { return op
== EXP
.throw_ ?
cast(typeof(return))this : null; }
780 inout(DotIdExp
) isDotIdExp() { return op
== EXP
.dotIdentifier ?
cast(typeof(return))this : null; }
781 inout(DotTemplateExp
) isDotTemplateExp() { return op
== EXP
.dotTemplateDeclaration ?
cast(typeof(return))this : null; }
782 inout(DotVarExp
) isDotVarExp() { return op
== EXP
.dotVariable ?
cast(typeof(return))this : null; }
783 inout(DotTemplateInstanceExp
) isDotTemplateInstanceExp() { return op
== EXP
.dotTemplateInstance ?
cast(typeof(return))this : null; }
784 inout(DelegateExp
) isDelegateExp() { return op
== EXP
.delegate_ ?
cast(typeof(return))this : null; }
785 inout(DotTypeExp
) isDotTypeExp() { return op
== EXP
.dotType ?
cast(typeof(return))this : null; }
786 inout(CallExp
) isCallExp() { return op
== EXP
.call ?
cast(typeof(return))this : null; }
787 inout(AddrExp
) isAddrExp() { return op
== EXP
.address ?
cast(typeof(return))this : null; }
788 inout(PtrExp
) isPtrExp() { return op
== EXP
.star ?
cast(typeof(return))this : null; }
789 inout(NegExp
) isNegExp() { return op
== EXP
.negate ?
cast(typeof(return))this : null; }
790 inout(UAddExp
) isUAddExp() { return op
== EXP
.uadd ?
cast(typeof(return))this : null; }
791 inout(ComExp
) isComExp() { return op
== EXP
.tilde ?
cast(typeof(return))this : null; }
792 inout(NotExp
) isNotExp() { return op
== EXP
.not ?
cast(typeof(return))this : null; }
793 inout(DeleteExp
) isDeleteExp() { return op
== EXP
.delete_ ?
cast(typeof(return))this : null; }
794 inout(CastExp
) isCastExp() { return op
== EXP
.cast_ ?
cast(typeof(return))this : null; }
795 inout(VectorExp
) isVectorExp() { return op
== EXP
.vector ?
cast(typeof(return))this : null; }
796 inout(VectorArrayExp
) isVectorArrayExp() { return op
== EXP
.vectorArray ?
cast(typeof(return))this : null; }
797 inout(SliceExp
) isSliceExp() { return op
== EXP
.slice ?
cast(typeof(return))this : null; }
798 inout(ArrayLengthExp
) isArrayLengthExp() { return op
== EXP
.arrayLength ?
cast(typeof(return))this : null; }
799 inout(ArrayExp
) isArrayExp() { return op
== EXP
.array ?
cast(typeof(return))this : null; }
800 inout(DotExp
) isDotExp() { return op
== EXP
.dot ?
cast(typeof(return))this : null; }
801 inout(CommaExp
) isCommaExp() { return op
== EXP
.comma ?
cast(typeof(return))this : null; }
802 inout(IntervalExp
) isIntervalExp() { return op
== EXP
.interval ?
cast(typeof(return))this : null; }
803 inout(DelegatePtrExp
) isDelegatePtrExp() { return op
== EXP
.delegatePointer ?
cast(typeof(return))this : null; }
804 inout(DelegateFuncptrExp
) isDelegateFuncptrExp() { return op
== EXP
.delegateFunctionPointer ?
cast(typeof(return))this : null; }
805 inout(IndexExp
) isIndexExp() { return op
== EXP
.index ?
cast(typeof(return))this : null; }
806 inout(PostExp
) isPostExp() { return (op
== EXP
.plusPlus || op
== EXP
.minusMinus
) ?
cast(typeof(return))this : null; }
807 inout(PreExp
) isPreExp() { return (op
== EXP
.prePlusPlus || op
== EXP
.preMinusMinus
) ?
cast(typeof(return))this : null; }
808 inout(AssignExp
) isAssignExp() { return op
== EXP
.assign ?
cast(typeof(return))this : null; }
809 inout(LoweredAssignExp
) isLoweredAssignExp() { return op
== EXP
.loweredAssignExp ?
cast(typeof(return))this : null; }
810 inout(ConstructExp
) isConstructExp() { return op
== EXP
.construct ?
cast(typeof(return))this : null; }
811 inout(BlitExp
) isBlitExp() { return op
== EXP
.blit ?
cast(typeof(return))this : null; }
812 inout(AddAssignExp
) isAddAssignExp() { return op
== EXP
.addAssign ?
cast(typeof(return))this : null; }
813 inout(MinAssignExp
) isMinAssignExp() { return op
== EXP
.minAssign ?
cast(typeof(return))this : null; }
814 inout(MulAssignExp
) isMulAssignExp() { return op
== EXP
.mulAssign ?
cast(typeof(return))this : null; }
816 inout(DivAssignExp
) isDivAssignExp() { return op
== EXP
.divAssign ?
cast(typeof(return))this : null; }
817 inout(ModAssignExp
) isModAssignExp() { return op
== EXP
.modAssign ?
cast(typeof(return))this : null; }
818 inout(AndAssignExp
) isAndAssignExp() { return op
== EXP
.andAssign ?
cast(typeof(return))this : null; }
819 inout(OrAssignExp
) isOrAssignExp() { return op
== EXP
.orAssign ?
cast(typeof(return))this : null; }
820 inout(XorAssignExp
) isXorAssignExp() { return op
== EXP
.xorAssign ?
cast(typeof(return))this : null; }
821 inout(PowAssignExp
) isPowAssignExp() { return op
== EXP
.powAssign ?
cast(typeof(return))this : null; }
823 inout(ShlAssignExp
) isShlAssignExp() { return op
== EXP
.leftShiftAssign ?
cast(typeof(return))this : null; }
824 inout(ShrAssignExp
) isShrAssignExp() { return op
== EXP
.rightShiftAssign ?
cast(typeof(return))this : null; }
825 inout(UshrAssignExp
) isUshrAssignExp() { return op
== EXP
.unsignedRightShiftAssign ?
cast(typeof(return))this : null; }
827 inout(CatAssignExp
) isCatAssignExp() { return op
== EXP
.concatenateAssign
828 ?
cast(typeof(return))this
831 inout(CatElemAssignExp
) isCatElemAssignExp() { return op
== EXP
.concatenateElemAssign
832 ?
cast(typeof(return))this
835 inout(CatDcharAssignExp
) isCatDcharAssignExp() { return op
== EXP
.concatenateDcharAssign
836 ?
cast(typeof(return))this
839 inout(AddExp
) isAddExp() { return op
== EXP
.add ?
cast(typeof(return))this : null; }
840 inout(MinExp
) isMinExp() { return op
== EXP
.min ?
cast(typeof(return))this : null; }
841 inout(CatExp
) isCatExp() { return op
== EXP
.concatenate ?
cast(typeof(return))this : null; }
842 inout(MulExp
) isMulExp() { return op
== EXP
.mul ?
cast(typeof(return))this : null; }
843 inout(DivExp
) isDivExp() { return op
== EXP
.div ?
cast(typeof(return))this : null; }
844 inout(ModExp
) isModExp() { return op
== EXP
.mod ?
cast(typeof(return))this : null; }
845 inout(PowExp
) isPowExp() { return op
== EXP
.pow ?
cast(typeof(return))this : null; }
846 inout(ShlExp
) isShlExp() { return op
== EXP
.leftShift ?
cast(typeof(return))this : null; }
847 inout(ShrExp
) isShrExp() { return op
== EXP
.rightShift ?
cast(typeof(return))this : null; }
848 inout(UshrExp
) isUshrExp() { return op
== EXP
.unsignedRightShift ?
cast(typeof(return))this : null; }
849 inout(AndExp
) isAndExp() { return op
== EXP
.and ?
cast(typeof(return))this : null; }
850 inout(OrExp
) isOrExp() { return op
== EXP
.or ?
cast(typeof(return))this : null; }
851 inout(XorExp
) isXorExp() { return op
== EXP
.xor ?
cast(typeof(return))this : null; }
852 inout(LogicalExp
) isLogicalExp() { return (op
== EXP
.andAnd || op
== EXP
.orOr
) ?
cast(typeof(return))this : null; }
853 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
854 inout(InExp
) isInExp() { return op
== EXP
.in_ ?
cast(typeof(return))this : null; }
855 inout(RemoveExp
) isRemoveExp() { return op
== EXP
.remove ?
cast(typeof(return))this : null; }
856 inout(EqualExp
) isEqualExp() { return (op
== EXP
.equal || op
== EXP
.notEqual
) ?
cast(typeof(return))this : null; }
857 inout(IdentityExp
) isIdentityExp() { return (op
== EXP
.identity || op
== EXP
.notIdentity
) ?
cast(typeof(return))this : null; }
858 inout(CondExp
) isCondExp() { return op
== EXP
.question ?
cast(typeof(return))this : null; }
859 inout(GenericExp
) isGenericExp() { return op
== EXP
._Generic ?
cast(typeof(return))this : null; }
860 inout(DefaultInitExp
) isDefaultInitExp() { return
861 (op
== EXP
.prettyFunction || op
== EXP
.functionString ||
862 op
== EXP
.line || op
== EXP
.moduleString ||
863 op
== EXP
.file || op
== EXP
.fileFullPath
) ?
cast(typeof(return))this : null; }
864 inout(FileInitExp
) isFileInitExp() { return (op
== EXP
.file || op
== EXP
.fileFullPath
) ?
cast(typeof(return))this : null; }
865 inout(LineInitExp
) isLineInitExp() { return op
== EXP
.line ?
cast(typeof(return))this : null; }
866 inout(ModuleInitExp
) isModuleInitExp() { return op
== EXP
.moduleString ?
cast(typeof(return))this : null; }
867 inout(FuncInitExp
) isFuncInitExp() { return op
== EXP
.functionString ?
cast(typeof(return))this : null; }
868 inout(PrettyFuncInitExp
) isPrettyFuncInitExp() { return op
== EXP
.prettyFunction ?
cast(typeof(return))this : null; }
869 inout(ObjcClassReferenceExp
) isObjcClassReferenceExp() { return op
== EXP
.objcClassReference ?
cast(typeof(return))this : null; }
870 inout(ClassReferenceExp
) isClassReferenceExp() { return op
== EXP
.classReference ?
cast(typeof(return))this : null; }
871 inout(ThrownExceptionExp
) isThrownExceptionExp() { return op
== EXP
.thrownException ?
cast(typeof(return))this : null; }
873 inout(UnaExp
) isUnaExp() pure inout nothrow @nogc
875 return exptab
[op
] & EXPFLAGS
.unary ?
cast(typeof(return))this : null;
878 inout(BinExp
) isBinExp() pure inout nothrow @nogc
880 return exptab
[op
] & EXPFLAGS
.binary ?
cast(typeof(return))this : null;
883 inout(BinAssignExp
) isBinAssignExp() pure inout nothrow @nogc
885 return exptab
[op
] & EXPFLAGS
.binaryAssign ?
cast(typeof(return))this : null;
889 override void accept(Visitor v
)
895 /***********************************************************
896 * A compile-time known integer value
898 extern (C
++) final class IntegerExp
: Expression
900 private dinteger_t value
;
902 extern (D
) this(const ref Loc loc
, dinteger_t value
, Type type
)
904 super(loc
, EXP
.int64
);
905 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
907 if (!type
.isscalar())
909 //printf("%s, loc = %d\n", toChars(), loc.linnum);
910 if (type
.ty
!= Terror
)
911 error(loc
, "integral constant must be scalar type, not `%s`", type
.toChars());
915 this.value
= normalize(type
.toBasetype().ty
, value
);
918 extern (D
) this(dinteger_t value
)
920 super(Loc
.initial
, EXP
.int64
);
921 this.type
= Type
.tint32
;
922 this.value
= cast(int)value
;
925 static IntegerExp
create(const ref Loc loc
, dinteger_t value
, Type type
)
927 return new IntegerExp(loc
, value
, type
);
930 override bool equals(const RootObject o
) const
934 if (auto ne
= (cast(Expression
)o
).isIntegerExp())
936 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && value
== ne
.value
)
944 override dinteger_t
toInteger()
946 // normalize() is necessary until we fix all the paints of 'type'
947 return value
= normalize(type
.toBasetype().ty
, value
);
950 override real_t
toReal()
952 // normalize() is necessary until we fix all the paints of 'type'
953 const ty
= type
.toBasetype().ty
;
954 const val
= normalize(ty
, value
);
956 return (ty
== Tuns64
)
957 ?
real_t(cast(ulong)val
)
958 : real_t(cast(long)val
);
961 override real_t
toImaginary()
966 override complex_t
toComplex()
968 return complex_t(toReal());
971 override Optional
!bool toBool()
973 bool r
= toInteger() != 0;
974 return typeof(return)(r
);
977 override void accept(Visitor v
)
982 dinteger_t
getInteger()
987 extern (D
) void setInteger(dinteger_t value
)
989 this.value
= normalize(type
.toBasetype().ty
, value
);
992 extern (D
) static dinteger_t
normalize(TY ty
, dinteger_t value
)
994 /* 'Normalize' the value of the integer to be in range of the type
1000 result
= (value
!= 0);
1004 result
= cast(byte)value
;
1009 result
= cast(ubyte)value
;
1013 result
= cast(short)value
;
1018 result
= cast(ushort)value
;
1022 result
= cast(int)value
;
1027 result
= cast(uint)value
;
1031 result
= cast(long)value
;
1035 result
= cast(ulong)value
;
1039 if (target
.ptrsize
== 8)
1041 if (target
.ptrsize
== 4)
1043 if (target
.ptrsize
== 2)
1053 override IntegerExp
syntaxCopy()
1059 * Use this instead of creating new instances for commonly used literals
1063 * v = The value of the expression
1065 * A static instance of the expression, typed as `Tint32`.
1067 static IntegerExp
literal(int v
)()
1069 __gshared IntegerExp theConstant
;
1071 theConstant
= new IntegerExp(v
);
1076 * Use this instead of creating new instances for commonly used bools.
1079 * b = The value of the expression
1081 * A static instance of the expression, typed as `Type.tbool`.
1083 static IntegerExp
createBool(bool b
)
1085 __gshared IntegerExp trueExp
, falseExp
;
1088 trueExp
= new IntegerExp(Loc
.initial
, 1, Type
.tbool
);
1089 falseExp
= new IntegerExp(Loc
.initial
, 0, Type
.tbool
);
1091 return b ? trueExp
: falseExp
;
1095 /***********************************************************
1096 * Use this expression for error recovery.
1098 * It should behave as a 'sink' to prevent further cascaded error messages.
1100 extern (C
++) final class ErrorExp
: Expression
1104 super(Loc
.initial
, EXP
.error
);
1108 static ErrorExp
get ()
1110 if (errorexp
is null)
1111 errorexp
= new ErrorExp();
1113 if (global
.errors
== 0 && global
.gaggedErrors
== 0)
1115 /* Unfortunately, errors can still leak out of gagged errors,
1116 * and we need to set the error count to prevent bogus code
1117 * generation. At least give a message.
1119 .error(Loc
.initial
, "unknown, please file report on issues.dlang.org");
1125 override void accept(Visitor v
)
1130 extern (C
++) __gshared ErrorExp errorexp
; // handy shared value
1134 /***********************************************************
1135 * An uninitialized value,
1136 * generated from void initializers.
1138 * https://dlang.org/spec/declaration.html#void_init
1140 extern (C
++) final class VoidInitExp
: Expression
1142 VarDeclaration var
; /// the variable from where the void value came from, null if not known
1143 /// Useful for error messages
1145 extern (D
) this(VarDeclaration var
) @safe
1147 super(var
.loc
, EXP
.void_
);
1149 this.type
= var
.type
;
1152 override void accept(Visitor v
)
1159 /***********************************************************
1160 * A compile-time known floating point number
1162 extern (C
++) final class RealExp
: Expression
1166 extern (D
) this(const ref Loc loc
, real_t value
, Type type
) @safe
1168 super(loc
, EXP
.float64
);
1169 //printf("RealExp::RealExp(%Lg)\n", value);
1174 static RealExp
create(const ref Loc loc
, real_t value
, Type type
) @safe
1176 return new RealExp(loc
, value
, type
);
1179 /********************************
1180 * Test to see if two reals are the same.
1181 * Regard NaN's as equivalent.
1182 * Regard +0 and -0 as different.
1184 * x1 = first operand
1185 * x2 = second operand
1190 private static bool RealIdentical(real_t x1
, real_t x2
) @safe
1192 return (CTFloat
.isNaN(x1
) && CTFloat
.isNaN(x2
)) || CTFloat
.isIdentical(x1
, x2
);
1194 override bool equals(const RootObject o
) const
1198 if (auto ne
= (cast(Expression
)o
).isRealExp())
1200 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && RealIdentical(value
, ne
.value
))
1208 override bool isIdentical(const Expression e
) const
1212 return CTFloat
.isIdentical(value
, e
.isRealExp().value
);
1215 override dinteger_t
toInteger()
1217 return cast(sinteger_t
)toReal();
1220 override uinteger_t
toUInteger()
1222 return cast(uinteger_t
)toReal();
1225 override real_t
toReal()
1227 return type
.isreal() ? value
: CTFloat
.zero
;
1230 override real_t
toImaginary()
1232 return type
.isreal() ? CTFloat
.zero
: value
;
1235 override complex_t
toComplex()
1237 return complex_t(toReal(), toImaginary());
1240 override Optional
!bool toBool()
1242 return typeof(return)(!!value
);
1245 override void accept(Visitor v
)
1251 /***********************************************************
1252 * A compile-time complex number (deprecated)
1254 extern (C
++) final class ComplexExp
: Expression
1258 extern (D
) this(const ref Loc loc
, complex_t value
, Type type
) @safe
1260 super(loc
, EXP
.complex80
);
1263 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
1266 static ComplexExp
create(const ref Loc loc
, complex_t value
, Type type
) @safe
1268 return new ComplexExp(loc
, value
, type
);
1271 override bool equals(const RootObject o
) const
1275 if (auto ne
= (cast(Expression
)o
).isComplexExp())
1277 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) &&
1278 RealExp
.RealIdentical(creall(value
), creall(ne
.value
)) &&
1279 RealExp
.RealIdentical(cimagl(value
), cimagl(ne
.value
)))
1287 override bool isIdentical(const Expression e
) const
1291 // equals() regards different NaN values as 'equals'
1292 auto c
= e
.isComplexExp();
1293 return CTFloat
.isIdentical(creall(value
), creall(c
.value
)) &&
1294 CTFloat
.isIdentical(cimagl(value
), cimagl(c
.value
));
1297 override dinteger_t
toInteger()
1299 return cast(sinteger_t
)toReal();
1302 override uinteger_t
toUInteger()
1304 return cast(uinteger_t
)toReal();
1307 override real_t
toReal()
1309 return creall(value
);
1312 override real_t
toImaginary()
1314 return cimagl(value
);
1317 override complex_t
toComplex()
1322 override Optional
!bool toBool()
1324 return typeof(return)(!!value
);
1327 override void accept(Visitor v
)
1333 /***********************************************************
1334 * An identifier in the context of an expression (as opposed to a declaration)
1337 * int x; // VarDeclaration with Identifier
1338 * x++; // PostExp with IdentifierExp
1341 extern (C
++) class IdentifierExp
: Expression
1344 bool parens
; // if it appears as (identifier)
1346 extern (D
) this(const ref Loc loc
, Identifier ident
) scope @safe
1348 super(loc
, EXP
.identifier
);
1352 static IdentifierExp
create(const ref Loc loc
, Identifier ident
) @safe
1354 return new IdentifierExp(loc
, ident
);
1357 override final bool isLvalue()
1362 override void accept(Visitor v
)
1368 /***********************************************************
1369 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
1371 * https://dlang.org/spec/arrays.html#array-length
1373 extern (C
++) final class DollarExp
: IdentifierExp
1375 extern (D
) this(const ref Loc loc
)
1377 super(loc
, Id
.dollar
);
1380 override void accept(Visitor v
)
1386 /***********************************************************
1387 * Won't be generated by parser.
1389 extern (C
++) final class DsymbolExp
: Expression
1394 extern (D
) this(const ref Loc loc
, Dsymbol s
, bool hasOverloads
= true) @safe
1396 super(loc
, EXP
.dSymbol
);
1398 this.hasOverloads
= hasOverloads
;
1401 override bool isLvalue()
1406 override void accept(Visitor v
)
1412 /***********************************************************
1413 * https://dlang.org/spec/expression.html#this
1415 extern (C
++) class ThisExp
: Expression
1419 extern (D
) this(const ref Loc loc
) @safe
1421 super(loc
, EXP
.this_
);
1422 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1425 this(const ref Loc loc
, const EXP tok
) @safe
1428 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1431 override ThisExp
syntaxCopy()
1433 auto r
= cast(ThisExp
) super.syntaxCopy();
1434 // require new semantic (possibly new `var` etc.)
1440 override Optional
!bool toBool()
1442 // `this` is never null (what about structs?)
1443 return typeof(return)(true);
1446 override final bool isLvalue()
1448 // Class `this` should be an rvalue; struct `this` should be an lvalue.
1449 return type
.toBasetype().ty
!= Tclass
;
1452 override void accept(Visitor v
)
1458 /***********************************************************
1459 * https://dlang.org/spec/expression.html#super
1461 extern (C
++) final class SuperExp
: ThisExp
1463 extern (D
) this(const ref Loc loc
) @safe
1465 super(loc
, EXP
.super_
);
1468 override void accept(Visitor v
)
1474 /***********************************************************
1475 * A compile-time known `null` value
1477 * https://dlang.org/spec/expression.html#null
1479 extern (C
++) final class NullExp
: Expression
1481 extern (D
) this(const ref Loc loc
, Type type
= null) scope @safe
1483 super(loc
, EXP
.null_
);
1487 override bool equals(const RootObject o
) const
1489 if (auto e
= o
.isExpression())
1491 if (e
.op
== EXP
.null_
&& type
.equals(e
.type
))
1499 override Optional
!bool toBool()
1501 // null in any type is false
1502 return typeof(return)(false);
1505 override StringExp
toStringExp()
1507 if (this.type
.implicitConvTo(Type
.tstring
))
1509 auto se
= new StringExp(loc
, (cast(char*)mem
.xcalloc(1, 1))[0 .. 0]);
1510 se
.type
= Type
.tstring
;
1517 override void accept(Visitor v
)
1523 /***********************************************************
1524 * https://dlang.org/spec/expression.html#string_literals
1526 extern (C
++) final class StringExp
: Expression
1528 char postfix
= NoPostfix
; // 'c', 'w', 'd'
1529 OwnedBy ownedByCtfe
= OwnedBy
.code
;
1532 char* string
; // if sz == 1
1533 wchar* wstring
; // if sz == 2
1534 dchar* dstring
; // if sz == 4
1535 } // (const if ownedByCtfe == OwnedBy.code)
1536 size_t len
; // number of code units
1537 ubyte sz
= 1; // 1: char, 2: wchar, 4: dchar
1540 * Whether the string literal's type is fixed
1543 * wstring x = "abc"; // OK, string literal is flexible
1544 * wstring y = cast(string) "abc"; // Error: type was committed after cast
1549 /// If the string is parsed from a hex string literal
1550 bool hexString
= false;
1552 enum char NoPostfix
= 0;
1554 extern (D
) this(const ref Loc loc
, const(void)[] string
) scope
1556 super(loc
, EXP
.string_
);
1557 this.string
= cast(char*)string
.ptr
; // note that this.string should be const
1558 this.len
= string
.length
;
1559 this.sz
= 1; // work around LDC bug #1286
1562 extern (D
) this(const ref Loc loc
, const(void)[] string
, size_t len
, ubyte sz
, char postfix
= NoPostfix
) scope
1564 super(loc
, EXP
.string_
);
1565 this.string
= cast(char*)string
.ptr
; // note that this.string should be const
1568 this.postfix
= postfix
;
1571 static StringExp
create(const ref Loc loc
, const(char)* s
)
1573 return new StringExp(loc
, s
.toDString());
1576 static StringExp
create(const ref Loc loc
, const(void)* string
, size_t len
)
1578 return new StringExp(loc
, string
[0 .. len
]);
1581 override bool equals(const RootObject o
) const
1583 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
1584 if (auto e
= o
.isExpression())
1586 if (auto se
= e
.isStringExp())
1588 return compare(se
) == 0;
1594 /**********************************
1595 * Return the number of code units the string would be if it were re-encoded
1598 * tynto = code unit type of the target encoding
1600 * number of code units
1602 size_t
numberOfCodeUnits(int tynto
= 0) const
1608 case Tchar
: encSize
= 1; break;
1609 case Twchar
: encSize
= 2; break;
1610 case Tdchar
: encSize
= 4; break;
1623 for (size_t u
= 0; u
< len
;)
1625 if (const s
= utf_decodeChar(string
[0 .. len
], u
, c
))
1627 error(loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1630 result
+= utf_codeLength(encSize
, c
);
1635 for (size_t u
= 0; u
< len
;)
1637 if (const s
= utf_decodeWchar(wstring
[0 .. len
], u
, c
))
1639 error(loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1642 result
+= utf_codeLength(encSize
, c
);
1647 foreach (u
; 0 .. len
)
1649 result
+= utf_codeLength(encSize
, dstring
[u
]);
1659 /**********************************************
1660 * Write the contents of the string to dest.
1661 * Use numberOfCodeUnits() to determine size of result.
1663 * dest = destination
1664 * tyto = encoding type of the result
1665 * zero = add terminating 0
1667 void writeTo(void* dest
, bool zero
, int tyto
= 0) const
1672 case 0: encSize
= sz
; break;
1673 case Tchar
: encSize
= 1; break;
1674 case Twchar
: encSize
= 2; break;
1675 case Tdchar
: encSize
= 4; break;
1681 memcpy(dest
, string
, len
* sz
);
1683 memset(dest
+ len
* sz
, 0, sz
);
1689 /*********************************************
1690 * Get the code unit at index i
1694 * code unit at index i
1696 dchar getCodeUnit(size_t i
) const pure
1710 /*********************************************
1711 * Set the code unit at index i to c
1714 * c = code unit to set it to
1716 extern (D
) void setCodeUnit(size_t i
, dchar c
)
1722 string
[i
] = cast(char)c
;
1725 wstring
[i
] = cast(wchar)c
;
1733 override StringExp
toStringExp()
1740 * Compare two `StringExp` by length, then value
1742 * The comparison is not the usual C-style comparison as seen with
1743 * `strcmp` or `memcmp`, but instead first compare based on the length.
1744 * This allows both faster lookup and sorting when comparing sparse data.
1746 * This ordering scheme is relied on by the string-switching feature.
1747 * Code in Druntime's `core.internal.switch_` relies on this ordering
1748 * when doing a binary search among case statements.
1750 * Both `StringExp` should be of the same encoding.
1753 * se2 = String expression to compare `this` to
1756 * `0` when `this` is equal to se2, a value greater than `0` if
1757 * `this` should be considered greater than `se2`,
1758 * and a value less than `0` if `this` is lesser than `se2`.
1760 int compare(const StringExp se2
) const nothrow pure @nogc
1762 //printf("StringExp::compare()\n");
1764 const len2
= se2
.len
;
1766 assert(this.sz
== se2
.sz
, "Comparing string expressions of different sizes");
1767 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
1773 return memcmp(string
, se2
.string
, len1
);
1777 wchar* s1
= cast(wchar*)string
;
1778 wchar* s2
= cast(wchar*)se2
.string
;
1779 foreach (u
; 0 .. len
)
1782 return s1
[u
] - s2
[u
];
1788 dchar* s1
= cast(dchar*)string
;
1789 dchar* s2
= cast(dchar*)se2
.string
;
1790 foreach (u
; 0 .. len
)
1793 return s1
[u
] - s2
[u
];
1801 return cast(int)(len1
- len2
);
1804 override Optional
!bool toBool()
1806 // Keep the old behaviour for this refactoring
1807 // Should probably match language spec instead and check for length
1808 return typeof(return)(true);
1811 override bool isLvalue()
1813 /* string literal is rvalue in default, but
1814 * conversion to reference of static array is only allowed.
1816 return (type
&& type
.toBasetype().ty
== Tsarray
);
1819 /********************************
1820 * Convert string contents to a 0 terminated string,
1821 * allocated by mem.xmalloc().
1823 extern (D
) const(char)[] toStringz() const
1825 auto nbytes
= len
* sz
;
1826 char* s
= cast(char*)mem
.xmalloc(nbytes
+ sz
);
1828 return s
[0 .. nbytes
];
1831 extern (D
) const(char)[] peekString() const
1834 return this.string
[0 .. len
];
1837 extern (D
) const(wchar)[] peekWstring() const
1840 return this.wstring
[0 .. len
];
1843 extern (D
) const(dchar)[] peekDstring() const
1846 return this.dstring
[0 .. len
];
1849 /*******************
1850 * Get a slice of the data.
1852 extern (D
) const(ubyte)[] peekData() const
1854 return cast(const(ubyte)[])this.string
[0 .. len
* sz
];
1857 /*******************
1858 * Borrow a slice of the data, so the caller can modify
1861 extern (D
) ubyte[] borrowData()
1863 return cast(ubyte[])this.string
[0 .. len
* sz
];
1866 /***********************
1867 * Set new string data.
1868 * `this` becomes the new owner of the data.
1870 extern (D
) void setData(void* s
, size_t len
, ubyte sz
)
1872 this.string
= cast(char*)s
;
1877 override void accept(Visitor v
)
1883 /***********************************************************
1884 * A sequence of expressions
1887 * alias AliasSeq(T...) = T;
1888 * alias Tup = AliasSeq!(3, int, "abc");
1891 extern (C
++) final class TupleExp
: Expression
1893 /* Tuple-field access may need to take out its side effect part.
1897 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
1898 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
1904 extern (D
) this(const ref Loc loc
, Expression e0
, Expressions
* exps
) @safe
1906 super(loc
, EXP
.tuple
);
1907 //printf("TupleExp(this = %p)\n", this);
1912 extern (D
) this(const ref Loc loc
, Expressions
* exps
) @safe
1914 super(loc
, EXP
.tuple
);
1915 //printf("TupleExp(this = %p)\n", this);
1919 extern (D
) this(const ref Loc loc
, TupleDeclaration tup
)
1921 super(loc
, EXP
.tuple
);
1922 this.exps
= new Expressions();
1924 this.exps
.reserve(tup
.objects
.length
);
1925 foreach (o
; *tup
.objects
)
1927 if (Dsymbol s
= getDsymbol(o
))
1929 /* If tuple element represents a symbol, translate to DsymbolExp
1930 * to supply implicit 'this' if needed later.
1932 Expression e
= new DsymbolExp(loc
, s
);
1935 else if (auto eo
= o
.isExpression())
1938 e
.loc
= loc
; // https://issues.dlang.org/show_bug.cgi?id=15669
1941 else if (auto t
= o
.isType())
1943 Expression e
= new TypeExp(loc
, t
);
1948 error(loc
, "`%s` is not an expression", o
.toChars());
1953 static TupleExp
create(const ref Loc loc
, Expressions
* exps
) @safe
1955 return new TupleExp(loc
, exps
);
1958 override TupleExp
syntaxCopy()
1960 return new TupleExp(loc
, e0 ? e0
.syntaxCopy() : null, arraySyntaxCopy(exps
));
1963 override bool equals(const RootObject o
) const
1967 if (auto e
= o
.isExpression())
1968 if (auto te
= e
.isTupleExp())
1970 if (exps
.length
!= te
.exps
.length
)
1972 if (e0
&& !e0
.equals(te
.e0
) ||
!e0
&& te
.e0
)
1974 foreach (i
, e1
; *exps
)
1976 auto e2
= (*te
.exps
)[i
];
1985 override void accept(Visitor v
)
1991 /***********************************************************
1992 * [ e1, e2, e3, ... ]
1994 * https://dlang.org/spec/expression.html#array_literals
1996 extern (C
++) final class ArrayLiteralExp
: Expression
1998 OwnedBy ownedByCtfe
= OwnedBy
.code
;
1999 bool onstack
= false;
2001 /** If !is null, elements[] can be sparse and basis is used for the
2002 * "default" element value. In other words, non-null elements[i] overrides
2003 * this 'basis' value.
2007 Expressions
* elements
;
2009 extern (D
) this(const ref Loc loc
, Type type
, Expressions
* elements
) @safe
2011 super(loc
, EXP
.arrayLiteral
);
2013 this.elements
= elements
;
2016 extern (D
) this(const ref Loc loc
, Type type
, Expression e
)
2018 super(loc
, EXP
.arrayLiteral
);
2020 elements
= new Expressions();
2024 extern (D
) this(const ref Loc loc
, Type type
, Expression basis
, Expressions
* elements
) @safe
2026 super(loc
, EXP
.arrayLiteral
);
2029 this.elements
= elements
;
2032 static ArrayLiteralExp
create(const ref Loc loc
, Expressions
* elements
) @safe
2034 return new ArrayLiteralExp(loc
, null, elements
);
2037 override ArrayLiteralExp
syntaxCopy()
2039 return new ArrayLiteralExp(loc
,
2041 basis ? basis
.syntaxCopy() : null,
2042 arraySyntaxCopy(elements
));
2045 override bool equals(const RootObject o
) const
2049 auto e
= o
.isExpression();
2052 if (auto ae
= e
.isArrayLiteralExp())
2054 if (elements
.length
!= ae
.elements
.length
)
2056 if (elements
.length
== 0 && !type
.equals(ae
.type
))
2061 foreach (i
, e1
; *elements
)
2063 auto e2
= (*ae
.elements
)[i
];
2064 auto e1x
= e1 ? e1
: basis
;
2065 auto e2x
= e2 ? e2
: ae
.basis
;
2067 if (e1x
!= e2x
&& (!e1x ||
!e2x ||
!e1x
.equals(e2x
)))
2075 Expression
getElement(size_t i
) // use opIndex instead
2080 extern (D
) Expression
opIndex(size_t i
)
2082 auto el
= (*elements
)[i
];
2083 return el ? el
: basis
;
2086 override Optional
!bool toBool()
2088 size_t dim
= elements ? elements
.length
: 0;
2089 return typeof(return)(dim
!= 0);
2092 override StringExp
toStringExp()
2094 TY telem
= type
.nextOf().toBasetype().ty
;
2095 if (telem
.isSomeChar ||
(telem
== Tvoid
&& (!elements || elements
.length
== 0)))
2098 if (telem
== Twchar
)
2100 else if (telem
== Tdchar
)
2106 foreach (i
; 0 .. elements
.length
)
2109 if (ch
.op
!= EXP
.int64
)
2112 buf
.writeByte(cast(uint)ch
.toInteger());
2114 buf
.writeword(cast(uint)ch
.toInteger());
2116 buf
.write4(cast(uint)ch
.toInteger());
2136 const size_t len
= buf
.length
/ sz
- 1;
2137 auto se
= new StringExp(loc
, buf
.extractSlice()[0 .. len
* sz
], len
, sz
, prefix
);
2145 override void accept(Visitor v
)
2151 /***********************************************************
2152 * [ key0 : value0, key1 : value1, ... ]
2154 * https://dlang.org/spec/expression.html#associative_array_literals
2156 extern (C
++) final class AssocArrayLiteralExp
: Expression
2158 OwnedBy ownedByCtfe
= OwnedBy
.code
;
2161 Expressions
* values
;
2162 /// Lower to core.internal.newaa for static initializaton
2163 Expression lowering
;
2165 extern (D
) this(const ref Loc loc
, Expressions
* keys
, Expressions
* values
) @safe
2167 super(loc
, EXP
.assocArrayLiteral
);
2168 assert(keys
.length
== values
.length
);
2170 this.values
= values
;
2173 override bool equals(const RootObject o
) const
2177 auto e
= o
.isExpression();
2180 if (auto ae
= e
.isAssocArrayLiteralExp())
2182 if (keys
.length
!= ae
.keys
.length
)
2185 foreach (i
, key
; *keys
)
2187 foreach (j
, akey
; *ae
.keys
)
2189 if (key
.equals(akey
))
2191 if (!(*values
)[i
].equals((*ae
.values
)[j
]))
2197 return count
== keys
.length
;
2202 override AssocArrayLiteralExp
syntaxCopy()
2204 return new AssocArrayLiteralExp(loc
, arraySyntaxCopy(keys
), arraySyntaxCopy(values
));
2207 override Optional
!bool toBool()
2209 size_t dim
= keys
.length
;
2210 return typeof(return)(dim
!= 0);
2213 override void accept(Visitor v
)
2219 enum stageScrub
= 0x1; /// scrubReturnValue is running
2220 enum stageSearchPointers
= 0x2; /// hasNonConstPointers is running
2221 enum stageOptimize
= 0x4; /// optimize is running
2222 enum stageApply
= 0x8; /// apply is running
2223 enum stageInlineScan
= 0x10; /// inlineScan is running
2224 enum stageToCBuffer
= 0x20; /// toCBuffer is running
2226 /***********************************************************
2227 * sd( e1, e2, e3, ... )
2229 extern (C
++) final class StructLiteralExp
: Expression
2231 StructDeclaration sd
; /// which aggregate this is for
2232 Expressions
* elements
; /// parallels sd.fields[] with null entries for fields to skip
2233 Type stype
; /// final type of result (can be different from sd's type)
2235 // `inlineCopy` is only used temporarily in the `inline.d` pass,
2236 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
2239 void* sym
; /// back end symbol to initialize with literal (used as a Symbol*)
2241 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
2242 StructLiteralExp inlinecopy
;
2245 /** pointer to the origin instance of the expression.
2246 * once a new expression is created, origin is set to 'this'.
2247 * anytime when an expression copy is created, 'origin' pointer is set to
2248 * 'origin' pointer value of the original expression.
2250 StructLiteralExp origin
;
2253 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
2254 * current stage and unmarks before return from this function.
2255 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
2256 * (with infinite recursion) of this expression.
2260 bool useStaticInit
; /// if this is true, use the StructDeclaration's init symbol
2261 bool isOriginal
= false; /// used when moving instances to indicate `this is this.origin`
2262 OwnedBy ownedByCtfe
= OwnedBy
.code
;
2264 extern (D
) this(const ref Loc loc
, StructDeclaration sd
, Expressions
* elements
, Type stype
= null) @safe
2266 super(loc
, EXP
.structLiteral
);
2269 elements
= new Expressions();
2270 this.elements
= elements
;
2273 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
2276 static StructLiteralExp
create(const ref Loc loc
, StructDeclaration sd
, void* elements
, Type stype
= null)
2278 return new StructLiteralExp(loc
, sd
, cast(Expressions
*)elements
, stype
);
2281 override bool equals(const RootObject o
) const
2285 auto e
= o
.isExpression();
2288 if (auto se
= e
.isStructLiteralExp())
2290 if (!type
.equals(se
.type
))
2292 if (elements
.length
!= se
.elements
.length
)
2294 foreach (i
, e1
; *elements
)
2296 auto e2
= (*se
.elements
)[i
];
2297 if (e1
!= e2
&& (!e1 ||
!e2 ||
!e1
.equals(e2
)))
2305 override StructLiteralExp
syntaxCopy()
2307 auto exp
= new StructLiteralExp(loc
, sd
, arraySyntaxCopy(elements
), type ? type
: stype
);
2312 /**************************************
2313 * Gets expression at offset of type.
2314 * Returns NULL if not found.
2316 extern (D
) Expression
getField(Type type
, uint offset
)
2318 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
2319 // /*toChars()*/"", type.toChars(), offset);
2320 Expression e
= null;
2321 int i
= getFieldIndex(type
, offset
);
2325 //printf("\ti = %d\n", i);
2326 if (i
>= sd
.nonHiddenFields())
2329 assert(i
< elements
.length
);
2333 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
2335 /* If type is a static array, and e is an initializer for that array,
2336 * then the field initializer should be an array literal of e.
2338 auto tsa
= type
.isTypeSArray();
2339 if (tsa
&& e
.type
.castMod(0) != type
.castMod(0))
2341 const length
= cast(size_t
)tsa
.dim
.toInteger();
2342 auto z
= new Expressions(length
);
2345 e
= new ArrayLiteralExp(loc
, type
, z
);
2352 if (useStaticInit
&& e
.type
.needsNested())
2353 if (auto se
= e
.isStructLiteralExp())
2355 se
.useStaticInit
= true;
2362 /************************************
2363 * Get index of field.
2364 * Returns -1 if not found.
2366 extern (D
) int getFieldIndex(Type type
, uint offset
)
2368 /* Find which field offset is by looking at the field offsets
2370 if (elements
.length
)
2372 const sz
= type
.size();
2373 if (sz
== SIZE_INVALID
)
2375 foreach (i
, v
; sd
.fields
)
2377 if (offset
== v
.offset
&& sz
== v
.type
.size())
2379 /* context fields might not be filled. */
2380 if (i
>= sd
.nonHiddenFields())
2382 if (auto e
= (*elements
)[i
])
2393 override void accept(Visitor v
)
2399 /***********************************************************
2401 * ( type-name ) { initializer-list }
2403 extern (C
++) final class CompoundLiteralExp
: Expression
2405 Initializer initializer
; /// initializer-list
2407 extern (D
) this(const ref Loc loc
, Type type_name
, Initializer initializer
) @safe
2409 super(loc
, EXP
.compoundLiteral
);
2410 super.type
= type_name
;
2411 this.initializer
= initializer
;
2412 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
2415 override void accept(Visitor v
)
2421 /***********************************************************
2422 * Mainly just a placeholder
2424 extern (C
++) final class TypeExp
: Expression
2426 bool parens
; // if this is a parenthesized expression
2428 extern (D
) this(const ref Loc loc
, Type type
) @safe
2430 super(loc
, EXP
.type
);
2431 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
2435 override TypeExp
syntaxCopy()
2437 return new TypeExp(loc
, type
.syntaxCopy());
2440 override bool checkType()
2442 error(loc
, "type `%s` is not an expression", toChars());
2446 override bool checkValue()
2448 error(loc
, "type `%s` has no value", toChars());
2452 override void accept(Visitor v
)
2458 /***********************************************************
2459 * Mainly just a placeholder of
2460 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
2462 * A template instance that requires IFTI:
2463 * foo!tiargs(fargs) // foo!tiargs
2464 * is left until CallExp::semantic() or resolveProperties()
2466 extern (C
++) final class ScopeExp
: Expression
2470 extern (D
) this(const ref Loc loc
, ScopeDsymbol sds
) @safe
2472 super(loc
, EXP
.scope_
);
2473 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
2474 //static int count; if (++count == 38) *(char*)0=0;
2476 assert(!sds
.isTemplateDeclaration()); // instead, you should use TemplateExp
2479 override ScopeExp
syntaxCopy()
2481 return new ScopeExp(loc
, sds
.syntaxCopy(null));
2484 override bool checkType()
2486 if (sds
.isPackage())
2488 error(loc
, "%s `%s` has no type", sds
.kind(), sds
.toChars());
2491 if (auto ti
= sds
.isTemplateInstance())
2493 //assert(ti.needsTypeInference(sc));
2495 ti
.semantictiargsdone
&&
2496 ti
.semanticRun
== PASS
.initial
)
2498 error(loc
, "partial %s `%s` has no type", sds
.kind(), toChars());
2505 override bool checkValue()
2507 error(loc
, "%s `%s` has no value", sds
.kind(), sds
.toChars());
2511 override void accept(Visitor v
)
2517 /***********************************************************
2518 * Mainly just a placeholder
2520 extern (C
++) final class TemplateExp
: Expression
2522 TemplateDeclaration td
;
2525 extern (D
) this(const ref Loc loc
, TemplateDeclaration td
, FuncDeclaration fd
= null) @safe
2527 super(loc
, EXP
.template_
);
2528 //printf("TemplateExp(): %s\n", td.toChars());
2533 override bool isLvalue()
2538 override bool checkType()
2540 error(loc
, "%s `%s` has no type", td
.kind(), toChars());
2544 override bool checkValue()
2546 error(loc
, "%s `%s` has no value", td
.kind(), toChars());
2550 override void accept(Visitor v
)
2556 /***********************************************************
2557 * newtype(arguments)
2559 extern (C
++) final class NewExp
: Expression
2561 Expression thisexp
; // if !=null, 'this' for class being allocated
2563 Expressions
* arguments
; // Array of Expression's
2564 Identifiers
* names
; // Array of names corresponding to expressions
2566 Expression argprefix
; // expression to be evaluated just before arguments[]
2567 CtorDeclaration member
; // constructor function
2568 bool onstack
; // allocate on stack
2569 bool thrownew
; // this NewExp is the expression of a ThrowStatement
2571 Expression lowering
; // lowered druntime hook: `_d_new{class,itemT}`
2573 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
2574 /// The fields are still separate for backwards compatibility
2575 extern (D
) ArgumentList
argumentList() { return ArgumentList(arguments
, names
); }
2577 extern (D
) this(const ref Loc loc
, Expression thisexp
, Type newtype
, Expressions
* arguments
, Identifiers
* names
= null) @safe
2579 super(loc
, EXP
.new_
);
2580 this.thisexp
= thisexp
;
2581 this.newtype
= newtype
;
2582 this.arguments
= arguments
;
2586 static NewExp
create(const ref Loc loc
, Expression thisexp
, Type newtype
, Expressions
* arguments
) @safe
2588 return new NewExp(loc
, thisexp
, newtype
, arguments
);
2591 override NewExp
syntaxCopy()
2593 return new NewExp(loc
,
2594 thisexp ? thisexp
.syntaxCopy() : null,
2595 newtype
.syntaxCopy(),
2596 arraySyntaxCopy(arguments
),
2597 names ? names
.copy() : null);
2600 override void accept(Visitor v
)
2606 /***********************************************************
2607 * class baseclasses { } (arguments)
2609 extern (C
++) final class NewAnonClassExp
: Expression
2611 Expression thisexp
; // if !=null, 'this' for class being allocated
2612 ClassDeclaration cd
; // class being instantiated
2613 Expressions
* arguments
; // Array of Expression's to call class constructor
2615 extern (D
) this(const ref Loc loc
, Expression thisexp
, ClassDeclaration cd
, Expressions
* arguments
) @safe
2617 super(loc
, EXP
.newAnonymousClass
);
2618 this.thisexp
= thisexp
;
2620 this.arguments
= arguments
;
2623 override NewAnonClassExp
syntaxCopy()
2625 return new NewAnonClassExp(loc
, thisexp ? thisexp
.syntaxCopy() : null, cd
.syntaxCopy(null), arraySyntaxCopy(arguments
));
2628 override void accept(Visitor v
)
2634 /***********************************************************
2636 extern (C
++) class SymbolExp
: Expression
2639 Dsymbol originalScope
; // original scope before inlining
2642 extern (D
) this(const ref Loc loc
, EXP op
, Declaration var
, bool hasOverloads
) @safe
2647 this.hasOverloads
= hasOverloads
;
2650 override void accept(Visitor v
)
2656 /***********************************************************
2657 * Offset from symbol
2659 extern (C
++) final class SymOffExp
: SymbolExp
2663 extern (D
) this(const ref Loc loc
, Declaration var
, dinteger_t offset
, bool hasOverloads
= true)
2665 if (auto v
= var
.isVarDeclaration())
2667 // FIXME: This error report will never be handled anyone.
2668 // It should be done before the SymOffExp construction.
2671 auto t
= v
.isThis();
2673 .error(loc
, "taking the address of non-static variable `%s` requires an instance of `%s`", v
.toChars(), t
.toChars());
2675 hasOverloads
= false;
2677 super(loc
, EXP
.symbolOffset
, var
, hasOverloads
);
2678 this.offset
= offset
;
2681 override Optional
!bool toBool()
2683 return typeof(return)(true);
2686 override void accept(Visitor v
)
2692 /***********************************************************
2695 extern (C
++) final class VarExp
: SymbolExp
2697 bool delegateWasExtracted
;
2698 extern (D
) this(const ref Loc loc
, Declaration var
, bool hasOverloads
= true) @safe
2700 if (var
.isVarDeclaration())
2701 hasOverloads
= false;
2703 super(loc
, EXP
.variable
, var
, hasOverloads
);
2704 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
2705 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
2706 this.type
= var
.type
;
2709 static VarExp
create(const ref Loc loc
, Declaration var
, bool hasOverloads
= true) @safe
2711 return new VarExp(loc
, var
, hasOverloads
);
2714 override bool equals(const RootObject o
) const
2718 if (auto ne
= o
.isExpression().isVarExp())
2720 if (type
.toHeadMutable().equals(ne
.type
.toHeadMutable()) && var
== ne
.var
)
2728 override bool isLvalue()
2730 if (var
.storage_class
& (STC
.lazy_ | STC
.rvalue | STC
.manifest
))
2735 override void accept(Visitor v
)
2741 /***********************************************************
2744 extern (C
++) final class OverExp
: Expression
2748 extern (D
) this(const ref Loc loc
, OverloadSet s
)
2750 super(loc
, EXP
.overloadSet
);
2751 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
2756 override bool isLvalue()
2761 override void accept(Visitor v
)
2767 /***********************************************************
2768 * Function/Delegate literal
2771 extern (C
++) final class FuncExp
: Expression
2773 FuncLiteralDeclaration fd
;
2774 TemplateDeclaration td
;
2775 TOK tok
; // TOK.reserved, TOK.delegate_, TOK.function_
2777 extern (D
) this(const ref Loc loc
, Dsymbol s
)
2779 super(loc
, EXP
.function_
);
2780 this.td
= s
.isTemplateDeclaration();
2781 this.fd
= s
.isFuncLiteralDeclaration();
2785 assert(td
.members
&& td
.members
.length
== 1);
2786 fd
= (*td
.members
)[0].isFuncLiteralDeclaration();
2788 tok
= fd
.tok
; // save original kind of function/delegate/(infer)
2792 override bool equals(const RootObject o
) const
2796 auto e
= o
.isExpression();
2799 if (auto fe
= e
.isFuncExp())
2806 override FuncExp
syntaxCopy()
2809 return new FuncExp(loc
, td
.syntaxCopy(null));
2810 else if (fd
.semanticRun
== PASS
.initial
)
2811 return new FuncExp(loc
, fd
.syntaxCopy(null));
2812 else // https://issues.dlang.org/show_bug.cgi?id=13481
2813 // Prevent multiple semantic analysis of lambda body.
2814 return new FuncExp(loc
, fd
);
2817 override const(char)* toChars() const
2819 return fd
.toChars();
2822 override bool checkType()
2826 error(loc
, "template lambda has no type");
2832 override bool checkValue()
2836 error(loc
, "template lambda has no value");
2842 override void accept(Visitor v
)
2848 /***********************************************************
2849 * Declaration of a symbol
2851 * D grammar allows declarations only as statements. However in AST representation
2852 * it can be part of any expression. This is used, for example, during internal
2853 * syntax re-writes to inject hidden symbols.
2855 extern (C
++) final class DeclarationExp
: Expression
2857 Dsymbol declaration
;
2859 extern (D
) this(const ref Loc loc
, Dsymbol declaration
) @safe
2861 super(loc
, EXP
.declaration
);
2862 this.declaration
= declaration
;
2865 override DeclarationExp
syntaxCopy()
2867 return new DeclarationExp(loc
, declaration
.syntaxCopy(null));
2870 override bool hasCode()
2872 if (auto vd
= declaration
.isVarDeclaration())
2874 return !(vd
.storage_class
& (STC
.manifest | STC
.static_
));
2879 override void accept(Visitor v
)
2885 /***********************************************************
2888 extern (C
++) final class TypeidExp
: Expression
2892 extern (D
) this(const ref Loc loc
, RootObject o
) @safe
2894 super(loc
, EXP
.typeid_
);
2898 override TypeidExp
syntaxCopy()
2900 return new TypeidExp(loc
, objectSyntaxCopy(obj
));
2903 override void accept(Visitor v
)
2909 /***********************************************************
2910 * __traits(identifier, args...)
2912 extern (C
++) final class TraitsExp
: Expression
2917 extern (D
) this(const ref Loc loc
, Identifier ident
, Objects
* args
) @safe
2919 super(loc
, EXP
.traits
);
2924 override TraitsExp
syntaxCopy()
2926 return new TraitsExp(loc
, ident
, TemplateInstance
.arraySyntaxCopy(args
));
2929 override void accept(Visitor v
)
2935 /***********************************************************
2936 * Generates a halt instruction
2938 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
2940 extern (C
++) final class HaltExp
: Expression
2942 extern (D
) this(const ref Loc loc
) @safe
2944 super(loc
, EXP
.halt
);
2947 override void accept(Visitor v
)
2953 /***********************************************************
2954 * is(targ id tok tspec)
2955 * is(targ id == tok2)
2957 extern (C
++) final class IsExp
: Expression
2960 Identifier id
; // can be null
2961 Type tspec
; // can be null
2962 TemplateParameters
* parameters
;
2963 TOK tok
; // ':' or '=='
2964 TOK tok2
; // 'struct', 'union', etc.
2966 extern (D
) this(const ref Loc loc
, Type targ
, Identifier id
, TOK tok
, Type tspec
, TOK tok2
, TemplateParameters
* parameters
) scope @safe
2968 super(loc
, EXP
.is_
);
2974 this.parameters
= parameters
;
2977 override IsExp
syntaxCopy()
2979 // This section is identical to that in TemplateDeclaration::syntaxCopy()
2980 TemplateParameters
* p
= null;
2983 p
= new TemplateParameters(parameters
.length
);
2984 foreach (i
, el
; *parameters
)
2985 (*p
)[i
] = el
.syntaxCopy();
2987 return new IsExp(loc
, targ
.syntaxCopy(), id
, tok
, tspec ? tspec
.syntaxCopy() : null, tok2
, p
);
2990 override void accept(Visitor v
)
2996 /***********************************************************
2997 * Base class for unary operators
2999 * https://dlang.org/spec/expression.html#unary-expression
3001 extern (C
++) abstract class UnaExp
: Expression
3005 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
) scope @safe
3011 override UnaExp
syntaxCopy()
3013 UnaExp e
= cast(UnaExp
)copy();
3015 e
.e1
= e
.e1
.syntaxCopy();
3019 /********************************
3020 * The type for a unary expression is incompatible.
3021 * Print error message.
3025 extern (D
) final Expression
incompatibleTypes()
3027 if (e1
.type
.toBasetype() == Type
.terror
)
3030 if (e1
.op
== EXP
.type
)
3032 error(loc
, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op
).ptr
, e1
.toChars(), EXPtoString(op
).ptr
);
3036 error(loc
, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op
).ptr
, e1
.toChars(), e1
.type
.toChars());
3038 return ErrorExp
.get();
3041 /*********************
3042 * Mark the operand as will never be dereferenced,
3043 * which is useful info for @safe checks.
3044 * Do before semantic() on operands rewrites them.
3046 final void setNoderefOperand()
3048 if (auto edi
= e1
.isDotIdExp())
3053 override void accept(Visitor v
)
3059 /***********************************************************
3060 * Base class for binary operators
3062 extern (C
++) abstract class BinExp
: Expression
3066 Type att1
; // Save alias this type to detect recursion
3067 Type att2
; // Save alias this type to detect recursion
3069 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) scope @safe
3076 override BinExp
syntaxCopy()
3078 BinExp e
= cast(BinExp
)copy();
3080 e
.e1
= e
.e1
.syntaxCopy();
3081 e
.e2
= e
.e2
.syntaxCopy();
3085 /********************************
3086 * The types for a binary expression are incompatible.
3087 * Print error message.
3091 extern (D
) final Expression
incompatibleTypes()
3093 if (e1
.type
.toBasetype() == Type
.terror
)
3095 if (e2
.type
.toBasetype() == Type
.terror
)
3098 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
3099 const(char)* thisOp
= (op
== EXP
.question
) ?
":" : EXPtoString(op
).ptr
;
3100 if (e1
.op
== EXP
.type || e2
.op
== EXP
.type
)
3102 error(loc
, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
3103 e1
.toChars(), thisOp
, e2
.toChars(), EXPtoString(op
).ptr
);
3105 else if (e1
.type
.equals(e2
.type
))
3107 error(loc
, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
3108 e1
.toChars(), thisOp
, e2
.toChars(), e1
.type
.toChars());
3112 auto ts
= toAutoQualChars(e1
.type
, e2
.type
);
3113 error(loc
, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
3114 e1
.toChars(), thisOp
, e2
.toChars(), ts
[0], ts
[1]);
3116 return ErrorExp
.get();
3119 extern (D
) final bool checkIntegralBin()
3121 bool r1
= e1
.checkIntegral();
3122 bool r2
= e2
.checkIntegral();
3126 extern (D
) final bool checkArithmeticBin()
3128 bool r1
= e1
.checkArithmetic(this.op
);
3129 bool r2
= e2
.checkArithmetic(this.op
);
3133 /*********************
3134 * Mark the operands as will never be dereferenced,
3135 * which is useful info for @safe checks.
3136 * Do before semantic() on operands rewrites them.
3138 final void setNoderefOperands()
3140 if (auto edi
= e1
.isDotIdExp())
3142 if (auto edi
= e2
.isDotIdExp())
3147 override void accept(Visitor v
)
3153 /***********************************************************
3154 * Binary operator assignment, `+=` `-=` `*=` etc.
3156 extern (C
++) class BinAssignExp
: BinExp
3158 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) scope @safe
3160 super(loc
, op
, e1
, e2
);
3163 override final bool isLvalue()
3168 override void accept(Visitor v
)
3174 /***********************************************************
3175 * A string mixin, `mixin("x")`
3177 * https://dlang.org/spec/expression.html#mixin_expressions
3179 extern (C
++) final class MixinExp
: Expression
3183 extern (D
) this(const ref Loc loc
, Expressions
* exps
) @safe
3185 super(loc
, EXP
.mixin_
);
3189 override MixinExp
syntaxCopy()
3191 return new MixinExp(loc
, arraySyntaxCopy(exps
));
3194 override bool equals(const RootObject o
) const
3198 auto e
= o
.isExpression();
3201 if (auto ce
= e
.isMixinExp())
3203 if (exps
.length
!= ce
.exps
.length
)
3205 foreach (i
, e1
; *exps
)
3207 auto e2
= (*ce
.exps
)[i
];
3208 if (e1
!= e2
&& (!e1 ||
!e2 ||
!e1
.equals(e2
)))
3216 override void accept(Visitor v
)
3222 /***********************************************************
3223 * An import expression, `import("file.txt")`
3225 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
3227 * https://dlang.org/spec/expression.html#import_expressions
3229 extern (C
++) final class ImportExp
: UnaExp
3231 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3233 super(loc
, EXP
.import_
, e
);
3236 override void accept(Visitor v
)
3242 /***********************************************************
3243 * An assert expression, `assert(x == y)`
3245 * https://dlang.org/spec/expression.html#assert_expressions
3247 extern (C
++) final class AssertExp
: UnaExp
3251 extern (D
) this(const ref Loc loc
, Expression e
, Expression msg
= null) @safe
3253 super(loc
, EXP
.assert_
, e
);
3257 override AssertExp
syntaxCopy()
3259 return new AssertExp(loc
, e1
.syntaxCopy(), msg ? msg
.syntaxCopy() : null);
3262 override void accept(Visitor v
)
3268 /***********************************************************
3269 * `throw <e1>` as proposed by DIP 1034.
3271 * Replacement for the deprecated `ThrowStatement` that can be nested
3272 * in other expression.
3274 extern (C
++) final class ThrowExp
: UnaExp
3276 extern (D
) this(const ref Loc loc
, Expression e
)
3278 super(loc
, EXP
.throw_
, e
);
3279 this.type
= Type
.tnoreturn
;
3282 override ThrowExp
syntaxCopy()
3284 return new ThrowExp(loc
, e1
.syntaxCopy());
3287 override void accept(Visitor v
)
3293 /***********************************************************
3295 extern (C
++) final class DotIdExp
: UnaExp
3298 bool noderef
; // true if the result of the expression will never be dereferenced
3299 bool wantsym
; // do not replace Symbol with its initializer during semantic()
3300 bool arrow
; // ImportC: if -> instead of .
3302 extern (D
) this(const ref Loc loc
, Expression e
, Identifier ident
) @safe
3304 super(loc
, EXP
.dotIdentifier
, e
);
3308 static DotIdExp
create(const ref Loc loc
, Expression e
, Identifier ident
) @safe
3310 return new DotIdExp(loc
, e
, ident
);
3313 override void accept(Visitor v
)
3319 /***********************************************************
3320 * Mainly just a placeholder
3322 extern (C
++) final class DotTemplateExp
: UnaExp
3324 TemplateDeclaration td
;
3326 extern (D
) this(const ref Loc loc
, Expression e
, TemplateDeclaration td
) @safe
3328 super(loc
, EXP
.dotTemplateDeclaration
, e
);
3332 override bool checkType()
3334 error(loc
, "%s `%s` has no type", td
.kind(), toChars());
3338 override bool checkValue()
3340 error(loc
, "%s `%s` has no value", td
.kind(), toChars());
3344 override void accept(Visitor v
)
3350 /***********************************************************
3352 extern (C
++) final class DotVarExp
: UnaExp
3357 extern (D
) this(const ref Loc loc
, Expression e
, Declaration var
, bool hasOverloads
= true) @safe
3359 if (var
.isVarDeclaration())
3360 hasOverloads
= false;
3362 super(loc
, EXP
.dotVariable
, e
);
3363 //printf("DotVarExp()\n");
3365 this.hasOverloads
= hasOverloads
;
3368 override bool isLvalue()
3370 if (e1
.op
!= EXP
.structLiteral
)
3372 auto vd
= var
.isVarDeclaration();
3373 return !(vd
&& vd
.isField());
3376 override void accept(Visitor v
)
3382 /***********************************************************
3385 extern (C
++) final class DotTemplateInstanceExp
: UnaExp
3387 TemplateInstance ti
;
3389 extern (D
) this(const ref Loc loc
, Expression e
, Identifier name
, Objects
* tiargs
)
3391 super(loc
, EXP
.dotTemplateInstance
, e
);
3392 //printf("DotTemplateInstanceExp()\n");
3393 this.ti
= new TemplateInstance(loc
, name
, tiargs
);
3396 extern (D
) this(const ref Loc loc
, Expression e
, TemplateInstance ti
) @safe
3398 super(loc
, EXP
.dotTemplateInstance
, e
);
3402 override DotTemplateInstanceExp
syntaxCopy()
3404 return new DotTemplateInstanceExp(loc
, e1
.syntaxCopy(), ti
.name
, TemplateInstance
.arraySyntaxCopy(ti
.tiargs
));
3407 override bool checkType()
3409 // Same logic as ScopeExp.checkType()
3411 ti
.semantictiargsdone
&&
3412 ti
.semanticRun
== PASS
.initial
)
3414 error(loc
, "partial %s `%s` has no type", ti
.kind(), toChars());
3420 override bool checkValue()
3423 ti
.semantictiargsdone
&&
3424 ti
.semanticRun
== PASS
.initial
)
3426 error(loc
, "partial %s `%s` has no value", ti
.kind(), toChars());
3428 error(loc
, "%s `%s` has no value", ti
.kind(), ti
.toChars());
3432 override void accept(Visitor v
)
3438 /***********************************************************
3440 extern (C
++) final class DelegateExp
: UnaExp
3442 FuncDeclaration func
;
3444 VarDeclaration vthis2
; // container for multi-context
3446 extern (D
) this(const ref Loc loc
, Expression e
, FuncDeclaration f
, bool hasOverloads
= true, VarDeclaration vthis2
= null) @safe
3448 super(loc
, EXP
.delegate_
, e
);
3450 this.hasOverloads
= hasOverloads
;
3451 this.vthis2
= vthis2
;
3454 override void accept(Visitor v
)
3460 /***********************************************************
3462 extern (C
++) final class DotTypeExp
: UnaExp
3464 Dsymbol sym
; // symbol that represents a type
3466 extern (D
) this(const ref Loc loc
, Expression e
, Dsymbol s
) @safe
3468 super(loc
, EXP
.dotType
, e
);
3472 override void accept(Visitor v
)
3479 * The arguments of a function call
3481 * Contains a list of expressions. If it is a named argument, the `names`
3482 * list has a non-null entry at the same index.
3486 Expressions
* arguments
; // function arguments
3487 Identifiers
* names
; // named argument identifiers
3489 size_t
length() const @nogc nothrow pure @safe { return arguments ? arguments
.length
: 0; }
3491 /// Returns: whether this argument list contains any named arguments
3492 bool hasNames() const @nogc nothrow pure @safe
3496 foreach (name
; *names
)
3504 /***********************************************************
3506 extern (C
++) final class CallExp
: UnaExp
3508 Expressions
* arguments
; // function arguments
3509 Identifiers
* names
; // named argument identifiers
3510 FuncDeclaration f
; // symbol to call
3511 bool directcall
; // true if a virtual call is devirtualized
3512 bool inDebugStatement
; /// true if this was in a debug statement
3513 bool ignoreAttributes
; /// don't enforce attributes (e.g. call @gc function in @nogc code)
3514 bool isUfcsRewrite
; /// the first argument was pushed in here by a UFCS rewrite
3515 VarDeclaration vthis2
; // container for multi-context
3517 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3518 /// The fields are still separate for backwards compatibility
3519 extern (D
) ArgumentList
argumentList() { return ArgumentList(arguments
, names
); }
3521 extern (D
) this(const ref Loc loc
, Expression e
, Expressions
* exps
, Identifiers
* names
= null) @safe
3523 super(loc
, EXP
.call, e
);
3524 this.arguments
= exps
;
3528 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3530 super(loc
, EXP
.call, e
);
3533 extern (D
) this(const ref Loc loc
, Expression e
, Expression earg1
)
3535 super(loc
, EXP
.call, e
);
3536 this.arguments
= new Expressions();
3538 this.arguments
.push(earg1
);
3541 extern (D
) this(const ref Loc loc
, Expression e
, Expression earg1
, Expression earg2
)
3543 super(loc
, EXP
.call, e
);
3544 auto arguments
= new Expressions(2);
3545 (*arguments
)[0] = earg1
;
3546 (*arguments
)[1] = earg2
;
3547 this.arguments
= arguments
;
3550 /***********************************************************
3551 * Instatiates a new function call expression
3554 * fd = the declaration of the function to call
3555 * earg1 = the function argument
3557 extern(D
) this(const ref Loc loc
, FuncDeclaration fd
, Expression earg1
)
3559 this(loc
, new VarExp(loc
, fd
, false), earg1
);
3563 static CallExp
create(const ref Loc loc
, Expression e
, Expressions
* exps
) @safe
3565 return new CallExp(loc
, e
, exps
);
3568 static CallExp
create(const ref Loc loc
, Expression e
) @safe
3570 return new CallExp(loc
, e
);
3573 static CallExp
create(const ref Loc loc
, Expression e
, Expression earg1
)
3575 return new CallExp(loc
, e
, earg1
);
3578 /***********************************************************
3579 * Creates a new function call expression
3582 * fd = the declaration of the function to call
3583 * earg1 = the function argument
3585 static CallExp
create(const ref Loc loc
, FuncDeclaration fd
, Expression earg1
)
3587 return new CallExp(loc
, fd
, earg1
);
3590 override CallExp
syntaxCopy()
3592 return new CallExp(loc
, e1
.syntaxCopy(), arraySyntaxCopy(arguments
), names ? names
.copy() : null);
3595 override bool isLvalue()
3597 Type tb
= e1
.type
.toBasetype();
3598 if (tb
.ty
== Tdelegate || tb
.ty
== Tpointer
)
3600 auto tf
= tb
.isTypeFunction();
3603 if (auto dve
= e1
.isDotVarExp())
3604 if (dve
.var
.isCtorDeclaration())
3606 return true; // function returns a reference
3611 override void accept(Visitor v
)
3618 * Get the called function type from a call expression
3620 * ce = function call expression. Must have had semantic analysis done.
3621 * Returns: called function type, or `null` if error / no semantic analysis done
3623 TypeFunction
calledFunctionType(CallExp ce
)
3625 Type t
= ce
.e1
.type
;
3629 if (auto tf
= t
.isTypeFunction())
3631 else if (auto td
= t
.isTypeDelegate())
3632 return td
.nextOf().isTypeFunction();
3637 FuncDeclaration
isFuncAddress(Expression e
, bool* hasOverloads
= null) @safe
3639 if (auto ae
= e
.isAddrExp())
3642 if (auto ve
= ae1
.isVarExp())
3645 *hasOverloads
= ve
.hasOverloads
;
3646 return ve
.var
.isFuncDeclaration();
3648 if (auto dve
= ae1
.isDotVarExp())
3651 *hasOverloads
= dve
.hasOverloads
;
3652 return dve
.var
.isFuncDeclaration();
3657 if (auto soe
= e
.isSymOffExp())
3660 *hasOverloads
= soe
.hasOverloads
;
3661 return soe
.var
.isFuncDeclaration();
3663 if (auto dge
= e
.isDelegateExp())
3666 *hasOverloads
= dge
.hasOverloads
;
3667 return dge
.func
.isFuncDeclaration();
3673 /***********************************************************
3674 * The 'address of' operator, `&p`
3676 extern (C
++) final class AddrExp
: UnaExp
3678 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3680 super(loc
, EXP
.address
, e
);
3683 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3689 override void accept(Visitor v
)
3695 /***********************************************************
3696 * The pointer dereference operator, `*p`
3698 extern (C
++) final class PtrExp
: UnaExp
3700 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3702 super(loc
, EXP
.star
, e
);
3704 // type = ((TypePointer *)e.type).next;
3707 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3709 super(loc
, EXP
.star
, e
);
3713 override bool isLvalue()
3718 override void accept(Visitor v
)
3724 /***********************************************************
3725 * The negation operator, `-x`
3727 extern (C
++) final class NegExp
: UnaExp
3729 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3731 super(loc
, EXP
.negate
, e
);
3734 override void accept(Visitor v
)
3740 /***********************************************************
3741 * The unary add operator, `+x`
3743 extern (C
++) final class UAddExp
: UnaExp
3745 extern (D
) this(const ref Loc loc
, Expression e
) scope @safe
3747 super(loc
, EXP
.uadd
, e
);
3750 override void accept(Visitor v
)
3756 /***********************************************************
3757 * The bitwise complement operator, `~x`
3759 extern (C
++) final class ComExp
: UnaExp
3761 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3763 super(loc
, EXP
.tilde
, e
);
3766 override void accept(Visitor v
)
3772 /***********************************************************
3773 * The logical not operator, `!x`
3775 extern (C
++) final class NotExp
: UnaExp
3777 extern (D
) this(const ref Loc loc
, Expression e
) @safe
3779 super(loc
, EXP
.not, e
);
3782 override void accept(Visitor v
)
3788 /***********************************************************
3789 * The delete operator, `delete x` (deprecated)
3791 * https://dlang.org/spec/expression.html#delete_expressions
3793 extern (C
++) final class DeleteExp
: UnaExp
3795 bool isRAII
; // true if called automatically as a result of scoped destruction
3797 extern (D
) this(const ref Loc loc
, Expression e
, bool isRAII
) @safe
3799 super(loc
, EXP
.delete_
, e
);
3800 this.isRAII
= isRAII
;
3803 override void accept(Visitor v
)
3809 /***********************************************************
3810 * The type cast operator, `cast(T) x`
3812 * It's possible to cast to one type while painting to another type
3814 * https://dlang.org/spec/expression.html#cast_expressions
3816 extern (C
++) final class CastExp
: UnaExp
3818 Type to
; // type to cast to
3819 ubyte mod
= cast(ubyte)~0; // MODxxxxx
3821 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3823 super(loc
, EXP
.cast_
, e
);
3827 /* For cast(const) and cast(immutable)
3829 extern (D
) this(const ref Loc loc
, Expression e
, ubyte mod
) @safe
3831 super(loc
, EXP
.cast_
, e
);
3835 override CastExp
syntaxCopy()
3837 return to ?
new CastExp(loc
, e1
.syntaxCopy(), to
.syntaxCopy()) : new CastExp(loc
, e1
.syntaxCopy(), mod
);
3840 override bool isLvalue()
3842 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
3845 return (to
.ty
== Tsarray
&& (e1
.type
.ty
== Tvector || e1
.type
.ty
== Tsarray
)) ||
3846 e1
.type
.mutableOf().unSharedOf().equals(to
.mutableOf().unSharedOf());
3849 override void accept(Visitor v
)
3855 /***********************************************************
3857 extern (C
++) final class VectorExp
: UnaExp
3859 TypeVector to
; // the target vector type before semantic()
3860 uint dim
= ~0; // number of elements in the vector
3861 OwnedBy ownedByCtfe
= OwnedBy
.code
;
3863 extern (D
) this(const ref Loc loc
, Expression e
, Type t
) @safe
3865 super(loc
, EXP
.vector
, e
);
3866 assert(t
.ty
== Tvector
);
3867 to
= cast(TypeVector
)t
;
3870 static VectorExp
create(const ref Loc loc
, Expression e
, Type t
) @safe
3872 return new VectorExp(loc
, e
, t
);
3875 override VectorExp
syntaxCopy()
3877 return new VectorExp(loc
, e1
.syntaxCopy(), to
.syntaxCopy());
3880 override void accept(Visitor v
)
3886 /***********************************************************
3887 * e1.array property for vectors.
3889 * https://dlang.org/spec/simd.html#properties
3891 extern (C
++) final class VectorArrayExp
: UnaExp
3893 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
3895 super(loc
, EXP
.vectorArray
, e1
);
3898 override bool isLvalue()
3900 return e1
.isLvalue();
3903 override void accept(Visitor v
)
3909 /***********************************************************
3912 * https://dlang.org/spec/expression.html#slice_expressions
3914 extern (C
++) final class SliceExp
: UnaExp
3916 Expression upr
; // null if implicit 0
3917 Expression lwr
; // null if implicit [length - 1]
3919 VarDeclaration lengthVar
;
3921 private extern(D
) static struct BitFields
3923 bool upperIsInBounds
; // true if upr <= e1.length
3924 bool lowerIsLessThanUpper
; // true if lwr <= upr
3925 bool arrayop
; // an array operation, rather than a slice
3927 import dmd
.common
.bitfields
: generateBitFields
;
3928 mixin(generateBitFields
!(BitFields
, ubyte));
3930 /************************************************************/
3931 extern (D
) this(const ref Loc loc
, Expression e1
, IntervalExp ie
) @safe
3933 super(loc
, EXP
.slice
, e1
);
3934 this.upr
= ie ? ie
.upr
: null;
3935 this.lwr
= ie ? ie
.lwr
: null;
3938 extern (D
) this(const ref Loc loc
, Expression e1
, Expression lwr
, Expression upr
) @safe
3940 super(loc
, EXP
.slice
, e1
);
3945 override SliceExp
syntaxCopy()
3947 auto se
= new SliceExp(loc
, e1
.syntaxCopy(), lwr ? lwr
.syntaxCopy() : null, upr ? upr
.syntaxCopy() : null);
3948 se
.lengthVar
= this.lengthVar
; // bug7871
3952 override bool isLvalue()
3954 /* slice expression is rvalue in default, but
3955 * conversion to reference of static array is only allowed.
3957 return (type
&& type
.toBasetype().ty
== Tsarray
);
3960 override Optional
!bool toBool()
3965 override void accept(Visitor v
)
3971 /***********************************************************
3972 * The `.length` property of an array
3974 extern (C
++) final class ArrayLengthExp
: UnaExp
3976 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
3978 super(loc
, EXP
.arrayLength
, e1
);
3981 override void accept(Visitor v
)
3987 /***********************************************************
3988 * e1 [ a0, a1, a2, a3 ,... ]
3990 * https://dlang.org/spec/expression.html#index_expressions
3992 extern (C
++) final class ArrayExp
: UnaExp
3994 Expressions
* arguments
; // Array of Expression's a0..an
3996 size_t currentDimension
; // for opDollar
3997 VarDeclaration lengthVar
;
3999 extern (D
) this(const ref Loc loc
, Expression e1
, Expression index
= null)
4001 super(loc
, EXP
.array
, e1
);
4002 arguments
= new Expressions();
4004 arguments
.push(index
);
4007 extern (D
) this(const ref Loc loc
, Expression e1
, Expressions
* args
) @safe
4009 super(loc
, EXP
.array
, e1
);
4013 override ArrayExp
syntaxCopy()
4015 auto ae
= new ArrayExp(loc
, e1
.syntaxCopy(), arraySyntaxCopy(arguments
));
4016 ae
.lengthVar
= this.lengthVar
; // bug7871
4020 override bool isLvalue()
4022 if (type
&& type
.toBasetype().ty
== Tvoid
)
4027 override void accept(Visitor v
)
4033 /***********************************************************
4035 extern (C
++) final class DotExp
: BinExp
4037 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4039 super(loc
, EXP
.dot
, e1
, e2
);
4042 override void accept(Visitor v
)
4048 /***********************************************************
4050 extern (C
++) final class CommaExp
: BinExp
4052 /// This is needed because AssignExp rewrites CommaExp, hence it needs
4053 /// to trigger the deprecation.
4054 const bool isGenerated
;
4056 /// Temporary variable to enable / disable deprecation of comma expression
4057 /// depending on the context.
4058 /// Since most constructor calls are rewritting, the only place where
4059 /// false will be passed will be from the parser.
4063 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
, bool generated
= true) @safe
4065 super(loc
, EXP
.comma
, e1
, e2
);
4066 allowCommaExp
= isGenerated
= generated
;
4069 override bool isLvalue()
4071 return e2
.isLvalue();
4074 override Optional
!bool toBool()
4079 override void accept(Visitor v
)
4085 * If the argument is a CommaExp, set a flag to prevent deprecation messages
4087 * It's impossible to know from CommaExp.semantic if the result will
4088 * be used, hence when there is a result (type != void), a deprecation
4089 * message is always emitted.
4090 * However, some construct can produce a result but won't use it
4091 * (ExpStatement and for loop increment). Those should call this function
4092 * to prevent unwanted deprecations to be emitted.
4095 * exp = An expression that discards its result.
4096 * If the argument is null or not a CommaExp, nothing happens.
4098 static void allow(Expression exp
) @safe
4101 if (auto ce
= exp
.isCommaExp())
4102 ce
.allowCommaExp
= true;
4106 /***********************************************************
4107 * Mainly just a placeholder
4109 extern (C
++) final class IntervalExp
: Expression
4114 extern (D
) this(const ref Loc loc
, Expression lwr
, Expression upr
) @safe
4116 super(loc
, EXP
.interval
);
4121 override Expression
syntaxCopy()
4123 return new IntervalExp(loc
, lwr
.syntaxCopy(), upr
.syntaxCopy());
4126 override void accept(Visitor v
)
4132 /***********************************************************
4133 * The `dg.ptr` property, pointing to the delegate's 'context'
4135 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
4137 extern (C
++) final class DelegatePtrExp
: UnaExp
4139 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
4141 super(loc
, EXP
.delegatePointer
, e1
);
4144 override bool isLvalue()
4146 return e1
.isLvalue();
4149 override void accept(Visitor v
)
4155 /***********************************************************
4156 * The `dg.funcptr` property, pointing to the delegate's function
4158 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
4160 extern (C
++) final class DelegateFuncptrExp
: UnaExp
4162 extern (D
) this(const ref Loc loc
, Expression e1
) @safe
4164 super(loc
, EXP
.delegateFunctionPointer
, e1
);
4167 override bool isLvalue()
4169 return e1
.isLvalue();
4172 override void accept(Visitor v
)
4178 /***********************************************************
4181 extern (C
++) final class IndexExp
: BinExp
4183 VarDeclaration lengthVar
;
4184 bool modifiable
= false; // assume it is an rvalue
4185 bool indexIsInBounds
; // true if 0 <= e2 && e2 <= e1.length - 1
4187 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4189 super(loc
, EXP
.index
, e1
, e2
);
4190 //printf("IndexExp::IndexExp('%s')\n", toChars());
4193 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
, bool indexIsInBounds
) @safe
4195 super(loc
, EXP
.index
, e1
, e2
);
4196 this.indexIsInBounds
= indexIsInBounds
;
4197 //printf("IndexExp::IndexExp('%s')\n", toChars());
4200 override IndexExp
syntaxCopy()
4202 auto ie
= new IndexExp(loc
, e1
.syntaxCopy(), e2
.syntaxCopy());
4203 ie
.lengthVar
= this.lengthVar
; // bug7871
4207 override bool isLvalue()
4209 if (e1
.op
== EXP
.assocArrayLiteral
)
4211 if (e1
.type
.ty
== Tsarray ||
4212 (e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
))
4214 return e1
.isLvalue();
4219 extern (D
) Expression
markSettingAAElem()
4221 if (e1
.type
.toBasetype().ty
== Taarray
)
4223 Type t2b
= e2
.type
.toBasetype();
4224 if (t2b
.ty
== Tarray
&& t2b
.nextOf().isMutable())
4226 error(loc
, "associative arrays can only be assigned values with immutable keys, not `%s`", e2
.type
.toChars());
4227 return ErrorExp
.get();
4231 if (auto ie
= e1
.isIndexExp())
4233 Expression ex
= ie
.markSettingAAElem();
4234 if (ex
.op
== EXP
.error
)
4242 override void accept(Visitor v
)
4248 /***********************************************************
4249 * The postfix increment/decrement operator, `i++` / `i--`
4251 extern (C
++) final class PostExp
: BinExp
4253 extern (D
) this(EXP op
, const ref Loc loc
, Expression e
)
4255 super(loc
, op
, e
, IntegerExp
.literal
!1);
4256 assert(op
== EXP
.minusMinus || op
== EXP
.plusPlus
);
4259 override void accept(Visitor v
)
4265 /***********************************************************
4266 * The prefix increment/decrement operator, `++i` / `--i`
4268 extern (C
++) final class PreExp
: UnaExp
4270 extern (D
) this(EXP op
, const ref Loc loc
, Expression e
) @safe
4273 assert(op
== EXP
.preMinusMinus || op
== EXP
.prePlusPlus
);
4276 override void accept(Visitor v
)
4284 none
= 0, // simple assignment
4285 blockAssign
= 1, // setting the contents of an array
4286 referenceInit
= 2, // setting the reference of STC.ref_ variable
4289 /***********************************************************
4290 * The assignment / initialization operator, `=`
4292 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
4294 extern (C
++) class AssignExp
: BinExp
4298 /************************************************************/
4299 /* op can be EXP.assign, EXP.construct, or EXP.blit */
4300 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4302 super(loc
, EXP
.assign
, e1
, e2
);
4305 this(const ref Loc loc
, EXP tok
, Expression e1
, Expression e2
) @safe
4307 super(loc
, tok
, e1
, e2
);
4310 override final bool isLvalue()
4312 // Array-op 'x[] = y[]' should make an rvalue.
4313 // Setting array length 'x.length = v' should make an rvalue.
4314 if (e1
.op
== EXP
.slice || e1
.op
== EXP
.arrayLength
)
4321 override void accept(Visitor v
)
4327 /***********************************************************
4328 * When an assignment expression is lowered to a druntime call
4329 * this class is used to store the lowering.
4330 * It essentially behaves the same as an AssignExp, but it is
4331 * used to not waste space for other AssignExp that are not
4332 * lowered to anything.
4334 extern (C
++) final class LoweredAssignExp
: AssignExp
4336 Expression lowering
;
4337 extern (D
) this(AssignExp exp
, Expression lowering
) @safe
4339 super(exp
.loc
, EXP
.loweredAssignExp
, exp
.e1
, exp
.e2
);
4340 this.lowering
= lowering
;
4343 override const(char)* toChars() const
4345 return lowering
.toChars();
4347 override void accept(Visitor v
)
4353 /***********************************************************
4355 extern (C
++) final class ConstructExp
: AssignExp
4357 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4359 super(loc
, EXP
.construct
, e1
, e2
);
4362 // Internal use only. If `v` is a reference variable, the assignment
4363 // will become a reference initialization automatically.
4364 extern (D
) this(const ref Loc loc
, VarDeclaration v
, Expression e2
) @safe
4366 auto ve
= new VarExp(loc
, v
);
4367 assert(v
.type
&& ve
.type
);
4369 super(loc
, EXP
.construct
, ve
, e2
);
4371 if (v
.isReference())
4372 memset
= MemorySet
.referenceInit
;
4375 override void accept(Visitor v
)
4381 /***********************************************************
4382 * A bit-for-bit copy from `e2` to `e1`
4384 extern (C
++) final class BlitExp
: AssignExp
4386 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4388 super(loc
, EXP
.blit
, e1
, e2
);
4391 // Internal use only. If `v` is a reference variable, the assinment
4392 // will become a reference rebinding automatically.
4393 extern (D
) this(const ref Loc loc
, VarDeclaration v
, Expression e2
) @safe
4395 auto ve
= new VarExp(loc
, v
);
4396 assert(v
.type
&& ve
.type
);
4398 super(loc
, EXP
.blit
, ve
, e2
);
4400 if (v
.isReference())
4401 memset
= MemorySet
.referenceInit
;
4404 override void accept(Visitor v
)
4410 /***********************************************************
4413 extern (C
++) final class AddAssignExp
: BinAssignExp
4415 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4417 super(loc
, EXP
.addAssign
, e1
, e2
);
4420 override void accept(Visitor v
)
4426 /***********************************************************
4429 extern (C
++) final class MinAssignExp
: BinAssignExp
4431 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4433 super(loc
, EXP
.minAssign
, e1
, e2
);
4436 override void accept(Visitor v
)
4442 /***********************************************************
4445 extern (C
++) final class MulAssignExp
: BinAssignExp
4447 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4449 super(loc
, EXP
.mulAssign
, e1
, e2
);
4452 override void accept(Visitor v
)
4458 /***********************************************************
4461 extern (C
++) final class DivAssignExp
: BinAssignExp
4463 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4465 super(loc
, EXP
.divAssign
, e1
, e2
);
4468 override void accept(Visitor v
)
4474 /***********************************************************
4477 extern (C
++) final class ModAssignExp
: BinAssignExp
4479 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4481 super(loc
, EXP
.modAssign
, e1
, e2
);
4484 override void accept(Visitor v
)
4490 /***********************************************************
4493 extern (C
++) final class AndAssignExp
: BinAssignExp
4495 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4497 super(loc
, EXP
.andAssign
, e1
, e2
);
4500 override void accept(Visitor v
)
4506 /***********************************************************
4509 extern (C
++) final class OrAssignExp
: BinAssignExp
4511 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4513 super(loc
, EXP
.orAssign
, e1
, e2
);
4516 override void accept(Visitor v
)
4522 /***********************************************************
4525 extern (C
++) final class XorAssignExp
: BinAssignExp
4527 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4529 super(loc
, EXP
.xorAssign
, e1
, e2
);
4532 override void accept(Visitor v
)
4538 /***********************************************************
4541 extern (C
++) final class PowAssignExp
: BinAssignExp
4543 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4545 super(loc
, EXP
.powAssign
, e1
, e2
);
4548 override void accept(Visitor v
)
4554 /***********************************************************
4557 extern (C
++) final class ShlAssignExp
: BinAssignExp
4559 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4561 super(loc
, EXP
.leftShiftAssign
, e1
, e2
);
4564 override void accept(Visitor v
)
4570 /***********************************************************
4573 extern (C
++) final class ShrAssignExp
: BinAssignExp
4575 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4577 super(loc
, EXP
.rightShiftAssign
, e1
, e2
);
4580 override void accept(Visitor v
)
4586 /***********************************************************
4589 extern (C
++) final class UshrAssignExp
: BinAssignExp
4591 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4593 super(loc
, EXP
.unsignedRightShiftAssign
, e1
, e2
);
4596 override void accept(Visitor v
)
4602 /***********************************************************
4603 * The `~=` operator.
4605 * It can have one of the following operators:
4607 * EXP.concatenateAssign - appending T[] to T[]
4608 * EXP.concatenateElemAssign - appending T to T[]
4609 * EXP.concatenateDcharAssign - appending dchar to T[]
4611 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
4612 * of the three it will be set to.
4614 extern (C
++) class CatAssignExp
: BinAssignExp
4616 Expression lowering
; // lowered druntime hook `_d_arrayappend{cTX,T}`
4618 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
)
4620 super(loc
, EXP
.concatenateAssign
, e1
, e2
);
4623 extern (D
) this(const ref Loc loc
, EXP tok
, Expression e1
, Expression e2
) @safe
4625 super(loc
, tok
, e1
, e2
);
4628 override void accept(Visitor v
)
4634 /***********************************************************
4635 * The `~=` operator when appending a single element
4637 extern (C
++) final class CatElemAssignExp
: CatAssignExp
4639 extern (D
) this(const ref Loc loc
, Type type
, Expression e1
, Expression e2
) @safe
4641 super(loc
, EXP
.concatenateElemAssign
, e1
, e2
);
4645 override void accept(Visitor v
)
4651 /***********************************************************
4652 * The `~=` operator when appending a single `dchar`
4654 extern (C
++) final class CatDcharAssignExp
: CatAssignExp
4656 extern (D
) this(const ref Loc loc
, Type type
, Expression e1
, Expression e2
) @safe
4658 super(loc
, EXP
.concatenateDcharAssign
, e1
, e2
);
4662 override void accept(Visitor v
)
4668 /***********************************************************
4669 * The addition operator, `x + y`
4671 * https://dlang.org/spec/expression.html#add_expressions
4673 extern (C
++) final class AddExp
: BinExp
4675 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4677 super(loc
, EXP
.add, e1
, e2
);
4680 override void accept(Visitor v
)
4686 /***********************************************************
4687 * The minus operator, `x - y`
4689 * https://dlang.org/spec/expression.html#add_expressions
4691 extern (C
++) final class MinExp
: BinExp
4693 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4695 super(loc
, EXP
.min
, e1
, e2
);
4698 override void accept(Visitor v
)
4704 /***********************************************************
4705 * The concatenation operator, `x ~ y`
4707 * https://dlang.org/spec/expression.html#cat_expressions
4709 extern (C
++) final class CatExp
: BinExp
4711 Expression lowering
; // call to druntime hook `_d_arraycatnTX`
4713 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) scope @safe
4715 super(loc
, EXP
.concatenate
, e1
, e2
);
4718 override void accept(Visitor v
)
4724 /***********************************************************
4725 * The multiplication operator, `x * y`
4727 * https://dlang.org/spec/expression.html#mul_expressions
4729 extern (C
++) final class MulExp
: BinExp
4731 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4733 super(loc
, EXP
.mul, e1
, e2
);
4736 override void accept(Visitor v
)
4742 /***********************************************************
4743 * The division operator, `x / y`
4745 * https://dlang.org/spec/expression.html#mul_expressions
4747 extern (C
++) final class DivExp
: BinExp
4749 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4751 super(loc
, EXP
.div, e1
, e2
);
4754 override void accept(Visitor v
)
4760 /***********************************************************
4761 * The modulo operator, `x % y`
4763 * https://dlang.org/spec/expression.html#mul_expressions
4765 extern (C
++) final class ModExp
: BinExp
4767 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4769 super(loc
, EXP
.mod
, e1
, e2
);
4772 override void accept(Visitor v
)
4778 /***********************************************************
4779 * The 'power' operator, `x ^^ y`
4781 * https://dlang.org/spec/expression.html#pow_expressions
4783 extern (C
++) final class PowExp
: BinExp
4785 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4787 super(loc
, EXP
.pow
, e1
, e2
);
4790 override void accept(Visitor v
)
4796 /***********************************************************
4797 * The 'shift left' operator, `x << y`
4799 * https://dlang.org/spec/expression.html#shift_expressions
4801 extern (C
++) final class ShlExp
: BinExp
4803 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4805 super(loc
, EXP
.leftShift
, e1
, e2
);
4808 override void accept(Visitor v
)
4814 /***********************************************************
4815 * The 'shift right' operator, `x >> y`
4817 * https://dlang.org/spec/expression.html#shift_expressions
4819 extern (C
++) final class ShrExp
: BinExp
4821 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4823 super(loc
, EXP
.rightShift
, e1
, e2
);
4826 override void accept(Visitor v
)
4832 /***********************************************************
4833 * The 'unsigned shift right' operator, `x >>> y`
4835 * https://dlang.org/spec/expression.html#shift_expressions
4837 extern (C
++) final class UshrExp
: BinExp
4839 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4841 super(loc
, EXP
.unsignedRightShift
, e1
, e2
);
4844 override void accept(Visitor v
)
4850 /***********************************************************
4851 * The bitwise 'and' operator, `x & y`
4853 * https://dlang.org/spec/expression.html#and_expressions
4855 extern (C
++) final class AndExp
: BinExp
4857 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4859 super(loc
, EXP
.and, e1
, e2
);
4862 override void accept(Visitor v
)
4868 /***********************************************************
4869 * The bitwise 'or' operator, `x | y`
4871 * https://dlang.org/spec/expression.html#or_expressions
4873 extern (C
++) final class OrExp
: BinExp
4875 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4877 super(loc
, EXP
.or, e1
, e2
);
4880 override void accept(Visitor v
)
4886 /***********************************************************
4887 * The bitwise 'xor' operator, `x ^ y`
4889 * https://dlang.org/spec/expression.html#xor_expressions
4891 extern (C
++) final class XorExp
: BinExp
4893 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4895 super(loc
, EXP
.xor, e1
, e2
);
4898 override void accept(Visitor v
)
4904 /***********************************************************
4905 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
4907 * https://dlang.org/spec/expression.html#andand_expressions
4908 * https://dlang.org/spec/expression.html#oror_expressions
4910 extern (C
++) final class LogicalExp
: BinExp
4912 extern (D
) this(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) @safe
4914 super(loc
, op
, e1
, e2
);
4915 assert(op
== EXP
.andAnd || op
== EXP
.orOr
);
4918 override void accept(Visitor v
)
4924 /***********************************************************
4925 * A comparison operator, `<` `<=` `>` `>=`
4928 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
4930 * https://dlang.org/spec/expression.html#relation_expressions
4932 extern (C
++) final class CmpExp
: BinExp
4934 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
4936 super(loc
, op
, e1
, e2
);
4937 assert(op
== EXP
.lessThan || op
== EXP
.lessOrEqual || op
== EXP
.greaterThan || op
== EXP
.greaterOrEqual
);
4940 override void accept(Visitor v
)
4946 /***********************************************************
4947 * The `in` operator, `"a" in ["a": 1]`
4949 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
4951 * https://dlang.org/spec/expression.html#in_expressions
4953 extern (C
++) final class InExp
: BinExp
4955 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
) @safe
4957 super(loc
, EXP
.in_
, e1
, e2
);
4960 override void accept(Visitor v
)
4966 /***********************************************************
4967 * Associative array removal, `aa.remove(arg)`
4969 * This deletes the key e1 from the associative array e2
4971 extern (C
++) final class RemoveExp
: BinExp
4973 extern (D
) this(const ref Loc loc
, Expression e1
, Expression e2
)
4975 super(loc
, EXP
.remove
, e1
, e2
);
4979 override void accept(Visitor v
)
4985 /***********************************************************
4988 * EXP.equal and EXP.notEqual
4990 * https://dlang.org/spec/expression.html#equality_expressions
4992 extern (C
++) final class EqualExp
: BinExp
4994 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
4996 super(loc
, op
, e1
, e2
);
4997 assert(op
== EXP
.equal || op
== EXP
.notEqual
);
5000 override void accept(Visitor v
)
5006 /***********************************************************
5009 * EXP.identity and EXP.notIdentity
5011 * https://dlang.org/spec/expression.html#identity_expressions
5013 extern (C
++) final class IdentityExp
: BinExp
5015 extern (D
) this(EXP op
, const ref Loc loc
, Expression e1
, Expression e2
) @safe
5017 super(loc
, op
, e1
, e2
);
5018 assert(op
== EXP
.identity || op
== EXP
.notIdentity
);
5021 override void accept(Visitor v
)
5027 /***********************************************************
5028 * The ternary operator, `econd ? e1 : e2`
5030 * https://dlang.org/spec/expression.html#conditional_expressions
5032 extern (C
++) final class CondExp
: BinExp
5036 extern (D
) this(const ref Loc loc
, Expression econd
, Expression e1
, Expression e2
) scope @safe
5038 super(loc
, EXP
.question
, e1
, e2
);
5042 override CondExp
syntaxCopy()
5044 return new CondExp(loc
, econd
.syntaxCopy(), e1
.syntaxCopy(), e2
.syntaxCopy());
5047 override bool isLvalue()
5049 return e1
.isLvalue() && e2
.isLvalue();
5052 override void accept(Visitor v
)
5058 /***********************************************************
5059 * A special keyword when used as a function's default argument
5061 * When possible, special keywords are resolved in the parser, but when
5062 * appearing as a default argument, they result in an expression deriving
5063 * from this base class that is resolved for each function call.
5066 * const x = __LINE__; // resolved in the parser
5067 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
5070 * https://dlang.org/spec/expression.html#specialkeywords
5072 extern (C
++) class DefaultInitExp
: Expression
5074 /*************************
5077 * op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
5078 * EXP.line, EXP.file, EXP.fileFullPath
5080 extern (D
) this(const ref Loc loc
, EXP op
) @safe
5085 override void accept(Visitor v
)
5091 /***********************************************************
5092 * The `__FILE__` token as a default argument
5094 extern (C
++) final class FileInitExp
: DefaultInitExp
5096 extern (D
) this(const ref Loc loc
, EXP tok
) @safe
5101 override void accept(Visitor v
)
5107 /***********************************************************
5108 * The `__LINE__` token as a default argument
5110 extern (C
++) final class LineInitExp
: DefaultInitExp
5112 extern (D
) this(const ref Loc loc
) @safe
5114 super(loc
, EXP
.line
);
5117 override void accept(Visitor v
)
5123 /***********************************************************
5124 * The `__MODULE__` token as a default argument
5126 extern (C
++) final class ModuleInitExp
: DefaultInitExp
5128 extern (D
) this(const ref Loc loc
) @safe
5130 super(loc
, EXP
.moduleString
);
5133 override void accept(Visitor v
)
5139 /***********************************************************
5140 * The `__FUNCTION__` token as a default argument
5142 extern (C
++) final class FuncInitExp
: DefaultInitExp
5144 extern (D
) this(const ref Loc loc
) @safe
5146 super(loc
, EXP
.functionString
);
5149 override void accept(Visitor v
)
5155 /***********************************************************
5156 * The `__PRETTY_FUNCTION__` token as a default argument
5158 extern (C
++) final class PrettyFuncInitExp
: DefaultInitExp
5160 extern (D
) this(const ref Loc loc
) @safe
5162 super(loc
, EXP
.prettyFunction
);
5165 override void accept(Visitor v
)
5171 /***********************************************************
5172 * A reference to a class, or an interface. We need this when we
5173 * point to a base class (we must record what the type is).
5175 extern (C
++) final class ClassReferenceExp
: Expression
5177 StructLiteralExp value
;
5179 extern (D
) this(const ref Loc loc
, StructLiteralExp lit
, Type type
) @safe
5181 super(loc
, EXP
.classReference
);
5182 assert(lit
&& lit
.sd
&& lit
.sd
.isClassDeclaration());
5187 ClassDeclaration
originalClass()
5189 return value
.sd
.isClassDeclaration();
5192 // Return index of the field, or -1 if not found
5193 int getFieldIndex(Type fieldtype
, uint fieldoffset
)
5195 ClassDeclaration cd
= originalClass();
5196 uint fieldsSoFar
= 0;
5197 for (size_t j
= 0; j
< value
.elements
.length
; j
++)
5199 while (j
- fieldsSoFar
>= cd
.fields
.length
)
5201 fieldsSoFar
+= cd
.fields
.length
;
5204 VarDeclaration v2
= cd
.fields
[j
- fieldsSoFar
];
5205 if (fieldoffset
== v2
.offset
&& fieldtype
.size() == v2
.type
.size())
5207 return cast(int)(value
.elements
.length
- fieldsSoFar
- cd
.fields
.length
+ (j
- fieldsSoFar
));
5213 // Return index of the field, or -1 if not found
5214 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
5215 int findFieldIndexByName(VarDeclaration v
)
5217 ClassDeclaration cd
= originalClass();
5218 size_t fieldsSoFar
= 0;
5219 for (size_t j
= 0; j
< value
.elements
.length
; j
++)
5221 while (j
- fieldsSoFar
>= cd
.fields
.length
)
5223 fieldsSoFar
+= cd
.fields
.length
;
5226 VarDeclaration v2
= cd
.fields
[j
- fieldsSoFar
];
5229 return cast(int)(value
.elements
.length
- fieldsSoFar
- cd
.fields
.length
+ (j
- fieldsSoFar
));
5235 override void accept(Visitor v
)
5241 /***********************************************************
5242 * This type is only used by the interpreter.
5244 extern (C
++) final class CTFEExp
: Expression
5246 extern (D
) this(EXP tok
)
5248 super(Loc
.initial
, tok
);
5252 override const(char)* toChars() const
5256 case EXP
.cantExpression
:
5258 case EXP
.voidExpression
:
5259 return "cast(void)0";
5260 case EXP
.showCtfeContext
:
5265 return "<continue>";
5273 extern (D
) __gshared CTFEExp cantexp
;
5274 extern (D
) __gshared CTFEExp voidexp
;
5275 extern (D
) __gshared CTFEExp breakexp
;
5276 extern (D
) __gshared CTFEExp continueexp
;
5277 extern (D
) __gshared CTFEExp gotoexp
;
5278 /* Used when additional information is needed regarding
5281 extern (D
) __gshared CTFEExp showcontext
;
5283 extern (D
) static bool isCantExp(const Expression e
) @safe
5285 return e
&& e
.op
== EXP
.cantExpression
;
5288 extern (D
) static bool isGotoExp(const Expression e
) @safe
5290 return e
&& e
.op
== EXP
.goto_
;
5294 /***********************************************************
5295 * Fake class which holds the thrown exception.
5296 * Used for implementing exception handling.
5298 extern (C
++) final class ThrownExceptionExp
: Expression
5300 ClassReferenceExp thrown
; // the thing being tossed
5302 extern (D
) this(const ref Loc loc
, ClassReferenceExp victim
) @safe
5304 super(loc
, EXP
.thrownException
);
5305 this.thrown
= victim
;
5306 this.type
= victim
.type
;
5309 override const(char)* toChars() const
5311 return "CTFE ThrownException";
5314 override void accept(Visitor v
)
5321 * Objective-C class reference expression.
5323 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
5325 extern (C
++) final class ObjcClassReferenceExp
: Expression
5327 ClassDeclaration classDeclaration
;
5329 extern (D
) this(const ref Loc loc
, ClassDeclaration classDeclaration
)
5331 super(loc
, EXP
.objcClassReference
);
5332 this.classDeclaration
= classDeclaration
;
5335 override void accept(Visitor v
)
5341 /*******************
5342 * C11 6.5.1.1 Generic Selection
5345 extern (C
++) final class GenericExp
: Expression
5347 Expression cntlExp
; /// controlling expression of a generic selection (not evaluated)
5348 Types
* types
; /// type-names for generic associations (null entry for `default`)
5349 Expressions
* exps
; /// 1:1 mapping of typeNames to exps
5351 extern (D
) this(const ref Loc loc
, Expression cntlExp
, Types
* types
, Expressions
* exps
) @safe
5353 super(loc
, EXP
._Generic
);
5354 this.cntlExp
= cntlExp
;
5357 assert(types
.length
== exps
.length
); // must be the same and >=1
5360 override GenericExp
syntaxCopy()
5362 return new GenericExp(loc
, cntlExp
.syntaxCopy(), Type
.arraySyntaxCopy(types
), Expression
.arraySyntaxCopy(exps
));
5365 override void accept(Visitor v
)
5372 * Verify if the given identifier is _d_array{,set}ctor.
5375 * id = the identifier to verify
5378 * `true` if the identifier corresponds to a construction runtime hook,
5379 * `false` otherwise.
5381 bool isArrayConstruction(const Identifier id
)
5385 return id
== Id
._d_arrayctor || id
== Id
._d_arraysetctor
;
5388 /******************************
5389 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
5391 private immutable ubyte[EXP
.max
+ 1] exptab
=
5393 ubyte[EXP
.max
+ 1] tab
;
5396 foreach (i
; Eunary
) { tab
[i
] |
= unary
; }
5397 foreach (i
; Ebinary
) { tab
[i
] |
= unary | binary
; }
5398 foreach (i
; EbinaryAssign
) { tab
[i
] |
= unary | binary | binaryAssign
; }
5403 private enum EXPFLAGS
: ubyte
5410 private enum Eunary
=
5412 EXP
.import_
, EXP
.assert_
, EXP
.throw_
, EXP
.dotIdentifier
, EXP
.dotTemplateDeclaration
,
5413 EXP
.dotVariable
, EXP
.dotTemplateInstance
, EXP
.delegate_
, EXP
.dotType
, EXP
.call,
5414 EXP
.address
, EXP
.star
, EXP
.negate
, EXP
.uadd
, EXP
.tilde
, EXP
.not, EXP
.delete_
, EXP
.cast_
,
5415 EXP
.vector
, EXP
.vectorArray
, EXP
.slice
, EXP
.arrayLength
, EXP
.array
, EXP
.delegatePointer
,
5416 EXP
.delegateFunctionPointer
, EXP
.preMinusMinus
, EXP
.prePlusPlus
,
5419 private enum Ebinary
=
5421 EXP
.dot
, EXP
.comma
, EXP
.index
, EXP
.minusMinus
, EXP
.plusPlus
, EXP
.assign
,
5422 EXP
.add, EXP
.min
, EXP
.concatenate
, EXP
.mul, EXP
.div, EXP
.mod
, EXP
.pow
, EXP
.leftShift
,
5423 EXP
.rightShift
, EXP
.unsignedRightShift
, EXP
.and, EXP
.or, EXP
.xor, EXP
.andAnd
, EXP
.orOr
,
5424 EXP
.lessThan
, EXP
.lessOrEqual
, EXP
.greaterThan
, EXP
.greaterOrEqual
,
5425 EXP
.in_
, EXP
.remove
, EXP
.equal
, EXP
.notEqual
, EXP
.identity
, EXP
.notIdentity
,
5427 EXP
.construct
, EXP
.blit
,
5430 private enum EbinaryAssign
=
5432 EXP
.addAssign
, EXP
.minAssign
, EXP
.mulAssign
, EXP
.divAssign
, EXP
.modAssign
,
5433 EXP
.andAssign
, EXP
.orAssign
, EXP
.xorAssign
, EXP
.powAssign
,
5434 EXP
.leftShiftAssign
, EXP
.rightShiftAssign
, EXP
.unsignedRightShiftAssign
,
5435 EXP
.concatenateAssign
, EXP
.concatenateElemAssign
, EXP
.concatenateDcharAssign
,
5438 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
5439 /// Needed because the classes are `extern(C++)`
5440 private immutable ubyte[EXP
.max
+1] expSize
= [
5442 EXP
.negate
: __traits(classInstanceSize
, NegExp
),
5443 EXP
.cast_
: __traits(classInstanceSize
, CastExp
),
5444 EXP
.null_
: __traits(classInstanceSize
, NullExp
),
5445 EXP
.assert_
: __traits(classInstanceSize
, AssertExp
),
5446 EXP
.array
: __traits(classInstanceSize
, ArrayExp
),
5447 EXP
.call: __traits(classInstanceSize
, CallExp
),
5448 EXP
.address
: __traits(classInstanceSize
, AddrExp
),
5449 EXP
.type
: __traits(classInstanceSize
, TypeExp
),
5450 EXP
.throw_
: __traits(classInstanceSize
, ThrowExp
),
5451 EXP
.new_
: __traits(classInstanceSize
, NewExp
),
5452 EXP
.delete_
: __traits(classInstanceSize
, DeleteExp
),
5453 EXP
.star
: __traits(classInstanceSize
, PtrExp
),
5454 EXP
.symbolOffset
: __traits(classInstanceSize
, SymOffExp
),
5455 EXP
.variable
: __traits(classInstanceSize
, VarExp
),
5456 EXP
.dotVariable
: __traits(classInstanceSize
, DotVarExp
),
5457 EXP
.dotIdentifier
: __traits(classInstanceSize
, DotIdExp
),
5458 EXP
.dotTemplateInstance
: __traits(classInstanceSize
, DotTemplateInstanceExp
),
5459 EXP
.dotType
: __traits(classInstanceSize
, DotTypeExp
),
5460 EXP
.slice
: __traits(classInstanceSize
, SliceExp
),
5461 EXP
.arrayLength
: __traits(classInstanceSize
, ArrayLengthExp
),
5462 EXP
.dollar
: __traits(classInstanceSize
, DollarExp
),
5463 EXP
.template_
: __traits(classInstanceSize
, TemplateExp
),
5464 EXP
.dotTemplateDeclaration
: __traits(classInstanceSize
, DotTemplateExp
),
5465 EXP
.declaration
: __traits(classInstanceSize
, DeclarationExp
),
5466 EXP
.dSymbol
: __traits(classInstanceSize
, DsymbolExp
),
5467 EXP
.typeid_
: __traits(classInstanceSize
, TypeidExp
),
5468 EXP
.uadd
: __traits(classInstanceSize
, UAddExp
),
5469 EXP
.remove
: __traits(classInstanceSize
, RemoveExp
),
5470 EXP
.newAnonymousClass
: __traits(classInstanceSize
, NewAnonClassExp
),
5471 EXP
.arrayLiteral
: __traits(classInstanceSize
, ArrayLiteralExp
),
5472 EXP
.assocArrayLiteral
: __traits(classInstanceSize
, AssocArrayLiteralExp
),
5473 EXP
.structLiteral
: __traits(classInstanceSize
, StructLiteralExp
),
5474 EXP
.classReference
: __traits(classInstanceSize
, ClassReferenceExp
),
5475 EXP
.thrownException
: __traits(classInstanceSize
, ThrownExceptionExp
),
5476 EXP
.delegatePointer
: __traits(classInstanceSize
, DelegatePtrExp
),
5477 EXP
.delegateFunctionPointer
: __traits(classInstanceSize
, DelegateFuncptrExp
),
5478 EXP
.lessThan
: __traits(classInstanceSize
, CmpExp
),
5479 EXP
.greaterThan
: __traits(classInstanceSize
, CmpExp
),
5480 EXP
.lessOrEqual
: __traits(classInstanceSize
, CmpExp
),
5481 EXP
.greaterOrEqual
: __traits(classInstanceSize
, CmpExp
),
5482 EXP
.equal
: __traits(classInstanceSize
, EqualExp
),
5483 EXP
.notEqual
: __traits(classInstanceSize
, EqualExp
),
5484 EXP
.identity
: __traits(classInstanceSize
, IdentityExp
),
5485 EXP
.notIdentity
: __traits(classInstanceSize
, IdentityExp
),
5486 EXP
.index
: __traits(classInstanceSize
, IndexExp
),
5487 EXP
.is_
: __traits(classInstanceSize
, IsExp
),
5488 EXP
.leftShift
: __traits(classInstanceSize
, ShlExp
),
5489 EXP
.rightShift
: __traits(classInstanceSize
, ShrExp
),
5490 EXP
.leftShiftAssign
: __traits(classInstanceSize
, ShlAssignExp
),
5491 EXP
.rightShiftAssign
: __traits(classInstanceSize
, ShrAssignExp
),
5492 EXP
.unsignedRightShift
: __traits(classInstanceSize
, UshrExp
),
5493 EXP
.unsignedRightShiftAssign
: __traits(classInstanceSize
, UshrAssignExp
),
5494 EXP
.concatenate
: __traits(classInstanceSize
, CatExp
),
5495 EXP
.concatenateAssign
: __traits(classInstanceSize
, CatAssignExp
),
5496 EXP
.concatenateElemAssign
: __traits(classInstanceSize
, CatElemAssignExp
),
5497 EXP
.concatenateDcharAssign
: __traits(classInstanceSize
, CatDcharAssignExp
),
5498 EXP
.add: __traits(classInstanceSize
, AddExp
),
5499 EXP
.min
: __traits(classInstanceSize
, MinExp
),
5500 EXP
.addAssign
: __traits(classInstanceSize
, AddAssignExp
),
5501 EXP
.minAssign
: __traits(classInstanceSize
, MinAssignExp
),
5502 EXP
.mul: __traits(classInstanceSize
, MulExp
),
5503 EXP
.div: __traits(classInstanceSize
, DivExp
),
5504 EXP
.mod
: __traits(classInstanceSize
, ModExp
),
5505 EXP
.mulAssign
: __traits(classInstanceSize
, MulAssignExp
),
5506 EXP
.divAssign
: __traits(classInstanceSize
, DivAssignExp
),
5507 EXP
.modAssign
: __traits(classInstanceSize
, ModAssignExp
),
5508 EXP
.and: __traits(classInstanceSize
, AndExp
),
5509 EXP
.or: __traits(classInstanceSize
, OrExp
),
5510 EXP
.xor: __traits(classInstanceSize
, XorExp
),
5511 EXP
.andAssign
: __traits(classInstanceSize
, AndAssignExp
),
5512 EXP
.orAssign
: __traits(classInstanceSize
, OrAssignExp
),
5513 EXP
.xorAssign
: __traits(classInstanceSize
, XorAssignExp
),
5514 EXP
.assign
: __traits(classInstanceSize
, AssignExp
),
5515 EXP
.not: __traits(classInstanceSize
, NotExp
),
5516 EXP
.tilde
: __traits(classInstanceSize
, ComExp
),
5517 EXP
.plusPlus
: __traits(classInstanceSize
, PostExp
),
5518 EXP
.minusMinus
: __traits(classInstanceSize
, PostExp
),
5519 EXP
.construct
: __traits(classInstanceSize
, ConstructExp
),
5520 EXP
.blit
: __traits(classInstanceSize
, BlitExp
),
5521 EXP
.dot
: __traits(classInstanceSize
, DotExp
),
5522 EXP
.comma
: __traits(classInstanceSize
, CommaExp
),
5523 EXP
.question
: __traits(classInstanceSize
, CondExp
),
5524 EXP
.andAnd
: __traits(classInstanceSize
, LogicalExp
),
5525 EXP
.orOr
: __traits(classInstanceSize
, LogicalExp
),
5526 EXP
.prePlusPlus
: __traits(classInstanceSize
, PreExp
),
5527 EXP
.preMinusMinus
: __traits(classInstanceSize
, PreExp
),
5528 EXP
.identifier
: __traits(classInstanceSize
, IdentifierExp
),
5529 EXP
.string_
: __traits(classInstanceSize
, StringExp
),
5530 EXP
.this_
: __traits(classInstanceSize
, ThisExp
),
5531 EXP
.super_
: __traits(classInstanceSize
, SuperExp
),
5532 EXP
.halt
: __traits(classInstanceSize
, HaltExp
),
5533 EXP
.tuple
: __traits(classInstanceSize
, TupleExp
),
5534 EXP
.error
: __traits(classInstanceSize
, ErrorExp
),
5535 EXP
.void_
: __traits(classInstanceSize
, VoidInitExp
),
5536 EXP
.int64
: __traits(classInstanceSize
, IntegerExp
),
5537 EXP
.float64
: __traits(classInstanceSize
, RealExp
),
5538 EXP
.complex80
: __traits(classInstanceSize
, ComplexExp
),
5539 EXP
.import_
: __traits(classInstanceSize
, ImportExp
),
5540 EXP
.delegate_
: __traits(classInstanceSize
, DelegateExp
),
5541 EXP
.function_
: __traits(classInstanceSize
, FuncExp
),
5542 EXP
.mixin_
: __traits(classInstanceSize
, MixinExp
),
5543 EXP
.in_
: __traits(classInstanceSize
, InExp
),
5544 EXP
.break_
: __traits(classInstanceSize
, CTFEExp
),
5545 EXP
.continue_
: __traits(classInstanceSize
, CTFEExp
),
5546 EXP
.goto_
: __traits(classInstanceSize
, CTFEExp
),
5547 EXP
.scope_
: __traits(classInstanceSize
, ScopeExp
),
5548 EXP
.traits
: __traits(classInstanceSize
, TraitsExp
),
5549 EXP
.overloadSet
: __traits(classInstanceSize
, OverExp
),
5550 EXP
.line
: __traits(classInstanceSize
, LineInitExp
),
5551 EXP
.file
: __traits(classInstanceSize
, FileInitExp
),
5552 EXP
.fileFullPath
: __traits(classInstanceSize
, FileInitExp
),
5553 EXP
.moduleString
: __traits(classInstanceSize
, ModuleInitExp
),
5554 EXP
.functionString
: __traits(classInstanceSize
, FuncInitExp
),
5555 EXP
.prettyFunction
: __traits(classInstanceSize
, PrettyFuncInitExp
),
5556 EXP
.pow
: __traits(classInstanceSize
, PowExp
),
5557 EXP
.powAssign
: __traits(classInstanceSize
, PowAssignExp
),
5558 EXP
.vector
: __traits(classInstanceSize
, VectorExp
),
5559 EXP
.voidExpression
: __traits(classInstanceSize
, CTFEExp
),
5560 EXP
.cantExpression
: __traits(classInstanceSize
, CTFEExp
),
5561 EXP
.showCtfeContext
: __traits(classInstanceSize
, CTFEExp
),
5562 EXP
.objcClassReference
: __traits(classInstanceSize
, ObjcClassReferenceExp
),
5563 EXP
.vectorArray
: __traits(classInstanceSize
, VectorArrayExp
),
5564 EXP
.compoundLiteral
: __traits(classInstanceSize
, CompoundLiteralExp
),
5565 EXP
._Generic
: __traits(classInstanceSize
, GenericExp
),
5566 EXP
.interval
: __traits(classInstanceSize
, IntervalExp
),
5567 EXP
.loweredAssignExp
: __traits(classInstanceSize
, LoweredAssignExp
),