blob: 66eddd8ab5580a883ab439ec572ec85f79f6400b [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* https://www.boost.org/LICENSE_1_0.txt
* https://github.com/dlang/dmd/blob/master/src/dmd/statement.h
*/
#pragma once
#include "arraytypes.h"
#include "ast_node.h"
#include "dsymbol.h"
#include "visitor.h"
#include "tokens.h"
struct Scope;
class Expression;
class LabelDsymbol;
class Identifier;
class IfStatement;
class ExpStatement;
class DefaultStatement;
class VarDeclaration;
class Condition;
class ErrorStatement;
class ReturnStatement;
class CompoundStatement;
class Parameter;
class StaticAssert;
class AsmStatement;
class GotoStatement;
class ScopeStatement;
class TryCatchStatement;
class TryFinallyStatement;
class CaseStatement;
class DefaultStatement;
class LabelStatement;
class StaticForeach;
// Back end
struct code;
/* How a statement exits; this is returned by blockExit()
*/
enum BE : int32_t
{
BEnone = 0,
BEfallthru = 1,
BEthrow = 2,
BEreturn = 4,
BEgoto = 8,
BEhalt = 0x10,
BEbreak = 0x20,
BEcontinue = 0x40,
BEerrthrow = 0x80,
BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt)
};
typedef unsigned char STMT;
enum
{
STMTerror,
STMTpeel,
STMTexp, STMTdtorExp,
STMTcompile,
STMTcompound, STMTcompoundDeclaration, STMTcompoundAsm,
STMTunrolledLoop,
STMTscope,
STMTforwarding,
STMTwhile,
STMTdo,
STMTfor,
STMTforeach,
STMTforeachRange,
STMTif,
STMTconditional,
STMTstaticForeach,
STMTpragma,
STMTstaticAssert,
STMTswitch,
STMTcase,
STMTcaseRange,
STMTdefault,
STMTgotoDefault,
STMTgotoCase,
STMTswitchError,
STMTreturn,
STMTbreak,
STMTcontinue,
STMTsynchronized,
STMTwith,
STMTtryCatch,
STMTtryFinally,
STMTscopeGuard,
STMTthrow,
STMTdebug,
STMTgoto,
STMTlabel,
STMTasm, STMTinlineAsm, STMTgccAsm,
STMTimport
};
class Statement : public ASTNode
{
public:
Loc loc;
STMT stmt;
virtual Statement *syntaxCopy();
const char *toChars() const;
void error(const char *format, ...);
void warning(const char *format, ...);
void deprecation(const char *format, ...);
virtual Statement *getRelatedLabeled() { return this; }
virtual bool hasBreak() const;
virtual bool hasContinue() const;
bool usesEH();
bool comeFrom();
bool hasCode();
virtual Statement *last();
virtual ReturnStatement *endsWithReturnStatement() { return NULL; }
ErrorStatement *isErrorStatement() { return stmt == STMTerror ? (ErrorStatement*)this : NULL; }
ScopeStatement *isScopeStatement() { return stmt == STMTscope ? (ScopeStatement*)this : NULL; }
ExpStatement *isExpStatement() { return stmt == STMTexp ? (ExpStatement*)this : NULL; }
CompoundStatement *isCompoundStatement() { return stmt == STMTcompound ? (CompoundStatement*)this : NULL; }
ReturnStatement *isReturnStatement() { return stmt == STMTreturn ? (ReturnStatement*)this : NULL; }
IfStatement *isIfStatement() { return stmt == STMTif ? (IfStatement*)this : NULL; }
ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : NULL; }
StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : NULL; }
CaseStatement *isCaseStatement() { return stmt == STMTcase ? (CaseStatement*)this : NULL; }
DefaultStatement *isDefaultStatement() { return stmt == STMTdefault ? (DefaultStatement*)this : NULL; }
LabelStatement *isLabelStatement() { return stmt == STMTlabel ? (LabelStatement*)this : NULL; }
GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : NULL; }
GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : NULL; }
BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : NULL; }
DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : NULL; }
CompileStatement *isCompileStatement() { return stmt == STMTcompile ? (CompileStatement*)this : NULL; }
ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : NULL; }
DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : NULL; }
ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : NULL; }
ForeachStatement *isForeachStatement() { return stmt == STMTforeach ? (ForeachStatement*)this : NULL; }
SwitchStatement *isSwitchStatement() { return stmt == STMTswitch ? (SwitchStatement*)this : NULL; }
ContinueStatement *isContinueStatement() { return stmt == STMTcontinue ? (ContinueStatement*)this : NULL; }
WithStatement *isWithStatement() { return stmt == STMTwith ? (WithStatement*)this : NULL; }
TryCatchStatement *isTryCatchStatement() { return stmt == STMTtryCatch ? (TryCatchStatement*)this : NULL; }
ThrowStatement *isThrowStatement() { return stmt == STMTthrow ? (ThrowStatement*)this : NULL; }
DebugStatement *isDebugStatement() { return stmt == STMTdebug ? (DebugStatement*)this : NULL; }
TryFinallyStatement *isTryFinallyStatement() { return stmt == STMTtryFinally ? (TryFinallyStatement*)this : NULL; }
ScopeGuardStatement *isScopeGuardStatement() { return stmt == STMTscopeGuard ? (ScopeGuardStatement*)this : NULL; }
SwitchErrorStatement *isSwitchErrorStatement() { return stmt == STMTswitchError ? (SwitchErrorStatement*)this : NULL; }
UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : NULL; }
ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; }
void accept(Visitor *v) { v->visit(this); }
};
/** Any Statement that fails semantic() or has a component that is an ErrorExp or
* a TypeError should return an ErrorStatement from semantic().
*/
class ErrorStatement : public Statement
{
public:
ErrorStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class PeelStatement : public Statement
{
public:
Statement *s;
void accept(Visitor *v) { v->visit(this); }
};
class ExpStatement : public Statement
{
public:
Expression *exp;
static ExpStatement *create(const Loc &loc, Expression *exp);
ExpStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DtorExpStatement : public ExpStatement
{
public:
/* Wraps an expression that is the destruction of 'var'
*/
VarDeclaration *var;
DtorExpStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class CompileStatement : public Statement
{
public:
Expressions *exps;
CompileStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class CompoundStatement : public Statement
{
public:
Statements *statements;
static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2);
CompoundStatement *syntaxCopy();
ReturnStatement *endsWithReturnStatement();
Statement *last();
void accept(Visitor *v) { v->visit(this); }
};
class CompoundDeclarationStatement : public CompoundStatement
{
public:
CompoundDeclarationStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
/* The purpose of this is so that continue will go to the next
* of the statements, and break will go to the end of the statements.
*/
class UnrolledLoopStatement : public Statement
{
public:
Statements *statements;
UnrolledLoopStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ScopeStatement : public Statement
{
public:
Statement *statement;
Loc endloc; // location of closing curly bracket
ScopeStatement *syntaxCopy();
ReturnStatement *endsWithReturnStatement();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ForwardingStatement : public Statement
{
public:
ForwardingScopeDsymbol *sym;
Statement *statement;
ForwardingStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class WhileStatement : public Statement
{
public:
Parameter *param;
Expression *condition;
Statement *_body;
Loc endloc; // location of closing curly bracket
WhileStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class DoStatement : public Statement
{
public:
Statement *_body;
Expression *condition;
Loc endloc; // location of ';' after while
DoStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ForStatement : public Statement
{
public:
Statement *_init;
Expression *condition;
Expression *increment;
Statement *_body;
Loc endloc; // location of closing curly bracket
// When wrapped in try/finally clauses, this points to the outermost one,
// which may have an associated label. Internal break/continue statements
// treat that label as referring to this loop.
Statement *relatedLabeled;
ForStatement *syntaxCopy();
Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ForeachStatement : public Statement
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
Parameters *parameters; // array of Parameter*'s
Expression *aggr;
Statement *_body;
Loc endloc; // location of closing curly bracket
VarDeclaration *key;
VarDeclaration *value;
FuncDeclaration *func; // function we're lexically in
Statements *cases; // put breaks, continues, gotos and returns here
ScopeStatements *gotos; // forward referenced goto's go here
ForeachStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ForeachRangeStatement : public Statement
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
Parameter *prm; // loop index variable
Expression *lwr;
Expression *upr;
Statement *_body;
Loc endloc; // location of closing curly bracket
VarDeclaration *key;
ForeachRangeStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class IfStatement : public Statement
{
public:
Parameter *prm;
Expression *condition;
Statement *ifbody;
Statement *elsebody;
VarDeclaration *match; // for MatchExpression results
Loc endloc; // location of closing curly bracket
IfStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class ConditionalStatement : public Statement
{
public:
Condition *condition;
Statement *ifbody;
Statement *elsebody;
ConditionalStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class StaticForeachStatement : public Statement
{
public:
StaticForeach *sfe;
StaticForeachStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class PragmaStatement : public Statement
{
public:
Identifier *ident;
Expressions *args; // array of Expression's
Statement *_body;
PragmaStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class StaticAssertStatement : public Statement
{
public:
StaticAssert *sa;
StaticAssertStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class SwitchStatement : public Statement
{
public:
Expression *condition;
Statement *_body;
bool isFinal;
DefaultStatement *sdefault;
Statement *tryBody; // set to TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
CaseStatements *cases; // array of CaseStatement's
int hasNoDefault; // !=0 if no default statement
int hasVars; // !=0 if has variable case values
VarDeclaration *lastVar;
SwitchStatement *syntaxCopy();
bool hasBreak() const;
void accept(Visitor *v) { v->visit(this); }
};
class CaseStatement : public Statement
{
public:
Expression *exp;
Statement *statement;
int index; // which case it is (since we sort this)
VarDeclaration *lastVar;
void* extra; // for use by Statement_toIR()
CaseStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class CaseRangeStatement : public Statement
{
public:
Expression *first;
Expression *last;
Statement *statement;
CaseRangeStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DefaultStatement : public Statement
{
public:
Statement *statement;
VarDeclaration *lastVar;
DefaultStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class GotoDefaultStatement : public Statement
{
public:
SwitchStatement *sw;
GotoDefaultStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class GotoCaseStatement : public Statement
{
public:
Expression *exp; // NULL, or which case to goto
CaseStatement *cs; // case statement it resolves to
GotoCaseStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class SwitchErrorStatement : public Statement
{
public:
Expression *exp;
void accept(Visitor *v) { v->visit(this); }
};
class ReturnStatement : public Statement
{
public:
Expression *exp;
size_t caseDim;
ReturnStatement *syntaxCopy();
ReturnStatement *endsWithReturnStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class BreakStatement : public Statement
{
public:
Identifier *ident;
BreakStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class ContinueStatement : public Statement
{
public:
Identifier *ident;
ContinueStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class SynchronizedStatement : public Statement
{
public:
Expression *exp;
Statement *_body;
SynchronizedStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class WithStatement : public Statement
{
public:
Expression *exp;
Statement *_body;
VarDeclaration *wthis;
Loc endloc;
WithStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class TryCatchStatement : public Statement
{
public:
Statement *_body;
Catches *catches;
Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
TryCatchStatement *syntaxCopy();
bool hasBreak() const;
void accept(Visitor *v) { v->visit(this); }
};
class Catch : public RootObject
{
public:
Loc loc;
Type *type;
Identifier *ident;
Statement *handler;
VarDeclaration *var;
// set if semantic processing errors
bool errors;
// was generated by the compiler,
// wasn't present in source code
bool internalCatch;
Catch *syntaxCopy();
};
class TryFinallyStatement : public Statement
{
public:
Statement *_body;
Statement *finalbody;
Statement *tryBody; // set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
bool bodyFallsThru; // true if _body falls through to finally
static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody);
TryFinallyStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
class ScopeGuardStatement : public Statement
{
public:
TOK tok;
Statement *statement;
ScopeGuardStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class ThrowStatement : public Statement
{
public:
Expression *exp;
// was generated by the compiler,
// wasn't present in source code
bool internalThrow;
ThrowStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DebugStatement : public Statement
{
public:
Statement *statement;
DebugStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class GotoStatement : public Statement
{
public:
Identifier *ident;
LabelDsymbol *label;
Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
ScopeGuardStatement *os;
VarDeclaration *lastVar;
GotoStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class LabelStatement : public Statement
{
public:
Identifier *ident;
Statement *statement;
Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
ScopeGuardStatement *os;
VarDeclaration *lastVar;
Statement *gotoTarget; // interpret
void* extra; // used by Statement_toIR()
bool breaks; // someone did a 'break ident'
LabelStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class LabelDsymbol : public Dsymbol
{
public:
LabelStatement *statement;
bool deleted; // set if rewritten to return in foreach delegate
bool iasm; // set if used by inline assembler
static LabelDsymbol *create(Identifier *ident);
LabelDsymbol *isLabel();
void accept(Visitor *v) { v->visit(this); }
};
Statement* asmSemantic(AsmStatement *s, Scope *sc);
class AsmStatement : public Statement
{
public:
Token *tokens;
AsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class InlineAsmStatement : public AsmStatement
{
public:
code *asmcode;
unsigned asmalign; // alignment of this statement
unsigned regs; // mask of registers modified (must match regm_t in back end)
bool refparam; // true if function parameter is referenced
bool naked; // true if function is to be naked
InlineAsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
// A GCC asm statement - assembler instructions with D expression operands
class GccAsmStatement : public AsmStatement
{
public:
StorageClass stc; // attributes of the asm {} block
Expression *insn; // string expression that is the template for assembler code
Expressions *args; // input and output operands of the statement
unsigned outputargs; // of the operands in 'args', the number of output operands
Identifiers *names; // list of symbolic names for the operands
Expressions *constraints; // list of string constants specifying constraints on operands
Expressions *clobbers; // list of string constants specifying clobbers and scratch registers
Identifiers *labels; // list of goto labels
GotoStatements *gotos; // of the goto labels, the equivalent statements they represent
GccAsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
// a complete asm {} block
class CompoundAsmStatement : public CompoundStatement
{
public:
StorageClass stc; // postfix attributes like nothrow/pure/@trusted
CompoundAsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class ImportStatement : public Statement
{
public:
Dsymbols *imports; // Array of Import's
ImportStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};