Search in sources :

Example 11 with Reaction

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

the class LFValidator method checkConnection.

@Check(CheckType.FAST)
public void checkConnection(Connection connection) {
    // Report if connection is part of a cycle.
    Set<NamedInstance<?>> cycles = this.info.topologyCycles();
    for (VarRef lp : connection.getLeftPorts()) {
        for (VarRef rp : connection.getRightPorts()) {
            boolean leftInCycle = false;
            for (NamedInstance<?> it : cycles) {
                if ((lp.getContainer() == null && it.getDefinition().equals(lp.getVariable())) || (it.getDefinition().equals(lp.getVariable()) && it.getParent().equals(lp.getContainer()))) {
                    leftInCycle = true;
                    break;
                }
            }
            for (NamedInstance<?> it : cycles) {
                if ((rp.getContainer() == null && it.getDefinition().equals(rp.getVariable())) || (it.getDefinition().equals(rp.getVariable()) && it.getParent().equals(rp.getContainer()))) {
                    if (leftInCycle) {
                        Reactor reactor = ASTUtils.getEnclosingReactor(connection);
                        String reactorName = reactor.getName();
                        error(String.format("Connection in reactor %s creates", reactorName) + String.format("a cyclic dependency between %s and %s.", toText(lp), toText(rp)), Literals.CONNECTION__DELAY);
                    }
                }
            }
        }
    }
    // we leave type compatibility that language's compiler or interpreter.
    if (isCBasedTarget()) {
        Type type = (Type) null;
        for (VarRef port : connection.getLeftPorts()) {
            // error. Avoid a class cast exception.
            if (port.getVariable() instanceof Port) {
                if (type == null) {
                    type = ((Port) port.getVariable()).getType();
                } else {
                    // method for AST types, so we have to manually check the types.
                    if (!sameType(type, ((Port) port.getVariable()).getType())) {
                        error("Types do not match.", Literals.CONNECTION__LEFT_PORTS);
                    }
                }
            }
        }
        for (VarRef port : connection.getRightPorts()) {
            // error. Avoid a class cast exception.
            if (port.getVariable() instanceof Port) {
                if (type == null) {
                    type = ((Port) port.getVariable()).getType();
                } else {
                    if (!sameType(type, type = ((Port) port.getVariable()).getType())) {
                        error("Types do not match.", Literals.CONNECTION__RIGHT_PORTS);
                    }
                }
            }
        }
    }
    // Check whether the total width of the left side of the connection
    // matches the total width of the right side. This cannot be determined
    // here if the width is not given as a constant. In that case, it is up
    // to the code generator to check it.
    int leftWidth = 0;
    for (VarRef port : connection.getLeftPorts()) {
        // null args imply incomplete check.
        int width = inferPortWidth(port, null, null);
        if (width < 0 || leftWidth < 0) {
            // Cannot determine the width of the left ports.
            leftWidth = -1;
        } else {
            leftWidth += width;
        }
    }
    int rightWidth = 0;
    for (VarRef port : connection.getRightPorts()) {
        // null args imply incomplete check.
        int width = inferPortWidth(port, null, null);
        if (width < 0 || rightWidth < 0) {
            // Cannot determine the width of the left ports.
            rightWidth = -1;
        } else {
            rightWidth += width;
        }
    }
    if (leftWidth != -1 && rightWidth != -1 && leftWidth != rightWidth) {
        if (connection.isIterated()) {
            if (leftWidth == 0 || rightWidth % leftWidth != 0) {
                // FIXME: The second argument should be Literals.CONNECTION, but
                // stupidly, xtext will not accept that. There seems to be no way to
                // report an error for the whole connection statement.
                warning(String.format("Left width %s does not divide right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
            }
        } else {
            // FIXME: The second argument should be Literals.CONNECTION, but
            // stupidly, xtext will not accept that. There seems to be no way to
            // report an error for the whole connection statement.
            warning(String.format("Left width %s does not match right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
        }
    }
    Reactor reactor = ASTUtils.getEnclosingReactor(connection);
    // Make sure the right port is not already an effect of a reaction.
    for (Reaction reaction : ASTUtils.allReactions(reactor)) {
        for (VarRef effect : reaction.getEffects()) {
            for (VarRef rightPort : connection.getRightPorts()) {
                if (// Refers to the same variable
                rightPort.getVariable().equals(effect.getVariable()) && // Refers to the same instance
                rightPort.getContainer() == effect.getContainer() && (// Either is not part of a mode
                reaction.eContainer() instanceof Reactor || connection.eContainer() instanceof Reactor || // Or they are in the same mode
                connection.eContainer() == reaction.eContainer())) {
                    error("Cannot connect: Port named '" + effect.getVariable().getName() + "' is already effect of a reaction.", Literals.CONNECTION__RIGHT_PORTS);
                }
            }
        }
    }
    // upstream connection.
    for (Connection c : reactor.getConnections()) {
        if (c != connection) {
            for (VarRef thisRightPort : connection.getRightPorts()) {
                for (VarRef thatRightPort : c.getRightPorts()) {
                    if (// Refers to the same variable
                    thisRightPort.getVariable().equals(thatRightPort.getVariable()) && // Refers to the same instance
                    thisRightPort.getContainer() == thatRightPort.getContainer() && (// Or either of the connections in not part of a mode
                    connection.eContainer() instanceof Reactor || c.eContainer() instanceof Reactor || // Or they are in the same mode
                    connection.eContainer() == c.eContainer())) {
                        error("Cannot connect: Port named '" + thisRightPort.getVariable().getName() + "' may only appear once on the right side of a connection.", Literals.CONNECTION__RIGHT_PORTS);
                    }
                }
            }
        }
    }
}
Also used : VarRef(org.lflang.lf.VarRef) ASTUtils.isOfTimeType(org.lflang.ASTUtils.isOfTimeType) CheckType(org.eclipse.xtext.validation.CheckType) ModeTransitionType(org.lflang.generator.ModeInstance.ModeTransitionType) Type(org.lflang.lf.Type) Port(org.lflang.lf.Port) Connection(org.lflang.lf.Connection) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction) NamedInstance(org.lflang.generator.NamedInstance) Check(org.eclipse.xtext.validation.Check)

Example 12 with Reaction

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

the class PythonGenerator method generateSelfStructExtension.

/**
 * This function is provided to allow extensions of the CGenerator to append the structure of the self struct
 * @param selfStructBody The body of the self struct
 * @param decl The reactor declaration for the self struct
 * @param instance The current federate instance
 * @param constructorCode Code that is executed when the reactor is instantiated
 */
@Override
public void generateSelfStructExtension(CodeBuilder selfStructBody, ReactorDecl decl, CodeBuilder constructorCode) {
    Reactor reactor = ASTUtils.toDefinition(decl);
    // Add the name field
    selfStructBody.pr("char *_lf_name;");
    int reactionIndex = 0;
    for (Reaction reaction : ASTUtils.allReactions(reactor)) {
        // Create a PyObject for each reaction
        selfStructBody.pr("PyObject* " + PythonReactionGenerator.generateCPythonReactionFunctionName(reactionIndex) + ";");
        if (reaction.getDeadline() != null) {
            selfStructBody.pr("PyObject* " + PythonReactionGenerator.generateCPythonDeadlineFunctionName(reactionIndex) + ";");
        }
        reactionIndex++;
    }
}
Also used : Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction)

Example 13 with Reaction

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

the class PythonReactionGenerator method generatePythonReactions.

/**
 * Generate the Python code for reactions in reactor
 * @param reactor The reactor
 * @param reactions The reactions of reactor
 */
public static String generatePythonReactions(Reactor reactor, List<Reaction> reactions) {
    CodeBuilder code = new CodeBuilder();
    int reactionIndex = 0;
    for (Reaction reaction : reactions) {
        code.pr(generatePythonReaction(reactor, reaction, reactionIndex));
        reactionIndex++;
    }
    return code.toString();
}
Also used : Reaction(org.lflang.lf.Reaction) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 14 with Reaction

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

the class ReactorInstance method createReactionInstances.

// ////////////////////////////////////////////////////
// // Protected methods.
/**
 * Create all the reaction instances of this reactor instance
 * and record the dependencies and antidependencies
 * between ports, actions, and timers and reactions.
 * This also records the dependencies between reactions
 * that follows from the order in which they are defined.
 */
protected void createReactionInstances() {
    List<Reaction> reactions = ASTUtils.allReactions(reactorDefinition);
    if (reactions != null) {
        int count = 0;
        // Check for startup and shutdown triggers.
        for (Reaction reaction : reactions) {
            // Create the reaction instance.
            var reactionInstance = new ReactionInstance(reaction, this, unorderedReactions.contains(reaction), count++);
            // Add the reaction instance to the map of reactions for this
            // reactor.
            this.reactions.add(reactionInstance);
        }
    }
}
Also used : Reaction(org.lflang.lf.Reaction)

Aggregations

Reaction (org.lflang.lf.Reaction)14 Reactor (org.lflang.lf.Reactor)11 VarRef (org.lflang.lf.VarRef)9 Action (org.lflang.lf.Action)6 LfFactory (org.lflang.lf.LfFactory)6 ArrayList (java.util.ArrayList)4 List (java.util.List)4 TimeValue (org.lflang.TimeValue)4 GeneratorBase (org.lflang.generator.GeneratorBase)4 ActionOrigin (org.lflang.lf.ActionOrigin)4 Connection (org.lflang.lf.Connection)4 Delay (org.lflang.lf.Delay)4 Instantiation (org.lflang.lf.Instantiation)4 Parameter (org.lflang.lf.Parameter)4 Type (org.lflang.lf.Type)4 Value (org.lflang.lf.Value)4 Collectors (java.util.stream.Collectors)3 EcoreUtil (org.eclipse.emf.ecore.util.EcoreUtil)3 ASTUtils (org.lflang.ASTUtils)3 InferredType (org.lflang.InferredType)3