// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyc.lang;
import java.util.*;
import wybs.lang.Attribute;
import wybs.lang.SyntacticElement;
import wyil.lang.Constant;
import wyil.lang.Type;
import wyil.util.*;
/**
* Provides classes for representing statements in Whiley's source language.
* Examples include <i>assignments</i>, <i>for-loops</i>, <i>conditions</i>,
* etc. Each class is an instance of <code>SyntacticElement</code> and, hence,
* can be adorned with certain information (such as source location, etc).
*
* @author David J. Pearce
*
*/
public interface Stmt extends SyntacticElement {
/**
* Represents an assignment statement of the form <code>lhs = rhs</code>.
* Here, the <code>rhs</code> is any expression, whilst the <code>lhs</code>
* must be an <code>LVal</code> --- that is, an expression permitted on the
* left-side of an assignment. The following illustrates different possible
* assignment statements:
*
* <pre>
* x = y // variable assignment
* x.f = y // field assignment
* x[i] = y // list assignment
* x[i].f = y // compound assignment
* </pre>
*
* The last assignment here illustrates that the left-hand side of an
* assignment can be arbitrarily complex, involving nested assignments into
* lists and records.
*
* @author David J. Pearce
*
*/
public static final class Assign extends SyntacticElement.Impl implements
Stmt {
public final List<Expr.LVal> lvals;
public final List<Expr> rvals;
/**
* Create an assignment from a given sequence of lvals and expressions on the right-hand side.
*
* @param lvals
* Sequence of one or more lval expressions representing the
* left-hand side
* @param rvals
* Sequence of one or more expressions representing the
* right-hand side
* @param attributes
*/
public Assign(List<Expr.LVal> lvals, List<Expr> rvals, Attribute... attributes) {
super(attributes);
this.lvals = new ArrayList<Expr.LVal>(lvals);
this.rvals = new ArrayList<Expr>(rvals);
}
/**
* Create an assignment from a given sequence of lvals and expressions on the right-hand side.
*
* @param lvals
* Sequence of one or more lval expressions representing the
* left-hand side
* @param rvals
* Sequence of one or more expressions representing the
* right-hand side
* @param attributes
*/
public Assign(List<Expr.LVal> lvals, List<Expr> rvals, Collection<Attribute> attributes) {
super(attributes);
this.lvals = new ArrayList<Expr.LVal>(lvals);
this.rvals = new ArrayList<Expr>(rvals);
}
}
/**
* Represents a assert statement of the form <code>assert e</code>, where
* <code>e</code> is a boolean expression. The following illustrates:
*
* <pre>
* function abs(int x) -> int:
* if x < 0:
* x = -x
* assert x >= 0
* return x
* </pre>
*
* Assertions are either statically checked by the verifier, or turned into
* runtime checks.
*
* @author David J. Pearce
*
*/
public static final class Assert extends SyntacticElement.Impl implements Stmt {
public Expr expr;
/**
* Create a given assert statement.
*
* @param expr
* the asserted condition, which may not be <code>null</code>.
* @param attributes
*/
public Assert(Expr expr, Attribute... attributes) {
super(attributes);
this.expr = expr;
}
/**
* Create a given assert statement.
*
* @param expr
* the asserted condition, which may not be <code>null</code>.
* @param attributes
*/
public Assert(String msg, Expr expr, Collection<Attribute> attributes) {
super(attributes);
this.expr = expr;
}
}
/**
* Represents an assume statement of the form <code>assume e</code>, where
* <code>e</code> is a boolean expression. The following illustrates:
*
* <pre>
* function abs(int x) -> int:
* if x < 0:
* x = -x
* assume x >= 0
* return x
* </pre>
*
* Assumptions are assumed by the verifier and, since this may be unsound,
* always turned into runtime checks.
*
* @author David J. Pearce
*
*/
public static final class Assume extends SyntacticElement.Impl implements
Stmt {
public Expr expr;
/**
* Create a given assume statement.
*
* @param expr
* the assumed condition, which may not be <code>null</code>.
* @param attributes
*/
public Assume(Expr expr, Attribute... attributes) {
super(attributes);
this.expr = expr;
}
/**
* Create a given assume statement.
*
* @param expr
* the assumed condition, which may not be <code>null</code>.
* @param attributes
*/
public Assume(String msg, Expr expr, Collection<Attribute> attributes) {
super(attributes);
this.expr = expr;
}
}
/**
* Represents a return statement, which has the form:
*
* <pre>
* ReturnStmt ::= "return" [Expression] NewLine
* </pre>
*
* The optional expression is referred to as the <i>return value</i>. Note
* that, the returned expression (if there is one) must begin on the same
* line as the return statement itself.
*
* The following illustrates:
*
* <pre>
* function f(int x) -> int:
* return x + 1
* </pre>
*
* Here, we see a simple <code>return</code> statement which returns an
* <code>int</code> value.
*
* @author David J. Pearce
*
*/
public static final class Return extends SyntacticElement.Impl implements Stmt {
public ArrayList<Expr> returns;
/**
* Create a given return statement with an optional return value.
*
* @param expr
* value being returned (may be null)
* @param attributes
*/
public Return(List<Expr> returns, Attribute... attributes) {
super(attributes);
this.returns = new ArrayList<Expr>(returns);
}
/**
* Create a given return statement with an optional return value.
*
* @param expr
* the return value, which may be <code>null</code>.
* @param attributes
*/
public Return(List<Expr> returns, Collection<Attribute> attributes) {
super(attributes);
this.returns = new ArrayList<Expr>(returns);
}
@Override
public String toString() {
String r = "return";
for(int i=0;i!=returns.size();++i) {
if(i != 0) {
r = r + ",";
}
r = r + " " + returns.get(i);
}
return r;
}
}
/**
* Represents a named block, which has the form:
*
* <pre>
* NamedBlcok ::= LifetimeIdentifier ':' NewLine Block
* </pre>
*
* As an example:
*
* <pre>
* function sum():
* &this:int x = new:this x
* myblock:
* &myblock:int y = new:myblock y
* </pre>
*/
public static final class NamedBlock extends SyntacticElement.Impl implements Stmt {
public final String name;
public final ArrayList<Stmt> body;
/**
* Construct a named block from a given name and body of statements.
*
* @param name
* name of this named block.
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public NamedBlock(String name, Collection<Stmt> body, Attribute... attributes) {
super(attributes);
this.name = name;
this.body = new ArrayList<Stmt>(body);
}
/**
* Construct a named block from a given name and body of statements.
*
* @param name
* name of this named block.
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public NamedBlock(String name, Collection<Stmt> body, Collection<Attribute> attributes) {
super(attributes);
this.name = name;
this.body = new ArrayList<Stmt>(body);
}
}
/**
* Represents a while statement, which has the form:
*
* <pre>
* WhileStmt ::= "while" Expression (where Expression)* ':' NewLine Block
* </pre>
*
* As an example:
*
* <pre>
* function sum([int] xs) -> int:
* int r = 0
* int i = 0
* while i < |xs| where i >= 0:
* r = r + xs[i]
* i = i + 1
* return r
* </pre>
*
* The optional <code>where</code> clause(s) are commonly referred to as the
* "loop invariant". When multiple clauses are given, these are combined
* using a conjunction. The combined invariant defines a condition which
* must be true on every iteration of the loop.
*
* @author David J. Pearce
*
*/
public static final class While extends SyntacticElement.Impl implements Stmt {
public Expr condition;
public List<Expr> invariants;
public final ArrayList<Stmt> body;
/**
* Construct a While statement from a given condition and body of
* statements.
*
* @param condition
* non-null expression.
* @param invariant
* The loop invariant expression, which may be null (if no
* invariant is given)
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public While(Expr condition, List<Expr> invariants, Collection<Stmt> body, Attribute... attributes) {
super(attributes);
this.condition = condition;
this.invariants = invariants;
this.body = new ArrayList<Stmt>(body);
}
/**
* Construct a While statement from a given condition and body of
* statements.
*
* @param condition
* non-null expression.
* @param invariant
* The loop invariant expression, which may be null (if no
* invariant is given)
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public While(Expr condition, List<Expr> invariants, Collection<Stmt> body,
Collection<Attribute> attributes) {
super(attributes);
this.condition = condition;
this.invariants = invariants;
this.body = new ArrayList<Stmt>(body);
}
}
/**
* Represents a do-while statement whose body is made up from a block of
* statements separated by indentation. As an example:
*
* <pre>
* function sum([int] xs) -> int
* requires |xs| > 0:
* int r = 0
* int i = 0
* do:
* r = r + xs[i]
* i = i + 1
* while i < |xs| where i >= 0
* return r
* </pre>
*
* Here, the <code>where</code> is optional, and commonly referred to as the
* <i>loop invariant</i>.
*
* @author David J. Pearce
*
*/
public static final class DoWhile extends SyntacticElement.Impl implements Stmt {
public Expr condition;
public final ArrayList<Expr> invariants;
public final ArrayList<Stmt> body;
/**
* Construct a Do-While statement from a given condition and body of
* statements.
*
* @param condition
* non-null expression.
* @param invariant
* The loop invariant expression, which may be null (if no
* invariant is given)
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public DoWhile(Expr condition, List<Expr> invariants, Collection<Stmt> body, Attribute... attributes) {
super(attributes);
this.condition = condition;
this.invariants = new ArrayList<Expr>(invariants);
this.body = new ArrayList<Stmt>(body);
}
/**
* Construct a Do-While statement from a given condition and body of
* statements.
*
* @param condition
* non-null expression.
* @param invariant
* The loop invariant expression, which may be null (if no
* invariant is given)
* @param body
* non-null collection which contains zero or more
* statements.
* @param attributes
*/
public DoWhile(Expr condition, List<Expr> invariants,
Collection<Stmt> body, Collection<Attribute> attributes) {
super(attributes);
this.condition = condition;
this.invariants = new ArrayList<Expr>(invariants);
this.body = new ArrayList<Stmt>(body);
}
}
/**
* Represents a fail statement.
*/
public static final class Fail extends SyntacticElement.Impl implements Stmt {
public Fail(Attribute... attributes) {
super(attributes);
}
}
/**
* Represents a classical if-else statement, which is has the form:
*
* <pre>
* "if" Expression ':' NewLine Block ["else" ':' NewLine Block]
* </pre>
*
* The first expression is referred to as the <i>condition</i>, while the
* first block is referred to as the <i>true branch</i>. The optional second
* block is referred to as the <i>false branch</i>. The following
* illustrates:
*
* <pre>
* function max(int x, int y) -> int:
* if(x > y):
* return x
* else if(x == y):
* return 0
* else:
* return y
* </pre>
*
* @author David J. Pearce
*
*/
public static final class IfElse extends SyntacticElement.Impl implements Stmt {
public Expr condition;
public final ArrayList<Stmt> trueBranch;
public final ArrayList<Stmt> falseBranch;
/**
* Construct an if-else statement from a condition, true branch and
* optional false branch.
*
* @param condition
* May not be null.
* @param trueBranch
* A list of zero or more statements to be executed when the
* condition holds; may not be null.
* @param falseBranch
* A list of zero of more statements to be executed when the
* condition does not hold; may not be null.
* @param attributes
*/
public IfElse(Expr condition, List<Stmt> trueBranch,
List<Stmt> falseBranch, Attribute... attributes) {
super(attributes);
this.condition = condition;
this.trueBranch = new ArrayList<Stmt>(trueBranch);
this.falseBranch = new ArrayList<Stmt>(falseBranch);
}
/**
* Construct an if-else statement from a condition, true branch and
* optional false branch.
*
* @param condition
* May not be null.
* @param trueBranch
* A list of zero or more statements to be executed when the
* condition holds; may not be null.
* @param falseBranch
* A list of zero of more statements to be executed when the
* condition does not hold; may not be null.
* @param attributes
*/
public IfElse(Expr condition, List<Stmt> trueBranch,
List<Stmt> falseBranch, Collection<Attribute> attributes) {
super(attributes);
this.condition = condition;
this.trueBranch = new ArrayList<Stmt>(trueBranch);
this.falseBranch = new ArrayList<Stmt>(falseBranch);
}
}
/**
* Represents a variable declaration which has the form:
*
* <pre>
* Type Identifier ['=' Expression] NewLine
* </pre>
*
* The optional <code>Expression</code> assignment is referred to as an
* <i>initialiser</i>. If an initialiser is given, then this will be
* evaluated and assigned to the variable when the declaration is executed.
* Some example declarations:
*
* <pre>
* int x
* int y = 1
* int z = x + y
* </pre>
*
* Observe that, unlike C and Java, declarations that declare multiple
* variables (separated by commas) are not permitted.
*
* @author David J. Pearce
*
*/
public static final class VariableDeclaration extends SyntacticElement.Impl implements
Stmt {
public final WhileyFile.Parameter parameter;
public Type type;
public Expr expr;
/**
* Construct a variable declaration from a given type, variable name and
* optional initialiser expression.
*
* @param pattern
* Type pattern declaring one or more types.
* @param expr
* Optional initialiser expression, which may be null.
* @param attributes
*/
public VariableDeclaration(WhileyFile.Parameter parameter, Expr expr,
Attribute... attributes) {
super(attributes);
this.parameter = parameter;
this.expr = expr;
}
/**
* Construct a variable declaration from a given type, variable name and
* optional initialiser expression.
*
* @param pattern
* Type pattern declaring one or more types.
* @param expr
* Optional initialiser expression, which may be null.
* @param attributes
*/
public VariableDeclaration(WhileyFile.Parameter parameter, Expr expr,
Collection<Attribute> attributes) {
super(attributes);
this.parameter = parameter;
this.expr = expr;
}
}
public static final class Case extends SyntacticElement.Impl {
public ArrayList<Expr> expr; // needs to be proved all constants
public ArrayList<Constant> constants; // needs to be proved all constants
public final ArrayList<Stmt> stmts;
public Case(List<Expr> values, List<Stmt> statements,
Attribute... attributes) {
super(attributes);
this.expr = new ArrayList<Expr>(values);
this.stmts = new ArrayList<Stmt>(statements);
}
}
public static final class Break extends SyntacticElement.Impl implements Stmt {
public Break(Attribute... attributes) {
super(attributes);
// TODO: update to include labelled breaks
}
}
public static final class Continue extends SyntacticElement.Impl implements Stmt {
public Continue(Attribute... attributes) {
super(attributes);
// TODO: update to include labelled breaks
}
}
public static final class Switch extends SyntacticElement.Impl implements Stmt {
public Expr expr;
public final ArrayList<Case> cases;
public Switch(Expr condition, List<Case> cases, Attribute... attributes) {
super(attributes);
this.expr = condition;
this.cases = new ArrayList<Case>(cases);
}
public Switch(Expr condition, List<Case> cases, Collection<Attribute> attributes) {
super(attributes);
this.expr = condition;
this.cases = new ArrayList<Case>(cases);
}
}
public static class Skip extends SyntacticElement.Impl implements Stmt {
public Skip(Attribute... attributes) {
super(attributes);
}
public Skip(Collection<Attribute> attributes) {
super(attributes);
}
}
public static final class Debug extends Skip {
public Expr expr;
public Debug(Expr expr, Attribute... attributes) {
super(attributes);
this.expr = expr;
}
public Debug(Expr expr, Collection<Attribute> attributes) {
super(attributes);
this.expr = expr;
}
@Override
public String toString() {
return "debug " + expr;
}
}
}