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.
 
 
 
 
 
 

249 lines
8.8 KiB

//==============================================================================
//
// Copyright (c) 2002-
// Authors:
// * Dave Parker <d.a.parker@cs.bham.ac.uk> (University of Birmingham/Oxford)
//
//------------------------------------------------------------------------------
//
// 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.visitor;
import parser.ast.ConstantList;
import parser.ast.Expression;
import parser.ast.ExpressionFilter;
import parser.ast.ExpressionLabel;
import parser.ast.ExpressionProb;
import parser.ast.ExpressionReward;
import parser.ast.ExpressionSS;
import parser.ast.ExpressionTemporal;
import parser.ast.FormulaList;
import parser.ast.LabelList;
import parser.ast.ModulesFile;
import parser.ast.PropertiesFile;
import parser.ast.TemporalOperatorBound;
import prism.ModelInfo;
import prism.PrismLangException;
/**
* Perform any required semantic checks on a PropertiesFile (or parts of it).
* These checks are done *before* any undefined constants have been defined.
* Optionally pass in parent ModulesFile (or leave null);
*/
public class PropertiesSemanticCheck extends SemanticCheck
{
private PropertiesFile propertiesFile;
private ModelInfo modelInfo;
private ModulesFile modulesFile;
public PropertiesSemanticCheck(PropertiesFile propertiesFile)
{
this(propertiesFile, null);
}
public PropertiesSemanticCheck(PropertiesFile propertiesFile, ModelInfo modelInfo)
{
setPropertiesFile(propertiesFile);
setModelInfo(modelInfo);
}
public void setPropertiesFile(PropertiesFile propertiesFile)
{
this.propertiesFile = propertiesFile;
}
public void setModelInfo(ModelInfo modelInfo)
{
this.modelInfo = modelInfo;
if (modelInfo instanceof ModulesFile) {
this.modulesFile = (ModulesFile) modelInfo;
} else {
this.modulesFile = null;
}
}
public Object visit(FormulaList e) throws PrismLangException
{
// Override - don't need to do any semantic checks on formulas
// (they will have been expanded in place, where needed)
// (and we shouldn't check them - e.g. clock vars appearing in errors would show as an error)
return null;
}
public void visitPost(LabelList e) throws PrismLangException
{
int i, n;
String s;
n = e.size();
for (i = 0; i < n; i++) {
s = e.getLabelName(i);
if ("deadlock".equals(s))
throw new PrismLangException("Cannot define a label called \"deadlock\" - this is a built-in label", e.getLabel(i));
if ("init".equals(s))
throw new PrismLangException("Cannot define a label called \"init\" - this is a built-in label", e.getLabel(i));
}
}
public void visitPost(ConstantList e) throws PrismLangException
{
int i, n;
n = e.size();
for (i = 0; i < n; i++) {
if (e.getConstant(i) != null && !e.getConstant(i).isConstant()) {
throw new PrismLangException("Definition of constant \"" + e.getConstantName(i) + "\" is not constant", e.getConstant(i));
}
}
}
public void visitPost(ExpressionTemporal e) throws PrismLangException
{
int op = e.getOperator();
Expression operand1 = e.getOperand1();
Expression operand2 = e.getOperand2();
boolean hasBounds = e.getBounds().countBounds() > 0;
// Other checks (which parser should never allow to occur anyway)
if (op == ExpressionTemporal.P_X && (operand1 != null || operand2 == null || hasBounds)) {
throw new PrismLangException("Cannot attach bounds to " + e.getOperatorSymbol() + " operator", e);
}
if (op == ExpressionTemporal.R_C) {
boolean malformed = false;
if (operand1 != null || operand2 != null) { malformed = true;}
if (e.hasBounds()) {
if (e.getBounds().countBounds() > 1 || !e.getBounds().hasDefaultBound()) { malformed = true; }
else if (e.getBounds().getDefaultBound().hasLowerBound()) {
// NB: upper bound is optional (e.g. multi-objective allows R...[C] operator)
malformed = true;
}
}
if (malformed)
throw new PrismLangException("Badly formed " + e.getOperatorSymbol() + " operator", e);
}
if (op == ExpressionTemporal.R_I) {
boolean malformed = false;
if (operand1 != null || operand2 != null) {malformed = true;}
if (e.hasBounds()) {
if (e.getBounds().countBounds() > 1 || !e.getBounds().hasDefaultBound()) { malformed = true; }
else if (e.getBounds().getDefaultBound().hasLowerBound() || !e.getBounds().getDefaultBound().hasUpperBound()) {
malformed = true;
}
}
if (malformed)
throw new PrismLangException("Badly formed " + e.getOperatorSymbol() + " operator", e);
}
if (op == ExpressionTemporal.R_S && (operand1 != null || operand2 != null || hasBounds)) {
throw new PrismLangException("Badly formed " + e.getOperatorSymbol() + " operator", e);
}
}
public void visitPost(TemporalOperatorBound e) throws PrismLangException
{
Expression lBound = e.getLowerBound();
Expression uBound = e.getUpperBound();
if (lBound != null && !lBound.isConstant()) {
throw new PrismLangException("Lower bound " + e + " is not constant", lBound);
}
if (uBound != null && !uBound.isConstant()) {
throw new PrismLangException("Upper bound " + e + " not constant", uBound);
}
}
public void visitPost(ExpressionProb e) throws PrismLangException
{
if (e.getModifier() != null) {
throw new PrismLangException("Modifier \"" + e.getModifier() + "\" not supported for P operator");
}
if (e.getProb() != null && !e.getProb().isConstant()) {
throw new PrismLangException("P operator probability bound is not constant", e.getProb());
}
}
public void visitPost(ExpressionReward e) throws PrismLangException
{
if (e.getModifier() != null) {
throw new PrismLangException("Modifier \"" + e.getModifier() + "\" not supported for R operator");
}
if (e.getRewardStructIndex() != null) {
if (e.getRewardStructIndex() instanceof Expression) {
Expression rsi = (Expression) e.getRewardStructIndex();
if (!(rsi.isConstant())) {
throw new PrismLangException("R operator reward struct index is not constant", rsi);
}
} else if (e.getRewardStructIndex() instanceof String) {
String s = (String) e.getRewardStructIndex();
if (modulesFile != null && modulesFile.getRewardStructIndex(s) == -1) {
throw new PrismLangException("R operator reward struct index \"" + s + "\" does not exist", e);
}
}
}
if (e.getRewardStructIndexDiv() != null) {
if (e.getRewardStructIndexDiv() instanceof Expression) {
Expression rsi = (Expression) e.getRewardStructIndexDiv();
if (!(rsi.isConstant())) {
throw new PrismLangException("R operator reward struct index is not constant", rsi);
}
} else if (e.getRewardStructIndexDiv() instanceof String) {
String s = (String) e.getRewardStructIndexDiv();
if (modulesFile != null && modulesFile.getRewardStructIndex(s) == -1) {
throw new PrismLangException("R operator reward struct index \"" + s + "\" does not exist", e);
}
}
}
if (e.getReward() != null && !e.getReward().isConstant()) {
throw new PrismLangException("R operator reward bound is not constant", e.getReward());
}
}
public void visitPost(ExpressionSS e) throws PrismLangException
{
if (e.getModifier() != null) {
throw new PrismLangException("Modifier \"" + e.getModifier() + "\" not supported for S operator");
}
if (e.getProb() != null && !e.getProb().isConstant()) {
throw new PrismLangException("S operator probability bound is not constant", e.getProb());
}
}
public void visitPost(ExpressionLabel e) throws PrismLangException
{
String name = e.getName();
// Allow special cases
if ("deadlock".equals(name) || "init".equals(name))
return;
// Otherwise check if it exists
if (modelInfo != null && modelInfo.getLabelIndex(name) != -1) {
return;
} else if (propertiesFile != null) {
LabelList labelList = propertiesFile.getCombinedLabelList();
if (labelList != null && labelList.getLabelIndex(name) != -1) {
return;
}
}
throw new PrismLangException("Undeclared label", e);
}
public void visitPost(ExpressionFilter e) throws PrismLangException
{
// Check filter type is valid
if (e.getOperatorType() == null) {
throw new PrismLangException("Unknown filter type \"" + e.getOperatorName() + "\"", e);
}
}
}