-
Ludovic Apvrille authoredLudovic Apvrille authored
AvatarSyntaxChecker.java 24.93 KiB
/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
*
* ludovic.apvrille AT enst.fr
*
* This software is a computer program whose purpose is to allow the
* edition of TURTLE analysis, design and deployment diagrams, to
* allow the generation of RT-LOTOS or Java code from this diagram,
* and at last to allow the analysis of formal validation traces
* obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
* from INRIA Rhone-Alpes.
*
* This software is governed by the CeCILL license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
package avatartranslator;
import avatartranslator.intboolsolver.AvatarIBSExpressions;
import avatartranslator.intboolsolver.AvatarIBSolver;
import compiler.tmlparser.ParseException;
import compiler.tmlparser.SimpleNode;
import compiler.tmlparser.TMLExprParser;
import compiler.tmlparser.TokenMgrError;
import myutil.Conversion;
import myutil.IntExpressionEvaluator;
import myutil.NameChecker;
import myutil.TraceManager;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
* Class AvatarSyntaxChecker
* Creation: 21/05/2010
*
* @author Ludovic APVRILLE
* @version 1.0 21/05/2010
*/
public class AvatarSyntaxChecker {
// Errors are defined in AvatarError
private final static int UNUSED_ELEMENT = 10;
private final static int FIRST_UPPER_CASE = 11;
private final static int FIRST_LOWER_CASE = 12;
public AvatarSyntaxChecker() {
}
public static ArrayList<AvatarError> checkSyntaxErrors(AvatarSpecification avspec) {
ArrayList<AvatarError> errors = new ArrayList<>();
errors.addAll(checkNextASMSpec(avspec));
errors.addAll(checkSignalRelations(avspec));
errors.addAll(checkASMLibraryFunctions(avspec));
return errors;
}
public static ArrayList<AvatarError> checkSyntaxWarnings(AvatarSpecification avspec) {
ArrayList<AvatarError> warnings = new ArrayList<>();
//warnings.addAll(checkIsolatedElements(avspec));
warnings.addAll(checkNames(avspec));
return warnings;
}
public static ArrayList<AvatarError> checkIsolatedElements(AvatarSpecification avspec) {
ArrayList<AvatarError> warnings = new ArrayList<>();
for (AvatarBlock ab : avspec.getListOfBlocks()) {
warnings.addAll(checkIsolatedElements(avspec, ab));
}
return warnings;
}
public static ArrayList<AvatarError> checkIsolatedElements(AvatarSpecification avspec, AvatarBlock ab) {
ArrayList<AvatarError> warnings = new ArrayList<>();
AvatarStateMachine asm = ab.getStateMachine();
if (asm == null) {
return warnings;
}
List<AvatarStateMachineElement> unused = asm.getUnusedElements();
if (unused != null) {
for (AvatarStateMachineElement asme : unused) {
AvatarError warning = new AvatarError(avspec);
warning.firstAvatarElement = asme;
warning.secondAvatarElement = ab;
warning.error = UNUSED_ELEMENT;
warnings.add(warning);
}
}
return warnings;
}
public static ArrayList<AvatarError> checkNames(AvatarSpecification avspec) {
ArrayList<AvatarError> warnings = new ArrayList<>();
for(NameChecker.NamedElement ne: avspec.getSubNamedElements()) {
warnings.addAll(checkNames(avspec, ne));
}
return warnings;
}
public static ArrayList<AvatarError> checkNames(AvatarSpecification _avspec, NameChecker.NamedElement _ne) {
ArrayList<AvatarError> warnings = new ArrayList<>();
// Checking block name
//TraceManager.addDev("Checking name: " + _ne.getName());
if (_ne instanceof NameChecker.NameStartWithUpperCase) {
if (!NameChecker.checkName(_ne)) {
newError(_avspec, warnings, (AvatarElement) _ne, null, FIRST_UPPER_CASE);
}
} else if (_ne instanceof NameChecker.NameStartWithLowerCase) {
if (!NameChecker.checkName(_ne)) {
newError(_avspec, warnings, (AvatarElement) _ne, null, FIRST_LOWER_CASE);
}
}
for(NameChecker.NamedElement sub: _ne.getSubNamedElements()) {
//TraceManager.addDev("Checking sub name: " + sub.getName());
if (sub instanceof NameChecker.NameStartWithUpperCase) {
if (!NameChecker.checkName(sub)) {
newError(_avspec, warnings, (AvatarElement) _ne, (AvatarElement)sub, FIRST_UPPER_CASE);
}
} else if (sub instanceof NameChecker.NameStartWithLowerCase) {
if (!NameChecker.checkName(sub)) {
newError(_avspec, warnings, (AvatarElement) _ne, (AvatarElement)sub, FIRST_LOWER_CASE);
}
}
}
// Checking attribute, methods and signal names
/*for (AvatarAttribute aa: ab.getAttributes()) {
if (!Conversion.startsWithLowerCase(aa.getName())) {
newError(avspec, warnings, ab, aa, FIRST_LOWER_CASE);
}
}
for (AvatarMethod am: ab.getMethods()) {
if (!Conversion.startsWithLowerCase(am.getName())) {
newError(avspec, warnings, ab, am, FIRST_LOWER_CASE);
}
}
for (AvatarSignal as: ab.getSignals()) {
if (!Conversion.startsWithLowerCase(as.getName())) {
newError(avspec, warnings, ab, as, FIRST_LOWER_CASE);
}
}*/
return warnings;
}
public static ArrayList<AvatarError> checkNextASMSpec(AvatarSpecification avspec) {
ArrayList<AvatarError> errors = new ArrayList<>();
for (AvatarBlock ab : avspec.getListOfBlocks()) {
errors.addAll(checkNextASMBlock(avspec, ab));
}
return errors;
}
public static ArrayList<AvatarError> checkNextASMBlock(AvatarSpecification avspec, AvatarBlock ab) {
ArrayList<AvatarError> errors = new ArrayList<>();
AvatarStateMachine asm = ab.getStateMachine();
if (asm == null) {
AvatarError error = new AvatarError(avspec);
error.firstAvatarElement = ab;
error.secondAvatarElement = null;
error.error = 9;
errors.add(error);
} else {
for (AvatarStateMachineElement asme : asm.getListOfElements()) {
if (!((asme instanceof AvatarState) || (asme instanceof AvatarStopState) || (asme instanceof AvatarStartState))) {
if (asme.nexts.isEmpty()) {
AvatarError error = new AvatarError(avspec);
error.firstAvatarElement = asme;
error.secondAvatarElement = ab;
error.error = 8;
errors.add(error);
}
}
}
}
return errors;
}
public static ArrayList<AvatarError> checkASMLibraryFunctions(AvatarSpecification avspec) {
ArrayList<AvatarError> errors = new ArrayList<>();
for (AvatarLibraryFunction alf : avspec.getListOfLibraryFunctions()) {
errors.addAll(checkASMLibraryFunction(avspec, alf));
}
return errors;
}
public static ArrayList<AvatarError> checkASMLibraryFunction(AvatarSpecification avspec, AvatarLibraryFunction alf) {
ArrayList<AvatarError> errors = new ArrayList<>();
AvatarStateMachine asm = alf.getStateMachine();
for (AvatarStateMachineElement elt : asm.getListOfElements()) {
if (!(elt instanceof AvatarStopState)) {
if (elt.getNexts().size() == 0) {
AvatarError error = new AvatarError(avspec);
error.firstAvatarElement = alf;
error.secondAvatarElement = elt;
error.error = 7;
errors.add(error);
}
}
}
return errors;
}
public static ArrayList<AvatarError> checkSignalRelations(AvatarSpecification avspec) {
ArrayList<AvatarError> errors = new ArrayList<>();
List<AvatarSignal> signals1, signals2;
// Check relations are corrects
for (AvatarRelation relation : avspec.getRelations()) {
signals1 = relation.getSignals1();
signals2 = relation.getSignals2();
AvatarBlock block1, block2;
block1 = relation.block1;
block2 = relation.block2;
if (block1 == null) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.error = 4;
errors.add(error);
}
if (block2 == null) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.error = 5;
errors.add(error);
}
if (signals1.size() != signals2.size()) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.error = 0;
errors.add(error);
} else {
// Compare signals characteristics
AvatarSignal sig1, sig2;
for (int i = 0; i < signals1.size(); i++) {
sig1 = signals1.get(i);
sig2 = signals2.get(i);
// In vs out
if (sig1.isIn() && sig2.isIn()) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.firstAvatarElement = sig1;
error.secondAvatarElement = sig2;
error.error = 1;
errors.add(error);
} else if (sig1.isOut() && sig2.isOut()) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.firstAvatarElement = sig1;
error.secondAvatarElement = sig2;
error.error = 2;
errors.add(error);
}
// Attributes
//TraceManager.addDev("Checking attributes compatibility");
if (!(sig1.isCompatibleWith(sig2))) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.firstAvatarElement = sig1;
error.secondAvatarElement = sig2;
error.error = 3;
errors.add(error);
}
// Both signals exist in their respective block
if (block1 != null) {
AvatarSignal as = block1.getSignalByName(sig1.getSignalName());
if (as == null) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.block = block1;
error.firstAvatarElement = sig1;
error.error = 6;
errors.add(error);
}
}
if (block2 != null) {
AvatarSignal as = block2.getSignalByName(sig2.getSignalName());
if (as == null) {
AvatarError error = new AvatarError(avspec);
error.relation = relation;
error.block = block2;
error.firstAvatarElement = sig2;
error.error = 6;
errors.add(error);
}
}
}
}
}
return errors;
}
public static int isAValidGuard(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _guard) {
//TraceManager.addDev("Evaluating (non modified) guard:" + _guard);
String tmp = _guard.replaceAll(" ", "");
if (tmp.compareTo("[]") == 0) {
return 0;
}
// NEW
tmp = Conversion.replaceAllChar(tmp, '[', "").trim();
tmp = Conversion.replaceAllChar(tmp, ']', "").trim();
String act = tmp;
for (AvatarAttribute aa : _ab.getAttributes()) {
if (aa.getType() != AvatarType.TIMER) {
act = Conversion.putVariableValueInString(AvatarSpecification.ops, act, aa.getName(), aa.getDefaultInitialValue());
}
}
//TraceManager.addDev("Testing guard expr=" + act);
AvatarIBSExpressions.BExpr e1 = AvatarIBSolver.parseBool(act);
return (e1 != null ? 0 : -1);
/*BoolExpressionEvaluator bee = new BoolExpressionEvaluator();
//TraceManager.addDev("Evaluating (modified) guard:" + act);
boolean result = bee.getResultOfWithIntExpr(act);
if (bee.getError() != null) {
TraceManager.addDev("Error: " + bee.getError() + " result=" + result);
return -1;
}
return 0;*/
// END of NEW
//return parse(_as, _ab, "guard", act);
}
/*
* @return 0 if ok, -1 if failure
*/
public static int isAValidIntExprReplaceVariables(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
/*AvatarExpressionSolver e1 = new AvatarExpressionSolver("x + y");
e1.buildExpression(_ab);*/
if (_expr.trim().length() == 0) {
return 0;
}
String tmp = _expr.replaceAll(" ", "").trim();
String act = tmp;
for (AvatarAttribute aa : _ab.getAttributes()) {
act = Conversion.putVariableValueInString(AvatarSpecification.ops, act, aa.getName(), aa.getDefaultInitialValue());
}
//TraceManager.addDev("Checking if expr " + _expr + " is valid");
AvatarIBSExpressions.IExpr e1 = AvatarIBSolver.parseInt(act);
//TraceManager.addDev("Checking if expr " + _expr + " is valid: " + (e1 != null));
/*IntExpressionEvaluator iee = new IntExpressionEvaluator();
//TraceManager.addDev("Evaluating int:" + act);
double result = iee.getResultOf(act);
if (iee.getError() != null) {
TraceManager.addDev("My parsing Error: " + iee.getError());
} else {
TraceManager.addDev("My parsing ok");
}*/
//TraceManager.addDev("my parsing:" + parse(_as, _ab, "actionnat", _expr));
return (e1 != null ? 0 : -1);
}
public static int isAValidIntExpr(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
/*AvatarExpressionSolver e1 = new AvatarExpressionSolver("x + y");
e1.buildExpression(_ab);*/
if (_expr.trim().length() == 0) {
return 0;
}
String tmp = _expr.replaceAll(" ", "").trim();
String act = tmp;
/*for (AvatarAttribute aa : _ab.getAttributes()) {
act = Conversion.putVariableValueInString(AvatarSpecification.ops, act, aa.getName(), aa.getDefaultInitialValue());
}*/
//TraceManager.addDev("Checking if expr " + _expr + " is valid");
if (_ab instanceof AvatarBlock) {
AvatarIBSExpressions.IExpr e1 = AvatarIBSolver.parseInt((AvatarBlock)_ab, act);
return (e1 != null ? 0 : -1);
}
return isAValidIntExprReplaceVariables(_as, _ab, _expr);
//TraceManager.addDev("Checking if expr " + _expr + " is valid: " + (e1 != null));
/*IntExpressionEvaluator iee = new IntExpressionEvaluator();
//TraceManager.addDev("Evaluating int:" + act);
double result = iee.getResultOf(act);
if (iee.getError() != null) {
TraceManager.addDev("My parsing Error: " + iee.getError());
} else {
TraceManager.addDev("My parsing ok");
}*/
//TraceManager.addDev("my parsing:" + parse(_as, _ab, "actionnat", _expr));
}
public static int isAValidProbabilityExpr(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
if (_expr.trim().length() == 0) {
return 0;
}
String tmp = _expr.replaceAll(" ", "").trim();
double prob = 0.5;
try {
prob = Double.parseDouble(tmp);
} catch (Exception e) {
return -1;
}
if ((prob < 0) || (prob > 1000)) {
return -1;
}
return 0;
}
public static int newIsAValidBoolExpr(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
if (_expr.trim().length() == 0) {
return 0;
}
String tmp = _expr.replaceAll(" ", "").trim();
String act = tmp;
for (AvatarAttribute aa : _ab.getAttributes()) {
act = Conversion.putVariableValueInString(AvatarSpecification.ops, act, aa.getName(), aa.getDefaultInitialValueTF());
}
AvatarIBSExpressions.BExpr e1 = AvatarIBSolver.parseBool(act);
return (e1 == null ? 0 : 1);
}
public static int isAValidBoolExpr(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
if (_expr.trim().length() == 0) {
return 0;
}
String tmp = _expr.replaceAll(" ", "").trim();
String act = tmp;
//TraceManager.addDev("1. IsValidBoolExpr Evaluating bool:" + act);
for (AvatarAttribute aa : _ab.getAttributes()) {
act = Conversion.putVariableValueInString(AvatarSpecification.ops, act, aa.getName(), aa.getDefaultInitialValue());
}
//TraceManager.addDev("2. IsValidBoolExpr Evaluating bool:" + act);
/*BoolExpressionEvaluator bee = new BoolExpressionEvaluator();
boolean result = bee.getResultOfWithIntExpr(act);
if (bee.getError() != null) {
TraceManager.addDev("Error in bool expr: " + bee.getError());
return -1;
} else {
//TraceManager.addDev("IsValidBoolExpr: YES (" + act + ")");
}*/
// Testing with parsing AvatarExpressionSolver
//TraceManager.addDev("3. Now with avatar expression solver:" + _expr);
AvatarIBSExpressions.BExpr aee = AvatarIBSolver.parseBool(act);
if (aee == null) {
TraceManager.addDev("4. Error with avatar expression solver:" + act);
return -1;
}
//TraceManager.addDev("4. Ok with avatar expression solver:" + act);
return 0;
// OLD return parse(_as, _ab, "actionbool", _expr);
}
public static int isAValidVariableExpr(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _expr) {
int index0 = _expr.indexOf("=");
if (index0 == -1) {
return -1;
}
String attributeName = _expr.substring(0, index0).trim();
AvatarAttribute aa = _ab.getAvatarAttributeWithName(attributeName);
if (aa == null) {
return -1;
}
if (aa.isConstant()) { return -2;}
String action = _expr.substring(index0 + 1, _expr.length()).trim();
if (aa.isInt()) {
//TraceManager.addDev("Testing action+" + action);
return isAValidIntExpr(_as, _ab, action);
//return parse(_as, _ab, "actionnat", action);
} else if (aa.isBool()) {
return isAValidBoolExpr(_as, _ab, action);
//return parse(_as, _ab, "actionbool", action);
}
return -1;
}
/**
* Parsing in two steps:
* 1. Parsing the expression with no variable checking
* 2. Parsing the expression with variables values to see whether variables are well-placed or not
* The second parsing is performed iff the first one succeeds
*
* @param _as : Unused
* @param _ab : Avatar block
* @param _parseCmd : Parse Command
* @param _action : Action
* @return : return -1 in case of error in first pass
* return -2 in case of error in second pass
* return -3 in case a variable has not been declared
*/
public static int parse(AvatarSpecification _as, AvatarStateMachineOwner _ab, String _parseCmd, String _action) {
TMLExprParser parser;
SimpleNode root;
int i;
// First parsing
parser = new TMLExprParser(new StringReader(_parseCmd + " " + _action));
try {
//
root = parser.CompilationUnit();
//root.dump("pref=");
//
} catch (ParseException e) {
TraceManager.addDev("\nAvatar Parsing :" + _parseCmd + " " + _action);
TraceManager.addDev("ParseException --------> Parse error in :" + _parseCmd + " " + _action);
return -1;
} catch (TokenMgrError tke) {
TraceManager.addDev("Avatar TokenMgrError --------> Parse error in :" + _parseCmd + " " + _action);
return -1;
}
// Second parsing
// We only replace variables values after the "=" sign
int index = _action.indexOf('=');
String modif = _action;
if (_parseCmd.startsWith("ass")) {
if (index != -1) {
modif = _action.substring(index + 1, _action.length());
}
_parseCmd = "action" + _parseCmd.substring(3, _parseCmd.length());
}
/*for(i=0; i<_ab.attributeNb(); i++) {
modif = AvatarSpecification.putAttributeValueInString(modif, _ab.getAttribute(i));
}*/
parser = new TMLExprParser(new StringReader(_parseCmd + " " + modif));
try {
//
root = parser.CompilationUnit();
//root.dump("pref=");
//
} catch (ParseException e) {
TraceManager.addDev("\nAvatar Parsing :" + _parseCmd + " " + modif);
TraceManager.addDev("\n(Original parsing :" + _parseCmd + " " + _action + ")");
TraceManager.addDev("ParseException --------> Parse error in :" + _parseCmd + " " + _action);
return -2;
} catch (TokenMgrError tke) {
TraceManager.addDev("\nnAvatar Parsing :" + _parseCmd + " " + modif);
TraceManager.addDev("TokenMgrError --------> Parse error in :" + _parseCmd + " " + _action);
return -2;
}
// Tree analysis: if the tree contains a variable, then, this variable has not been declared
List<String> vars = root.getVariables();
for (String s : vars) {
// is that string a variable?
if ((s.compareTo("true") != 0) && (s.compareTo("false") != 0) && (s.compareTo("nil") != 0)) {
TraceManager.addDev("Variable not declared: " + s);
return -3;
}
}
return 0;
}
// Searches for numerical values over max
// @return list of AvatarElement not respecting this interval
public static ArrayList<AvatarElement> useOfInvalidUPPAALNumericalValues(AvatarSpecification _as, int maxV) {
ArrayList<AvatarElement> invalids = new ArrayList<AvatarElement>();
for (AvatarBlock ab : _as.getListOfBlocks()) {
// Check for attribute initial value
invalids.addAll(ab.getAttributesOverMax(maxV));
// Check operators of State machine
invalids.addAll(ab.getStateMachine().elementsWithNumericalValueOver(maxV));
}
return invalids;
}
private static void newError(AvatarSpecification _spec, ArrayList<AvatarError> _errors,
AvatarElement _first, AvatarElement _second, int _errorIndex) {
AvatarError error = new AvatarError(_spec);
error.firstAvatarElement = _first;
error.secondAvatarElement = _second;
error.error = _errorIndex;
_errors.add(error);
}
}