| /** |
| * Defines AST nodes for statements. |
| * |
| * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) |
| * |
| * Copyright: Copyright (C) 1999-2022 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/src/dmd/statement.d, _statement.d) |
| * Documentation: https://dlang.org/phobos/dmd_statement.html |
| * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d |
| */ |
| |
| module dmd.statement; |
| |
| import core.stdc.stdarg; |
| import core.stdc.stdio; |
| |
| import dmd.aggregate; |
| import dmd.arraytypes; |
| import dmd.astenums; |
| import dmd.ast_node; |
| import dmd.gluelayer; |
| import dmd.cond; |
| import dmd.dclass; |
| import dmd.declaration; |
| import dmd.denum; |
| import dmd.dimport; |
| import dmd.dscope; |
| import dmd.dsymbol; |
| import dmd.dtemplate; |
| import dmd.errors; |
| import dmd.expression; |
| import dmd.func; |
| import dmd.globals; |
| import dmd.hdrgen; |
| import dmd.id; |
| import dmd.identifier; |
| import dmd.dinterpret; |
| import dmd.mtype; |
| import dmd.common.outbuffer; |
| import dmd.root.rootobject; |
| import dmd.sapply; |
| import dmd.sideeffect; |
| import dmd.staticassert; |
| import dmd.tokens; |
| import dmd.visitor; |
| |
| /** |
| * Returns: |
| * `TypeIdentifier` corresponding to `object.Throwable` |
| */ |
| TypeIdentifier getThrowable() |
| { |
| auto tid = new TypeIdentifier(Loc.initial, Id.empty); |
| tid.addIdent(Id.object); |
| tid.addIdent(Id.Throwable); |
| return tid; |
| } |
| |
| /** |
| * Returns: |
| * TypeIdentifier corresponding to `object.Exception` |
| */ |
| TypeIdentifier getException() |
| { |
| auto tid = new TypeIdentifier(Loc.initial, Id.empty); |
| tid.addIdent(Id.object); |
| tid.addIdent(Id.Exception); |
| return tid; |
| } |
| |
| /*********************************************************** |
| * 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(const ref Loc loc, STMT stmt) |
| { |
| 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; |
| } |
| |
| override final const(char)* toChars() const |
| { |
| HdrGenState hgs; |
| OutBuffer buf; |
| .toCBuffer(this, &buf, &hgs); |
| buf.writeByte(0); |
| return buf.extractSlice().ptr; |
| } |
| |
| static if (__VERSION__ < 2092) |
| { |
| final void error(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .verror(loc, format, ap); |
| va_end(ap); |
| } |
| |
| final void warning(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .vwarning(loc, format, ap); |
| va_end(ap); |
| } |
| |
| final void deprecation(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .vdeprecation(loc, format, ap); |
| va_end(ap); |
| } |
| } |
| else |
| { |
| pragma(printf) final void error(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .verror(loc, format, ap); |
| va_end(ap); |
| } |
| |
| pragma(printf) final void warning(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .vwarning(loc, format, ap); |
| va_end(ap); |
| } |
| |
| pragma(printf) final void deprecation(const(char)* format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| .vdeprecation(loc, format, ap); |
| va_end(ap); |
| } |
| } |
| |
| 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 |
| */ |
| 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 |
| */ |
| 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. |
| */ |
| 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) |
| { |
| } |
| } |
| |
| 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 @safe: |
| |
| /******************** |
| * 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(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(CompileStatement) isCompileStatement() { return stmt == STMT.Compile ? 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; } |
| } |
| |
| /*********************************************************** |
| * 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); |
| 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) |
| { |
| 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(const ref Loc loc, Expression exp) |
| { |
| super(loc, STMT.Exp); |
| this.exp = exp; |
| } |
| |
| final extern (D) this(const ref Loc loc, Expression exp, STMT stmt) |
| { |
| super(loc, stmt); |
| this.exp = exp; |
| } |
| |
| final extern (D) this(const ref Loc loc, Dsymbol declaration) |
| { |
| super(loc, STMT.Exp); |
| this.exp = new DeclarationExp(loc, declaration); |
| } |
| |
| static ExpStatement create(const ref Loc loc, Expression exp) |
| { |
| 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(const ref Loc loc, Expression exp, VarDeclaration var) |
| { |
| 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 |
| */ |
| extern (C++) final class CompileStatement : Statement |
| { |
| Expressions* exps; |
| |
| extern (D) this(const ref Loc loc, Expression exp) |
| { |
| Expressions* exps = new Expressions(); |
| exps.push(exp); |
| this(loc, exps); |
| } |
| |
| extern (D) this(const ref Loc loc, Expressions* exps) |
| { |
| super(loc, STMT.Compile); |
| this.exps = exps; |
| } |
| |
| override CompileStatement syntaxCopy() |
| { |
| return new CompileStatement(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(const ref Loc loc, Statements* statements) |
| { |
| super(loc, STMT.Compound); |
| this.statements = statements; |
| } |
| |
| final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt) |
| { |
| 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(const ref Loc loc, Statement[] sts...) |
| { |
| super(loc, STMT.Compound); |
| statements = new Statements(); |
| statements.reserve(sts.length); |
| foreach (s; sts) |
| statements.push(s); |
| } |
| |
| static CompoundStatement create(const ref 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.dim; 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(const ref Loc loc, Statements* statements) |
| { |
| super(loc, statements, STMT.CompoundDeclaration); |
| } |
| |
| override CompoundDeclarationStatement syntaxCopy() |
| { |
| auto a = new Statements(statements.dim); |
| foreach (i, s; *statements) |
| { |
| (*a)[i] = s ? s.syntaxCopy() : null; |
| } |
| return new CompoundDeclarationStatement(loc, a); |
| } |
| |
| 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(const ref Loc loc, Statements* statements) |
| { |
| super(loc, STMT.UnrolledLoop); |
| this.statements = statements; |
| } |
| |
| override UnrolledLoopStatement syntaxCopy() |
| { |
| auto a = new Statements(statements.dim); |
| foreach (i, s; *statements) |
| { |
| (*a)[i] = s ? s.syntaxCopy() : null; |
| } |
| return new UnrolledLoopStatement(loc, a); |
| } |
| |
| 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(const ref Loc loc, Statement statement, Loc endloc) |
| { |
| 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(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement) |
| { |
| super(loc, STMT.Forwarding); |
| this.sym = sym; |
| assert(statement); |
| this.statement = statement; |
| } |
| |
| extern (D) this(const ref Loc loc, Statement statement) |
| { |
| 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(const ref Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) |
| { |
| 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(const ref Loc loc, Statement _body, Expression condition, Loc endloc) |
| { |
| 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(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) |
| { |
| 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(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) |
| { |
| 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 prm; // loop index variable |
| Expression lwr; |
| Expression upr; |
| Statement _body; |
| Loc endloc; // location of closing curly bracket |
| |
| VarDeclaration key; |
| |
| extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) |
| { |
| super(loc, STMT.ForeachRange); |
| this.op = op; |
| this.prm = prm; |
| this.lwr = lwr; |
| this.upr = upr; |
| this._body = _body; |
| this.endloc = endloc; |
| } |
| |
| override ForeachRangeStatement syntaxCopy() |
| { |
| return new ForeachRangeStatement(loc, op, prm.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 prm; |
| Expression condition; |
| Statement ifbody; |
| Statement elsebody; |
| VarDeclaration match; // for MatchExpression results |
| Loc endloc; // location of closing curly bracket |
| |
| extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) |
| { |
| super(loc, STMT.If); |
| this.prm = prm; |
| this.condition = condition; |
| this.ifbody = ifbody; |
| this.elsebody = elsebody; |
| this.endloc = endloc; |
| } |
| |
| override IfStatement syntaxCopy() |
| { |
| return new IfStatement(loc, |
| prm ? prm.syntaxCopy() : null, |
| condition.syntaxCopy(), |
| ifbody ? ifbody.syntaxCopy() : null, |
| elsebody ? elsebody.syntaxCopy() : null, |
| endloc); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |
| |
| /*********************************************************** |
| * https://dlang.org/spec/version.html#ConditionalStatement |
| */ |
| extern (C++) final class ConditionalStatement : Statement |
| { |
| Condition condition; |
| Statement ifbody; |
| Statement elsebody; |
| |
| extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) |
| { |
| 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(const ref Loc loc, StaticForeach sfe) |
| { |
| 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(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body) |
| { |
| 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) |
| { |
| 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 |
| { |
| Expression condition; /// switch(condition) |
| Statement _body; /// |
| bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement |
| |
| DefaultStatement sdefault; /// default: |
| Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion |
| TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement |
| 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; /// last observed variable declaration in this statement |
| |
| extern (D) this(const ref Loc loc, Expression condition, Statement _body, bool isFinal) |
| { |
| super(loc, STMT.Switch); |
| this.condition = condition; |
| this._body = _body; |
| this.isFinal = isFinal; |
| } |
| |
| override SwitchStatement syntaxCopy() |
| { |
| return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal); |
| } |
| |
| override bool hasBreak() const pure nothrow |
| { |
| return true; |
| } |
| |
| /************************************ |
| * Returns: |
| * true if error |
| */ |
| extern (D) bool checkLabel() |
| { |
| /* |
| * Checks the scope of a label for existing variable declaration. |
| * Params: |
| * vd = last variable declared before this case/default label |
| * Returns: `true` if the variables declared in this label would be skipped. |
| */ |
| bool checkVar(VarDeclaration vd) |
| { |
| for (auto v = vd; v && v != lastVar; v = v.lastVar) |
| { |
| if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp) && vd.ident != Id.withSym) || v._init.isVoidInitializer()) |
| continue; |
| if (vd.ident == Id.withSym) |
| error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars()); |
| else |
| error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars()); |
| return true; |
| } |
| return false; |
| } |
| |
| enum error = true; |
| |
| if (sdefault && checkVar(sdefault.lastVar)) |
| return !error; // return error once fully deprecated |
| |
| foreach (scase; *cases) |
| { |
| if (scase && checkVar(scase.lastVar)) |
| return !error; // return error once fully deprecated |
| } |
| return !error; |
| } |
| |
| 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(const ref Loc loc, Expression exp, Statement statement) |
| { |
| 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(const ref Loc loc, Expression first, Expression last, Statement statement) |
| { |
| 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(const ref Loc loc, Statement statement) |
| { |
| 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(const ref Loc loc) |
| { |
| 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(const ref Loc loc, Expression exp) |
| { |
| 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(const ref Loc loc) |
| { |
| super(loc, STMT.SwitchError); |
| } |
| |
| final extern (D) this(const ref Loc loc, Expression exp) |
| { |
| 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(const ref Loc loc, Expression exp) |
| { |
| 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(const ref Loc loc, Identifier ident) |
| { |
| 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(const ref Loc loc, Identifier ident) |
| { |
| 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(const ref Loc loc, Expression exp, Statement _body) |
| { |
| 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(const ref Loc loc, Expression exp, Statement _body, Loc endloc) |
| { |
| 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(const ref Loc loc, Statement _body, Catches* catches) |
| { |
| super(loc, STMT.TryCatch); |
| this._body = _body; |
| this.catches = catches; |
| } |
| |
| override TryCatchStatement syntaxCopy() |
| { |
| auto a = new Catches(catches.dim); |
| 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(const ref Loc loc, Type type, Identifier ident, Statement handler) |
| { |
| //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(const ref Loc loc, Statement _body, Statement finalbody) |
| { |
| super(loc, STMT.TryFinally); |
| this._body = _body; |
| this.finalbody = finalbody; |
| this.bodyFallsThru = true; // assume true until statementSemantic() |
| } |
| |
| static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody) |
| { |
| 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(const ref Loc loc, TOK tok, Statement statement) |
| { |
| 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(const ref Loc loc, Expression exp) |
| { |
| 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(const ref Loc loc, Statement statement) |
| { |
| 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; |
| |
| extern (D) this(const ref Loc loc, Identifier ident) |
| { |
| super(loc, STMT.Goto); |
| this.ident = ident; |
| } |
| |
| override GotoStatement syntaxCopy() |
| { |
| return new GotoStatement(loc, ident); |
| } |
| |
| /************** |
| * Returns: true for error |
| */ |
| extern (D) bool checkLabel() |
| { |
| if (!label.statement) |
| return true; // error should have been issued for this already |
| |
| if (label.statement.os != os) |
| { |
| if (os && os.tok == TOK.onScopeFailure && !label.statement.os) |
| { |
| // Jump out from scope(failure) block is allowed. |
| } |
| else |
| { |
| if (label.statement.os) |
| error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); |
| else |
| error("cannot `goto` out of `%s` block", Token.toChars(os.tok)); |
| return true; |
| } |
| } |
| |
| if (label.statement.tf != tf) |
| { |
| error("cannot `goto` in or out of `finally` block"); |
| return true; |
| } |
| |
| Statement stbnext; |
| for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext) |
| { |
| if (!stb) |
| { |
| error("cannot `goto` into `try` block"); |
| return true; |
| } |
| if (auto stf = stb.isTryFinallyStatement()) |
| stbnext = stf.tryBody; |
| else if (auto stc = stb.isTryCatchStatement()) |
| stbnext = stc.tryBody; |
| else |
| assert(0); |
| } |
| |
| VarDeclaration vd = label.statement.lastVar; |
| if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest)) |
| return false; |
| |
| VarDeclaration last = lastVar; |
| while (last && last != vd) |
| last = last.lastVar; |
| if (last == vd) |
| { |
| // All good, the label's scope has no variables |
| } |
| else if (vd.storage_class & STC.exptemp) |
| { |
| // Lifetime ends at end of expression, so no issue with skipping the statement |
| } |
| else if (vd.ident == Id.withSym) |
| { |
| error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars()); |
| return true; |
| } |
| else |
| { |
| error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars()); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| 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' |
| |
| extern (D) this(const ref Loc loc, Identifier ident, Statement statement) |
| { |
| 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 |
| |
| extern (D) this(Identifier ident, const ref Loc loc = Loc.initial) |
| { |
| super(loc, ident); |
| } |
| |
| static LabelDsymbol create(Identifier ident) |
| { |
| 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; |
| |
| extern (D) this(const ref Loc loc, Token* tokens) |
| { |
| super(loc, STMT.Asm); |
| this.tokens = tokens; |
| } |
| |
| extern (D) this(const ref Loc loc, Token* tokens, STMT stmt) |
| { |
| 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 |
| { |
| code* 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(const ref Loc loc, Token* tokens) |
| { |
| 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 |
| { |
| 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 |
| 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(const ref Loc loc, Token* tokens) |
| { |
| 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 |
| { |
| StorageClass stc; // postfix attributes like nothrow/pure/@trusted |
| |
| extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc) |
| { |
| super(loc, statements, STMT.CompoundAsm); |
| this.stc = stc; |
| } |
| |
| override CompoundAsmStatement syntaxCopy() |
| { |
| auto a = new Statements(statements.dim); |
| foreach (i, s; *statements) |
| { |
| (*a)[i] = s ? s.syntaxCopy() : null; |
| } |
| return new CompoundAsmStatement(loc, a, 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(const ref Loc loc, Dsymbols* imports) |
| { |
| super(loc, STMT.Import); |
| this.imports = imports; |
| } |
| |
| override ImportStatement syntaxCopy() |
| { |
| auto m = new Dsymbols(imports.dim); |
| foreach (i, s; *imports) |
| { |
| (*m)[i] = s.syntaxCopy(null); |
| } |
| return new ImportStatement(loc, m); |
| } |
| |
| override void accept(Visitor v) |
| { |
| v.visit(this); |
| } |
| } |