You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
12 KiB
437 lines
12 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// This file is part of PRISM.
|
|
//
|
|
// PRISM is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// PRISM is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with PRISM; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
package parser.ast;
|
|
|
|
import param.BigRational;
|
|
import parser.EvaluateContext;
|
|
import parser.visitor.ASTVisitor;
|
|
import prism.PrismLangException;
|
|
|
|
public class ExpressionTemporal extends Expression
|
|
{
|
|
// Operator constants
|
|
public static final int P_X = 1; // Next (for P operator)
|
|
public static final int P_U = 2; // Until (for P operator)
|
|
public static final int P_F = 3; // Future (for P operator)
|
|
public static final int P_G = 4; // Globally (for P operator)
|
|
public static final int P_W = 5; // Weak until (for P operator)
|
|
public static final int P_R = 6; // Release (for P operator)
|
|
public static final int R_C = 11; // Cumulative (for R operator)
|
|
public static final int R_I = 12; // Instantaneous (for R operator)
|
|
public static final int R_F = 13; // Reachability (for R operator) // DEPRECATED: Use P_F
|
|
public static final int R_S = 14; // Steady-state (for R operator)
|
|
// Operator symbols
|
|
public static final String opSymbols[] = { "", "X", "U", "F", "G", "W", "R", "", "", "", "", "C", "I", "F", "S" };
|
|
|
|
/** Operator, one of the operator constants above */
|
|
protected int op = 0;
|
|
|
|
// Up to two operands (either may be null)
|
|
/** LHS of operator, null for unary operators */
|
|
protected Expression operand1 = null;
|
|
/** RHS of operator, null for nullary operators (e.g., S) */
|
|
protected Expression operand2 = null;
|
|
|
|
|
|
// the bounds
|
|
protected TemporalOperatorBounds bounds = new TemporalOperatorBounds();
|
|
|
|
// Constructors
|
|
|
|
/** Constructor */
|
|
public ExpressionTemporal()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Constructor.
|
|
* @param op the temporal operator (see constants at ExpressionTemporal)
|
|
* @param operand1 the LHS operand ({@code null} for unary operators)
|
|
* @param operand2 the RHS operand
|
|
*/
|
|
public ExpressionTemporal(int op, Expression operand1, Expression operand2)
|
|
{
|
|
this.op = op;
|
|
this.operand1 = operand1;
|
|
this.operand2 = operand2;
|
|
}
|
|
|
|
// Set methods
|
|
|
|
/** Set the operator to i */
|
|
public void setOperator(int i)
|
|
{
|
|
op = i;
|
|
}
|
|
|
|
/** Set the LHS operand to e1 */
|
|
public void setOperand1(Expression e1)
|
|
{
|
|
operand1 = e1;
|
|
}
|
|
|
|
/** Set the RHS operand to e2 */
|
|
public void setOperand2(Expression e2)
|
|
{
|
|
operand2 = e2;
|
|
}
|
|
|
|
/**
|
|
* Take the bounds information from the other ExpressionTemporal
|
|
* and store them in this ExpressionTemporal (no deep copy).
|
|
*/
|
|
public void setBoundsFrom(ExpressionTemporal exprTemp)
|
|
{
|
|
bounds = exprTemp.getBounds();
|
|
}
|
|
|
|
/**
|
|
* Take the bounds information from the other ExpressionTemporal
|
|
* and store a copy in this ExpressionTemporal.
|
|
*/
|
|
public void copyBoundsFrom(ExpressionTemporal exprTemp)
|
|
{
|
|
bounds = exprTemp.getBounds().deepCopy();
|
|
}
|
|
|
|
// Get methods
|
|
|
|
/** Set the operator */
|
|
public int getOperator()
|
|
{
|
|
return op;
|
|
}
|
|
|
|
public String getOperatorSymbol()
|
|
{
|
|
return opSymbols[op];
|
|
}
|
|
|
|
/** Get the LHS operand (should be {@code null} for unary operators) */
|
|
public Expression getOperand1()
|
|
{
|
|
return operand1;
|
|
}
|
|
|
|
/** Get the RHS operand */
|
|
public Expression getOperand2()
|
|
{
|
|
return operand2;
|
|
}
|
|
|
|
/* Get the number of stored operands */
|
|
public int getNumOperands()
|
|
{
|
|
if (operand2 == null)
|
|
return 0;
|
|
else
|
|
return (operand1 == null) ? 1 : 2;
|
|
}
|
|
|
|
public boolean hasBounds()
|
|
{
|
|
return bounds.hasBounds();
|
|
}
|
|
|
|
|
|
// Methods required for Expression:
|
|
|
|
@Override
|
|
public boolean isConstant()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isProposition()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Object evaluate(EvaluateContext ec) throws PrismLangException
|
|
{
|
|
throw new PrismLangException("Cannot evaluate a temporal operator without a path");
|
|
}
|
|
|
|
@Override
|
|
public BigRational evaluateExact(EvaluateContext ec) throws PrismLangException
|
|
{
|
|
throw new PrismLangException("Cannot evaluate a temporal operator without a path");
|
|
}
|
|
|
|
@Override
|
|
public boolean returnsSingleValue()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Methods required for ASTElement:
|
|
|
|
@Override
|
|
public Object accept(ASTVisitor v) throws PrismLangException
|
|
{
|
|
return v.visit(this);
|
|
}
|
|
|
|
@Override
|
|
public Expression deepCopy()
|
|
{
|
|
ExpressionTemporal expr = new ExpressionTemporal();
|
|
expr.setOperator(op);
|
|
if (operand1 != null)
|
|
expr.setOperand1(operand1.deepCopy());
|
|
if (operand2 != null)
|
|
expr.setOperand2(operand2.deepCopy());
|
|
expr.setBounds(bounds.deepCopy());
|
|
|
|
expr.setType(type);
|
|
expr.setPosition(this);
|
|
return expr;
|
|
}
|
|
|
|
public void setBounds(TemporalOperatorBounds bounds) {
|
|
this.bounds = bounds;
|
|
}
|
|
|
|
public TemporalOperatorBounds getBounds() {
|
|
return bounds;
|
|
}
|
|
|
|
// Standard methods
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
String s = "";
|
|
if (operand1 != null)
|
|
s += operand1 + " ";
|
|
s += opSymbols[op];
|
|
|
|
if (bounds.hasBounds()) {
|
|
s+=bounds.toString();
|
|
}
|
|
if (operand2 != null)
|
|
s += " " + operand2;
|
|
return s;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + ((bounds == null) ? 0 : bounds.hashCode());
|
|
result = prime * result + op;
|
|
result = prime * result + ((operand1 == null) ? 0 : operand1.hashCode());
|
|
result = prime * result + ((operand2 == null) ? 0 : operand2.hashCode());
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj)
|
|
{
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null)
|
|
return false;
|
|
if (!(obj instanceof ExpressionTemporal))
|
|
return false;
|
|
ExpressionTemporal other = (ExpressionTemporal) obj;
|
|
if (bounds == null) {
|
|
if (other.bounds != null)
|
|
return false;
|
|
} else if (!bounds.equals(other.bounds))
|
|
return false;
|
|
if (op != other.op)
|
|
return false;
|
|
if (operand1 == null) {
|
|
if (other.operand1 != null)
|
|
return false;
|
|
} else if (!operand1.equals(other.operand1))
|
|
return false;
|
|
if (operand2 == null) {
|
|
if (other.operand2 != null)
|
|
return false;
|
|
} else if (!operand2.equals(other.operand2))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Other useful methods
|
|
|
|
/**
|
|
* Convert (P operator) path formula to untils, using standard equivalences.
|
|
*/
|
|
public Expression convertToUntilForm() throws PrismLangException
|
|
{
|
|
Expression op1, op2;
|
|
ExpressionTemporal exprTemp = null;
|
|
switch (op) {
|
|
case P_U:
|
|
return this;
|
|
case P_F:
|
|
// F a == true U a
|
|
op1 = Expression.True();
|
|
exprTemp = new ExpressionTemporal(P_U, op1, operand2);
|
|
exprTemp.setBoundsFrom(this);
|
|
return exprTemp;
|
|
case P_G:
|
|
// G a == !(true U !a)
|
|
op1 = Expression.True();
|
|
op2 = Expression.Not(operand2);
|
|
exprTemp = new ExpressionTemporal(P_U, op1, op2);
|
|
exprTemp.setBoundsFrom(this);
|
|
return Expression.Not(exprTemp);
|
|
case P_W:
|
|
// a W b == !(a&!b U !a&!b)
|
|
op1 = Expression.And(operand1, Expression.Not(operand2));
|
|
op2 = Expression.And(Expression.Not(operand1), Expression.Not(operand2));
|
|
exprTemp = new ExpressionTemporal(P_U, op1, op2);
|
|
exprTemp.setBoundsFrom(this);
|
|
return Expression.Not(exprTemp);
|
|
case P_R:
|
|
// a R b == !(!a U !b)
|
|
op1 = Expression.Not(operand1);
|
|
op2 = Expression.Not(operand2);
|
|
exprTemp = new ExpressionTemporal(P_U, op1, op2);
|
|
exprTemp.setBoundsFrom(this);
|
|
return Expression.Not(exprTemp);
|
|
}
|
|
throw new PrismLangException("Cannot convert " + getOperatorSymbol() + " to until form");
|
|
}
|
|
|
|
// ---- convenience methods for distinguishing top-level temporal operators -----------------
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the next step (X) top-level operator.
|
|
*/
|
|
public static boolean isNext(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_X;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the Until (U) top-level operator.
|
|
*/
|
|
public static boolean isUntil(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_U;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the Weak Until (W) top-level operator.
|
|
*/
|
|
public static boolean isWeakUntil(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_W;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the Release (R) top-level operator.
|
|
*/
|
|
public static boolean isRelease(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_R;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the finally / eventually (F) top-level operator.
|
|
*/
|
|
public static boolean isFinally(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_F;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal with the globally / always (G) top-level operator.
|
|
*/
|
|
public static boolean isGlobally(Expression e)
|
|
{
|
|
return (e instanceof ExpressionTemporal) && ((ExpressionTemporal) e).getOperator() == P_G;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal
|
|
* with a globally finally / always eventually (G followed by F) top-level operator pair.
|
|
*/
|
|
public static boolean isGloballyFinally(Expression e)
|
|
{
|
|
return isGlobally(e) && isFinally(((ExpressionTemporal) e).getOperand2());
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given expression is an ExpressionTemporal
|
|
* with a finally globally / eventually always (F followed by G) top-level operator pair.
|
|
*/
|
|
public static boolean isFinallyGlobally(Expression e)
|
|
{
|
|
return isFinally(e) && isGlobally(((ExpressionTemporal) e).getOperand2());
|
|
}
|
|
|
|
|
|
// ---- static constructors for building temporal expressions -----------------
|
|
|
|
/** Construct a ExpressionTemporal for "X expr" */
|
|
public static ExpressionTemporal Next(Expression expr)
|
|
{
|
|
return new ExpressionTemporal(P_X, null, expr);
|
|
}
|
|
|
|
/** Construct a ExpressionTemporal for "F expr" */
|
|
public static ExpressionTemporal Finally(Expression expr)
|
|
{
|
|
return new ExpressionTemporal(P_F, null, expr);
|
|
}
|
|
|
|
/** Construct a ExpressionTemporal for "G expr" */
|
|
public static ExpressionTemporal Globally(Expression expr)
|
|
{
|
|
return new ExpressionTemporal(P_G, null, expr);
|
|
}
|
|
|
|
/** Construct a ExpressionTemporal for "expr1 U expr2" */
|
|
public static ExpressionTemporal Globally(Expression expr1, Expression expr2)
|
|
{
|
|
return new ExpressionTemporal(P_U, expr1, expr2);
|
|
}
|
|
|
|
/** Construct a ExpressionTemporal for "expr1 W expr2" */
|
|
public static ExpressionTemporal WeakUntil(Expression expr1, Expression expr2)
|
|
{
|
|
return new ExpressionTemporal(P_W, expr1, expr2);
|
|
}
|
|
|
|
/** Construct a ExpressionTemporal for "expr1 R expr2" */
|
|
public static ExpressionTemporal Release(Expression expr1, Expression expr2)
|
|
{
|
|
return new ExpressionTemporal(P_R, expr1, expr2);
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|