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.
 
 
 
 
 
 

420 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 java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import parser.*;
import parser.visitor.*;
import prism.PrismLangException;
import prism.PrismUtils;
import parser.type.*;
/**
* Class to store list of (defined and undefined) constants
*/
public class ConstantList extends ASTElement
{
// Name/expression/type triples to define constants
private Vector<String> names = new Vector<String>();
private Vector<Expression> constants = new Vector<Expression>(); // these can be null, i.e. undefined
private Vector<Type> types = new Vector<Type>();
// We also store an ExpressionIdent to match each name.
// This is to just to provide positional info.
private Vector<ExpressionIdent> nameIdents = new Vector<ExpressionIdent>();
/** Constructor */
public ConstantList()
{
}
/** Constructor from a Values object, i.e., a list of name=value tuples */
public ConstantList(Values constValues) throws PrismLangException
{
for (int i = 0; i < constValues.getNumValues(); i++) {
Type type = constValues.getType(i);
if (type.equals(TypeBool.getInstance()) ||
type.equals(TypeInt.getInstance()) ||
type.equals(TypeDouble.getInstance())) {
addConstant(new ExpressionIdent(constValues.getName(i)),
new ExpressionLiteral(type, constValues.getValue(i)),
type);
} else {
throw new PrismLangException("Unsupported type for constant " + constValues.getName(i));
}
}
}
// Set methods
public void addConstant(ExpressionIdent n, Expression c, Type t)
{
names.addElement(n.getName());
constants.addElement(c);
types.addElement(t);
nameIdents.addElement(n);
}
public void setConstant(int i, Expression c)
{
constants.setElementAt(c, i);
}
// Get methods
public int size()
{
return constants.size();
}
public String getConstantName(int i)
{
return names.elementAt(i);
}
public Expression getConstant(int i)
{
return constants.elementAt(i);
}
public Type getConstantType(int i)
{
return types.elementAt(i);
}
public ExpressionIdent getConstantNameIdent(int i)
{
return nameIdents.elementAt(i);
}
/**
* Get the index of a constant by its name (returns -1 if it does not exist).
*/
public int getConstantIndex(String s)
{
return names.indexOf(s);
}
/**
* Find cyclic dependencies.
*/
public void findCycles() throws PrismLangException
{
// Create boolean matrix of dependencies
// (matrix[i][j] is true if constant i contains constant j)
int n = constants.size();
boolean matrix[][] = new boolean[n][n];
for (int i = 0; i < n; i++) {
Expression e = getConstant(i);
if (e != null) {
Vector<String> v = e.getAllConstants();
for (int j = 0; j < v.size(); j++) {
int k = getConstantIndex(v.elementAt(j));
if (k != -1) {
matrix[i][k] = true;
}
}
}
}
// Check for and report dependencies
int firstCycle = PrismUtils.findCycle(matrix);
if (firstCycle != -1) {
String s = "Cyclic dependency in definition of constant \"" + getConstantName(firstCycle) + "\"";
throw new PrismLangException(s, getConstant(firstCycle));
}
}
/**
* Get the number of undefined constants in the list.
*/
public int getNumUndefined()
{
int i, n, res;
Expression e;
res = 0;
n = constants.size();
for (i = 0; i < n; i++) {
e = getConstant(i);
if (e == null) {
res++;
}
}
return res;
}
/**
* Get a list of the undefined constants in the list.
*/
public Vector<String> getUndefinedConstants()
{
int i, n;
Expression e;
Vector<String> v;
v = new Vector<String>();
n = constants.size();
for (i = 0; i < n; i++) {
e = getConstant(i);
if (e == null) {
v.addElement(getConstantName(i));
}
}
return v;
}
/**
* Check if {@code name} is a *defined* constants in the list,
* i.e. a constant whose value was *not* left unspecified in the model/property.
*/
public boolean isDefinedConstant(String name)
{
int i = getConstantIndex(name);
if (i == -1)
return false;
return (getConstant(i) != null);
}
/**
* Set values for *all* undefined constants, evaluate values for *all* constants
* and return a Values object with values for *all* constants.
* Argument 'someValues' contains values for undefined ones, can be null if all already defined
* Argument 'otherValues' contains any other values which may be needed, null if none
*/
public Values evaluateConstants(Values someValues, Values otherValues) throws PrismLangException
{
return evaluateSomeOrAllConstants(someValues, otherValues, true);
}
/**
* Set values for *some* undefined constants, evaluate values for constants where possible
* and return a Values object with values for all constants that could be evaluated.
* Argument 'someValues' contains values for undefined ones, can be null if all already defined
* Argument 'otherValues' contains any other values which may be needed, null if none
*/
public Values evaluateSomeConstants(Values someValues, Values otherValues) throws PrismLangException
{
return evaluateSomeOrAllConstants(someValues, otherValues, false);
}
/**
* Set values for *some* or *all* undefined constants, evaluate values for constants where possible
* and return a Values object with values for all constants that could be evaluated.
* Argument 'someValues' contains values for undefined ones, can be null if all already defined.
* Argument 'otherValues' contains any other values which may be needed, null if none.
* If argument 'all' is true, an exception is thrown if any undefined constant is not defined.
*/
private Values evaluateSomeOrAllConstants(Values someValues, Values otherValues, boolean all) throws PrismLangException
{
ConstantList cl;
Expression e;
Values allValues;
int i, j, n, numToEvaluate;
Type t = null;
ExpressionIdent s;
Object val;
// Create new copy of this ConstantList
// (copy existing constant definitions, add new ones where undefined)
cl = new ConstantList();
n = constants.size();
for (i = 0; i < n; i++) {
s = getConstantNameIdent(i);
e = getConstant(i);
t = getConstantType(i);
if (e != null) {
cl.addConstant((ExpressionIdent)s.deepCopy(), e.deepCopy(), t);
} else {
// Create new literal expression using values passed in (if possible and needed)
if (someValues != null && (j = someValues.getIndexOf(s.getName())) != -1) {
cl.addConstant((ExpressionIdent) s.deepCopy(), new ExpressionLiteral(t, t.castValueTo(someValues.getValue(j))), t);
} else {
if (all)
throw new PrismLangException("No value specified for constant", s);
}
}
}
numToEvaluate = cl.size();
// Now add constants corresponding to the 'otherValues' argument to the new constant list
if (otherValues != null) {
n = otherValues.getNumValues();
for (i = 0; i < n; i++) {
Type iType = otherValues.getType(i);
cl.addConstant(new ExpressionIdent(otherValues.getName(i)), new ExpressionLiteral(iType, iType.castValueTo(otherValues.getValue(i))), iType);
}
}
// Go trough and expand definition of each constant
// (i.e. replace other constant references with their definitions)
// Note: work with new copy of constant list, don't need to expand 'otherValues' ones.
for (i = 0; i < numToEvaluate; i++) {
try {
e = (Expression)cl.getConstant(i).expandConstants(cl);
cl.setConstant(i, e);
} catch (PrismLangException ex) {
if (all) {
throw ex;
} else {
cl.setConstant(i, null);
}
}
}
// Evaluate constants and store in new Values object (again, ignoring 'otherValues' ones)
allValues = new Values();
for (i = 0; i < numToEvaluate; i++) {
if (cl.getConstant(i) != null) {
val = cl.getConstant(i).evaluate(null, otherValues);
allValues.addValue(cl.getConstantName(i), val);
}
}
return allValues;
}
/**
* Set values for some undefined constants, then partially evaluate values for constants where possible
* and return a map from constant names to the Expression representing its value.
* Argument 'someValues' contains values for undefined ones, can be null if all already defined.
* Argument 'otherValues' contains any other values which may be needed, null if none.
*/
public Map<String,Expression> evaluateConstantsPartially(Values someValues, Values otherValues) throws PrismLangException
{
ConstantList cl;
Expression e;
int i, j, n, numToEvaluate;
Type t = null;
ExpressionIdent s;
// Create new copy of this ConstantList
// (copy existing constant definitions, add new ones where undefined)
cl = new ConstantList();
n = constants.size();
for (i = 0; i < n; i++) {
s = getConstantNameIdent(i);
e = getConstant(i);
t = getConstantType(i);
if (e != null) {
cl.addConstant((ExpressionIdent)s.deepCopy(), e.deepCopy(), t);
} else {
// Create new literal expression using values passed in (if possible and needed)
if (someValues != null && (j = someValues.getIndexOf(s.getName())) != -1) {
cl.addConstant((ExpressionIdent) s.deepCopy(), new ExpressionLiteral(t, t.castValueTo(someValues.getValue(j))), t);
}
}
}
numToEvaluate = cl.size();
// Now add constants corresponding to the 'otherValues' argument to the new constant list
if (otherValues != null) {
n = otherValues.getNumValues();
for (i = 0; i < n; i++) {
Type iType = otherValues.getType(i);
cl.addConstant(new ExpressionIdent(otherValues.getName(i)), new ExpressionLiteral(iType, iType.castValueTo(otherValues.getValue(i))), iType);
}
}
// Go trough and expand definition of each constant
// (i.e. replace other constant references with their definitions)
// Note: work with new copy of constant list, don't need to expand 'otherValues' ones.
for (i = 0; i < numToEvaluate; i++) {
try {
e = (Expression)cl.getConstant(i).expandConstants(cl);
cl.setConstant(i, e);
} catch (PrismLangException ex) {
cl.setConstant(i, null);
}
}
// Store final expressions for each constant in a map and return
Map<String,Expression> constExprs = new HashMap<>();
for (i = 0; i < numToEvaluate; i++) {
if (cl.getConstant(i) != null) {
constExprs.put(cl.getConstantName(i), cl.getConstant(i).deepCopy());
}
}
return constExprs;
}
// Methods required for ASTElement:
/**
* Visitor method.
*/
public Object accept(ASTVisitor v) throws PrismLangException
{
return v.visit(this);
}
/**
* Convert to string.
*/
public String toString()
{
String s = "";
int i, n;
Expression e;
n = constants.size();
for (i = 0; i < n; i++) {
s += "const ";
s += getConstantType(i).getTypeString() + " ";
s += getConstantName(i);
e = getConstant(i);
if (e != null) {
s += " = " + e;
}
s += ";\n";
}
return s;
}
/**
* Perform a deep copy.
*/
public ASTElement deepCopy()
{
int i, n;
ConstantList ret = new ConstantList();
n = size();
for (i = 0; i < n; i++) {
Expression constantNew = (getConstant(i) == null) ? null : getConstant(i).deepCopy();
ret.addConstant((ExpressionIdent)getConstantNameIdent(i).deepCopy(), constantNew, getConstantType(i));
}
ret.setPosition(this);
return ret;
}
}
//------------------------------------------------------------------------------