Search in sources :

Example 1 with Variable

use of org.lflang.lf.Variable in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkOutputControlReaction.

/**
 * Add a network control reaction for a given output port 'source' to
 * source's parent reactor. This reaction will send a port absent
 * message if the status of the output port is absent.
 *
 * @note Used in federated execution
 *
 * @param source The output port of the source federate
 * @param instance The federate instance is used to keep track of all
 *  network reactions and some relevant triggers
 * @param receivingPortID The ID of the receiving port
 * @param channelIndex The channel index of the sending port, if it is a multiport.
 * @param bankIndex The bank index of the sending federate, if it is a bank.
 * @param receivingFedID The ID of destination federate.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param delay The delay value imposed on the connection using after
 */
private static void addNetworkOutputControlReaction(PortInstance source, FederateInstance instance, int receivingPortID, int bankIndex, int channelIndex, int receivingFedID, GeneratorBase generator, Delay delay) {
    LfFactory factory = LfFactory.eINSTANCE;
    Reaction reaction = factory.createReaction();
    // Top-level reactor.
    Reactor top = source.getParent().getParent().reactorDefinition;
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(reaction, bankIndex);
    // Add the output from the contained reactor as a source to
    // the reaction to preserve precedence order.
    VarRef newPortRef = factory.createVarRef();
    newPortRef.setContainer(source.getParent().getDefinition());
    newPortRef.setVariable(source.getDefinition());
    reaction.getSources().add(newPortRef);
    // Check whether the action already has been created.
    if (instance.networkOutputControlReactionsTrigger == null) {
        // The port has not been created.
        String triggerName = "outputControlReactionTrigger";
        // Find the trigger definition in the reactor definition, which could have been
        // generated for another federate instance if there are multiple instances
        // of the same reactor that are each distinct federates.
        Optional<Action> optTriggerInput = top.getActions().stream().filter(I -> I.getName().equals(triggerName)).findFirst();
        if (optTriggerInput.isEmpty()) {
            // If no trigger with the name "outputControlReactionTrigger" is
            // already added to the reactor definition, we need to create it
            // for the first time. The trigger is a logical action.
            Action newTriggerForControlReactionVariable = factory.createAction();
            newTriggerForControlReactionVariable.setName(triggerName);
            newTriggerForControlReactionVariable.setOrigin(ActionOrigin.LOGICAL);
            top.getActions().add(newTriggerForControlReactionVariable);
            // Now that the variable is created, store it in the federate instance
            instance.networkOutputControlReactionsTrigger = newTriggerForControlReactionVariable;
        } else {
            // If the "outputControlReactionTrigger" trigger is already
            // there, we can re-use it for this new reaction since a single trigger
            // will trigger
            // all network output control reactions.
            instance.networkOutputControlReactionsTrigger = optTriggerInput.get();
        }
    }
    // Add the trigger for all output control reactions to the list of triggers
    VarRef triggerRef = factory.createVarRef();
    triggerRef.setVariable(instance.networkOutputControlReactionsTrigger);
    reaction.getTriggers().add(triggerRef);
    // Generate the code
    reaction.setCode(factory.createCode());
    reaction.getCode().setBody(generator.generateNetworkOutputControlReactionBody(newPortRef, receivingPortID, receivingFedID, bankIndex, channelIndex, delay));
    // Make the reaction unordered w.r.t. other reactions in the top level.
    generator.makeUnordered(reaction);
    // Insert the newly generated reaction after the generated sender and
    // receiver top-level reactions.
    top.getReactions().add(reaction);
    // Add the network output control reaction to the federate instance's list
    // of network reactions
    instance.networkReactions.add(reaction);
}
Also used : VarRef(org.lflang.lf.VarRef) Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) Instantiation(org.lflang.lf.Instantiation) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Connection(org.lflang.lf.Connection) Type(org.lflang.lf.Type) GeneratorBase(org.lflang.generator.GeneratorBase) CoordinationType(org.lflang.TargetProperty.CoordinationType) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) PortInstance(org.lflang.generator.PortInstance) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) Optional(java.util.Optional) VarRef(org.lflang.lf.VarRef) Collections(java.util.Collections) ASTUtils(org.lflang.ASTUtils) Action(org.lflang.lf.Action) LfFactory(org.lflang.lf.LfFactory) Reaction(org.lflang.lf.Reaction) Reactor(org.lflang.lf.Reactor)

Example 2 with Variable

use of org.lflang.lf.Variable in project lingua-franca by lf-lang.

the class FedASTUtils method findMaxSTP.

/**
 * Find the maximum STP offset for the given 'port'.
 *
 * An STP offset predicate can be nested in contained reactors in
 * the federate.
 * @param port The port to generate the STP list for.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param reactor The top-level reactor (not the federate reactor)
 * @return The maximum STP as a TimeValue
 */
private static TimeValue findMaxSTP(Variable port, FederateInstance instance, GeneratorBase generator, Reactor reactor) {
    // Find a list of STP offsets (if any exists)
    List<Value> STPList = new LinkedList<>();
    // First, check if there are any connections to contained reactors that
    // need to be handled
    List<Connection> connectionsWithPort = ASTUtils.allConnections(reactor).stream().filter(c -> c.getLeftPorts().stream().anyMatch((VarRef v) -> v.getVariable().equals(port))).collect(Collectors.toList());
    // Find the list of reactions that have the port as trigger or source
    // (could be a variable name)
    List<Reaction> reactionsWithPort = ASTUtils.allReactions(reactor).stream().filter(r -> {
        // Check the triggers of reaction r first
        return r.getTriggers().stream().anyMatch(t -> {
            if (t instanceof VarRef) {
                // Check if the variables match
                return ((VarRef) t).getVariable() == port;
            } else {
                // Not a network port (startup or shutdown)
                return false;
            }
        }) || // Then check the sources of reaction r
        r.getSources().stream().anyMatch(s -> s.getVariable() == port);
    }).collect(Collectors.toList());
    // Find a list of STP offsets (if any exists)
    if (generator.isFederatedAndDecentralized()) {
        for (Reaction r : safe(reactionsWithPort)) {
            if (!instance.contains(r)) {
                continue;
            }
            // If not, assume it is zero
            if (r.getStp() != null) {
                if (r.getStp().getValue().getParameter() != null) {
                    List<Instantiation> instantList = new ArrayList<>();
                    instantList.add(instance.instantiation);
                    STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
                } else {
                    STPList.add(r.getStp().getValue());
                }
            }
        }
        // Check the children for STPs as well
        for (Connection c : safe(connectionsWithPort)) {
            VarRef childPort = c.getRightPorts().get(0);
            Reactor childReactor = (Reactor) childPort.getVariable().eContainer();
            // Find the list of reactions that have the port as trigger or
            // source (could be a variable name)
            List<Reaction> childReactionsWithPort = ASTUtils.allReactions(childReactor).stream().filter(r -> r.getTriggers().stream().anyMatch(t -> {
                if (t instanceof VarRef) {
                    // Check if the variables match
                    return ((VarRef) t).getVariable() == childPort.getVariable();
                } else {
                    // Not a network port (startup or shutdown)
                    return false;
                }
            }) || r.getSources().stream().anyMatch(s -> s.getVariable() == childPort.getVariable())).collect(Collectors.toList());
            for (Reaction r : safe(childReactionsWithPort)) {
                if (!instance.contains(r)) {
                    continue;
                }
                // If not, assume it is zero
                if (r.getStp() != null) {
                    if (r.getStp().getValue() instanceof Parameter) {
                        List<Instantiation> instantList = new ArrayList<>();
                        instantList.add(childPort.getContainer());
                        STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
                    } else {
                        STPList.add(r.getStp().getValue());
                    }
                }
            }
        }
    }
    return STPList.stream().map(ASTUtils::getLiteralTimeValue).filter(Objects::nonNull).reduce(TimeValue.ZERO, TimeValue::max);
}
Also used : Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) Instantiation(org.lflang.lf.Instantiation) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Connection(org.lflang.lf.Connection) Type(org.lflang.lf.Type) GeneratorBase(org.lflang.generator.GeneratorBase) CoordinationType(org.lflang.TargetProperty.CoordinationType) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) PortInstance(org.lflang.generator.PortInstance) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) Optional(java.util.Optional) VarRef(org.lflang.lf.VarRef) Collections(java.util.Collections) ASTUtils(org.lflang.ASTUtils) VarRef(org.lflang.lf.VarRef) ASTUtils(org.lflang.ASTUtils) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Value(org.lflang.lf.Value) Parameter(org.lflang.lf.Parameter) Instantiation(org.lflang.lf.Instantiation) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 3 with Variable

use of org.lflang.lf.Variable in project lingua-franca by lf-lang.

the class ASTUtils method findConflictingConnectionsInModalReactors.

/**
 * Find connections in the given resource that would be conflicting writes if they were not located in mutually
 * exclusive modes.
 *
 * @param resource The AST.
 * @return a list of connections being able to be transformed
 */
public static Collection<Connection> findConflictingConnectionsInModalReactors(Resource resource) {
    var transform = new HashSet<Connection>();
    var reactors = Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), Reactor.class);
    for (Reactor reactor : reactors) {
        if (!reactor.getModes().isEmpty()) {
            // Only for modal reactors
            var allWriters = HashMultimap.<Pair<Instantiation, Variable>, EObject>create();
            // Collect destinations
            for (var rea : allReactions(reactor)) {
                for (var eff : rea.getEffects()) {
                    if (eff.getVariable() instanceof Port) {
                        allWriters.put(Tuples.pair(eff.getContainer(), eff.getVariable()), rea);
                    }
                }
            }
            for (var con : ASTUtils.<Connection>collectElements(reactor, featurePackage.getReactor_Connections(), false, true)) {
                for (var port : con.getRightPorts()) {
                    allWriters.put(Tuples.pair(port.getContainer(), port.getVariable()), con);
                }
            }
            // Handle conflicting writers
            for (var key : allWriters.keySet()) {
                var writers = allWriters.get(key);
                if (writers.size() > 1) {
                    // has multiple sources
                    var writerModes = HashMultimap.<Mode, EObject>create();
                    // find modes
                    for (var writer : writers) {
                        if (writer.eContainer() instanceof Mode) {
                            writerModes.put((Mode) writer.eContainer(), writer);
                        } else {
                            writerModes.put(null, writer);
                        }
                    }
                    // Conflicting connection can only be handled if..
                    if (// no writer is on root level (outside of modes) and...
                    !writerModes.containsKey(null) && writerModes.keySet().stream().map(m -> writerModes.get(m)).allMatch(// all writers in a mode are either...
                    writersInMode -> // the only writer or...
                    writersInMode.size() == 1 || // all are reactions and hence ordered
                    writersInMode.stream().allMatch(w -> w instanceof Reaction))) {
                        // Add connections to transform list
                        writers.stream().filter(w -> w instanceof Connection).forEach(c -> transform.add((Connection) c));
                    }
                }
            }
        }
    }
    return transform;
}
Also used : Code(org.lflang.lf.Code) LfPackage(org.lflang.lf.LfPackage) Delay(org.lflang.lf.Delay) WidthSpec(org.lflang.lf.WidthSpec) EStructuralFeature(org.eclipse.emf.ecore.EStructuralFeature) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) ILeafNode(org.eclipse.xtext.nodemodel.ILeafNode) StateVar(org.lflang.lf.StateVar) Matcher(java.util.regex.Matcher) HashMultimap(com.google.common.collect.HashMultimap) Port(org.lflang.lf.Port) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) INode(org.eclipse.xtext.nodemodel.INode) Connection(org.lflang.lf.Connection) GeneratorBase(org.lflang.generator.GeneratorBase) Element(org.lflang.lf.Element) TypeParm(org.lflang.lf.TypeParm) Collection(java.util.Collection) CompositeNode(org.eclipse.xtext.nodemodel.impl.CompositeNode) Set(java.util.Set) InvalidSourceException(org.lflang.generator.InvalidSourceException) EObject(org.eclipse.emf.ecore.EObject) ICompositeNode(org.eclipse.xtext.nodemodel.ICompositeNode) ArraySpec(org.lflang.lf.ArraySpec) Mode(org.lflang.lf.Mode) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) CodeMap(org.lflang.generator.CodeMap) WidthTerm(org.lflang.lf.WidthTerm) Assignment(org.lflang.lf.Assignment) Resource(org.eclipse.emf.ecore.resource.Resource) ActionOrigin(org.lflang.lf.ActionOrigin) Pattern(java.util.regex.Pattern) StringExtensions(org.eclipse.xtext.xbase.lib.StringExtensions) Output(org.lflang.lf.Output) Variable(org.lflang.lf.Variable) Iterables(com.google.common.collect.Iterables) LfFactory(org.lflang.lf.LfFactory) NodeModelUtils(org.eclipse.xtext.nodemodel.util.NodeModelUtils) ImportedReactor(org.lflang.lf.ImportedReactor) Iterators(com.google.common.collect.Iterators) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Pair(org.eclipse.xtext.util.Pair) TargetDecl(org.lflang.lf.TargetDecl) StringUtil(org.lflang.util.StringUtil) Reaction(org.lflang.lf.Reaction) KeyValuePair(org.lflang.lf.KeyValuePair) Type(org.lflang.lf.Type) LinkedHashSet(java.util.LinkedHashSet) Tuples(org.eclipse.xtext.util.Tuples) XtextResource(org.eclipse.xtext.resource.XtextResource) HiddenLeafNode(org.eclipse.xtext.nodemodel.impl.HiddenLeafNode) Model(org.lflang.lf.Model) ReactorDecl(org.lflang.lf.ReactorDecl) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) Time(org.lflang.lf.Time) EList(org.eclipse.emf.common.util.EList) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) TerminalRule(org.eclipse.xtext.TerminalRule) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) Timer(org.lflang.lf.Timer) EObject(org.eclipse.emf.ecore.EObject) Port(org.lflang.lf.Port) Mode(org.lflang.lf.Mode) Connection(org.lflang.lf.Connection) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Pair(org.eclipse.xtext.util.Pair) KeyValuePair(org.lflang.lf.KeyValuePair)

Example 4 with Variable

use of org.lflang.lf.Variable in project lingua-franca by lf-lang.

the class FederateInstance method indexExcludedTopLevelReactions.

/**
 * Build an index of reactions at the top-level (in the
 * federatedReactor) that don't belong to this federate
 * instance. This index is put in the excludeReactions
 * class variable.
 *
 * @param federatedReactor The top-level federated reactor
 */
private void indexExcludedTopLevelReactions(Reactor federatedReactor) {
    boolean inFederate = false;
    if (excludeReactions != null) {
        throw new IllegalStateException("The index for excluded reactions at the top level is already built.");
    }
    excludeReactions = new LinkedHashSet<Reaction>();
    // Construct the set of excluded reactions for this federate.
    // If a reaction is a network reaction that belongs to this federate, we
    // don't need to perform this analysis.
    Iterable<Reaction> reactions = IterableExtensions.filter(ASTUtils.allReactions(federatedReactor), it -> {
        return !networkReactions.contains(it);
    });
    for (Reaction react : reactions) {
        // Create a collection of all the VarRefs (i.e., triggers, sources, and effects) in the react
        // signature that are ports that reference federates.
        // We then later check that all these VarRefs reference this federate. If not, we will add this
        // react to the list of reactions that have to be excluded (note that mixing VarRefs from
        // different federates is not allowed).
        List<VarRef> allVarRefsReferencingFederates = new ArrayList<VarRef>();
        // Add all the triggers that are outputs
        Stream<VarRef> triggersAsVarRef = react.getTriggers().stream().filter(it -> it instanceof VarRef).map(it -> (VarRef) it);
        allVarRefsReferencingFederates.addAll(triggersAsVarRef.filter(it -> it.getVariable() instanceof Output).collect(Collectors.toList()));
        // Add all the sources that are outputs
        allVarRefsReferencingFederates.addAll(react.getSources().stream().filter(it -> it.getVariable() instanceof Output).collect(Collectors.toList()));
        // Add all the effects that are inputs
        allVarRefsReferencingFederates.addAll(react.getEffects().stream().filter(it -> it.getVariable() instanceof Input).collect(Collectors.toList()));
        inFederate = containsAllVarRefs(allVarRefsReferencingFederates);
        if (!inFederate) {
            excludeReactions.add(react);
        }
    }
}
Also used : VarRef(org.lflang.lf.VarRef) Variable(org.lflang.lf.Variable) Delay(org.lflang.lf.Delay) ErrorReporter(org.lflang.ErrorReporter) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) TriggerInstance(org.lflang.generator.TriggerInstance) Reaction(org.lflang.lf.Reaction) Objects(com.google.common.base.Objects) TimeValue(org.lflang.TimeValue) LinkedHashSet(java.util.LinkedHashSet) GeneratorBase(org.lflang.generator.GeneratorBase) Set(java.util.Set) PortInstance(org.lflang.generator.PortInstance) ReactionInstance(org.lflang.generator.ReactionInstance) Collectors(java.util.stream.Collectors) ActionInstance(org.lflang.generator.ActionInstance) ReactorInstance(org.lflang.generator.ReactorInstance) List(java.util.List) Stream(java.util.stream.Stream) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) VarRef(org.lflang.lf.VarRef) ASTUtils(org.lflang.ASTUtils) Output(org.lflang.lf.Output) Timer(org.lflang.lf.Timer) TriggerRef(org.lflang.lf.TriggerRef) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction)

Example 5 with Variable

use of org.lflang.lf.Variable in project lingua-franca by lf-lang.

the class LFValidator method checkReaction.

@Check(CheckType.FAST)
public void checkReaction(Reaction reaction) {
    if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
        warning("Reaction has no trigger.", Literals.REACTION__TRIGGERS);
    }
    HashSet<Variable> triggers = new HashSet<>();
    // Make sure input triggers have no container and output sources do.
    for (TriggerRef trigger : reaction.getTriggers()) {
        if (trigger instanceof VarRef) {
            VarRef triggerVarRef = (VarRef) trigger;
            triggers.add(triggerVarRef.getVariable());
            if (triggerVarRef instanceof Input) {
                if (triggerVarRef.getContainer() != null) {
                    error(String.format("Cannot have an input of a contained reactor as a trigger: %s.%s", triggerVarRef.getContainer().getName(), triggerVarRef.getVariable().getName()), Literals.REACTION__TRIGGERS);
                }
            } else if (triggerVarRef.getVariable() instanceof Output) {
                if (triggerVarRef.getContainer() == null) {
                    error(String.format("Cannot have an output of this reactor as a trigger: %s", triggerVarRef.getVariable().getName()), Literals.REACTION__TRIGGERS);
                }
            }
        }
    }
    // Also check that a source is not already listed as a trigger.
    for (VarRef source : reaction.getSources()) {
        if (triggers.contains(source.getVariable())) {
            error(String.format("Source is already listed as a trigger: %s", source.getVariable().getName()), Literals.REACTION__SOURCES);
        }
        if (source.getVariable() instanceof Input) {
            if (source.getContainer() != null) {
                error(String.format("Cannot have an input of a contained reactor as a source: %s.%s", source.getContainer().getName(), source.getVariable().getName()), Literals.REACTION__SOURCES);
            }
        } else if (source.getVariable() instanceof Output) {
            if (source.getContainer() == null) {
                error(String.format("Cannot have an output of this reactor as a source: %s", source.getVariable().getName()), Literals.REACTION__SOURCES);
            }
        }
    }
    // Make sure output effects have no container and input effects do.
    for (VarRef effect : reaction.getEffects()) {
        if (effect.getVariable() instanceof Input) {
            if (effect.getContainer() == null) {
                error(String.format("Cannot have an input of this reactor as an effect: %s", effect.getVariable().getName()), Literals.REACTION__EFFECTS);
            }
        } else if (effect.getVariable() instanceof Output) {
            if (effect.getContainer() != null) {
                error(String.format("Cannot have an output of a contained reactor as an effect: %s.%s", effect.getContainer().getName(), effect.getVariable().getName()), Literals.REACTION__EFFECTS);
            }
        }
    }
    // // Report error if this reaction is part of a cycle.
    Set<NamedInstance<?>> cycles = this.info.topologyCycles();
    Reactor reactor = ASTUtils.getEnclosingReactor(reaction);
    boolean reactionInCycle = false;
    for (NamedInstance<?> it : cycles) {
        if (it.getDefinition().equals(reaction)) {
            reactionInCycle = true;
        }
    }
    if (reactionInCycle) {
        // Report involved triggers.
        List<CharSequence> trigs = new ArrayList<>();
        for (TriggerRef t : reaction.getTriggers()) {
            if (!(t instanceof VarRef)) {
                continue;
            }
            VarRef tVarRef = (VarRef) t;
            boolean triggerExistsInCycle = false;
            for (NamedInstance<?> c : cycles) {
                if (c.getDefinition().equals(tVarRef.getVariable())) {
                    triggerExistsInCycle = true;
                    break;
                }
            }
            if (triggerExistsInCycle) {
                trigs.add(toText(tVarRef));
            }
        }
        if (trigs.size() > 0) {
            error(String.format("Reaction triggers involved in cyclic dependency in reactor %s: %s.", reactor.getName(), String.join(", ", trigs)), Literals.REACTION__TRIGGERS);
        }
        // Report involved sources.
        List<CharSequence> sources = new ArrayList<>();
        for (VarRef t : reaction.getSources()) {
            boolean sourceExistInCycle = false;
            for (NamedInstance<?> c : cycles) {
                if (c.getDefinition().equals(t.getVariable())) {
                    sourceExistInCycle = true;
                    break;
                }
            }
            if (sourceExistInCycle) {
                sources.add(toText(t));
            }
        }
        if (sources.size() > 0) {
            error(String.format("Reaction sources involved in cyclic dependency in reactor %s: %s.", reactor.getName(), String.join(", ", sources)), Literals.REACTION__SOURCES);
        }
        // Report involved effects.
        List<CharSequence> effects = new ArrayList<>();
        for (VarRef t : reaction.getEffects()) {
            boolean effectExistInCycle = false;
            for (NamedInstance<?> c : cycles) {
                if (c.getDefinition().equals(t.getVariable())) {
                    effectExistInCycle = true;
                    break;
                }
            }
            if (effectExistInCycle) {
                effects.add(toText(t));
            }
        }
        if (effects.size() > 0) {
            error(String.format("Reaction effects involved in cyclic dependency in reactor %s: %s.", reactor.getName(), String.join(", ", effects)), Literals.REACTION__EFFECTS);
        }
        if (trigs.size() + sources.size() == 0) {
            error(String.format("Cyclic dependency due to preceding reaction. Consider reordering reactions within reactor %s to avoid causality loop.", reactor.getName()), reaction.eContainer(), Literals.REACTOR__REACTIONS, reactor.getReactions().indexOf(reaction));
        } else if (effects.size() == 0) {
            error(String.format("Cyclic dependency due to succeeding reaction. Consider reordering reactions within reactor %s to avoid causality loop.", reactor.getName()), reaction.eContainer(), Literals.REACTOR__REACTIONS, reactor.getReactions().indexOf(reaction));
        }
    // Not reporting reactions that are part of cycle _only_ due to reaction ordering.
    // Moving them won't help solve the problem.
    }
// FIXME: improve error message.
}
Also used : VarRef(org.lflang.lf.VarRef) TypedVariable(org.lflang.lf.TypedVariable) Variable(org.lflang.lf.Variable) ArrayList(java.util.ArrayList) TriggerRef(org.lflang.lf.TriggerRef) NamedInstance(org.lflang.generator.NamedInstance) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Check(org.eclipse.xtext.validation.Check)

Aggregations

Reactor (org.lflang.lf.Reactor)8 Variable (org.lflang.lf.Variable)8 VarRef (org.lflang.lf.VarRef)7 ArrayList (java.util.ArrayList)6 Action (org.lflang.lf.Action)6 Instantiation (org.lflang.lf.Instantiation)6 LinkedHashSet (java.util.LinkedHashSet)5 List (java.util.List)4 GeneratorBase (org.lflang.generator.GeneratorBase)4 ActionOrigin (org.lflang.lf.ActionOrigin)4 Delay (org.lflang.lf.Delay)4 Input (org.lflang.lf.Input)4 Output (org.lflang.lf.Output)4 TriggerRef (org.lflang.lf.TriggerRef)4 HashSet (java.util.HashSet)3 LinkedHashMap (java.util.LinkedHashMap)3 Collectors (java.util.stream.Collectors)3 EcoreUtil (org.eclipse.emf.ecore.util.EcoreUtil)3 ASTUtils (org.lflang.ASTUtils)3 TimeValue (org.lflang.TimeValue)3