| /** |
| * Defines AST nodes for statements. |
| * |
| * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) |
| * |
| * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved |
| * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) |
| * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) |
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement.d, _statement.d) |
| * Documentation: https://dlang.org/phobos/dmd_statement.html |
| * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/statement.d |
| */ |
| |
| module dmd.statement; |
| |
| import core.stdc.stdarg; |
| import core.stdc.stdio; |
| |
| import dmd.arraytypes; |
| import dmd.astenums; |
| import dmd.ast_node; |
| import dmd.cond; |
| import dmd.declaration; |
| import dmd.dsymbol; |
| import dmd.expression; |
| import dmd.func; |
| import dmd.id; |
| import dmd.identifier; |
| import dmd.location; |
| import dmd.mtype; |
| import dmd.rootobject; |
| import dmd.staticassert; |
| import dmd.tokens; |
| import dmd.visitor; |
| import dmd.visitor.postorder; |
| |
| /*********************************************************** |
| * Specification: https://dlang.org/spec/statement.html |
| */ |
| extern (C++) abstract class Statement : ASTNode |
| { |
| const Loc loc; |
| const STMT stmt; |
| |
| override final DYNCAST dyncast() const |
| { |
| return DYNCAST.statement; |
| } |
| |
| final extern (D) this(Loc loc, STMT stmt) @safe |
| { |
| this.loc = loc; |
| this.stmt = stmt; |
| // If this is an in{} contract scope statement (skip for determining |
| // inlineStatus of a function body for header content) |
| } |
| |
| Statement syntaxCopy() |
| { |
| assert(0); |
| } |
| |
| /************************************* |
| * Do syntax copy of an array of Statement's. |
| */ |
| static Statements* arraySyntaxCopy(Statements* a) |
| { |
| Statements* b = null; |
| if (a) |
| { |
| b = a.copy(); |
| foreach (i, s; *a) |
| { |
| (*b)[i] = s ? s.syntaxCopy() : null; |
| } |
| } |
| return b; |
| } |
| |
| Statement getRelatedLabeled() |
| { |
| return this; |
| } |
| |
| /**************************** |
| * Determine if an enclosed `break` would apply to this |
| * statement, such as if it is a loop or switch statement. |
| * Returns: |
| * `true` if it does |
| */ |
| bool hasBreak() const pure nothrow |
| { |
| //printf("Statement::hasBreak()\n"); |
| return false; |
| } |
| |
| /**************************** |
| * Determine if an enclosed `continue` would apply to this |
| * statement, such as if it is a loop statement. |
| * Returns: |
| * `true` if it does |
| */ |
| bool hasContinue() const pure nothrow |
| { |
| return false; |
| } |
| |
| /********************************** |
| * Returns: |
| * `true` if statement uses exception handling |
| */ |
| extern (D) final bool usesEH() |
| { |
| extern (C++) final class UsesEH : StoppableVisitor |
| { |
| alias visit = typeof(super).visit; |
| public: |
| override void visit(Statement s) |
| { |
| } |
| |
| override void visit(TryCatchStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(TryFinallyStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(ScopeGuardStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(SynchronizedStatement s) |
| { |
| stop = true; |
| } |
| } |
| |
| scope UsesEH ueh = new UsesEH(); |
| return walkPostorder(this, ueh); |
| } |
| |
| /********************************** |
| * Returns: |
| * `true` if statement 'comes from' somewhere else, like a goto |
| */ |
| extern (D) final bool comeFrom() |
| { |
| extern (C++) final class ComeFrom : StoppableVisitor |
| { |
| alias visit = typeof(super).visit; |
| public: |
| override void visit(Statement s) |
| { |
| } |
| |
| override void visit(CaseStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(DefaultStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(LabelStatement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(AsmStatement s) |
| { |
| stop = true; |
| } |
| } |
| |
| scope ComeFrom cf = new ComeFrom(); |
| return walkPostorder(this, cf); |
| } |
| |
| /********************************** |
| * Returns: |
| * `true` if statement has executable code. |
| */ |
| extern (D) final bool hasCode() |
| { |
| extern (C++) final class HasCode : StoppableVisitor |
| { |
| alias visit = typeof(super).visit; |
| public: |
| override void visit(Statement s) |
| { |
| stop = true; |
| } |
| |
| override void visit(ExpStatement s) |
| { |
| if (s.exp !is null) |
| { |
| stop = s.exp.hasCode(); |
| } |
| } |
| |
| override void visit(CompoundStatement s) |
| { |
| } |
| |
| override void visit(ScopeStatement s) |
| { |
| } |
| |
| override void visit(ImportStatement s) |
| { |
| } |
| |
| override void visit(CaseStatement s) |
| { |
| } |
| |
| override void visit(DefaultStatement s) |
| { |
| } |
| |
| override void visit(LabelStatement s) |
| { |
| } |
| } |
| |
| scope HasCode hc = new HasCode(); |
| return walkPostorder(this, hc); |
| } |
| |
| /******************************* |
| * Find last statement in a sequence of statements. |
| * Returns: |
| * the last statement, or `null` if there isn't one |
| */ |
| inout(Statement) last() inout nothrow pure |
| { |
| return this; |
| } |
| |
| /************************** |
| * Support Visitor Pattern |
| * Params: |
| * v = visitor |
| */ |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| |
| /************************************ |
| * Does this statement end with a return statement? |
| * |
| * I.e. is it a single return statement or some compound statement |
| * that unconditionally hits a return statement. |
| * Returns: |
| * return statement it ends with, otherwise null |
| */ |
| pure nothrow @nogc |
| inout(ReturnStatement) endsWithReturnStatement() inout { return null; } |
| |
| final pure inout nothrow @nogc @trusted |
| { |
| /******************** |
| * A cheaper method of doing downcasting of Statements. |
| * Returns: |
| * the downcast statement if it can be downcasted, otherwise `null` |
| */ |
| inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } |
| inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } |
| inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } |
| inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } |
| inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } |
| inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } |
| inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } |
| inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; } |
| inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; } |
| inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } |
| inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } |
| inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } |
| inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } |
| inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } |
| inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } |
| inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } |
| inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } |
| inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } |
| inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } |
| inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } |
| inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } |
| inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } |
| inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } |
| inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } |
| inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } |
| inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } |
| inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } |
| inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } |
| inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; } |
| inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } |
| inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; } |
| inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } |
| inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } |
| inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } |
| inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } |
| inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } |
| inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } |
| inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } |
| inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } |
| inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } |
| inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } |
| inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } |
| inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } |
| inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } |
| } |
| } |
| |
| /*********************************************************** |
| * Any Statement that fails semantic() or has a component that is an ErrorExp or |
| * a TypeError should return an ErrorStatement from semantic(). |
| */ |
| extern (C++) final class ErrorStatement : Statement |
| { |
| extern (D) this() |
| { |
| super(Loc.initial, STMT.Error); |
| |
| import dmd.globals; |
| assert(global.gaggedErrors || global.errors); |
| } |
| |
| override ErrorStatement syntaxCopy() |
| { |
| return this; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class PeelStatement : Statement |
| { |
| Statement s; |
| |
| extern (D) this(Statement s) @safe |
| { |
| super(s.loc, STMT.Peel); |
| this.s = s; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#ExpressionStatement |
| */ |
| extern (C++) class ExpStatement : Statement |
| { |
| Expression exp; |
| |
| final extern (D) this(Loc loc, Expression exp) @safe |
| { |
| super(loc, STMT.Exp); |
| this.exp = exp; |
| } |
| |
| final extern (D) this(Loc loc, Expression exp, STMT stmt) @safe |
| { |
| super(loc, stmt); |
| this.exp = exp; |
| } |
| |
| final extern (D) this(Loc loc, Dsymbol declaration) @safe |
| { |
| super(loc, STMT.Exp); |
| this.exp = new DeclarationExp(loc, declaration); |
| } |
| |
| static ExpStatement create(Loc loc, Expression exp) @safe |
| { |
| return new ExpStatement(loc, exp); |
| } |
| |
| override ExpStatement syntaxCopy() |
| { |
| return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class DtorExpStatement : ExpStatement |
| { |
| // Wraps an expression that is the destruction of 'var' |
| VarDeclaration var; |
| |
| extern (D) this(Loc loc, Expression exp, VarDeclaration var) @safe |
| { |
| super(loc, exp, STMT.DtorExp); |
| this.var = var; |
| } |
| |
| override DtorExpStatement syntaxCopy() |
| { |
| return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#mixin-statement |
| */ |
| // Note: was called CompileStatement |
| extern (C++) final class MixinStatement : Statement |
| { |
| Expressions* exps; |
| |
| extern (D) this(Loc loc, Expression exp) |
| { |
| Expressions* exps = new Expressions(); |
| exps.push(exp); |
| this(loc, exps); |
| } |
| |
| extern (D) this(Loc loc, Expressions* exps) @safe |
| { |
| super(loc, STMT.Mixin); |
| this.exps = exps; |
| } |
| |
| override MixinStatement syntaxCopy() |
| { |
| return new MixinStatement(loc, Expression.arraySyntaxCopy(exps)); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) class CompoundStatement : Statement |
| { |
| Statements* statements; |
| |
| /** |
| * Construct a `CompoundStatement` using an already existing |
| * array of `Statement`s |
| * |
| * Params: |
| * loc = Instantiation information |
| * statements = An array of `Statement`s, that will referenced by this class |
| */ |
| final extern (D) this(Loc loc, Statements* statements) @safe |
| { |
| super(loc, STMT.Compound); |
| this.statements = statements; |
| } |
| |
| final extern (D) this(Loc loc, Statements* statements, STMT stmt) @safe |
| { |
| super(loc, stmt); |
| this.statements = statements; |
| } |
| |
| /** |
| * Construct a `CompoundStatement` from an array of `Statement`s |
| * |
| * Params: |
| * loc = Instantiation information |
| * sts = A variadic array of `Statement`s, that will copied in this class |
| * The entries themselves will not be copied. |
| */ |
| final extern (D) this(Loc loc, Statement[] sts...) |
| { |
| super(loc, STMT.Compound); |
| statements = new Statements(); |
| statements.reserve(sts.length); |
| foreach (s; sts) |
| statements.push(s); |
| } |
| |
| static CompoundStatement create(Loc loc, Statement s1, Statement s2) |
| { |
| return new CompoundStatement(loc, s1, s2); |
| } |
| |
| override CompoundStatement syntaxCopy() |
| { |
| return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements)); |
| } |
| |
| override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure |
| { |
| foreach (s; *statements) |
| { |
| if (s) |
| { |
| if (inout rs = s.endsWithReturnStatement()) |
| return rs; |
| } |
| } |
| return null; |
| } |
| |
| override final inout(Statement) last() inout nothrow pure |
| { |
| Statement s = null; |
| for (size_t i = statements.length; i; --i) |
| { |
| s = cast(Statement)(*statements)[i - 1]; |
| if (s) |
| { |
| s = cast(Statement)s.last(); |
| if (s) |
| break; |
| } |
| } |
| return cast(inout)s; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class CompoundDeclarationStatement : CompoundStatement |
| { |
| extern (D) this(Loc loc, Statements* statements) @safe |
| { |
| super(loc, statements, STMT.CompoundDeclaration); |
| } |
| |
| override CompoundDeclarationStatement syntaxCopy() |
| { |
| return new CompoundDeclarationStatement(loc, Statement.arraySyntaxCopy(statements)); |
| } |
| |
| override 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. |
| */ |
| extern (C++) final class UnrolledLoopStatement : Statement |
| { |
| Statements* statements; |
| |
| extern (D) this(Loc loc, Statements* statements) @safe |
| { |
| super(loc, STMT.UnrolledLoop); |
| this.statements = statements; |
| } |
| |
| override UnrolledLoopStatement syntaxCopy() |
| { |
| return new UnrolledLoopStatement(loc, Statement.arraySyntaxCopy(statements)); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class ScopeStatement : Statement |
| { |
| Statement statement; |
| Loc endloc; // location of closing curly bracket |
| |
| extern (D) this(Loc loc, Statement statement, Loc endloc) @safe |
| { |
| super(loc, STMT.Scope); |
| this.statement = statement; |
| this.endloc = endloc; |
| } |
| |
| override ScopeStatement syntaxCopy() |
| { |
| return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); |
| } |
| |
| override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure |
| { |
| if (statement) |
| return statement.endsWithReturnStatement(); |
| return null; |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| //printf("ScopeStatement::hasBreak() %s\n", toChars()); |
| return statement ? statement.hasBreak() : false; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return statement ? statement.hasContinue() : false; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * Statement whose symbol table contains foreach index variables in a |
| * local scope and forwards other members to the parent scope. This |
| * wraps a statement. |
| * |
| * Also see: `dmd.attrib.ForwardingAttribDeclaration` |
| */ |
| extern (C++) final class ForwardingStatement : Statement |
| { |
| /// The symbol containing the `static foreach` variables. |
| ForwardingScopeDsymbol sym = null; |
| /// The wrapped statement. |
| Statement statement; |
| |
| extern (D) this(Loc loc, ForwardingScopeDsymbol sym, Statement statement) @safe |
| { |
| super(loc, STMT.Forwarding); |
| this.sym = sym; |
| assert(statement); |
| this.statement = statement; |
| } |
| |
| extern (D) this(Loc loc, Statement statement) @safe |
| { |
| auto sym = new ForwardingScopeDsymbol(); |
| sym.symtab = new DsymbolTable(); |
| this(loc, sym, statement); |
| } |
| |
| override ForwardingStatement syntaxCopy() |
| { |
| return new ForwardingStatement(loc, statement.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#while-statement |
| */ |
| extern (C++) final class WhileStatement : Statement |
| { |
| Parameter param; |
| Expression condition; |
| Statement _body; |
| Loc endloc; // location of closing curly bracket |
| |
| extern (D) this(Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) @safe |
| { |
| super(loc, STMT.While); |
| this.condition = condition; |
| this._body = _body; |
| this.endloc = endloc; |
| this.param = param; |
| } |
| |
| override WhileStatement syntaxCopy() |
| { |
| return new WhileStatement(loc, |
| condition.syntaxCopy(), |
| _body ? _body.syntaxCopy() : null, |
| endloc, param ? param.syntaxCopy() : null); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#do-statement |
| */ |
| extern (C++) final class DoStatement : Statement |
| { |
| Statement _body; |
| Expression condition; |
| Loc endloc; // location of ';' after while |
| |
| extern (D) this(Loc loc, Statement _body, Expression condition, Loc endloc) @safe |
| { |
| super(loc, STMT.Do); |
| this._body = _body; |
| this.condition = condition; |
| this.endloc = endloc; |
| } |
| |
| override DoStatement syntaxCopy() |
| { |
| return new DoStatement(loc, |
| _body ? _body.syntaxCopy() : null, |
| condition.syntaxCopy(), |
| endloc); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#for-statement |
| */ |
| extern (C++) final class ForStatement : Statement |
| { |
| 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; |
| |
| extern (D) this(Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) @safe |
| { |
| super(loc, STMT.For); |
| this._init = _init; |
| this.condition = condition; |
| this.increment = increment; |
| this._body = _body; |
| this.endloc = endloc; |
| } |
| |
| override ForStatement syntaxCopy() |
| { |
| return new ForStatement(loc, |
| _init ? _init.syntaxCopy() : null, |
| condition ? condition.syntaxCopy() : null, |
| increment ? increment.syntaxCopy() : null, |
| _body.syntaxCopy(), |
| endloc); |
| } |
| |
| override Statement getRelatedLabeled() |
| { |
| return relatedLabeled ? relatedLabeled : this; |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| //printf("ForStatement::hasBreak()\n"); |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#foreach-statement |
| */ |
| extern (C++) final class ForeachStatement : Statement |
| { |
| TOK op; // TOK.foreach_ or TOK.foreach_reverse_ |
| Parameters* parameters; // array of Parameters, one for each ForeachType |
| Expression aggr; // ForeachAggregate |
| Statement _body; // NoScopeNonEmptyStatement |
| 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 |
| |
| extern (D) this(Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) @safe |
| { |
| super(loc, STMT.Foreach); |
| this.op = op; |
| this.parameters = parameters; |
| this.aggr = aggr; |
| this._body = _body; |
| this.endloc = endloc; |
| } |
| |
| override ForeachStatement syntaxCopy() |
| { |
| return new ForeachStatement(loc, op, |
| Parameter.arraySyntaxCopy(parameters), |
| aggr.syntaxCopy(), |
| _body ? _body.syntaxCopy() : null, |
| endloc); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#foreach-range-statement |
| */ |
| extern (C++) final class ForeachRangeStatement : Statement |
| { |
| TOK op; // TOK.foreach_ or TOK.foreach_reverse_ |
| Parameter param; // loop index variable |
| Expression lwr; |
| Expression upr; |
| Statement _body; |
| Loc endloc; // location of closing curly bracket |
| |
| VarDeclaration key; |
| |
| extern (D) this(Loc loc, TOK op, Parameter param, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe |
| { |
| super(loc, STMT.ForeachRange); |
| this.op = op; |
| this.param = param; |
| this.lwr = lwr; |
| this.upr = upr; |
| this._body = _body; |
| this.endloc = endloc; |
| } |
| |
| override ForeachRangeStatement syntaxCopy() |
| { |
| return new ForeachRangeStatement(loc, op, param.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#if-statement |
| */ |
| extern (C++) final class IfStatement : Statement |
| { |
| Parameter param; |
| Expression condition; |
| Statement ifbody; |
| Statement elsebody; |
| VarDeclaration match; // for MatchExpression results |
| Loc endloc; // location of closing curly bracket |
| |
| extern (D) this(Loc loc, Parameter param, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe |
| { |
| super(loc, STMT.If); |
| this.param = param; |
| this.condition = condition; |
| this.ifbody = ifbody; |
| this.elsebody = elsebody; |
| this.endloc = endloc; |
| } |
| |
| override IfStatement syntaxCopy() |
| { |
| return new IfStatement(loc, |
| param ? param.syntaxCopy() : null, |
| condition.syntaxCopy(), |
| ifbody ? ifbody.syntaxCopy() : null, |
| elsebody ? elsebody.syntaxCopy() : null, |
| endloc); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| |
| /****** |
| * Returns: true if `if (__ctfe)` |
| */ |
| bool isIfCtfeBlock() |
| { |
| if (auto cv = condition.isVarExp()) |
| return cv.var.ident == Id.ctfe; |
| return false; |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/version.html#ConditionalStatement |
| */ |
| extern (C++) final class ConditionalStatement : Statement |
| { |
| Condition condition; |
| Statement ifbody; |
| Statement elsebody; |
| |
| extern (D) this(Loc loc, Condition condition, Statement ifbody, Statement elsebody) @safe |
| { |
| super(loc, STMT.Conditional); |
| this.condition = condition; |
| this.ifbody = ifbody; |
| this.elsebody = elsebody; |
| } |
| |
| override ConditionalStatement syntaxCopy() |
| { |
| return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| |
| /*********************************************************** |
| * https://dlang.org/spec/version.html#StaticForeachStatement |
| * Static foreach statements, like: |
| * void main() |
| * { |
| * static foreach(i; 0 .. 10) |
| * { |
| * pragma(msg, i); |
| * } |
| * } |
| */ |
| extern (C++) final class StaticForeachStatement : Statement |
| { |
| StaticForeach sfe; |
| |
| extern (D) this(Loc loc, StaticForeach sfe) @safe |
| { |
| super(loc, STMT.StaticForeach); |
| this.sfe = sfe; |
| } |
| |
| override StaticForeachStatement syntaxCopy() |
| { |
| return new StaticForeachStatement(loc, sfe.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#pragma-statement |
| */ |
| extern (C++) final class PragmaStatement : Statement |
| { |
| const Identifier ident; |
| Expressions* args; // array of Expression's |
| Statement _body; |
| |
| extern (D) this(Loc loc, const Identifier ident, Expressions* args, Statement _body) @safe |
| { |
| super(loc, STMT.Pragma); |
| this.ident = ident; |
| this.args = args; |
| this._body = _body; |
| } |
| |
| override PragmaStatement syntaxCopy() |
| { |
| return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/version.html#StaticAssert |
| */ |
| extern (C++) final class StaticAssertStatement : Statement |
| { |
| StaticAssert sa; |
| |
| extern (D) this(StaticAssert sa) @safe |
| { |
| super(sa.loc, STMT.StaticAssert); |
| this.sa = sa; |
| } |
| |
| override StaticAssertStatement syntaxCopy() |
| { |
| return new StaticAssertStatement(sa.syntaxCopy(null)); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#switch-statement |
| */ |
| extern (C++) final class SwitchStatement : Statement |
| { |
| Parameter param; |
| Expression condition; /// switch(condition) |
| Statement _body; /// |
| bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement |
| Loc endloc; |
| |
| bool hasDefault; /// true if has default statement |
| bool hasVars; /// true if has variable case values |
| DefaultStatement sdefault; /// default: |
| Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion |
| TryFinallyStatement tryFinally; /// set if in the 'finally' block of a TryFinallyStatement |
| GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's |
| CaseStatements* cases; /// array of CaseStatement's |
| VarDeclaration lastVar; /// last observed variable declaration in this statement |
| |
| extern (D) this(Loc loc, Parameter param, Expression condition, Statement _body, bool isFinal, Loc endloc) |
| { |
| super(loc, STMT.Switch); |
| this.param = param; |
| this.condition = condition; |
| this._body = _body; |
| this.isFinal = isFinal; |
| this.endloc = endloc; |
| } |
| |
| override SwitchStatement syntaxCopy() |
| { |
| return new SwitchStatement(loc, |
| param ? param.syntaxCopy() : null, |
| condition.syntaxCopy(), |
| _body.syntaxCopy(), |
| isFinal, |
| endloc); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#CaseStatement |
| */ |
| extern (C++) final class CaseStatement : Statement |
| { |
| Expression exp; |
| Statement statement; |
| |
| int index; // which case it is (since we sort this) |
| VarDeclaration lastVar; |
| void* extra; // for use by Statement_toIR() |
| |
| extern (D) this(Loc loc, Expression exp, Statement statement) @safe |
| { |
| super(loc, STMT.Case); |
| this.exp = exp; |
| this.statement = statement; |
| } |
| |
| override CaseStatement syntaxCopy() |
| { |
| return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#CaseRangeStatement |
| */ |
| extern (C++) final class CaseRangeStatement : Statement |
| { |
| Expression first; |
| Expression last; |
| Statement statement; |
| |
| extern (D) this(Loc loc, Expression first, Expression last, Statement statement) @safe |
| { |
| super(loc, STMT.CaseRange); |
| this.first = first; |
| this.last = last; |
| this.statement = statement; |
| } |
| |
| override CaseRangeStatement syntaxCopy() |
| { |
| return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#DefaultStatement |
| */ |
| extern (C++) final class DefaultStatement : Statement |
| { |
| Statement statement; |
| |
| VarDeclaration lastVar; |
| |
| extern (D) this(Loc loc, Statement statement) @safe |
| { |
| super(loc, STMT.Default); |
| this.statement = statement; |
| } |
| |
| override DefaultStatement syntaxCopy() |
| { |
| return new DefaultStatement(loc, statement.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#GotoStatement |
| */ |
| extern (C++) final class GotoDefaultStatement : Statement |
| { |
| SwitchStatement sw; |
| |
| extern (D) this(Loc loc) @safe |
| { |
| super(loc, STMT.GotoDefault); |
| } |
| |
| override GotoDefaultStatement syntaxCopy() |
| { |
| return new GotoDefaultStatement(loc); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#GotoStatement |
| */ |
| extern (C++) final class GotoCaseStatement : Statement |
| { |
| Expression exp; // null, or which case to goto |
| |
| CaseStatement cs; // case statement it resolves to |
| |
| extern (D) this(Loc loc, Expression exp) @safe |
| { |
| super(loc, STMT.GotoCase); |
| this.exp = exp; |
| } |
| |
| override GotoCaseStatement syntaxCopy() |
| { |
| return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class SwitchErrorStatement : Statement |
| { |
| Expression exp; |
| |
| extern (D) this(Loc loc) @safe |
| { |
| super(loc, STMT.SwitchError); |
| } |
| |
| final extern (D) this(Loc loc, Expression exp) @safe |
| { |
| super(loc, STMT.SwitchError); |
| this.exp = exp; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#return-statement |
| */ |
| extern (C++) final class ReturnStatement : Statement |
| { |
| Expression exp; |
| size_t caseDim; |
| |
| extern (D) this(Loc loc, Expression exp) @safe |
| { |
| super(loc, STMT.Return); |
| this.exp = exp; |
| } |
| |
| override ReturnStatement syntaxCopy() |
| { |
| return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); |
| } |
| |
| override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure |
| { |
| return this; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#break-statement |
| */ |
| extern (C++) final class BreakStatement : Statement |
| { |
| Identifier ident; |
| |
| extern (D) this(Loc loc, Identifier ident) @safe |
| { |
| super(loc, STMT.Break); |
| this.ident = ident; |
| } |
| |
| override BreakStatement syntaxCopy() |
| { |
| return new BreakStatement(loc, ident); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#continue-statement |
| */ |
| extern (C++) final class ContinueStatement : Statement |
| { |
| Identifier ident; |
| |
| extern (D) this(Loc loc, Identifier ident) @safe |
| { |
| super(loc, STMT.Continue); |
| this.ident = ident; |
| } |
| |
| override ContinueStatement syntaxCopy() |
| { |
| return new ContinueStatement(loc, ident); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#SynchronizedStatement |
| */ |
| extern (C++) final class SynchronizedStatement : Statement |
| { |
| Expression exp; |
| Statement _body; |
| |
| extern (D) this(Loc loc, Expression exp, Statement _body) @safe |
| { |
| super(loc, STMT.Synchronized); |
| this.exp = exp; |
| this._body = _body; |
| } |
| |
| override SynchronizedStatement syntaxCopy() |
| { |
| return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return false; //true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return false; //true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#with-statement |
| */ |
| extern (C++) final class WithStatement : Statement |
| { |
| Expression exp; |
| Statement _body; |
| VarDeclaration wthis; |
| Loc endloc; |
| |
| extern (D) this(Loc loc, Expression exp, Statement _body, Loc endloc) @safe |
| { |
| super(loc, STMT.With); |
| this.exp = exp; |
| this._body = _body; |
| this.endloc = endloc; |
| } |
| |
| override WithStatement syntaxCopy() |
| { |
| return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#try-statement |
| */ |
| extern (C++) final class TryCatchStatement : Statement |
| { |
| Statement _body; |
| Catches* catches; |
| |
| Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion |
| |
| extern (D) this(Loc loc, Statement _body, Catches* catches) @safe |
| { |
| super(loc, STMT.TryCatch); |
| this._body = _body; |
| this.catches = catches; |
| } |
| |
| override TryCatchStatement syntaxCopy() |
| { |
| auto a = new Catches(catches.length); |
| foreach (i, c; *catches) |
| { |
| (*a)[i] = c.syntaxCopy(); |
| } |
| return new TryCatchStatement(loc, _body.syntaxCopy(), a); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return false; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#Catch |
| */ |
| extern (C++) final class Catch : RootObject |
| { |
| const Loc loc; |
| Type type; |
| Identifier ident; |
| Statement handler; |
| |
| VarDeclaration var; |
| bool errors; // set if semantic processing errors |
| |
| // was generated by the compiler, wasn't present in source code |
| bool internalCatch; |
| |
| extern (D) this(Loc loc, Type type, Identifier ident, Statement handler) @safe |
| { |
| //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); |
| this.loc = loc; |
| this.type = type; |
| this.ident = ident; |
| this.handler = handler; |
| } |
| |
| Catch syntaxCopy() |
| { |
| auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); |
| c.internalCatch = internalCatch; |
| return c; |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#try-statement |
| */ |
| extern (C++) final class TryFinallyStatement : Statement |
| { |
| 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 |
| |
| extern (D) this(Loc loc, Statement _body, Statement finalbody) @safe |
| { |
| super(loc, STMT.TryFinally); |
| this._body = _body; |
| this.finalbody = finalbody; |
| this.bodyFallsThru = true; // assume true until statementSemantic() |
| } |
| |
| static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody) @safe |
| { |
| return new TryFinallyStatement(loc, _body, finalbody); |
| } |
| |
| override TryFinallyStatement syntaxCopy() |
| { |
| return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return false; //true; |
| } |
| |
| override bool hasContinue() const pure nothrow |
| { |
| return false; //true; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#scope-guard-statement |
| */ |
| extern (C++) final class ScopeGuardStatement : Statement |
| { |
| TOK tok; |
| Statement statement; |
| |
| extern (D) this(Loc loc, TOK tok, Statement statement) @safe |
| { |
| super(loc, STMT.ScopeGuard); |
| this.tok = tok; |
| this.statement = statement; |
| } |
| |
| override ScopeGuardStatement syntaxCopy() |
| { |
| return new ScopeGuardStatement(loc, tok, statement.syntaxCopy()); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#throw-statement |
| */ |
| extern (C++) final class ThrowStatement : Statement |
| { |
| Expression exp; |
| |
| // was generated by the compiler, wasn't present in source code |
| bool internalThrow; |
| |
| extern (D) this(Loc loc, Expression exp) @safe |
| { |
| super(loc, STMT.Throw); |
| this.exp = exp; |
| } |
| |
| override ThrowStatement syntaxCopy() |
| { |
| auto s = new ThrowStatement(loc, exp.syntaxCopy()); |
| s.internalThrow = internalThrow; |
| return s; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class DebugStatement : Statement |
| { |
| Statement statement; |
| |
| extern (D) this(Loc loc, Statement statement) @safe |
| { |
| super(loc, STMT.Debug); |
| this.statement = statement; |
| } |
| |
| override DebugStatement syntaxCopy() |
| { |
| return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#goto-statement |
| */ |
| extern (C++) final class GotoStatement : Statement |
| { |
| Identifier ident; |
| LabelDsymbol label; |
| Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion |
| TryFinallyStatement tf; |
| ScopeGuardStatement os; |
| VarDeclaration lastVar; |
| bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block |
| |
| extern (D) this(Loc loc, Identifier ident) @safe |
| { |
| super(loc, STMT.Goto); |
| this.ident = ident; |
| } |
| |
| override GotoStatement syntaxCopy() |
| { |
| return new GotoStatement(loc, ident); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#LabeledStatement |
| */ |
| extern (C++) final class LabelStatement : Statement |
| { |
| Identifier ident; |
| Statement statement; |
| |
| Statement tryBody; /// set to 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' |
| bool inCtfeBlock; // inside a block dominated by `if (__ctfe)` |
| |
| extern (D) this(Loc loc, Identifier ident, Statement statement) @safe |
| { |
| super(loc, STMT.Label); |
| this.ident = ident; |
| this.statement = statement; |
| } |
| |
| override LabelStatement syntaxCopy() |
| { |
| return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| */ |
| extern (C++) final class LabelDsymbol : Dsymbol |
| { |
| LabelStatement statement; |
| |
| bool deleted; // set if rewritten to return in foreach delegate |
| bool iasm; // set if used by inline assembler |
| |
| // set if label was defined multiple times, to avoid duplicate errors |
| // can be removed if generic error message deduplication is implemented |
| bool duplicated; |
| |
| extern (D) this(Identifier ident, Loc loc = Loc.initial) @safe |
| { |
| super(DSYM.labelDsymbol, loc, ident); |
| } |
| |
| static LabelDsymbol create(Identifier ident) @safe |
| { |
| return new LabelDsymbol(ident); |
| } |
| |
| // is this a LabelDsymbol()? |
| override LabelDsymbol isLabel() |
| { |
| return this; |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/statement.html#asm |
| */ |
| extern (C++) class AsmStatement : Statement |
| { |
| Token* tokens; |
| bool caseSensitive; // for register names |
| |
| extern (D) this(Loc loc, Token* tokens) @safe |
| { |
| super(loc, STMT.Asm); |
| this.tokens = tokens; |
| } |
| |
| extern (D) this(Loc loc, Token* tokens, STMT stmt) @safe |
| { |
| super(loc, stmt); |
| this.tokens = tokens; |
| } |
| |
| override AsmStatement syntaxCopy() |
| { |
| return new AsmStatement(loc, tokens); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/iasm.html |
| */ |
| extern (C++) final class InlineAsmStatement : AsmStatement |
| { |
| void* asmcode; |
| uint asmalign; // alignment of this statement |
| uint 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 |
| |
| extern (D) this(Loc loc, Token* tokens) @safe |
| { |
| super(loc, tokens, STMT.InlineAsm); |
| } |
| |
| override InlineAsmStatement syntaxCopy() |
| { |
| return new InlineAsmStatement(loc, tokens); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html |
| * Assembler instructions with D expression operands. |
| */ |
| extern (C++) final class GccAsmStatement : AsmStatement |
| { |
| STC 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 |
| uint 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 |
| |
| extern (D) this(Loc loc, Token* tokens) @safe |
| { |
| super(loc, tokens, STMT.GccAsm); |
| } |
| |
| override GccAsmStatement syntaxCopy() |
| { |
| return new GccAsmStatement(loc, tokens); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * a complete asm {} block |
| */ |
| extern (C++) final class CompoundAsmStatement : CompoundStatement |
| { |
| STC stc; // postfix attributes like nothrow/pure/@trusted |
| |
| extern (D) this(Loc loc, Statements* statements, STC stc) @safe |
| { |
| super(loc, statements, STMT.CompoundAsm); |
| this.stc = stc; |
| } |
| |
| override CompoundAsmStatement syntaxCopy() |
| { |
| return new CompoundAsmStatement(loc, Statement.arraySyntaxCopy(statements), stc); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/module.html#ImportDeclaration |
| */ |
| extern (C++) final class ImportStatement : Statement |
| { |
| Dsymbols* imports; // Array of Import's |
| |
| extern (D) this(Loc loc, Dsymbols* imports) @safe |
| { |
| super(loc, STMT.Import); |
| this.imports = imports; |
| } |
| |
| override ImportStatement syntaxCopy() |
| { |
| auto m = new Dsymbols(imports.length); |
| foreach (i, s; *imports) |
| { |
| (*m)[i] = s.syntaxCopy(null); |
| } |
| return new ImportStatement(loc, m); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| |
| mixin template VisitStatement(Result) |
| { |
| Result VisitStatement(Statement s) |
| { |
| final switch (s.stmt) |
| { |
| case STMT.Error: mixin(visitStmtCase("Error")); |
| case STMT.Scope: mixin(visitStmtCase("Scope")); |
| case STMT.Exp: mixin(visitStmtCase("Exp")); |
| case STMT.Compound: mixin(visitStmtCase("Compound")); |
| case STMT.Return: mixin(visitStmtCase("Return")); |
| case STMT.If: mixin(visitStmtCase("If")); |
| case STMT.Conditional: mixin(visitStmtCase("Conditional")); |
| case STMT.StaticForeach: mixin(visitStmtCase("StaticForeach")); |
| case STMT.Case: mixin(visitStmtCase("Case")); |
| case STMT.Default: mixin(visitStmtCase("Default")); |
| case STMT.Label: mixin(visitStmtCase("Label")); |
| case STMT.Goto: mixin(visitStmtCase("Goto")); |
| case STMT.GotoDefault: mixin(visitStmtCase("GotoDefault")); |
| case STMT.GotoCase: mixin(visitStmtCase("GotoCase")); |
| case STMT.Break: mixin(visitStmtCase("Break")); |
| case STMT.DtorExp: mixin(visitStmtCase("DtorExp")); |
| case STMT.Mixin: mixin(visitStmtCase("Mixin")); |
| case STMT.Forwarding: mixin(visitStmtCase("Forwarding")); |
| case STMT.Do: mixin(visitStmtCase("Do")); |
| case STMT.While: mixin(visitStmtCase("While")); |
| case STMT.For: mixin(visitStmtCase("For")); |
| case STMT.Foreach: mixin(visitStmtCase("Foreach")); |
| case STMT.Switch: mixin(visitStmtCase("Switch")); |
| case STMT.Continue: mixin(visitStmtCase("Continue")); |
| case STMT.With: mixin(visitStmtCase("With")); |
| case STMT.TryCatch: mixin(visitStmtCase("TryCatch")); |
| case STMT.Throw: mixin(visitStmtCase("Throw")); |
| case STMT.Debug: mixin(visitStmtCase("Debug")); |
| case STMT.TryFinally: mixin(visitStmtCase("TryFinally")); |
| case STMT.ScopeGuard: mixin(visitStmtCase("ScopeGuard")); |
| case STMT.SwitchError: mixin(visitStmtCase("SwitchError")); |
| case STMT.UnrolledLoop: mixin(visitStmtCase("UnrolledLoop")); |
| case STMT.ForeachRange: mixin(visitStmtCase("ForeachRange")); |
| case STMT.CompoundDeclaration: mixin(visitStmtCase("CompoundDeclaration")); |
| case STMT.Peel: mixin(visitStmtCase("Peel")); |
| case STMT.CompoundAsm: mixin(visitStmtCase("CompoundAsm")); |
| case STMT.Pragma: mixin(visitStmtCase("Pragma")); |
| case STMT.StaticAssert: mixin(visitStmtCase("StaticAssert")); |
| case STMT.CaseRange: mixin(visitStmtCase("CaseRange")); |
| case STMT.Synchronized: mixin(visitStmtCase("Synchronized")); |
| case STMT.Asm: mixin(visitStmtCase("Asm")); |
| case STMT.InlineAsm: mixin(visitStmtCase("InlineAsm")); |
| case STMT.GccAsm: mixin(visitStmtCase("GccAsm")); |
| case STMT.Import: mixin(visitStmtCase("Import")); |
| } |
| } |
| } |
| |
| /**************************************** |
| * CTFE-only helper function for VisitInitializer. |
| * Params: |
| * handler = string for the name of the visit handler |
| * Returns: boilerplate code for a case |
| */ |
| pure string visitStmtCase(string handler) @safe |
| { |
| if (__ctfe) |
| { |
| return |
| " |
| enum isVoid = is(Result == void); |
| auto sx = s.is"~handler~"Statement(); |
| static if (__traits(compiles, visit"~handler~"(sx))) |
| { |
| static if (isVoid) |
| { |
| visit"~handler~"(sx); |
| return; |
| } |
| else |
| { |
| if (Result r = visit"~handler~"(sx)) |
| return r; |
| return Result.init; |
| } |
| } |
| else static if (__traits(compiles, visitDefaultCase(s))) |
| { |
| static if (isVoid) |
| { |
| visitDefaultCase(sx); |
| return; |
| } |
| else |
| { |
| if (Result r = visitDefaultCase(s)) |
| return r; |
| return Result.init; |
| } |
| } |
| else |
| static assert(0, "~handler~"); |
| "; |
| } |
| assert(0); |
| } |