Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

ddmd.expression

Compiler implementation of the D programming language.
Authors:

Source: expression.d

Expression getRightThis(Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Declaration var, int flag = 0);
Given var, get the right this pointer if var is in an outer class, but our existing this pointer is in an inner class.
Parameters:
Expression e1 existing this
AggregateDeclaration ad struct or class we need the correct this for
Declaration var the specific member of ad we're accessing
Returns:
Expression representing the this for the var
FuncDeclaration hasThis(Scope* sc);
Determine if this is available by walking up the enclosing scopes until a function is found.
Parameters:
Scope* sc context
Returns:
Found function if it satisfies isThis(), otherwise null
bool isNeedThisScope(Scope* sc, Declaration d);
Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null);
Pull out any properties.
bool checkPropertyCall(Expression e, Expression emsg);
Check the tail CallExp is really property function call.
Bugs:
This doesn't appear to do anything.
Expression resolvePropertiesOnly(Scope* sc, Expression e1);
If e1 is a property function (template), resolve it.
Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident);
Find symbol in accordance with the UFCS name look up rule
bool isDotOpDispatch(Expression e);
check e is exp.opDispatch!(tiargs) or not It's used to switch to UFCS the semantic analysis path
Expression resolveUFCS(Scope* sc, CallExp ce);
Pull out callable entity with UFCS.
Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null);
Pull out property with UFCS.
bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false);
Perform semantic() on an array of Expressions.
void expandTuples(Expressions* exps);
Expand tuples.

Input: exps aray of Expressions

Output: exps rewritten in place

TupleDeclaration isAliasThisTuple(Expression e);
Expand alias this tuples.
bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type* pt);
The common type is determined by applying ?: to each pair.

Output: exps[] properties resolved, implicitly cast to common type, rewritten in place *pt if pt is not NULL, set to the common type

Returns:
true a semantic error was detected
TemplateDeclaration getFuncTemplateDecl(Dsymbol s);
Get TemplateDeclaration enclosing FuncDeclaration.
bool preFunctionParameters(Loc loc, Scope* sc, Expressions* exps);
Preprocess arguments to function.

Output: exps[] tuples expanded, properties resolved, rewritten in place

Returns:
true a semantic error occurred
Expression valueNoDtor(Expression e);
If we want the value of this expression, but do not want to call the destructor on it.
bool checkDefCtor(Loc loc, Type t);
Issue an error if default construction is disabled for type t. Default construction is required for arrays and 'out' parameters.
Returns:
true an error was issued
Expression callCpCtor(Scope* sc, Expression e);
If e is an instance of a struct, and that struct has a copy constructor, rewrite e as: (tmp = e),tmp

Input: sc just used to specify the scope of created temporary variable

Expression doCopyOrMove(Scope* sc, Expression e);
Handle the postblit call on lvalue, or the move of rvalue.
bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type tthis, Expressions* arguments, FuncDeclaration fd, Type* prettype, Expression* peprefix);
Now that we know the exact type of the function we're calling, the arguments[] need to be adjusted: 1. implicitly convert argument to the corresponding parameter type 2. add default arguments for any missing arguments 3. do default promotions on arguments corresponding to ... 4. add hidden arguments[] argument 5. call copy constructor for struct value arguments

Input: tf type of the function fd the function being called, NULL if called indirectly

Output: *prettype return type of function *peprefix expression to execute before arguments[] are evaluated, NULL if none

Returns:
true errors happened
struct UnionExp;
int RealEquals(real_t x1, real_t x2);
Test to see if two reals are the same. Regard NaN's as equivalent. Regard +0 and -0 as different.
DotIdExp typeDotIdExp(Loc loc, Type type, Identifier ident);
TypeDotIdExp
int modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1);
Mark variable v as modified if it is inside a constructor that var is a field in.
Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue);
Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0);
Runs semantic on ae.arguments. Declares temporary variables if '$' was used.
Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0);
Runs semantic on se.lwr and se.upr. Declares a temporary variable if '$' was used.
StringExp semanticString(Scope* sc, Expression exp, const char* s);
Resolve exp as a compile-time known string.
Parameters:
Scope* sc scope
Expression exp Expression which expected as a string
char* s What the string is expected for, will be used in error diagnostic.
Returns:
String literal, or null if error happens.
abstract class Expression: ddmd.root.rootobject.RootObject;
final Expression copy();
Does *not* do a deep copy.
Expression semantic(Scope* sc);
Semantically analyze Expression. Determine types, fold constants, etc.
final Expression trySemantic(Scope* sc);
Try to run semantic routines. If they fail, return NULL.
static Expression combine(Expression e1, Expression e2);
Combine e1 and e2 by CommaExp if both are not NULL.
static Expression extractLast(Expression e, Expression* pe0);
If 'e' is a tree of commas, returns the leftmost expression by stripping off it from the tree. The remained part of the tree is returned via *pe0. Otherwise 'e' is directly returned and *pe0 is set to NULL.
bool isLvalue();
Return !=0 if expression is an lvalue.
Expression toLvalue(Scope* sc, Expression e);
Give error if we're not an lvalue. If we can, convert expression to be an lvalue.
Expression resolveLoc(Loc loc, Scope* sc);
Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc.
bool checkType();
Check that the expression has a valid type. If not, generates an error "... has no type".
Returns:
true if the expression is not valid.

Note: When this function returns true, checkValue() should also return true.

bool checkValue();
Check that the expression has a valid value. If not, generates an error "... has no value".
Returns:
true if the expression is not valid or has void type.
final bool checkPurity(Scope* sc, FuncDeclaration f);
Calling function f. Check the purity, i.e. if we're in a pure function we can only call other pure functions. Returns true if error occurs.
final bool checkPurity(Scope* sc, VarDeclaration v);
Accessing variable v. Check for purity and safety violations. Returns true if error occurs.
final bool checkSafety(Scope* sc, FuncDeclaration f);
Calling function f. Check the safety, i.e. if we're in a @safe function we can only call @safe or @trusted functions. Returns true if error occurs.
final bool checkNogc(Scope* sc, FuncDeclaration f);
Calling function f. Check the @nogc-ness, i.e. if we're in a @nogc function we can only call other @nogc functions. Returns true if error occurs.
final bool checkPostblit(Scope* sc, Type t);
Check that the postblit is callable if t is an array of structs. Returns true if error happens.
final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null);
Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) Returns true if error occurs.
int checkModifiable(Scope* sc, int flag = 0);

Parameters:

sc: scope

flag: 1: do not issue error message for invalid modification

Returns:
0: is not modifiable 1: is modifiable in default == being related to type.isMutable() 2: is modifiable, because this is a part of initializing.
Expression toBoolean(Scope* sc);
If expression can be tested for true or false, returns the modified expression. Otherwise returns ErrorExp.
Expression addDtorHook(Scope* sc);
Destructors are attached to VarDeclarations. Hence, if expression returns a temp that needs a destructor, make sure and create a VarDeclaration for that temp.
final Expression addressOf();
Take address of expression.
final Expression deref();
If this is a reference, dereference it.
bool isBool(bool result);
Does this expression statically evaluate to a boolean 'result' (true or false)?
class IntegerExp: ddmd.expression.Expression;
class ErrorExp: ddmd.expression.Expression;
Use this expression for error recovery. It should behave as a 'sink' to prevent further cascaded error messages.
class RealExp: ddmd.expression.Expression;
class ComplexExp: ddmd.expression.Expression;
class IdentifierExp: ddmd.expression.Expression;
class DollarExp: ddmd.expression.IdentifierExp;
class DsymbolExp: ddmd.expression.Expression;
Won't be generated by parser. A placeholder expression to call DsymbolExp.resolve on specific symbol.
static Expression resolve(Loc loc, Scope* sc, Dsymbol s, bool hasOverloads);
Resolve a symbol s and wraps it in an expression object.
Parameters:
bool hasOverloads works if the aliased symbol is a function.

true: it's overloaded and will be resolved later.

false: it's exact function symbol.

class ThisExp: ddmd.expression.Expression;
class SuperExp: ddmd.expression.ThisExp;
class NullExp: ddmd.expression.Expression;
class StringExp: ddmd.expression.Expression;
final const size_t numberOfCodeUnits(int tynto = 0);
Return the number of code units the string would be if it were re-encoded as tynto.
Parameters:
int tynto code unit type of the target encoding
Returns:
number of code units
const void writeTo(void* dest, bool zero, int tyto = 0);
Write the contents of the string to dest. Use numberOfCodeUnits() to determine size of result.
Parameters:
void* dest destination
int tyto encoding type of the result
bool zero add terminating 0
final const pure dchar getCodeUnit(size_t i);
Get the code unit at index i
Parameters:
size_t i index
Returns:
code unit at index i
final void setCodeUnit(size_t i, dchar c);
Set the code unit at index i to c
Parameters:
size_t i index
dchar c code unit to set it to
char* toPtr();
If the string data is UTF-8 and can be accessed directly, return a pointer to it. Do not assume a terminating 0.
Returns:
pointer to string data if possible, null if not
StringExp toUTF8(Scope* sc);
Convert string to char[].
final const const(char)[] toStringz();
Convert string contents to a 0 terminated string, allocated by mem.xmalloc().
class TupleExp: ddmd.expression.Expression;
class ArrayLiteralExp: ddmd.expression.Expression;
[ e1, e2, e3, ... ]
Expression basis;
If !is null, elements[] can be sparse and basis is used for the "default" element value. In other words, non-null elements[i] overrides this 'basis' value.
static Expressions* copyElements(Expression e1, Expression e2 = null);
Copy element Expressions in the parameters when they're ArrayLiteralExps.
Parameters:
Expression e1 If it's ArrayLiteralExp, its elements will be copied. Otherwise, e1 itself will be pushed into the new Expressions.
Expression e2 If it's not null, it will be pushed/appended to the new Expressions by the same way with e1.
Returns:
Newly allocated Expressions. Note that it points to the original Expression values in e1 and e2.
class AssocArrayLiteralExp: ddmd.expression.Expression;
[ key0 : value0, key1 : value1, ... ]
enum int stageScrub;
scrubReturnValue is running
enum int stageSearchPointers;
hasNonConstPointers is running
enum int stageOptimize;
optimize is running
enum int stageApply;
apply is running
enum int stageInlineScan;
inlineScan is running
enum int stageToCBuffer;
toCBuffer is running
class StructLiteralExp: ddmd.expression.Expression;
sd( e1, e2, e3, ... )
StructDeclaration sd;
which aggregate this is for
Expressions* elements;
parallels sd.fields[] with null entries for fields to skip
Type stype;
final type of result (can be different from sd's type)
bool useStaticInit;
if this is true, use the StructDeclaration's init symbol
Symbol* sym;
back end symbol to initialize with literal
StructLiteralExp origin;
pointer to the origin instance of the expression. once a new expression is created, origin is set to 'this'. anytime when an expression copy is created, 'origin' pointer is set to 'origin' pointer value of the original expression.
StructLiteralExp inlinecopy;
those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
int stageflags;
anytime when recursive function is calling, 'stageflags' marks with bit flag of current stage and unmarks before return from this function. 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' (with infinite recursion) of this expression.
Expression getField(Type type, uint offset);
Gets expression at offset of type. Returns NULL if not found.
int getFieldIndex(Type type, uint offset);
Get index of field. Returns -1 if not found.
class TypeExp: ddmd.expression.Expression;
Mainly just a placeholder
class ScopeExp: ddmd.expression.Expression;
Mainly just a placeholder of Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
A template instance that requires IFTI: foo!tiargs(fargs) // foo!tiargs is left until CallExp::semantic() or resolveProperties()
class TemplateExp: ddmd.expression.Expression;
Mainly just a placeholder
class NewExp: ddmd.expression.Expression;
thisexp.new(newargs) newtype(arguments)
class NewAnonClassExp: ddmd.expression.Expression;
thisexp.new(newargs) class baseclasses { } (arguments)
class SymbolExp: ddmd.expression.Expression;
class SymOffExp: ddmd.expression.SymbolExp;
Offset from symbol
class VarExp: ddmd.expression.SymbolExp;
Variable
class OverExp: ddmd.expression.Expression;
Overload Set
class FuncExp: ddmd.expression.Expression;
Function/Delegate literal
class DeclarationExp: ddmd.expression.Expression;
Declaration of a symbol
D grammar allows declarations only as statements. However in AST representation it can be part of any expression. This is used, for example, during internal syntax re-writes to inject hidden symbols.
class TypeidExp: ddmd.expression.Expression;
typeid(int)
class TraitsExp: ddmd.expression.Expression;
_traits(identifier, args...)
class HaltExp: ddmd.expression.Expression;
class IsExp: ddmd.expression.Expression;
is(targ id tok tspec) is(targ id == tok2)
abstract class UnaExp: ddmd.expression.Expression;
final Expression unaSemantic(Scope* sc);
Helper function for easy error propagation. If error occurs, returns ErrorExp. Otherwise returns NULL.
final Expression incompatibleTypes();
The type for a unary expression is incompatible. Print error message.
Returns:
ErrorExp
final void setNoderefOperand();
Mark the operand as will never be dereferenced, which is useful info for @safe checks. Do before semantic() on operands rewrites them.
abstract class BinExp: ddmd.expression.Expression;
final Expression binSemantic(Scope* sc);
Helper function for easy error propagation. If error occurs, returns ErrorExp. Otherwise returns NULL.
final Expression incompatibleTypes();
The types for a binary expression are incompatible. Print error message.
Returns:
ErrorExp
final void setNoderefOperands();
Mark the operands as will never be dereferenced, which is useful info for @safe checks. Do before semantic() on operands rewrites them.
class BinAssignExp: ddmd.expression.BinExp;
class CompileExp: ddmd.expression.UnaExp;
class ImportExp: ddmd.expression.UnaExp;
class AssertExp: ddmd.expression.UnaExp;
class DotIdExp: ddmd.expression.UnaExp;
class DotTemplateExp: ddmd.expression.UnaExp;
Mainly just a placeholder
class DotVarExp: ddmd.expression.UnaExp;
class DotTemplateInstanceExp: ddmd.expression.UnaExp;
foo.bar!(args)
class DelegateExp: ddmd.expression.UnaExp;
class DotTypeExp: ddmd.expression.UnaExp;
class CallExp: ddmd.expression.UnaExp;
class AddrExp: ddmd.expression.UnaExp;
class PtrExp: ddmd.expression.UnaExp;
class NegExp: ddmd.expression.UnaExp;
class UAddExp: ddmd.expression.UnaExp;
class ComExp: ddmd.expression.UnaExp;
class NotExp: ddmd.expression.UnaExp;
class DeleteExp: ddmd.expression.UnaExp;
class CastExp: ddmd.expression.UnaExp;
Possible to cast to one type while painting to another type
class VectorExp: ddmd.expression.UnaExp;
class SliceExp: ddmd.expression.UnaExp;
this(Loc loc, Expression e1, IntervalExp ie);
class ArrayLengthExp: ddmd.expression.UnaExp;
static Expression rewriteOpAssign(BinExp exp);

Rewrite: array.length op= e2

as: array.length = array.length op e2

or: auto tmp = &array; (*tmp).length = (*tmp).length op e2

class ArrayExp: ddmd.expression.UnaExp;
e1 [ a0, a1, a2, a3 ,... ]
class DotExp: ddmd.expression.BinExp;
class CommaExp: ddmd.expression.BinExp;
const bool isGenerated;
This is needed because AssignExp rewrites CommaExp, hence it needs
to trigger the deprecation.
bool allowCommaExp;
Temporary variable to enable / disable deprecation of comma expression
depending on the context.
Since most constructor calls are rewritting, the only place where
false will be passed will be from the parser.
static void allow(Expression exp);
If the argument is a CommaExp, set a flag to prevent deprecation messages
It's impossible to know from CommaExp.semantic if the result will be used, hence when there is a result (type != void), a deprecation message is always emitted. However, some construct can produce a result but won't use it (ExpStatement and for loop increment). Those should call this function to prevent unwanted deprecations to be emitted.
Parameters:
Expression exp An expression that discards its result. If the argument is null or not a CommaExp, nothing happens.
class IntervalExp: ddmd.expression.Expression;
Mainly just a placeholder
class DelegateFuncptrExp: ddmd.expression.UnaExp;
class IndexExp: ddmd.expression.BinExp;
e1 [ e2 ]
class PostExp: ddmd.expression.BinExp;
For both i++ and i--
class PreExp: ddmd.expression.UnaExp;
For both ++i and --i
class AssignExp: ddmd.expression.BinExp;
final this(Loc loc, Expression e1, Expression e2);
class ConstructExp: ddmd.expression.AssignExp;
class BlitExp: ddmd.expression.AssignExp;
class AddAssignExp: ddmd.expression.BinAssignExp;
class MinAssignExp: ddmd.expression.BinAssignExp;
class MulAssignExp: ddmd.expression.BinAssignExp;
class DivAssignExp: ddmd.expression.BinAssignExp;
class ModAssignExp: ddmd.expression.BinAssignExp;
class AndAssignExp: ddmd.expression.BinAssignExp;
class OrAssignExp: ddmd.expression.BinAssignExp;
class XorAssignExp: ddmd.expression.BinAssignExp;
class PowAssignExp: ddmd.expression.BinAssignExp;
class ShlAssignExp: ddmd.expression.BinAssignExp;
class ShrAssignExp: ddmd.expression.BinAssignExp;
class UshrAssignExp: ddmd.expression.BinAssignExp;
class CatAssignExp: ddmd.expression.BinAssignExp;
class AddExp: ddmd.expression.BinExp;
class MinExp: ddmd.expression.BinExp;
class CatExp: ddmd.expression.BinExp;
class MulExp: ddmd.expression.BinExp;
class DivExp: ddmd.expression.BinExp;
class ModExp: ddmd.expression.BinExp;
class PowExp: ddmd.expression.BinExp;
class ShlExp: ddmd.expression.BinExp;
class ShrExp: ddmd.expression.BinExp;
class UshrExp: ddmd.expression.BinExp;
class AndExp: ddmd.expression.BinExp;
class OrExp: ddmd.expression.BinExp;
class XorExp: ddmd.expression.BinExp;
class OrOrExp: ddmd.expression.BinExp;
class AndAndExp: ddmd.expression.BinExp;
class CmpExp: ddmd.expression.BinExp;
class InExp: ddmd.expression.BinExp;
class RemoveExp: ddmd.expression.BinExp;
This deletes the key e1 from the associative array e2
class EqualExp: ddmd.expression.BinExp;
== and !=
class IdentityExp: ddmd.expression.BinExp;
is and !is
class CondExp: ddmd.expression.BinExp;
class DefaultInitExp: ddmd.expression.Expression;
class FileInitExp: ddmd.expression.DefaultInitExp;
class LineInitExp: ddmd.expression.DefaultInitExp;
class ModuleInitExp: ddmd.expression.DefaultInitExp;
class FuncInitExp: ddmd.expression.DefaultInitExp;
class PrettyFuncInitExp: ddmd.expression.DefaultInitExp;