Skip to content
Snippets Groups Projects
AvatarFromSysML.java 82.4 KiB
Newer Older
                                AvatarSetTimer state = (AvatarSetTimer) tgtState;

                                // some unrecovered errors (transition skipped)
                                if (transition.getTimer() == null) {
                                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                            "set-timer transition has no associated timer", transition.getRleft()));
                                    continue;
                                }
                                state.setTimer(getTimerByName(transition.getTimer(), theBlock));
                                if (transition.getSendPayload() == null || transition.getSendPayload().size() != 1
                                        || !(transition.getSendPayload().get(0) instanceof StxExpr)) {
                                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                            "payload of set-timer transition is not well formed", transition.getRleft()));
                                    continue;
                                }

                                // update target state with its specific parameters
                                state.setTimerValue(((StxExpr)transition.getSendPayload().get(0)).toString().replaceAll(".","__"));
                                state.setTimerOriginalValue(((StxExpr)transition.getSendPayload().get(0)).toString());
                            }
                            else  { // unrecoved error, skip transition
                                addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                        "set-timer transition should lead to a set-timer state", transition.getRleft()));
                                continue;
                            }

                        // reset-timer transitions =====================
                        else if (transition.getType() == AvatarFromSysMLSyntax.STXRESETTIMERTRANSITION) {
                            if(tgtState instanceof AvatarResetTimer) {
                                AvatarResetTimer state = (AvatarResetTimer) tgtState;

                                // an unrecovered error (transition skipped)
Sophie Coudert's avatar
Sophie Coudert committed
                                if (transition.getTimer() == null) {
                                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                            "reset-timer transition has no associated timer", transition.getRleft()));
                                    continue;
Sophie Coudert's avatar
Sophie Coudert committed
                                }

                                // update target state with its specific parameter
                                state.setTimer(getTimerByName(transition.getTimer(), theBlock));
                            }
                            else  { // unrecoved error, skip transition
                                addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                        "reset-timer transition should lead to a reset-timer state", transition.getRleft()));
                                continue;
                            }
                        // expire-timer transitions =====================
                        else if (transition.getType() == AvatarFromSysMLSyntax.STXEXPIRETIMERTRANSITION) {
                            if(tgtState instanceof AvatarExpireTimer) {
                                AvatarExpireTimer state = (AvatarExpireTimer) tgtState;

                                // an unrecovered error (transition skipped)
Sophie Coudert's avatar
Sophie Coudert committed
                                if (transition.getTimer() == null) {
                                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                            "expire-timer transition has no associated timer", transition.getRleft()));
                                    continue;
Sophie Coudert's avatar
Sophie Coudert committed
                                }

                                // update target state with its specific parameter
                                state.setTimer(getTimerByName(transition.getTimer(), theBlock));
                            else  { // unrecoved error, skip transition
                                addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                        "expire-timer transition should lead to a expire-timer state", transition.getRleft()));
                                continue;
                            }

                        // standard transitions to non-communicating state =====================
                        else if (! (tgtType == AvatarFromSysMLSyntax.STXSTOPSTATE ||
                                tgtType == AvatarFromSysMLSyntax.STXSTANDARDSTATE ||
                                tgtType == AvatarFromSysMLSyntax.STXRANDOMSTATE ||
                                tgtType == AvatarFromSysMLSyntax.STXCOUNTSTATE ||
                                tgtType == AvatarFromSysMLSyntax.STXSTARTSTATE) ) {
                            addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, transition.getLeft(),
                                    "transition type is not consistant with the type of its target state", transition.getTarget().getLeft()));

                        // All unrecovered errors have been avoided, the transition can be added
                        asm.addElement(theTransition);
                        theSourceState.addNext(theTransition);
Sophie Coudert's avatar
Sophie Coudert committed
                        theTransition.addNext(tgtState);
                        addTransition(theTransition, tgtState); // memorize incoming transition for post-processing
Sophie Coudert's avatar
Sophie Coudert committed
                    }
            // post-processing: verify some constraints on incoming transitions
            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)) { // 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)) { // 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++) {
                    st.getTransitions().get(i).getNexts().clear();
                    AvatarStopState nw = new AvatarStopState("errorstate",null, st.getBlock());
                    st.getTransitions().get(i).addNext(nw);
                    st.getBlock().getStateMachine().addElement(nw);
            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"));

                for(int i = 1; i < s; i++) {
                    st.getTransitions().get(i).getNexts().clear();
                    AvatarStopState nw = new AvatarStopState("errorstate",null, st.getBlock());
                    st.getTransitions().get(i).addNext(nw);
                    st.getBlock().getStateMachine().addElement(nw);
    /** 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)
     */
Sophie Coudert's avatar
Sophie Coudert committed
    private void setDistributionLaw(AvatarTransition _t, String distributionLaw, HashMap<String,String> delayExtra, StxTransition _st) {

        // identify distribution law......... set default DELAY_UNIFORM_LAW when a problem is encountered
        if (distributionLaw == null || distributionLaw.equals("")) law = DELAY_UNIFORM_LAW;
            size = DISTRIBUTION_LAWS.length;
            for (int i = 0; i < size; i++) { // search in defined laws
                if (DISTRIBUTION_LAWS[i].equals(distributionLaw)) {
            if (law == -1) { // not found
Sophie Coudert's avatar
Sophie Coudert committed
                addError(new AvatarFromSysMLError(AvatarFromSysMLError.HIGHERROR, _st.getLeft(),
                 "transition with unknown transition law : " + distributionLaw + " (set to uniform)"));
                law = DELAY_UNIFORM_LAW;
Sophie Coudert's avatar
Sophie Coudert committed
            }
        // 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;
Sophie Coudert's avatar
Sophie Coudert committed
        String tmpString;
Sophie Coudert's avatar
Sophie Coudert committed
            tmpString = extra1;
            extra1 = delayExtra.get(extra1); // try to get value of first parameter through its name
            if (extra1 == null) { // not found
Sophie Coudert's avatar
Sophie Coudert committed
                addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, _st.getLeft(),
                 "transition law : " + distributionLaw + " requires a " + tmpString + " parameter"));
                max--;
Sophie Coudert's avatar
Sophie Coudert committed
            }
Sophie Coudert's avatar
Sophie Coudert committed
                tmpString = extra2;
                extra2 = delayExtra.get(extra2); // try to get value of second parameter through its name
                if (extra2 == null) { // not found
Sophie Coudert's avatar
Sophie Coudert committed
                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, _st.getLeft(),
                     "transition law : " + distributionLaw + " requires a " + tmpString + " parameter"));
                    max--;
Sophie Coudert's avatar
Sophie Coudert committed
                }
        if (delayExtra != null && delayExtra.size() > max) { // there is some unexpected parameter value
Sophie Coudert's avatar
Sophie Coudert committed
                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, _st.getLeft(),
                     "transition law : " + distributionLaw + " has irrelevant parameters"));
Sophie Coudert's avatar
Sophie Coudert committed

        }
        // 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++) { // 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);
Sophie Coudert's avatar
Sophie Coudert committed
                am.addOriginalParameter(aa);
                aa.setAsConstant(false);
                aa = new AvatarAttribute(ss.getFieldName(i), AvatarType.INTEGER, b, null);
                am.addParameter(aa);
                aa.setAsConstant(false);
           } else if (type.equals("Boolean")) {
                aa = new AvatarAttribute(ss.getFieldName(i), AvatarType.BOOLEAN, b, null);
Sophie Coudert's avatar
Sophie Coudert committed
                am.addOriginalParameter(aa);
                aa.setAsConstant(false);
                aa = new AvatarAttribute(ss.getFieldName(i), AvatarType.BOOLEAN, b, null);
                am.addParameter(aa);
                aa.setAsConstant(false);
            } else { // the field is datatype-typed
Sophie Coudert's avatar
Sophie Coudert committed
                AvatarDataType adt = avSpec.getDataTypeByName(type);
Sophie Coudert's avatar
Sophie Coudert committed
                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);
Sophie Coudert's avatar
Sophie Coudert committed
                aa.setDataType(adt);
                am.addOriginalParameter(aa);
                aa.setAsConstant(false);
                // 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++) {
            if (blk.getAttribute(i).getName().equals(name)) return blk.getAttribute(i).getType();
        }
        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);
        int size = path.length;
        for (int i = 1; i < size; i++) {
Sophie Coudert's avatar
Sophie Coudert committed
            AvatarDataType adt = avSpec.getDataTypeByName(type);
            if (adt == null) return null;
            int nbFields = adt.attributeNb();
            int j;
            for (j = 0; j < nbFields; j++)
Sophie Coudert's avatar
Sophie Coudert committed
                if (adt.getAttribute(j).getName().equals(path[i])) break;
            if (j == nbFields) return null;
Sophie Coudert's avatar
Sophie Coudert committed
            AvatarType adtType = adt.getAttribute(j).getType();
            if (adtType == AvatarType.INTEGER)
Sophie Coudert's avatar
Sophie Coudert committed
            else if (adtType == AvatarType.BOOLEAN)
                type = adt.getAttribute(j).getDataType().getName();
    /** (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) {
        extendTypeString = getStxPathType(path, b);
        if (extendTypeString == null) { // path cannot be typed, return null to notify the error
            extendDataType = null;
            extendPrimitiveType = null;
            return null;
        }
        if (extendTypeString.equals("Integer")) {
            extendDataType = null;
            extendPrimitiveType = AvatarType.INTEGER;
            return path;
        }
        if (extendTypeString.equals("Boolean")) {
            extendDataType = null;
            extendPrimitiveType = AvatarType.BOOLEAN;
        extendPrimitiveType = null;
        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);
Sophie Coudert's avatar
Sophie Coudert committed
            int size = primitiveFields.size() -1;
            StringBuffer res = new StringBuffer();
            int i;
            for (i = 0; i < size; i++)
                res.append(name + "__" + primitiveFields.getName(i) + ", ");
            res.append(name + "__" + primitiveFields.getName(i));
            return res.toString();
        }
        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();
        int i;
        for (i =0 ; i < size; i++) {
            result.append(call.getSegment(i));
            result.append(extendPath(call.getIdent(i).replaceAll("\\.", "__"), b));
        }
        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();
        int i;
        for (i =0 ; i < size; i++) {
            result.append(call.getSegment(i));
Sophie Coudert's avatar
Sophie Coudert committed
            result.append(call.getIdent(i));
        }
        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()) { // 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) { // empty relation is droped
                    addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, r.getLeft(),
                     "relation is empty"));
                    return;
                } 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) { // 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) { // 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) { // empty relation, kept because coherent although useless
Sophie Coudert's avatar
Sophie Coudert committed
                addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWWARNING, r.getLeft(),
                 "relation " + r.getName() + " is empty"));
Sophie Coudert's avatar
Sophie Coudert committed
            }
            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
                 addError(new AvatarFromSysMLError(AvatarFromSysMLError.LOWERROR, c.getLeft(),
                 "missing signal binding for channel"));
           }