summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/stmtstate.d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/stmtstate.d')
-rw-r--r--gcc/d/dmd/stmtstate.d142
1 files changed, 142 insertions, 0 deletions
diff --git a/gcc/d/dmd/stmtstate.d b/gcc/d/dmd/stmtstate.d
new file mode 100644
index 00000000000..bb13d7c0d06
--- /dev/null
+++ b/gcc/d/dmd/stmtstate.d
@@ -0,0 +1,142 @@
+/**
+ * Used to help transform statement AST into flow graph.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d)
+ * Documentation: https://dlang.org/phobos/dmd_stmtstate.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/stmtstate.d
+ */
+
+module dmd.stmtstate;
+
+import dmd.identifier;
+import dmd.statement;
+
+
+/************************************************
+ * Used to traverse the statement AST to transform it into
+ * a flow graph.
+ * Keeps track of things like "where does the `break` go".
+ * Params:
+ * block = type of the flow graph node
+ */
+struct StmtState(block)
+{
+ StmtState* prev;
+ Statement statement;
+
+ Identifier ident;
+ block* breakBlock;
+ block* contBlock;
+ block* switchBlock;
+ block* defaultBlock;
+ block* finallyBlock;
+ block* tryBlock;
+
+ this(StmtState* prev, Statement statement)
+ {
+ this.prev = prev;
+ this.statement = statement;
+ if (prev)
+ this.tryBlock = prev.tryBlock;
+ }
+
+ block* getBreakBlock(Identifier ident)
+ {
+ StmtState* bc;
+ if (ident)
+ {
+ Statement related = null;
+ block* ret = null;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ // The label for a breakBlock may actually be some levels up (e.g.
+ // on a try/finally wrapping a loop). We'll see if this breakBlock
+ // is the one to return once we reach that outer statement (which
+ // in many cases will be this same statement).
+ if (bc.breakBlock)
+ {
+ related = bc.statement.getRelatedLabeled();
+ ret = bc.breakBlock;
+ }
+ if (bc.statement == related && bc.prev.ident == ident)
+ return ret;
+ }
+ }
+ else
+ {
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.breakBlock)
+ return bc.breakBlock;
+ }
+ }
+ return null;
+ }
+
+ block* getContBlock(Identifier ident)
+ {
+ StmtState* bc;
+ if (ident)
+ {
+ block* ret = null;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ // The label for a contBlock may actually be some levels up (e.g.
+ // on a try/finally wrapping a loop). We'll see if this contBlock
+ // is the one to return once we reach that outer statement (which
+ // in many cases will be this same statement).
+ if (bc.contBlock)
+ {
+ ret = bc.contBlock;
+ }
+ if (bc.prev && bc.prev.ident == ident)
+ return ret;
+ }
+ }
+ else
+ {
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.contBlock)
+ return bc.contBlock;
+ }
+ }
+ return null;
+ }
+
+ block* getSwitchBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.switchBlock)
+ return bc.switchBlock;
+ }
+ return null;
+ }
+
+ block* getDefaultBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.defaultBlock)
+ return bc.defaultBlock;
+ }
+ return null;
+ }
+
+ block* getFinallyBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.finallyBlock)
+ return bc.finallyBlock;
+ }
+ return null;
+ }
+}