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.
 
 
 
 
 
 

536 lines
16 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.*;
import parser.*;
import parser.visitor.*;
import prism.PrismLangException;
// Class representing parsed properties file/list
public class PropertiesFile extends ASTElement
{
// Associated ModulesFile (for constants, ...)
private ModulesFile modulesFile;
// Components
private FormulaList formulaList;
private LabelList labelList;
private LabelList combinedLabelList; // Labels from both model/here
private ConstantList constantList;
private Vector<Property> properties; // Properties
// list of all identifiers used
private Vector<String> allIdentsUsed;
// actual values of (some or all) constants
private Values constantValues;
// Constructor
public PropertiesFile(ModulesFile mf)
{
setModulesFile(mf);
formulaList = new FormulaList();
labelList = new LabelList();
combinedLabelList = new LabelList();
constantList = new ConstantList();
properties = new Vector<Property>();
allIdentsUsed = new Vector<String>();
constantValues = null;
}
// Set methods
/** Attach to a ModulesFile (so can access labels/constants etc.) */
public void setModulesFile(ModulesFile mf) { this.modulesFile = mf; }
public void setFormulaList(FormulaList fl) { formulaList = fl; }
public void setLabelList(LabelList ll) { labelList = ll; }
public void setConstantList(ConstantList cl) { constantList = cl; }
public void addProperty(Property prop)
{
properties.add(prop);
}
public void addProperty(Expression p, String c)
{
properties.addElement(new Property(p, null, c));
}
public void setPropertyObject(int i, Property prop) { properties.set(i, prop); }
public void setPropertyExpression(int i, Expression p) { properties.get(i).setExpression(p); }
/**
* Insert the contents of another PropertiesFile (just a shallow copy).
*/
public void insertPropertiesFile(PropertiesFile pf) throws PrismLangException
{
FormulaList fl;
LabelList ll;
ConstantList cl;
int i, n;
fl = pf.formulaList;
n = fl.size();
for (i = 0; i < n; i++) {
formulaList.addFormula(fl.getFormulaNameIdent(i), fl.getFormula(i));
}
ll = pf.labelList;
n = ll.size();
for (i = 0; i < n; i++) {
labelList.addLabel(ll.getLabelNameIdent(i), ll.getLabel(i));
}
cl = pf.constantList;
n = cl.size();
for (i = 0; i < n; i++) {
constantList.addConstant(cl.getConstantNameIdent(i), cl.getConstant(i), cl.getConstantType(i));
}
n = pf.properties.size();
for (i = 0; i < n; i++) {
properties.add(pf.properties.get(i));
}
// Need to re-tidy (some checks should be re-done, some new info created)
tidyUp();
}
// Get methods
public FormulaList getFormulaList() { return formulaList; }
public LabelList getLabelList() { return labelList; }
public LabelList getCombinedLabelList() { return combinedLabelList; }
public ConstantList getConstantList() { return constantList; }
public int getNumProperties() { return properties.size(); }
public Property getPropertyObject(int i) { return properties.get(i); }
public Expression getProperty(int i) { return properties.get(i).getExpression(); }
public String getPropertyName(int i) { return properties.get(i).getName(); }
public String getPropertyComment(int i) { return properties.get(i).getComment(); }
/**
* Look up a property by name from those listed in this properties file.
* (Use {@link #lookUpPropertyObjectByName} to search model file too)
* Returns null if not found.
*/
public Property getPropertyObjectByName(String name)
{
int i, n;
n = getNumProperties();
for (i = 0; i < n; i++) {
if (name.equals(getPropertyName(i))) {
return getPropertyObject(i);
}
}
return null;
}
/**
* Look up a property by name, currently just locally like {@link #getPropertyObjectByName}.
* Returns null if not found.
*/
public Property lookUpPropertyObjectByName(String name)
{
return getPropertyObjectByName(name);
}
/**
* Check if an identifier is used by this properties file
* (as a formula or constant)
*/
public boolean isIdentUsed(String ident)
{
return allIdentsUsed.contains(ident);
}
// method to tidy up (called after parsing)
public void tidyUp() throws PrismLangException
{
// Clear lists that will generated by this method
// (in case it has already been called previously).
allIdentsUsed.clear();
// Check formula identifiers
checkFormulaIdents();
// Find all instances of formulas (i.e. locate idents which are formulas),
// check for any cyclic dependencies in the formula list and then expand all formulas.
// Note: We have to look for formulas defined both here and in the model.
// Note also that we opt not to do actual replacement of formulas in calls to exandFormulas
// (to improve legibility of properties)
findAllFormulas(modulesFile.getFormulaList());
findAllFormulas(formulaList);
formulaList.findCycles();
expandFormulas(modulesFile.getFormulaList(), false);
expandFormulas(formulaList, false);
// Check label identifiers
checkLabelIdents();
// Check constant identifiers
checkConstantIdents();
// Find all instances of constants (i.e. locate idents which are constants).
// Note: We have to look in both constant lists
findAllConstants(modulesFile.getConstantList());
findAllConstants(constantList);
// check constants for cyclic dependencies
constantList.findCycles();
// Set up some values for constants
// (without assuming any info about undefined constants)
setSomeUndefinedConstants(null);
// Check property names
checkPropertyNames();
// Find all instances of variables (i.e. locate idents which are variables).
findAllVars(modulesFile.getVarNames(), modulesFile.getVarTypes());
// Find all instances of property refs
findAllProps(null, this);
// Various semantic checks
semanticCheck(modulesFile, this);
// Type checking
typeCheck();
}
// check formula identifiers
private void checkFormulaIdents() throws PrismLangException
{
int i, n;
String s;
n = formulaList.size();
for (i = 0; i < n; i++) {
s = formulaList.getFormulaName(i);
// see if ident has been used elsewhere
if (modulesFile.isIdentUsed(s)) {
throw new PrismLangException("Identifier \"" + s + "\" already used in model file", formulaList.getFormulaNameIdent(i));
}
else if (isIdentUsed(s)) {
throw new PrismLangException("Duplicated identifier \"" + s + "\"", formulaList.getFormulaNameIdent(i));
}
else {
allIdentsUsed.add(s);
}
}
}
// check label identifiers
// also check reference to these identifiers in properties
private void checkLabelIdents() throws PrismLangException
{
int i, n;
String s;
Vector<String> labelIdents;
LabelList mfLabels;
// get label list from model file
mfLabels = modulesFile.getLabelList();
// add model file labels to combined label list (cloning them just for good measure)
n = mfLabels.size();
for (i = 0; i < n; i++) {
combinedLabelList.addLabel(mfLabels.getLabelNameIdent(i), mfLabels.getLabel(i).deepCopy());
}
// go thru labels
n = labelList.size();
labelIdents = new Vector<String>();
for (i = 0; i < n; i++) {
s = labelList.getLabelName(i);
// see if ident has been used already for a label in model file
if (mfLabels.getLabelIndex(s) != -1) {
throw new PrismLangException("Label \"" + s + "\" already defined in model file", labelList.getLabelNameIdent(i));
}
// see if ident has been used already for a label
if (labelIdents.contains(s)) {
throw new PrismLangException("Duplicated label name \"" + s + "\"", labelList.getLabelNameIdent(i));
}
// store identifier
// and add label to combined list
else {
labelIdents.addElement(s);
combinedLabelList.addLabel(labelList.getLabelNameIdent(i), labelList.getLabel(i));
}
}
}
// check constant identifiers
private void checkConstantIdents() throws PrismLangException
{
int i, n;
String s;
// go thru constants
n = constantList.size();
for (i = 0; i < n; i++) {
s = constantList.getConstantName(i);
// see if ident has been used elsewhere
if (modulesFile.isIdentUsed(s)) {
throw new PrismLangException("Identifier \"" + s + "\" already used in model file", constantList.getConstantNameIdent(i));
}
else if (isIdentUsed(s)) {
throw new PrismLangException("Duplicated identifier \"" + s + "\"", constantList.getConstantNameIdent(i));
}
else {
allIdentsUsed.add(s);
}
}
}
/**
* Check for any duplicate property names (or clashes with labels).
*/
private void checkPropertyNames() throws PrismLangException
{
int i, n;
String s;
Vector<String> propNames;
LabelList mfLabels;
// get label list from model file
mfLabels = modulesFile.getLabelList();
// Go thru properties
n = properties.size();
propNames = new Vector<String>();
for (i = 0; i < n; i++) {
s = properties.get(i).getName();
if (s == null)
continue;
// see if ident has been used already for a label in model file
if (mfLabels.getLabelIndex(s) != -1) {
throw new PrismLangException("Property name \"" + s + "\" clashes with label in model file", getPropertyObject(i));
}
// see if ident has been used already for a label in properties file
if (labelList.getLabelIndex(s) != -1) {
throw new PrismLangException("Property name \"" + s + "\" clashes with label", getPropertyObject(i));
}
// see if ident has been used already for a property name
if (propNames.contains(s)) {
throw new PrismLangException("Duplicated property name \"" + s + "\"", getPropertyObject(i));
}
// store identifier
else {
propNames.addElement(s);
}
}
}
/**
* Get a list of all undefined constants in the properties files
* ("const int x;" rather than "const int x = 1;")
*/
public Vector<String> getUndefinedConstants()
{
return constantList.getUndefinedConstants();
}
/**
* Get a list of undefined (properties file) constants appearing in labels of the properties file
* (undefined constants are those of form "const int x;" rather than "const int x = 1;")
*/
public Vector<String> getUndefinedConstantsUsedInLabels()
{
int i, n;
Expression expr;
Vector<String> consts, tmp;
consts = new Vector<String>();
n = labelList.size();
for (i = 0; i < n; i++) {
expr = labelList.getLabel(i);
tmp = expr.getAllUndefinedConstantsRecursively(constantList, combinedLabelList);
for (String s : tmp) {
if (!consts.contains(s)) {
consts.add(s);
}
}
}
return consts;
}
/**
* Get a list of undefined (properties file) constants used in a property
* (including those that appear in required labels/properties)
* (undefined constants are those of form "const int x;" rather than "const int x = 1;")
*/
public Vector<String> getUndefinedConstantsUsedInProperty(Property prop)
{
return prop.getExpression().getAllUndefinedConstantsRecursively(constantList, combinedLabelList);
}
/**
* Get a list of undefined (properties file) constants used in a list of properties
* (including those that appear in required labels/properties)
* (undefined constants are those of form "const int x;" rather than "const int x = 1;")
*/
public Vector<String> getUndefinedConstantsUsedInProperties(List <Property> props)
{
Vector<String> consts, tmp;
consts = new Vector<String>();
for (Property prop : props) {
tmp = prop.getExpression().getAllUndefinedConstantsRecursively(constantList, combinedLabelList);
for (String s : tmp) {
if (!consts.contains(s)) {
consts.add(s);
}
}
}
return consts;
}
/**
* Set values for *all* undefined constants and then evaluate all constants.
* If there are no undefined constants, {@code someValues} can be null.
* Undefined constants can be subsequently redefined to different values with the same method.
* The current constant values (if set) are available via {@link #getConstantValues()}.
*/
public void setUndefinedConstants(Values someValues) throws PrismLangException
{
// Might need values for ModulesFile constants too
constantValues = constantList.evaluateConstants(someValues, modulesFile.getConstantValues());
// Note: unlike ModulesFile, we don't trigger any semantic checks at this point
// This will usually be done on a per-property basis later
// (and sometimes we don't want to have to define all constants)
}
/**
* Set values for *some* undefined constants and then evaluate all constants where possible.
* If there are no undefined constants, {@code someValues} can be null.
* Undefined constants can be subsequently redefined to different values with the same method.
* The current constant values (if set) are available via {@link #getConstantValues()}.
*/
public void setSomeUndefinedConstants(Values someValues) throws PrismLangException
{
// Might need values for ModulesFile constants too
constantValues = constantList.evaluateSomeConstants(someValues, modulesFile.getConstantValues());
// Note: unlike ModulesFile, we don't trigger any semantic checks at this point
// This will usually be done on a per-property basis later
// (and sometimes we don't want to have to define all constants)
}
/**
* Check if {@code name} is a *defined* constant in the properties file,
* i.e. a constant whose value was *not* left unspecified.
*/
public boolean isDefinedConstant(String name)
{
return constantList.isDefinedConstant(name);
}
/**
* Get access to the values for all constants in the properties file, including the
* undefined constants set previously via the method {@link #setUndefinedConstants(Values)}
* or {@link #setUndefinedConstants(Values)}. If neither method has been called
* constant values will have been evaluated assuming that there are no undefined constants.
*/
public Values getConstantValues()
{
return constantValues;
}
// 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 = "", tmp;
int i, n;
tmp = "" + formulaList;
if (tmp.length() > 0) tmp += "\n";
s += tmp;
tmp = "" + labelList;
if (tmp.length() > 0) tmp += "\n";
s += tmp;
tmp = "" + constantList;
if (tmp.length() > 0) tmp += "\n";
s += tmp;
n = getNumProperties();
for (i = 0; i < n; i++) {
s += getPropertyObject(i) + ";\n";
if (i < n-1) s += "\n";
}
return s;
}
/**
* Perform a deep copy.
*/
@SuppressWarnings("unchecked")
public ASTElement deepCopy()
{
int i, n;
PropertiesFile ret = new PropertiesFile(modulesFile);
// Copy ASTElement stuff
ret.setPosition(this);
// Deep copy main components
ret.setFormulaList((FormulaList) formulaList.deepCopy());
ret.setLabelList((LabelList) labelList.deepCopy());
ret.combinedLabelList = (LabelList) combinedLabelList.deepCopy();
ret.setConstantList((ConstantList) constantList.deepCopy());
n = getNumProperties();
for (i = 0; i < n; i++) {
ret.addProperty((Property) getPropertyObject(i).deepCopy());
}
// Copy other (generated) info
ret.allIdentsUsed = (allIdentsUsed == null) ? null : (Vector<String>)allIdentsUsed.clone();
ret.constantValues = (constantValues == null) ? null : new Values(constantValues);
return ret;
}
}
//------------------------------------------------------------------------------