blob: 9413ad9a9312b6d7018d762909533d85fd28f272 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
* https://github.com/dlang/dmd/blob/master/src/dmd/expression.h
*/
#pragma once
#include "ast_node.h"
#include "complex_t.h"
#include "globals.h"
#include "identifier.h"
#include "arraytypes.h"
#include "intrange.h"
#include "visitor.h"
#include "tokens.h"
#include "root/rmem.h"
class Type;
class TypeVector;
struct Scope;
class TupleDeclaration;
class VarDeclaration;
class FuncDeclaration;
class FuncLiteralDeclaration;
class Declaration;
class CtorDeclaration;
class NewDeclaration;
class Dsymbol;
class Import;
class Module;
class ScopeDsymbol;
class Expression;
class Declaration;
class AggregateDeclaration;
class StructDeclaration;
class TemplateInstance;
class TemplateDeclaration;
class ClassDeclaration;
class BinExp;
class UnaExp;
class DotIdExp;
class DotTemplateInstanceExp;
class OverloadSet;
class Initializer;
class StringExp;
class ArrayExp;
class SliceExp;
struct UnionExp;
#ifdef IN_GCC
typedef union tree_node Symbol;
#else
struct Symbol; // back end symbol
#endif
Expression *expressionSemantic(Expression *e, Scope *sc);
Expression *semanticX(DotIdExp *exp, Scope *sc);
Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
Expression *trySemantic(Expression *e, Scope *sc);
Expression *unaSemantic(UnaExp *e, Scope *sc);
Expression *binSemantic(BinExp *e, Scope *sc);
Expression *binSemanticProp(BinExp *e, Scope *sc);
StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
Expression *resolveProperties(Scope *sc, Expression *e);
Expression *resolvePropertiesOnly(Scope *sc, Expression *e1);
bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d);
bool checkAccess(Scope *sc, Package *p);
Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d);
Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid);
void expandTuples(Expressions *exps);
TupleDeclaration *isAliasThisTuple(Expression *e);
int expandAliasThisTuples(Expressions *exps, size_t starti = 0);
FuncDeclaration *hasThis(Scope *sc);
Expression *fromConstInitializer(int result, Expression *e);
bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors = false);
TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
Expression *valueNoDtor(Expression *e);
int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
Expression *doCopyOrMove(Scope *sc, Expression *e);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
Expression *integralPromotions(Expression *e, Scope *sc);
bool discardValue(Expression *e);
bool isTrivialExp(Expression *e);
int isConst(Expression *e);
Expression *toDelegate(Expression *e, Type* t, Scope *sc);
AggregateDeclaration *isAggregate(Type *t);
IntRange getIntRange(Expression *e);
bool checkNonAssignmentArrayOp(Expression *e, bool suggestion = false);
bool isUnaArrayOp(TOK op);
bool isBinArrayOp(TOK op);
bool isBinAssignArrayOp(TOK op);
bool isArrayOpOperand(Expression *e);
Expression *arrayOp(BinExp *e, Scope *sc);
Expression *arrayOp(BinAssignExp *e, Scope *sc);
bool hasSideEffect(Expression *e);
bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
Expression *Expression_optimize(Expression *e, int result, bool keepLvalue);
MATCH implicitConvTo(Expression *e, Type *t);
Expression *implicitCastTo(Expression *e, Scope *sc, Type *t);
Expression *castTo(Expression *e, Scope *sc, Type *t);
Expression *ctfeInterpret(Expression *);
Expression *inlineCopy(Expression *e, Scope *sc);
Expression *op_overload(Expression *e, Scope *sc);
Type *toStaticArrayType(SliceExp *e);
Expression *scaleFactor(BinExp *be, Scope *sc);
Expression *typeCombine(BinExp *be, Scope *sc);
Expression *inferType(Expression *e, Type *t, int flag = 0);
Expression *semanticTraits(TraitsExp *e, Scope *sc);
Type *getIndirection(Type *t);
Expression *checkGC(Scope *sc, Expression *e);
/* Run CTFE on the expression, but allow the expression to be a TypeExp
* or a tuple containing a TypeExp. (This is required by pragma(msg)).
*/
Expression *ctfeInterpretForPragmaMsg(Expression *e);
enum OwnedBy
{
OWNEDcode, // normal code expression in AST
OWNEDctfe, // value expression for CTFE
OWNEDcache // constant value cached for CTFE
};
#define WANTvalue 0 // default
#define WANTexpand 1 // expand const/immutable variables if possible
class Expression : public ASTNode
{
public:
Loc loc; // file location
Type *type; // !=NULL means that semantic() has been run
TOK op; // to minimize use of dynamic_cast
unsigned char size; // # of bytes in Expression so we can copy() it
unsigned char parens; // if this is a parenthesized expression
Expression(Loc loc, TOK op, int size);
static void _init();
Expression *copy();
virtual Expression *syntaxCopy();
// kludge for template.isExpression()
int dyncast() const { return DYNCAST_EXPRESSION; }
void print();
const char *toChars();
void error(const char *format, ...) const;
void warning(const char *format, ...) const;
void deprecation(const char *format, ...) const;
// creates a single expression which is effectively (e1, e2)
// this new expression does not necessarily need to have valid D source code representation,
// for example, it may include declaration expressions
static Expression *combine(Expression *e1, Expression *e2);
static Expression *extractLast(Expression *e, Expression **pe0);
static Expressions *arraySyntaxCopy(Expressions *exps);
virtual dinteger_t toInteger();
virtual uinteger_t toUInteger();
virtual real_t toReal();
virtual real_t toImaginary();
virtual complex_t toComplex();
virtual StringExp *toStringExp();
virtual TupleExp *toTupleExp();
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
Expression *implicitCastTo(Scope *sc, Type *t)
{
return ::implicitCastTo(this, sc, t);
}
MATCH implicitConvTo(Type *t)
{
return ::implicitConvTo(this, t);
}
Expression *castTo(Scope *sc, Type *t)
{
return ::castTo(this, sc, t);
}
virtual Expression *resolveLoc(Loc loc, Scope *sc);
virtual bool checkType();
virtual bool checkValue();
bool checkScalar();
bool checkNoBool();
bool checkIntegral();
bool checkArithmetic();
bool checkDeprecated(Scope *sc, Dsymbol *s);
bool checkDisabled(Scope *sc, Dsymbol *s);
bool checkPurity(Scope *sc, FuncDeclaration *f);
bool checkPurity(Scope *sc, VarDeclaration *v);
bool checkSafety(Scope *sc, FuncDeclaration *f);
bool checkNogc(Scope *sc, FuncDeclaration *f);
bool checkPostblit(Scope *sc, Type *t);
bool checkRightThis(Scope *sc);
bool checkReadModifyWrite(TOK rmwOp, Expression *ex = NULL);
virtual int checkModifiable(Scope *sc, int flag = 0);
virtual Expression *toBoolean(Scope *sc);
virtual Expression *addDtorHook(Scope *sc);
Expression *addressOf();
Expression *deref();
Expression *optimize(int result, bool keepLvalue = false)
{
return Expression_optimize(this, result, keepLvalue);
}
// Entry point for CTFE.
// A compile-time result is required. Give an error if not possible
Expression *ctfeInterpret()
{
return ::ctfeInterpret(this);
}
int isConst() { return ::isConst(this); }
virtual bool isBool(bool result);
Expression *op_overload(Scope *sc)
{
return ::op_overload(this, sc);
}
virtual bool hasCode()
{
return true;
}
IntegerExp* isIntegerExp();
ErrorExp* isErrorExp();
VoidInitExp* isVoidInitExp();
RealExp* isRealExp();
ComplexExp* isComplexExp();
IdentifierExp* isIdentifierExp();
DollarExp* isDollarExp();
DsymbolExp* isDsymbolExp();
ThisExp* isThisExp();
SuperExp* isSuperExp();
NullExp* isNullExp();
StringExp* isStringExp();
TupleExp* isTupleExp();
ArrayLiteralExp* isArrayLiteralExp();
AssocArrayLiteralExp* isAssocArrayLiteralExp();
StructLiteralExp* isStructLiteralExp();
TypeExp* isTypeExp();
ScopeExp* isScopeExp();
TemplateExp* isTemplateExp();
NewExp* isNewExp();
NewAnonClassExp* isNewAnonClassExp();
SymOffExp* isSymOffExp();
VarExp* isVarExp();
OverExp* isOverExp();
FuncExp* isFuncExp();
DeclarationExp* isDeclarationExp();
TypeidExp* isTypeidExp();
TraitsExp* isTraitsExp();
HaltExp* isHaltExp();
IsExp* isExp();
CompileExp* isCompileExp();
ImportExp* isImportExp();
AssertExp* isAssertExp();
DotIdExp* isDotIdExp();
DotTemplateExp* isDotTemplateExp();
DotVarExp* isDotVarExp();
DotTemplateInstanceExp* isDotTemplateInstanceExp();
DelegateExp* isDelegateExp();
DotTypeExp* isDotTypeExp();
CallExp* isCallExp();
AddrExp* isAddrExp();
PtrExp* isPtrExp();
NegExp* isNegExp();
UAddExp* isUAddExp();
ComExp* isComExp();
NotExp* isNotExp();
DeleteExp* isDeleteExp();
CastExp* isCastExp();
VectorExp* isVectorExp();
VectorArrayExp* isVectorArrayExp();
SliceExp* isSliceExp();
ArrayLengthExp* isArrayLengthExp();
ArrayExp* isArrayExp();
DotExp* isDotExp();
CommaExp* isCommaExp();
IntervalExp* isIntervalExp();
DelegatePtrExp* isDelegatePtrExp();
DelegateFuncptrExp* isDelegateFuncptrExp();
IndexExp* isIndexExp();
PostExp* isPostExp();
PreExp* isPreExp();
AssignExp* isAssignExp();
ConstructExp* isConstructExp();
BlitExp* isBlitExp();
AddAssignExp* isAddAssignExp();
MinAssignExp* isMinAssignExp();
MulAssignExp* isMulAssignExp();
DivAssignExp* isDivAssignExp();
ModAssignExp* isModAssignExp();
AndAssignExp* isAndAssignExp();
OrAssignExp* isOrAssignExp();
XorAssignExp* isXorAssignExp();
PowAssignExp* isPowAssignExp();
ShlAssignExp* isShlAssignExp();
ShrAssignExp* isShrAssignExp();
UshrAssignExp* isUshrAssignExp();
CatAssignExp* isCatAssignExp();
AddExp* isAddExp();
MinExp* isMinExp();
CatExp* isCatExp();
MulExp* isMulExp();
DivExp* isDivExp();
ModExp* isModExp();
PowExp* isPowExp();
ShlExp* isShlExp();
ShrExp* isShrExp();
UshrExp* isUshrExp();
AndExp* isAndExp();
OrExp* isOrExp();
XorExp* isXorExp();
LogicalExp* isLogicalExp();
InExp* isInExp();
RemoveExp* isRemoveExp();
EqualExp* isEqualExp();
IdentityExp* isIdentityExp();
CondExp* isCondExp();
DefaultInitExp* isDefaultInitExp();
FileInitExp* isFileInitExp();
LineInitExp* isLineInitExp();
ModuleInitExp* isModuleInitExp();
FuncInitExp* isFuncInitExp();
PrettyFuncInitExp* isPrettyFuncInitExp();
ClassReferenceExp* isClassReferenceExp();
void accept(Visitor *v) { v->visit(this); }
};
class IntegerExp : public Expression
{
public:
dinteger_t value;
IntegerExp(Loc loc, dinteger_t value, Type *type);
IntegerExp(dinteger_t value);
static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
bool equals(RootObject *o);
dinteger_t toInteger();
real_t toReal();
real_t toImaginary();
complex_t toComplex();
bool isBool(bool result);
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
dinteger_t getInteger() { return value; }
void setInteger(dinteger_t value);
void normalize();
};
class ErrorExp : public Expression
{
public:
ErrorExp();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
static ErrorExp *errorexp; // handy shared value
};
class RealExp : public Expression
{
public:
real_t value;
RealExp(Loc loc, real_t value, Type *type);
static RealExp *create(Loc loc, real_t value, Type *type);
bool equals(RootObject *o);
dinteger_t toInteger();
uinteger_t toUInteger();
real_t toReal();
real_t toImaginary();
complex_t toComplex();
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
class ComplexExp : public Expression
{
public:
complex_t value;
ComplexExp(Loc loc, complex_t value, Type *type);
static ComplexExp *create(Loc loc, complex_t value, Type *type);
bool equals(RootObject *o);
dinteger_t toInteger();
uinteger_t toUInteger();
real_t toReal();
real_t toImaginary();
complex_t toComplex();
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
class IdentifierExp : public Expression
{
public:
Identifier *ident;
IdentifierExp(Loc loc, Identifier *ident);
static IdentifierExp *create(Loc loc, Identifier *ident);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class DollarExp : public IdentifierExp
{
public:
DollarExp(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class DsymbolExp : public Expression
{
public:
Dsymbol *s;
bool hasOverloads;
DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = true);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class ThisExp : public Expression
{
public:
VarDeclaration *var;
ThisExp(Loc loc);
bool isBool(bool result);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class SuperExp : public ThisExp
{
public:
SuperExp(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class NullExp : public Expression
{
public:
unsigned char committed; // !=0 if type is committed
NullExp(Loc loc, Type *t = NULL);
bool equals(RootObject *o);
bool isBool(bool result);
StringExp *toStringExp();
void accept(Visitor *v) { v->visit(this); }
};
class StringExp : public Expression
{
public:
void *string; // char, wchar, or dchar data
size_t len; // number of chars, wchars, or dchars
unsigned char sz; // 1: char, 2: wchar, 4: dchar
unsigned char committed; // !=0 if type is committed
utf8_t postfix; // 'c', 'w', 'd'
OwnedBy ownedByCtfe;
StringExp(Loc loc, char *s);
StringExp(Loc loc, void *s, size_t len);
StringExp(Loc loc, void *s, size_t len, utf8_t postfix);
static StringExp *create(Loc loc, char *s);
static StringExp *create(Loc loc, void *s, size_t len);
bool equals(RootObject *o);
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
int compare(RootObject *obj);
bool isBool(bool result);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
unsigned charAt(uinteger_t i) const;
void accept(Visitor *v) { v->visit(this); }
size_t numberOfCodeUnits(int tynto = 0) const;
void writeTo(void* dest, bool zero, int tyto = 0) const;
char *toPtr();
};
// Tuple
class TupleExp : public Expression
{
public:
Expression *e0; // side-effect part
/* Tuple-field access may need to take out its side effect part.
* For example:
* foo().tupleof
* is rewritten as:
* (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
* The declaration of temporary variable __tup will be stored in TupleExp::e0.
*/
Expressions *exps;
TupleExp(Loc loc, Expression *e0, Expressions *exps);
TupleExp(Loc loc, Expressions *exps);
TupleExp(Loc loc, TupleDeclaration *tup);
TupleExp *toTupleExp();
Expression *syntaxCopy();
bool equals(RootObject *o);
void accept(Visitor *v) { v->visit(this); }
};
class ArrayLiteralExp : public Expression
{
public:
Expression *basis;
Expressions *elements;
OwnedBy ownedByCtfe;
ArrayLiteralExp(Loc loc, Type *type, Expressions *elements);
ArrayLiteralExp(Loc loc, Type *type, Expression *e);
ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements);
static ArrayLiteralExp *create(Loc loc, Expressions *elements);
Expression *syntaxCopy();
bool equals(RootObject *o);
Expression *getElement(size_t i);
static Expressions* copyElements(Expression *e1, Expression *e2 = NULL);
bool isBool(bool result);
StringExp *toStringExp();
void accept(Visitor *v) { v->visit(this); }
};
class AssocArrayLiteralExp : public Expression
{
public:
Expressions *keys;
Expressions *values;
OwnedBy ownedByCtfe;
AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values);
bool equals(RootObject *o);
Expression *syntaxCopy();
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
// scrubReturnValue is running
#define stageScrub 0x1
// hasNonConstPointers is running
#define stageSearchPointers 0x2
// optimize is running
#define stageOptimize 0x4
// apply is running
#define stageApply 0x8
//inlineScan is running
#define stageInlineScan 0x10
// toCBuffer is running
#define stageToCBuffer 0x20
class StructLiteralExp : public Expression
{
public:
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
OwnedBy ownedByCtfe;
// 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 *origin;
// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
StructLiteralExp *inlinecopy;
// 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.
int stageflags;
StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL);
static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
bool equals(RootObject *o);
Expression *syntaxCopy();
Expression *getField(Type *type, unsigned offset);
int getFieldIndex(Type *type, unsigned offset);
Expression *addDtorHook(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class DotIdExp;
DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident);
class TypeExp : public Expression
{
public:
TypeExp(Loc loc, Type *type);
Expression *syntaxCopy();
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
class ScopeExp : public Expression
{
public:
ScopeDsymbol *sds;
ScopeExp(Loc loc, ScopeDsymbol *sds);
Expression *syntaxCopy();
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
class TemplateExp : public Expression
{
public:
TemplateDeclaration *td;
FuncDeclaration *fd;
TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd = NULL);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
class NewExp : public Expression
{
public:
/* thisexp.new(newargs) newtype(arguments)
*/
Expression *thisexp; // if !NULL, 'this' for class being allocated
Expressions *newargs; // Array of Expression's to call new operator
Type *newtype;
Expressions *arguments; // Array of Expression's
Expression *argprefix; // expression to be evaluated just before arguments[]
CtorDeclaration *member; // constructor function
NewDeclaration *allocator; // allocator function
int onstack; // allocate on stack
NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
Type *newtype, Expressions *arguments);
static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class NewAnonClassExp : public Expression
{
public:
/* thisexp.new(newargs) class baseclasses { } (arguments)
*/
Expression *thisexp; // if !NULL, 'this' for class being allocated
Expressions *newargs; // Array of Expression's to call new operator
ClassDeclaration *cd; // class being instantiated
Expressions *arguments; // Array of Expression's to call class constructor
NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs,
ClassDeclaration *cd, Expressions *arguments);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class SymbolExp : public Expression
{
public:
Declaration *var;
bool hasOverloads;
SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads);
void accept(Visitor *v) { v->visit(this); }
};
// Offset from symbol
class SymOffExp : public SymbolExp
{
public:
dinteger_t offset;
SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads = true);
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
// Variable
class VarExp : public SymbolExp
{
public:
VarExp(Loc loc, Declaration *var, bool hasOverloads = true);
static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
bool equals(RootObject *o);
int checkModifiable(Scope *sc, int flag);
bool checkReadModifyWrite();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
// Overload Set
class OverExp : public Expression
{
public:
OverloadSet *vars;
OverExp(Loc loc, OverloadSet *s);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
// Function/Delegate literal
class FuncExp : public Expression
{
public:
FuncLiteralDeclaration *fd;
TemplateDeclaration *td;
TOK tok;
FuncExp(Loc loc, Dsymbol *s);
bool equals(RootObject *o);
void genIdent(Scope *sc);
Expression *syntaxCopy();
MATCH matchType(Type *to, Scope *sc, FuncExp **pfe, int flag = 0);
const char *toChars();
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
// 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 DeclarationExp : public Expression
{
public:
Dsymbol *declaration;
DeclarationExp(Loc loc, Dsymbol *declaration);
Expression *syntaxCopy();
bool hasCode();
void accept(Visitor *v) { v->visit(this); }
};
class TypeidExp : public Expression
{
public:
RootObject *obj;
TypeidExp(Loc loc, RootObject *obj);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class TraitsExp : public Expression
{
public:
Identifier *ident;
Objects *args;
TraitsExp(Loc loc, Identifier *ident, Objects *args);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class HaltExp : public Expression
{
public:
HaltExp(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class IsExp : public Expression
{
public:
/* is(targ id tok tspec)
* is(targ id == tok2)
*/
Type *targ;
Identifier *id; // can be NULL
TOK tok; // ':' or '=='
Type *tspec; // can be NULL
TOK tok2; // 'struct', 'union', etc.
TemplateParameters *parameters;
IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, Type *tspec,
TOK tok2, TemplateParameters *parameters);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
class UnaExp : public Expression
{
public:
Expression *e1;
Type *att1; // Save alias this type to detect recursion
UnaExp(Loc loc, TOK op, int size, Expression *e1);
Expression *syntaxCopy();
Expression *incompatibleTypes();
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
typedef UnionExp (*fp_t)(Loc loc, Type *, Expression *, Expression *);
typedef int (*fp2_t)(Loc loc, TOK, Expression *, Expression *);
class BinExp : public Expression
{
public:
Expression *e1;
Expression *e2;
Type *att1; // Save alias this type to detect recursion
Type *att2; // Save alias this type to detect recursion
BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
Expression *syntaxCopy();
Expression *incompatibleTypes();
Expression *checkOpAssignTypes(Scope *sc);
bool checkIntegralBin();
bool checkArithmeticBin();
Expression *reorderSettingAAElem(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class BinAssignExp : public BinExp
{
public:
BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *ex);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
class CompileExp : public Expression
{
public:
Expressions *exps;
CompileExp(Loc loc, Expressions *exps);
Expression *syntaxCopy();
bool equals(RootObject *o);
void accept(Visitor *v) { v->visit(this); }
};
class ImportExp : public UnaExp
{
public:
ImportExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class AssertExp : public UnaExp
{
public:
Expression *msg;
AssertExp(Loc loc, Expression *e, Expression *msg = NULL);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DotIdExp : public UnaExp
{
public:
Identifier *ident;
bool noderef; // true if the result of the expression will never be dereferenced
bool wantsym; // do not replace Symbol with its initializer during semantic()
DotIdExp(Loc loc, Expression *e, Identifier *ident);
static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
void accept(Visitor *v) { v->visit(this); }
};
class DotTemplateExp : public UnaExp
{
public:
TemplateDeclaration *td;
DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
class DotVarExp : public UnaExp
{
public:
Declaration *var;
bool hasOverloads;
DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads = true);
int checkModifiable(Scope *sc, int flag);
bool checkReadModifyWrite();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class DotTemplateInstanceExp : public UnaExp
{
public:
TemplateInstance *ti;
DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs);
DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti);
Expression *syntaxCopy();
bool findTempDecl(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class DelegateExp : public UnaExp
{
public:
FuncDeclaration *func;
bool hasOverloads;
DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, bool hasOverloads = true);
void accept(Visitor *v) { v->visit(this); }
};
class DotTypeExp : public UnaExp
{
public:
Dsymbol *sym; // symbol that represents a type
DotTypeExp(Loc loc, Expression *e, Dsymbol *sym);
void accept(Visitor *v) { v->visit(this); }
};
class CallExp : public UnaExp
{
public:
Expressions *arguments; // function arguments
FuncDeclaration *f; // symbol to call
bool directcall; // true if a virtual call is devirtualized
CallExp(Loc loc, Expression *e, Expressions *exps);
CallExp(Loc loc, Expression *e);
CallExp(Loc loc, Expression *e, Expression *earg1);
CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2);
static CallExp *create(Loc loc, Expression *e, Expressions *exps);
static CallExp *create(Loc loc, Expression *e);
static CallExp *create(Loc loc, Expression *e, Expression *earg1);
Expression *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *addDtorHook(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class AddrExp : public UnaExp
{
public:
AddrExp(Loc loc, Expression *e);
AddrExp(Loc loc, Expression *e, Type *t);
void accept(Visitor *v) { v->visit(this); }
};
class PtrExp : public UnaExp
{
public:
PtrExp(Loc loc, Expression *e);
PtrExp(Loc loc, Expression *e, Type *t);
int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class NegExp : public UnaExp
{
public:
NegExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class UAddExp : public UnaExp
{
public:
UAddExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class ComExp : public UnaExp
{
public:
ComExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class NotExp : public UnaExp
{
public:
NotExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class DeleteExp : public UnaExp
{
public:
bool isRAII;
DeleteExp(Loc loc, Expression *e, bool isRAII);
Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class CastExp : public UnaExp
{
public:
// Possible to cast to one type while painting to another type
Type *to; // type to cast to
unsigned char mod; // MODxxxxx
CastExp(Loc loc, Expression *e, Type *t);
CastExp(Loc loc, Expression *e, unsigned char mod);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class VectorExp : public UnaExp
{
public:
TypeVector *to; // the target vector type before semantic()
unsigned dim; // number of elements in the vector
OwnedBy ownedByCtfe;
VectorExp(Loc loc, Expression *e, Type *t);
static VectorExp *create(Loc loc, Expression *e, Type *t);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class VectorArrayExp : public UnaExp
{
public:
VectorArrayExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class SliceExp : public UnaExp
{
public:
Expression *upr; // NULL if implicit 0
Expression *lwr; // NULL if implicit [length - 1]
VarDeclaration *lengthVar;
bool upperIsInBounds; // true if upr <= e1.length
bool lowerIsLessThanUpper; // true if lwr <= upr
bool arrayop; // an array operation, rather than a slice
SliceExp(Loc loc, Expression *e1, IntervalExp *ie);
SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
Expression *syntaxCopy();
int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
class ArrayLengthExp : public UnaExp
{
public:
ArrayLengthExp(Loc loc, Expression *e1);
void accept(Visitor *v) { v->visit(this); }
};
class IntervalExp : public Expression
{
public:
Expression *lwr;
Expression *upr;
IntervalExp(Loc loc, Expression *lwr, Expression *upr);
Expression *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DelegatePtrExp : public UnaExp
{
public:
DelegatePtrExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
class DelegateFuncptrExp : public UnaExp
{
public:
DelegateFuncptrExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
// e1[a0,a1,a2,a3,...]
class ArrayExp : public UnaExp
{
public:
Expressions *arguments; // Array of Expression's
size_t currentDimension; // for opDollar
VarDeclaration *lengthVar;
ArrayExp(Loc loc, Expression *e1, Expression *index = NULL);
ArrayExp(Loc loc, Expression *e1, Expressions *args);
Expression *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
class DotExp : public BinExp
{
public:
DotExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class CommaExp : public BinExp
{
public:
bool isGenerated;
bool allowCommaExp;
CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated = true);
int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
bool isBool(bool result);
Expression *toBoolean(Scope *sc);
Expression *addDtorHook(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class IndexExp : public BinExp
{
public:
VarDeclaration *lengthVar;
bool modifiable;
bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
IndexExp(Loc loc, Expression *e1, Expression *e2);
Expression *syntaxCopy();
int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
Expression *markSettingAAElem();
void accept(Visitor *v) { v->visit(this); }
};
/* For both i++ and i--
*/
class PostExp : public BinExp
{
public:
PostExp(TOK op, Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
/* For both ++i and --i
*/
class PreExp : public UnaExp
{
public:
PreExp(TOK op, Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
enum MemorySet
{
blockAssign = 1, // setting the contents of an array
referenceInit = 2 // setting the reference of STCref variable
};
class AssignExp : public BinExp
{
public:
int memset; // combination of MemorySet flags
AssignExp(Loc loc, Expression *e1, Expression *e2);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *ex);
Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class ConstructExp : public AssignExp
{
public:
ConstructExp(Loc loc, Expression *e1, Expression *e2);
ConstructExp(Loc loc, VarDeclaration *v, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class BlitExp : public AssignExp
{
public:
BlitExp(Loc loc, Expression *e1, Expression *e2);
BlitExp(Loc loc, VarDeclaration *v, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AddAssignExp : public BinAssignExp
{
public:
AddAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MinAssignExp : public BinAssignExp
{
public:
MinAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MulAssignExp : public BinAssignExp
{
public:
MulAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class DivAssignExp : public BinAssignExp
{
public:
DivAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ModAssignExp : public BinAssignExp
{
public:
ModAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AndAssignExp : public BinAssignExp
{
public:
AndAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class OrAssignExp : public BinAssignExp
{
public:
OrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class XorAssignExp : public BinAssignExp
{
public:
XorAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class PowAssignExp : public BinAssignExp
{
public:
PowAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShlAssignExp : public BinAssignExp
{
public:
ShlAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShrAssignExp : public BinAssignExp
{
public:
ShrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class UshrAssignExp : public BinAssignExp
{
public:
UshrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class CatAssignExp : public BinAssignExp
{
public:
CatAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AddExp : public BinExp
{
public:
AddExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MinExp : public BinExp
{
public:
MinExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class CatExp : public BinExp
{
public:
CatExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MulExp : public BinExp
{
public:
MulExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class DivExp : public BinExp
{
public:
DivExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ModExp : public BinExp
{
public:
ModExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class PowExp : public BinExp
{
public:
PowExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShlExp : public BinExp
{
public:
ShlExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShrExp : public BinExp
{
public:
ShrExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class UshrExp : public BinExp
{
public:
UshrExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AndExp : public BinExp
{
public:
AndExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class OrExp : public BinExp
{
public:
OrExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class XorExp : public BinExp
{
public:
XorExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class LogicalExp : public BinExp
{
public:
LogicalExp(Loc loc, TOK op, Expression *e1, Expression *e2);
Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class CmpExp : public BinExp
{
public:
CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class InExp : public BinExp
{
public:
InExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class RemoveExp : public BinExp
{
public:
RemoveExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
// == and !=
class EqualExp : public BinExp
{
public:
EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
// is and !is
class IdentityExp : public BinExp
{
public:
IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
class CondExp : public BinExp
{
public:
Expression *econd;
CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2);
Expression *syntaxCopy();
int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
Expression *toBoolean(Scope *sc);
void hookDtors(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
class DefaultInitExp : public Expression
{
public:
TOK subop; // which of the derived classes this is
DefaultInitExp(Loc loc, TOK subop, int size);
void accept(Visitor *v) { v->visit(this); }
};
class FileInitExp : public DefaultInitExp
{
public:
FileInitExp(Loc loc, TOK tok);
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class LineInitExp : public DefaultInitExp
{
public:
LineInitExp(Loc loc);
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class ModuleInitExp : public DefaultInitExp
{
public:
ModuleInitExp(Loc loc);
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class FuncInitExp : public DefaultInitExp
{
public:
FuncInitExp(Loc loc);
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class PrettyFuncInitExp : public DefaultInitExp
{
public:
PrettyFuncInitExp(Loc loc);
Expression *resolveLoc(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
/* A type meant as a union of all the Expression types,
* to serve essentially as a Variant that will sit on the stack
* during CTFE to reduce memory consumption.
*/
struct UnionExp
{
UnionExp() { } // yes, default constructor does nothing
UnionExp(Expression *e)
{
memcpy(this, (void *)e, e->size);
}
/* Extract pointer to Expression
*/
Expression *exp() { return (Expression *)&u; }
/* Convert to an allocated Expression
*/
Expression *copy();
private:
// Ensure that the union is suitably aligned.
#if defined(__GNUC__) || defined(__clang__)
__attribute__((aligned(8)))
#elif defined(_MSC_VER)
__declspec(align(8))
#elif defined(__DMC__)
#pragma pack(8)
#endif
union
{
char exp [sizeof(Expression)];
char integerexp[sizeof(IntegerExp)];
char errorexp [sizeof(ErrorExp)];
char realexp [sizeof(RealExp)];
char complexexp[sizeof(ComplexExp)];
char symoffexp [sizeof(SymOffExp)];
char stringexp [sizeof(StringExp)];
char arrayliteralexp [sizeof(ArrayLiteralExp)];
char assocarrayliteralexp [sizeof(AssocArrayLiteralExp)];
char structliteralexp [sizeof(StructLiteralExp)];
char nullexp [sizeof(NullExp)];
char dotvarexp [sizeof(DotVarExp)];
char addrexp [sizeof(AddrExp)];
char indexexp [sizeof(IndexExp)];
char sliceexp [sizeof(SliceExp)];
char vectorexp [sizeof(VectorExp)];
} u;
#if defined(__DMC__)
#pragma pack()
#endif
};
/****************************************************************/
/* Special values used by the interpreter
*/
Expression *expType(Type *type, Expression *e);
UnionExp Neg(Type *type, Expression *e1);
UnionExp Com(Type *type, Expression *e1);
UnionExp Not(Type *type, Expression *e1);
UnionExp Bool(Type *type, Expression *e1);
UnionExp Cast(Loc loc, Type *type, Type *to, Expression *e1);
UnionExp ArrayLength(Type *type, Expression *e1);
UnionExp Ptr(Type *type, Expression *e1);
UnionExp Add(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Min(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Mul(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Mod(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Pow(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Shl(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Shr(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Ushr(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp And(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Or(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Xor(Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Index(Type *type, Expression *e1, Expression *e2);
UnionExp Cat(Type *type, Expression *e1, Expression *e2);
UnionExp Equal(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Cmp(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Identity(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);
// Const-folding functions used by CTFE
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex);
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex);
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex);
int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len);
int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len);