From 6bfb78663e6f0e90264db649122ff3b39b049e65 Mon Sep 17 00:00:00 2001 From: Sophie Coudert <sophie.coudert@telecom-paris.fr> Date: Thu, 4 Jul 2024 15:25:02 +0200 Subject: [PATCH] AvatarFromSysML commented --- .../tosysmlv2/AvatarFromSysML.java | 184 +++++++++++++----- 1 file changed, 134 insertions(+), 50 deletions(-) diff --git a/src/main/java/avatartranslator/tosysmlv2/AvatarFromSysML.java b/src/main/java/avatartranslator/tosysmlv2/AvatarFromSysML.java index d5375cfc00..717b3739e6 100644 --- a/src/main/java/avatartranslator/tosysmlv2/AvatarFromSysML.java +++ b/src/main/java/avatartranslator/tosysmlv2/AvatarFromSysML.java @@ -57,7 +57,7 @@ import java_cup.runtime.ComplexSymbolFactory; import myutil.TraceManager; import static java.lang.System.out; - +import static avatartranslator.AvatarTransition.*; /** Class AvatarFromSysML * Creation: 20/06/2024 @@ -596,6 +596,8 @@ public class AvatarFromSysML { transitionMap.clear(); AvatarStateMachineElement theSourceState; // technical variable + AvatarStartState startState = null; + Location startStateLocation = null; // iterate on syntactic states of the syntactic block // - build statemachine @@ -623,10 +625,8 @@ public class AvatarFromSysML { states[i].setType(AvatarFromSysMLSyntax.STXSTANDARDSTATE); } - // create-and-add the handled state, which is the source state of outgoing transitions that will be handled + // create the handled state, which is the source state of outgoing transitions that will be handled theSourceState = getState(states[i], theBlock); - addState(theSourceState, theBlock); - asm.addElement(theSourceState); // two state types that require some specific transition-independent handling if (stateType == AvatarFromSysMLSyntax.STXRANDOMSTATE) { @@ -636,7 +636,19 @@ public class AvatarFromSysML { states[i].getMaxValue().replaceAll("\\.", "__")); ((AvatarRandom) theSourceState).setVariable(states[i].getVariable().replaceAll("\\.", "__")); } else if (stateType == AvatarFromSysMLSyntax.STXSTARTSTATE) - asm.setStartState((AvatarStartState) theSourceState); + if (startState == null) { + startState = (AvatarStartState) theSourceState; + startStateLocation = states[i].getLeft(); + asm.setStartState(startState); + } else { + addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, states[i].getLeft(), + "several start-states declared, only one is kept", startStateLocation)); + continue; + } + + // add the handled state................. + addState(theSourceState, theBlock); + asm.addElement(theSourceState); // build and add transitions......................................... @@ -1079,19 +1091,22 @@ public class AvatarFromSysML { transitionMap.forEach(new CheckIncommings()); } } + + /** makes some verifications relative to incomming edges, not all. In particular, not all unreachable states are removed, but this must ensure at + * least that keeped states are sufficiently well defined to be handled by the graphic representation building process (avoiding crashes) */ private class CheckIncommings implements BiConsumer<AvatarStateMachineElement, StateTransitions> { List<AvatarDataType> dataTypeList; public CheckIncommings(){} public void accept(AvatarStateMachineElement e, StateTransitions st) { int s = st.getTransitions().size(); - if (s == 0 && ! (e instanceof AvatarStartState)) { + if (s == 0 && ! (e instanceof AvatarStartState)) { // unreachable state that may be not well defined => to remove addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, "state " + e.getName() + " of block " + st.getBlock().getName() + " is unreachable --> removed")); st.getBlock().getStateMachine().removeElement(e); for(AvatarStateMachineElement x : e.getNexts()) st.getBlock().getStateMachine().removeElement(x); } - if (s > 0 && (e instanceof AvatarStartState)) { + if (s > 0 && (e instanceof AvatarStartState)) { // start state has input edges => redirected to error stopstate addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, "start state in bloc " + st.getBlock().getName() + " has some input transition")); for(int i = 0; i < s; i++) { @@ -1101,7 +1116,7 @@ public class AvatarFromSysML { st.getBlock().getStateMachine().addElement(nw); } } - if (s > 1 && !(e instanceof AvatarStartState || e instanceof AvatarStateElement)) { + if (s > 1 && !(e instanceof AvatarStartState || e instanceof AvatarStateElement)) { // too much input edges => redirected to error stopstate addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, "state " + e.getName() + " in bloc " + st.getBlock().getName() + " has more than one incomming transition")); @@ -1114,59 +1129,84 @@ public class AvatarFromSysML { } } } + /** create-and-add AvatarBlocks. successive calls of BuildBlock and BuildStateMachine for each syntactic block */ private void buildBlocks(){ stxSpec.getBlockMap().forEach(new BuildBlock()); stxSpec.getBlockMap().forEach(new BuildStateMachine()); } + + /** complete the parameter transition with distribution law information provided in other parameters. + * + * @param _t the transition to provide with distribution law information + * @param distributionLaw the distribution law name + * @param delayExtra a map of distribution law parameters to values + * @param _st the syntactic transition (provides locations for error messages) + */ private void setDistributionLaw(AvatarTransition _t, String distributionLaw, HashMap<String,String> delayExtra, StxTransition _st) { int law = -1; int size; - if (distributionLaw == null || distributionLaw.equals("")) law = AvatarTransition.DELAY_UNIFORM_LAW; + + // identify distribution law......... set default DELAY_UNIFORM_LAW when a problem is encountered + if (distributionLaw == null || distributionLaw.equals("")) law = DELAY_UNIFORM_LAW; else { - size = _t.DISTRIBUTION_LAWS.length; - for (int i = 0; i < size; i++) { - if (_t.DISTRIBUTION_LAWS[i].equals(distributionLaw)) { + size = DISTRIBUTION_LAWS.length; + for (int i = 0; i < size; i++) { // search in defined laws + if (DISTRIBUTION_LAWS[i].equals(distributionLaw)) { law = i; break; } } - if (law == -1) { + if (law == -1) { // not found addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, _st.getLeft(), "transition with unknown transition law : " + distributionLaw + " (set to uniform)")); - law = AvatarTransition.DELAY_UNIFORM_LAW; + law = DELAY_UNIFORM_LAW; } } - String extra1 = _t.LABELS_OF_EXTRA_ATTRIBUTES_1[law]; - String extra2 = _t.LABELS_OF_EXTRA_ATTRIBUTES_2[law]; - size = _t.NB_OF_EXTRA_ATTRIBUTES[law]; + // try to get law parameters............ + // get law parameter names + String extra1 = LABELS_OF_EXTRA_ATTRIBUTES_1[law]; + String extra2 = LABELS_OF_EXTRA_ATTRIBUTES_2[law]; + + size = NB_OF_EXTRA_ATTRIBUTES[law]; + int max = size; String tmpString; if (size > 0) { tmpString = extra1; - extra1 = delayExtra.get(extra1); - if (extra1 == null) { + extra1 = delayExtra.get(extra1); // try to get value of first parameter through its name + if (extra1 == null) { // not found addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, _st.getLeft(), "transition law : " + distributionLaw + " requires a " + tmpString + " parameter")); + max--; } if (size > 1) { tmpString = extra2; - extra2 = delayExtra.get(extra2); - if (extra2 == null) { + extra2 = delayExtra.get(extra2); // try to get value of second parameter through its name + if (extra2 == null) { // not found addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, _st.getLeft(), "transition law : " + distributionLaw + " requires a " + tmpString + " parameter")); + max--; } } } - if (delayExtra != null && delayExtra.size() > size) { + if (delayExtra != null && delayExtra.size() > max) { // there is some unexpected parameter value addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, _st.getLeft(), - "transition law : " + distributionLaw + " has too much parameters")); + "transition law : " + distributionLaw + " has irrelevant parameters")); } + // complete transition with identified data _t.setDistributionLaw(law, extra1, extra2); } + + /** fills the parameters of a method (or signal) w.r.t. the data of a syntactic structure + * + * @param ss the syntactic structure containing field information + * @param am the method to update by adding the fields characterized in ss + * @param b the block of the method + */ private void buildProfile(StxStructure ss, AvatarMethod am, AvatarBlock b) { AvatarAttribute aa; int size = ss.getSize(); - for (int i = 0; i < size; i++) { + for (int i = 0; i < size; i++) { // iterates on the fields of the structure ss String type = ss.getFieldType(i); if (type.equals("Integer")){ aa = new AvatarAttribute(ss.getFieldName(i), AvatarType.INTEGER, b, null); @@ -1182,29 +1222,39 @@ public class AvatarFromSysML { aa = new AvatarAttribute(ss.getFieldName(i), AvatarType.BOOLEAN, b, null); am.addParameter(aa); aa.setAsConstant(false); - } else { + } else { // the field is datatype-typed AvatarDataType adt = avSpec.getDataTypeByName(type); if (adt == null) { addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, ss.getLeft(), "message profile uses undefined datatype " + type)); } + // add the original version of the field to am String aaName = ss.getFieldName(i); aa = new AvatarAttribute(aaName, AvatarType.UNDEFINED, b, null); aa.setDataType(adt); am.addOriginalParameter(aa); aa.setAsConstant(false); - aaName = aaName + "__"; - AvatarDataTypePrimitiveFields primitiveFields = primitiveFieldsMap.get(adt); - int dtsize = primitiveFields.size(); - for (int j = 0; j < dtsize; j++) { - aa = new AvatarAttribute(aaName + primitiveFields.getName(j), - primitiveFields.getType(j), b, null); + // add the primitive basic attributes corresponding to the datatype's field + if (adt != null) { + aaName = aaName + "__"; + AvatarDataTypePrimitiveFields primitiveFields = primitiveFieldsMap.get(adt); + int dtsize = primitiveFields.size(); + for (int j = 0; j < dtsize; j++) { + aa = new AvatarAttribute(aaName + primitiveFields.getName(j), + primitiveFields.getType(j), b, null); + am.addParameter(aa); + aa.setAsConstant(false); + } + } else { // error, try to continue with the non coherent attribute alone + aa = new AvatarAttribute(aaName, AvatarType.UNDEFINED, b, null); am.addParameter(aa); aa.setAsConstant(false); } } } } + + /** get the type of an attribute (not an attribute field) from a syntactic block */ private String getStxAttributeType(String name, StxBlock blk){ int size = blk.getNbAttributes(); for (int i = 0; i < size; i++) { @@ -1212,6 +1262,8 @@ public class AvatarFromSysML { } return null; } + + /** get the type of an attribute (or an attribute field, with "__" as field delimiter) from a syntactic block */ private String getStxPathType(String s, StxBlock b) { String[] path = s.split("__"); String type = getStxAttributeType(path[0], b); @@ -1234,32 +1286,40 @@ public class AvatarFromSysML { } return type; } - private String extendString; + /** (string) Type found for ident extended by by extendPath (and thus extendIdent) */ + private String extendTypeString; + /** DataType found for ident extended by extendPath (and thus extendIdent) if not primitive type */ private AvatarDataType extendDataType; + /** Primitive type found for ident extended by extendPath (and thus extendIdent) if not datatype type */ private AvatarType extendPrimitiveType; + + /** extends a parameter attribute or field name x in a list "x__field1, ..., x__fieldN" respecting the fields of its associated type. + * If type is primitive, returns x unchanged. Updates extendTypeString, extendDataType and extendPrimitiveType w.r.t. the found type. */ private String extendPath(String path, StxBlock b) { - extendString = getStxPathType(path, b); - if (extendString == null) { + extendTypeString = getStxPathType(path, b); + if (extendTypeString == null) { // path cannot be typed, return null to notify the error extendDataType = null; extendPrimitiveType = null; return null; } - if (extendString.equals("Integer")) { + if (extendTypeString.equals("Integer")) { extendDataType = null; extendPrimitiveType = AvatarType.INTEGER; return path; } - if (extendString.equals("Boolean")) { + if (extendTypeString.equals("Boolean")) { extendDataType = null; extendPrimitiveType = AvatarType.BOOLEAN; return path; } extendPrimitiveType = null; - extendDataType = avSpec.getDataTypeByName(extendString); + extendDataType = avSpec.getDataTypeByName(extendTypeString); if (extendDataType != null) return extendName(path, extendDataType); else return null; } + + /** extends a parameter name x in a list "x__field1, ..., x__fieldN" respecting the fields of parameter datatype */ private String extendName(String name, AvatarDataType adt) { if (adt != null) { AvatarDataTypePrimitiveFields primitiveFields = primitiveFieldsMap.get(adt); @@ -1273,10 +1333,16 @@ public class AvatarFromSysML { } else return null; } + /** extends a parameter attribute or field name x in a list in brackets "(x__field1, ..., x__fieldN)" respecting the fields of its associated + * type. If this type is primitive, returns x unchanged. Updates extendTypeString, extendDataType and extendPrimitiveType w.r.t. the found type. + * extends a parameter name x in a list "x__field1, ..., x__fieldN" respecting the fields of parameter datatype + */ private String extendIdent (String path, StxBlock b) { String result = extendPath(path, b); return (result.indexOf(',') == -1 ? result : "(" + result + ")"); } + + /** builds the string associated to a method call while extending the ones among the idents it uses that are datatype-typed */ private String extendCall (StxCall call, StxBlock b) { StringBuffer result = new StringBuffer(); int size = call.getNbIdents(); @@ -1288,6 +1354,7 @@ public class AvatarFromSysML { result.append(call.getSegment(i)); return result.toString().replaceAll("\\.", "__"); } + /** rebuilds the original string associated to a method call, without ident extension */ private String extendOriginalCall (StxCall call, StxBlock b) { StringBuffer result = new StringBuffer(); int size = call.getNbIdents(); @@ -1299,61 +1366,78 @@ public class AvatarFromSysML { result.append(call.getSegment(i)); return result.toString(); } + // BUILD RELATIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + /** create-and-add-to-avSpec the relations identified in stxSpec */ private void buildRelations(){ stxSpec.getRelationMap().forEach(new BuildRelation()); } + + /** to be run on relations identified while parsing and memorized in stxSpec's relation map. Create, fill and adds-to-avSpec a relation. */ private class BuildRelation implements BiConsumer<String, StxRelation> { public BuildRelation() { } public void accept(String n, StxRelation r) { - if (!r.isDeclared()) { + if (!r.isDeclared()) { // declaration part is missing in source addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, "relation " + r.getName() +" has been used but has not been declared")); + // try to recover int size = r.getSize(); - if (size == 0) { + if (size == 0) { // empty relation is droped addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, r.getLeft(), "relation is empty")); return; - } else { + } else { // channels found, try to recover blocks from them int i = 0; while (i < size && (r.getChannel(i).getBlockA() == null || r.getChannel(i).getBlockB() == null)) i++; - if (i == size) { + if (i == size) { // cannot find a channel with two clearly named blocks, drop relation addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, "cannot determine blocs of relation " + r.getName())); return; } + // block names found, search associated AvatarBlock structures r.setBlock1(stxSpec.getBlockMap().get(r.getChannel(i).getBlockA())); r.setBlock2(stxSpec.getBlockMap().get(r.getChannel(i).getBlockB())); - if (r.getBlock1() == null || r.getBlock2() == null) { + if (r.getBlock1() == null || r.getBlock2() == null) { // AvatarBlock structures not found, drop relation addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, "cannot determine blocs of relation " + r.getName())); return; } } } + + // from here, relation has blocks (from declaration or recovered) + AvatarBlock blk1 = getBlock(r.getBlock1()); AvatarBlock blk2 = getBlock(r.getBlock2()); + + // create-and-add-to-avSpec the Avatar relation AvatarRelation theRelation = new AvatarRelation(n, blk1, blk2, null); avSpec.addRelation(theRelation); + + // set relation parameters theRelation.setAsynchronous(r.getAsynchronous()); theRelation.setPrivate(r.getPrivate()); theRelation.setLossy(r.getLossy()); theRelation.setBlocking(r.getBlocking()); theRelation.setSizeOfFIFO(r.getFifoSize()); + + // add channels to the relation int size = r.getSize(); - if (size == 0) { + if (size == 0) { // empty relation, kept because coherent although useless addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, r.getLeft(), "relation " + r.getName() + " is empty")); } - for (int i = 0; i < size; i++) { - StxChannel c = r.getChannel(i); - c.commuteSignals(r.getBlock1().getName()); - if (!blk1.getName().equals(c.getBlockA()) || !blk2.getName().equals(c.getBlockB())) { - addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, c.getLeft(), - "inconsistency between blocs of channel " + c.getName() + " and relation " + r.getName())); - continue; + for (int i = 0; i < size; i++) { // iterate on channels + StxChannel c = r.getChannel(i); // get channel + c.commuteSignals(r.getBlock1().getName()); // make channel respect block order in relation + if (!blk1.getName().equals(c.getBlockA()) || !blk2.getName().equals(c.getBlockB())) { // channel doesn't respect relation's blocks + addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, c.getLeft(), + "inconsistency between blocs of channel " + c.getName() + " and its relation " + r.getName())); + continue; } + // try to add channel to relation if (c.getSignalA() != null && c.getSignalB() != null) theRelation.addSignals(getSignal(c.getSignalA()),getSignal(c.getSignalB())); else -- GitLab