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