Code Map
module volta.ir.statement;
//! Base class for all statements.
class Statement : Node
{
public:
this(nt: NodeType) { }
this(nt: NodeType, old: Statement) { }
}
//! A block statement is a group of zero or more statements. Why these
//! exist depends on where they live.
class BlockStatement : Statement
{
public:
statements: Node[];
myScope: Scope;
public:
this() { }
this(old: BlockStatement) { }
}
//! The return statement returns execution to the caller of the current
//! function, and optionally returns a value.
class ReturnStatement : Statement
{
public:
exp: Exp;
public:
this() { }
this(old: ReturnStatement) { }
}
//! The asm statement contains inline assembly. It's a list of tokens so
//! different backends can parse it however they want. It all still has to
//! lex as valid Volt, of course.
class AsmStatement : Statement
{
public:
tokens: Token[];
public:
this() { }
this(old: AsmStatement) { }
}
//! The assert statement aborts if condition is flase, optionally
//! displaying message. isStatic determines whether condition is checked at
//! compile time or not.
class AssertStatement : Statement
{
public:
condition: Exp;
message: Exp;
isStatic: bool;
public:
this() { }
this(old: AssertStatement) { }
}
//! If exp is true, execution flows to thenState. If exp is false,
//! execution flows to elseState, if it exists, otherwise it skips to the
//! end of the if statement.
class IfStatement : Statement
{
public:
exp: Exp;
thenState: BlockStatement;
elseState: BlockStatement;
autoName: string;
public:
this() { }
this(old: IfStatement) { }
}
//! The while statement keeps executing the statements in block, as long as
//! condition evaluates in true.
class WhileStatement : Statement
{
public:
condition: Exp;
block: BlockStatement;
public:
this() { }
this(old: WhileStatement) { }
}
//! Like a while statement, executes block while condition is true. Unlike
//! the while statement, at least one execution of block is guaranteed.
class DoStatement : Statement
{
public:
block: BlockStatement;
condition: Exp;
public:
this() { }
this(old: DoStatement) { }
}
//! The for statement is a while statement that evaluates init first
//! (optionally introducing Variables into the for's scope), and running
//! increment at the end of each block's execution. Other than that, it
//! keeps executing block while test evaluates to true.
class ForStatement : Statement
{
public:
initVars: Variable[];
initExps: Exp[];
test: Exp;
increments: Exp[];
block: BlockStatement;
public:
this() { }
this(old: ForStatement) { }
}
//! The foreach statement loops over elements in an aggregate. Arrays and
//! AAs have builtin support, but users can define iteration solutions for
//! their own types too.
class ForeachStatement : Statement
{
public:
reverse: bool;
itervars: Variable[];
refvars: bool[];
aggregate: Exp;
beginIntegerRange: Exp;
endIntegerRange: Exp;
block: BlockStatement;
opApplyType: Named;
decodeFunction: Function;
public:
this() { }
this(old: ForeachStatement) { }
}
//! A label statement associates a string with a position in the statement
//! stream. Goto can then be used to jump to that position and anger
//! Dijkstra.
class LabelStatement : Statement
{
public:
label: string;
childStatement: Node[];
public:
this() { }
this(old: LabelStatement) { }
}
//! An ExpStatement wraps an Expression in a Statement.
class ExpStatement : Statement
{
public:
exp: Exp;
public:
this() { }
this(old: ExpStatement) { }
}
//! Represents a case in a switch statement.
class SwitchCase : Node
{
public:
firstExp: Exp;
originalFirstExp: Exp;
secondExp: Exp;
originalSecondExp: Exp;
exps: Exp[];
originalExps: Exp[];
isDefault: bool;
statements: BlockStatement;
public:
this() { }
this(old: SwitchCase) { }
}
//! A switch statement jumps to various case labels depending on the value
//! of its condition.
class SwitchStatement : Statement
{
public:
isFinal: bool;
condition: Exp;
cases: SwitchCase[];
withs: Exp[];
condVar: Variable;
public:
this() { }
this(old: SwitchStatement) { }
}
//! The continue statement restarts a loop (while, dowhile, for, foreach).
class ContinueStatement : Statement
{
public:
label: string;
public:
this() { }
this(old: ContinueStatement) { }
}
//! The break statement halts execution of a loop or a switch statement.
class BreakStatement : Statement
{
public:
label: string;
public:
this() { }
this(old: BreakStatement) { }
}
//! The goto statement jumps to a label, or controls flow inside a switch
//! statement.
class GotoStatement : Statement
{
public:
label: string;
isDefault: bool;
isCase: bool;
exp: Exp;
public:
this() { }
this(old: GotoStatement) { }
}
//! All lookups inside of a WithStatement first check exp before performing
//! a regular lookup. Ambiguities are still errors.
class WithStatement : Statement
{
public:
exp: Exp;
block: BlockStatement;
public:
this() { }
this(old: WithStatement) { }
}
//! A synchronized statement ensures that only one thread of execution can
//! enter its block. An explicit mutex may be provided.
class SynchronizedStatement : Statement
{
public:
exp: Exp;
block: BlockStatement;
public:
this() { }
this(old: SynchronizedStatement) { }
}
//! The try statement allows the resolution of throw statements, by
//! rerouting thrown exceptions into various catch blocks.
class TryStatement : Statement
{
public:
tryBlock: BlockStatement;
catchVars: Variable[];
catchBlocks: BlockStatement[];
finallyBlock: BlockStatement;
public:
this() { }
this(old: TryStatement) { }
}
//! A throw statements halts the current functions execution and unwinds
//! the stack until it hits a try statement with an appropriate catch
//! statement or, failing that, it halts execution of the entire program.
class ThrowStatement : Statement
{
public:
exp: Exp;
public:
this() { }
this(old: ThrowStatement) { }
}
//! ScopeStatements are executed on various conditions. Exits are always
//! executed when the given scope is left. Successes are executed when the
//! scope is left normally. Failures are executed when the scope is left by
//! way of an Exception.
class ScopeStatement : Statement
{
public:
kind: ScopeKind;
block: BlockStatement;
public:
this() { }
this(old: ScopeStatement) { }
}
//! Pragma statements do magical things. pragma(lib, "SDL"), for instance,
//! tells the compiler to link with SDL without the user having to specify
//! it on the command line. What pragmas are supported vary from compiler
//! to compiler, the only thing specified is that complying implementations
//! must die on unknown pragmas by default.
class PragmaStatement : Statement
{
public:
type: string;
arguments: Exp[];
block: BlockStatement;
public:
this() { }
this(old: PragmaStatement) { }
}
//! A ConditionStatement provides for conditional compilation of
//! statements. If condition is true, then it is as if block was where the
//! ConditionStatement was. Otherwise, the _else block replaces it (if
//! present).
class ConditionStatement : Statement
{
public:
condition: Condition;
block: BlockStatement;
_else: BlockStatement;
public:
this() { }
this(old: ConditionStatement) { }
}
//! The mixin statement mixes in a mixin function, mixin template or a
//! string.
class MixinStatement : Statement
{
public:
//! Not optional for mixin("string").
stringExp: Exp;
//! Not optional for mixin .my.Ident!(...)
id: QualifiedName;
resolved: BlockStatement;
public:
this() { }
this(old: MixinStatement) { }
}
Base class for all statements.
A block statement is a group of zero or more statements. Why these exist depends on where they live.
The return statement returns execution to the caller of the current function, and optionally returns a value.
The asm statement contains inline assembly. It's a list of tokens so different backends can parse it however they want. It all still has to lex as valid Volt, of course.
The assert statement aborts if condition is flase, optionally displaying message. isStatic determines whether condition is checked at compile time or not.
If exp is true, execution flows to thenState. If exp is false, execution flows to elseState, if it exists, otherwise it skips to the end of the if statement.
The while statement keeps executing the statements in block, as long as condition evaluates in true.
Like a while statement, executes block while condition is true. Unlike the while statement, at least one execution of block is guaranteed.
The for statement is a while statement that evaluates init first (optionally introducing Variables into the for's scope), and running increment at the end of each block's execution. Other than that, it keeps executing block while test evaluates to true.
for (init; test; increment) block
The foreach statement loops over elements in an aggregate. Arrays and AAs have builtin support, but users can define iteration solutions for their own types too.
A label statement associates a string with a position in the statement stream. Goto can then be used to jump to that position and anger Dijkstra.
An ExpStatement wraps an Expression in a Statement.
Represents a case in a switch statement.
If firstExp !is null and secondExp is null: case firstExp: If firstExp !is null and secondExp !is null: case firstExp: .. case secondExp: If exps.length > 0: case exps[0], exps[1], ... exps[$-1]: If isDefault: default:
The above are all mutually exclusive.
A switch statement jumps to various case labels depending on the value of its condition.
Fallthrough is only permitted on empty cases, unlike C and C++.
The continue statement restarts a loop (while, dowhile, for, foreach).
The break statement halts execution of a loop or a switch statement.
The goto statement jumps to a label, or controls flow inside a switch statement.
All lookups inside of a WithStatement first check exp before performing a regular lookup. Ambiguities are still errors.
A synchronized statement ensures that only one thread of execution can enter its block. An explicit mutex may be provided.
The try statement allows the resolution of throw statements, by rerouting thrown exceptions into various catch blocks.
A throw statements halts the current functions execution and unwinds the stack until it hits a try statement with an appropriate catch statement or, failing that, it halts execution of the entire program.
ScopeStatements are executed on various conditions. Exits are always executed when the given scope is left. Successes are executed when the scope is left normally. Failures are executed when the scope is left by way of an Exception.
Pragma statements do magical things. pragma(lib, "SDL"), for instance, tells the compiler to link with SDL without the user having to specify it on the command line. What pragmas are supported vary from compiler to compiler, the only thing specified is that complying implementations must die on unknown pragmas by default.
A ConditionStatement provides for conditional compilation of statements. If condition is true, then it is as if block was where the ConditionStatement was. Otherwise, the _else block replaces it (if present).
The mixin statement mixes in a mixin function, mixin template or a string.
Not optional for mixin("string").
Not optional for mixin .my.Ident!(...)