A statement is an entity in the abstract syntax that describes actions to be taken by a thread. Statements are executed for their effect, rather than evaluated to produce a value.
Statement :
ExpressionStatement
| DeclarationStatement
| BlockStatement
| EmptyStatement
| IfStatement
| SwitchStatement
| CaseStmt
| ForStatement
| WhileStatement
| DoWhileStatement
| BreakStatement
| ContinueStatement
| ReturnStatement
| DiscardStatement
| LabeledStatement
An expression statement evaluates an expression, and then ignores the resulting value.
ExpressionStatement :
Expression `;`
GIVEN context c, expression e
GIVEN e synthesizes type t in context c
THEN e `;` checks in context c
An implementation may diagnose a warning when execution of an expression statement cannot have side effects.
A declaration statement introduces a declaration into the current scope.
DeclarationStatement :
Declaration
GIVEN context c, declaration d
GIVEN declaration d checks in context c
THEN statement d checks in context c
Only the following types of declarations may be used in a declaration statement:
- VariableDeclaration}
A block statement executes each of its constituent statements in order.
BlockStatement :
`{` Statement* `}`
GIVEN context c
GIVEN statements s0,s1,...
GIVEN context d, a fresh sub-context of c
GIVEN s0,s1,... check in d
THEN `{` s0,s1,... `}` checks in c
Note: Declarations in a block statement are visible to later statements in the same block, but not to earlier statements in the block, or to code outside the block.
Executing an empty statement has no effect.
EmptyStatement :
`;`
GIVEN context c
THEN `;` checks in c
An if
statement executes a sub-statement conditionally.
IfStatement :
`if` `(` IfCondition `)`
Statement
ElseClause?
IfCondition :
Expression
| LetDeclaration
ElseClause :
`else` Statement
GIVEN context c, expression e, statement t
GIVEN e checks against `Bool` in c
GIVEN t checks in C
THEN `if(` e `)` t checks in c
GIVEN context c, expression e, statement t
GIVEN e checks against `Bool` in c
GIVEN t checks in C
GIVEN f checks in C
THEN `if(` e `)` t `else` f checks in c
If the condition of an if
statement is an expression, then it is evaluated against an expected type of Bool
to yield a value |C|.
If |C| is true
, then the ThenClause is executed.
If |C| is false
and there is a ElseClause, then it is executed.
If the condition of an if
statement is a let
declaration, then that declaration must have an initial-value expression.
That initial-value expression is evaluated against an expected type of Optional<T>
, where |T| is a fresh type variable, to yield a value |D|.
If |D| is Some(|C|)
, then the ThenClause is executed, in an environment where the name of the let
declaration is bound to |C|.
If |D| is null
and there is a ElseClause, then it is executed.
A switch
statement conditionally executes up to one of its alternatives, based on the value of an expression.
SwitchStatement :
`switch` `(` Expression `)`
`{` SwitchAlternative+ `}`
SwitchAlternative :
SwitchAlternativeLabel+ Statement+
SwitchAlternativeLabel :
CaseClause
| DefaultClause
CaseClause :
`case` Expression `:`
DefaultClause
`default` `:`
GIVEN context c, expression e, switch alternatives a0,a1,...
GIVEN e synthesizes type t in c
GIVEN a0,a1,... check against t in c
THEN `switch(` e `) {` a0,a1,... `}` checks in c
Note:
A switch
statement is checked by first checking the expression, and then checking each of the alternatives against the type of that expression.
GIVEN context c, type t,
GIVEN switch alternative labels l0,l1,...
GIVEN statements s0,s1,...
GIVEN l0,l1,... check against t in c
GIVEN s0,s1,... check in c
THEN switch alternative l0,l1,... s0,s1,... checks in c
GIVEN context c, type t, expression e
GIVEN e checks against t in c
THEN `case` e `:` checks against t in c
GIVEN context c, type t
THEN `default:` checks against t in c
Note:
A case
clause is valid if its expression checks against the type of the control expressio nof the switch
statement.
A switch
statement may have at most one default
clause.
If the type of the controlling expression of a switch
statement is a built-in integer type, then:
- The expression of each
case
clause must be a compile-time constant expression. - The constant value of the expression for each
case
clause must not be equal to that of any othercase
clause in the sameswitch
.
Each alternative of a switch
statement must exit the switch
statement via a break
or other control transfer statement.
"Fall-through" from one switch case clause to another is not allowed.
Note:
Semantically, a switch
statement is equivalent to an "if
cascade" that compares the value of the conditional expression against each case
clause,
ForStatement :
`for` `(`
initial:Statement? `;`
conditional:Expression? `;`
sideEffect:Expression? `)`
body:Statement
GIVEN init checks in c
GIVEN cond checks against `Bool` in c
GIVEN iter synthesizes type t in c
GIVEN body checks in c
THEN `for(init;cond;iter) body` checks in c
Issue: The checking judgements above aren't complete because they don't handle the case where |cond| is absent, in which case it should be treated like it was true
.
WhileStatement :
`while` `(`
conditional:Expression? `)`
body:Statement
GIVEN cond checks against `Bool` in c
GIVEN body checks in c
THEN `while(cond) body` checks in c
A do-while statement uses the following form:
DoWhileStatement :
`do` body:Statement
`while` `(` conditional:Expression? `)` `;`
GIVEN body checks in c
GIVEN cond checks againt `Bool` in c
THEN `do body while(cond);` checks in c
Issue: These simplified prose checking rules are leaving out all the subtlties of sub-contexts, etc.
BreakStatement :
`break` label:Identifier? `;`
A [[=break statement=]] without a [[=label=]] transfers control to after the end of the closest lexically enclosing [[=switch statement=]] or [[=loop statement=]].
A [[=break statement=]] with a [[=label=]] transfers control to after the end of the lexically enclosing [[=switch statement=]] or [[=loop statement=]] labeled with a matching [[=label=]].
GIVEN context c
GIVEN lookup of BREAK_LABEL in c yields label l
THEN `break;` checks in context c
GIVEN context c, label l
GIVEN c contains an entry of the form BREAK_LABEL = l
THEN `break l;` checks in context c
We also need to define the context-containment rule that is being used to look up the break
item in the context.
ContinueStatement :
`continue` label:Identifier? `;`
A continue
statement transfers control to the start of the next iteration of a loop statement.
In a for
statement with a side effect expression, the side effect expression is evaluated when continue
is used:
GIVEN context c
GIVEN lookup of CONTINUE_LABEL in c yields label l
THEN `continue;` checks in context c
GIVEN context c, label l
GIVEN c contains an entry of the form CONTINUE_LABEL = l
THEN `continue l;` checks in context c
A return
statement transfers control out of the current function.
ReturnStatement :
`return` Expression? `;`
GIVEN context c, expression e
GIVEN lookup of RESULT_TYPE in c yields type t
GIVEN e checks against t in c
THEN `return e;` checks in c
GIVEN context c
GIVEN lookup of RESULT_TYPE in c yield type t
GIVEN `Unit` is a subtype of t
THEN `return;` checks in c
Note: A return
statement without an expression is equivalent to a return
of a value of type Unit
.
DiscardStatement :
`discard` `;`
A discard
statement may only be used in the context of a fragment shader, in which case it causes the current invocation to terminate and the graphics system to discard the corresponding fragment so that it does not get combined with the framebuffer pixel at its coordinates.
Operations with side effects that were executed by the invocation before a discard
will still be performed and their results will become visible according to the rules of the platform.
GIVEN context c
GIVEN capability `fragment` is available in c
THEN `discard;` checks in c
Issue:
The intent of the above rule is that checking a discard
statement will add the fragment
capability to the context, so that it can be checked against the capabilities of the surrounding function/context.
However, the way the other statement rules handle the context, they do not allow for anything in the context to flow upward/outward in that fashion.
It may be simplest to have the process of collecting the capabilities required by a function body be a different judgement than the type checking rules.