Search in sources :

Example 1 with TriggerRef

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

the class PythonReactionGenerator method generateCPythonInitializers.

/**
 * Generate necessary Python-specific initialization code for <code>reaction<code> that belongs to reactor
 * <code>decl<code>.
 *
 * @param reaction The reaction to generate Python-specific initialization for.
 * @param decl The reactor to which <code>reaction<code> belongs to.
 * @param pyObjectDescriptor For each port object created, a Python-specific descriptor will be added to this that
 *  then can be used as an argument to <code>Py_BuildValue<code>
 *  (@see <a href="https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue">docs.python.org/3/c-api</a>).
 * @param pyObjects A "," delimited list of expressions that would be (or result in a creation of) a PyObject.
 */
private static String generateCPythonInitializers(Reaction reaction, ReactorDecl decl, List<String> pyObjects, ErrorReporter errorReporter) {
    Set<Action> actionsAsTriggers = new LinkedHashSet<>();
    Reactor reactor = ASTUtils.toDefinition(decl);
    CodeBuilder code = new CodeBuilder();
    // TODO: handle triggers
    for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
        if (trigger instanceof VarRef) {
            VarRef triggerAsVarRef = (VarRef) trigger;
            code.pr(generateVariableToSendPythonReaction(triggerAsVarRef, actionsAsTriggers, decl, pyObjects));
        }
    }
    if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
        // NOTE: this does not include contained outputs.
        for (Input input : reactor.getInputs()) {
            PythonPortGenerator.generateInputVariablesToSendToPythonReaction(pyObjects, input, decl);
        }
    }
    // Next add non-triggering inputs.
    for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
        code.pr(generateVariableToSendPythonReaction(src, actionsAsTriggers, decl, pyObjects));
    }
    // Next, handle effects
    if (reaction.getEffects() != null) {
        for (VarRef effect : reaction.getEffects()) {
            if (effect.getVariable() instanceof Action) {
                // If it has already appeared as trigger, do not redefine it.
                if (!actionsAsTriggers.contains(effect.getVariable())) {
                    PythonPortGenerator.generateActionVariableToSendToPythonReaction(pyObjects, (Action) effect.getVariable(), decl);
                }
            } else {
                if (effect.getVariable() instanceof Output) {
                    PythonPortGenerator.generateOutputVariablesToSendToPythonReaction(pyObjects, (Output) effect.getVariable());
                } else if (effect.getVariable() instanceof Input) {
                    // It is the input of a contained reactor.
                    code.pr(PythonPortGenerator.generateVariablesForSendingToContainedReactors(pyObjects, effect.getContainer(), (Input) effect.getVariable()));
                } else {
                    errorReporter.reportError(reaction, "In generateReaction(): " + effect.getVariable().getName() + " is neither an input nor an output.");
                }
            }
        }
    }
    return code.toString();
}
Also used : LinkedHashSet(java.util.LinkedHashSet) VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) Reactor(org.lflang.lf.Reactor) TriggerRef(org.lflang.lf.TriggerRef) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 2 with TriggerRef

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

the class PythonReactionGenerator method generatePythonReactionParametersAndInitializations.

/**
 * Generate parameters and their respective initialization code for a reaction function
 * The initialization code is put at the beginning of the reaction before user code
 * @param parameters The parameters used for function definition
 * @param inits The initialization code for those paramters
 * @param decl Reactor declaration
 * @param reaction The reaction to be used to generate parameters for
 */
public static void generatePythonReactionParametersAndInitializations(List<String> parameters, CodeBuilder inits, ReactorDecl decl, Reaction reaction) {
    Reactor reactor = ASTUtils.toDefinition(decl);
    LinkedHashSet<String> generatedParams = new LinkedHashSet<>();
    // Handle triggers
    for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
        if (!(trigger instanceof VarRef)) {
            continue;
        }
        VarRef triggerAsVarRef = (VarRef) trigger;
        if (triggerAsVarRef.getVariable() instanceof Port) {
            if (triggerAsVarRef.getVariable() instanceof Input) {
                if (((Input) triggerAsVarRef.getVariable()).isMutable()) {
                    generatedParams.add("mutable_" + triggerAsVarRef.getVariable().getName() + "");
                    // Create a deep copy
                    if (ASTUtils.isMultiport((Input) triggerAsVarRef.getVariable())) {
                        inits.pr(triggerAsVarRef.getVariable().getName() + " = [Make() for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + "))]");
                        inits.pr("for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + ")):");
                        inits.pr("    " + triggerAsVarRef.getVariable().getName() + "[i].value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + "[i].value)");
                    } else {
                        inits.pr(triggerAsVarRef.getVariable().getName() + " = Make()");
                        inits.pr(triggerAsVarRef.getVariable().getName() + ".value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + ".value)");
                    }
                } else {
                    generatedParams.add(triggerAsVarRef.getVariable().getName());
                }
            } else {
                // Handle contained reactors' ports
                generatedParams.add(triggerAsVarRef.getContainer().getName() + "_" + triggerAsVarRef.getVariable().getName());
                inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(triggerAsVarRef));
            }
        } else if (triggerAsVarRef.getVariable() instanceof Action) {
            generatedParams.add(triggerAsVarRef.getVariable().getName());
        }
    }
    // Handle non-triggering inputs
    if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
        for (Input input : ASTUtils.convertToEmptyListIfNull(reactor.getInputs())) {
            generatedParams.add(input.getName());
            if (input.isMutable()) {
                // Create a deep copy
                inits.pr(input.getName() + " = copy.deepcopy(" + input.getName() + ")");
            }
        }
    }
    for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
        if (src.getVariable() instanceof Output) {
            // Output of a contained reactor
            generatedParams.add(src.getContainer().getName() + "_" + src.getVariable().getName());
            inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(src));
        } else {
            generatedParams.add(src.getVariable().getName());
            if (src.getVariable() instanceof Input) {
                if (((Input) src.getVariable()).isMutable()) {
                    // Create a deep copy
                    inits.pr(src.getVariable().getName() + " = copy.deepcopy(" + src.getVariable().getName() + ")");
                }
            }
        }
    }
    // Handle effects
    for (VarRef effect : ASTUtils.convertToEmptyListIfNull(reaction.getEffects())) {
        if (effect.getVariable() instanceof Input) {
            generatedParams.add(effect.getContainer().getName() + "_" + effect.getVariable().getName());
            inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(effect));
        } else {
            generatedParams.add(effect.getVariable().getName());
            if (effect.getVariable() instanceof Port) {
                if (ASTUtils.isMultiport((Port) effect.getVariable())) {
                // Handle multiports
                }
            }
        }
    }
    for (String s : generatedParams) {
        parameters.add(s);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) VarRef(org.lflang.lf.VarRef) Input(org.lflang.lf.Input) Action(org.lflang.lf.Action) Port(org.lflang.lf.Port) Output(org.lflang.lf.Output) Reactor(org.lflang.lf.Reactor) TriggerRef(org.lflang.lf.TriggerRef)

Example 3 with TriggerRef

use of org.lflang.lf.TriggerRef 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)

Example 4 with TriggerRef

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

the class CReactionGenerator method generateIntendedTagInheritence.

/**
 * Generate code that passes existing intended tag to all output ports
 * and actions. This intended tag is the minimum intended tag of the
 * triggering inputs of the reaction.
 *
 * @param body The body of the reaction. Used to check for the DISABLE_REACTION_INITIALIZATION_MARKER.
 * @param reaction The initialization code will be generated for this specific reaction
 * @param decl The reactor that has the reaction
 * @param reactionIndex The index of the reaction relative to other reactions in the reactor, starting from 0
 */
public static String generateIntendedTagInheritence(String body, Reaction reaction, ReactorDecl decl, int reactionIndex, CTypes types, boolean isFederatedAndDecentralized) {
    // Construct the intended_tag inheritance code to go into
    // the body of the function.
    CodeBuilder intendedTagInheritenceCode = new CodeBuilder();
    // Check if the coordination mode is decentralized and if the reaction has any effects to inherit the STP violation
    if (isFederatedAndDecentralized && !(reaction.getEffects() == null || reaction.getEffects().isEmpty())) {
        intendedTagInheritenceCode.pr(String.join("\n", "#pragma GCC diagnostic push", "#pragma GCC diagnostic ignored \"-Wunused-variable\"", "if (self->_lf__reaction_" + reactionIndex + ".is_STP_violated == true) {"));
        intendedTagInheritenceCode.indent();
        intendedTagInheritenceCode.pr(String.join("\n", "// The operations inside this if clause (if any exists) are expensive ", "// and must only be done if the reaction has unhandled STP violation.", "// Otherwise, all intended_tag values are (NEVER, 0) by default.", "", "// Inherited intended tag. This will take the minimum", "// intended_tag of all input triggers", types.getTargetTagType() + " inherited_min_intended_tag = (" + types.getTargetTagType() + ") { .time = FOREVER, .microstep = UINT_MAX };"));
        intendedTagInheritenceCode.pr("// Find the minimum intended tag");
        // value of intended_tag to choose the minimum.
        for (TriggerRef inputTrigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
            if (inputTrigger instanceof VarRef) {
                VarRef inputTriggerAsVarRef = (VarRef) inputTrigger;
                Variable variable = inputTriggerAsVarRef.getVariable();
                String variableName = inputTriggerAsVarRef.getVariable().getName();
                if (variable instanceof Output) {
                    // Output from a contained reactor
                    String containerName = inputTriggerAsVarRef.getContainer().getName();
                    Output outputPort = (Output) variable;
                    if (ASTUtils.isMultiport(outputPort)) {
                        intendedTagInheritenceCode.pr(String.join("\n", "for (int i=0; i < " + containerName + "." + generateWidthVariable(variableName) + "; i++) {", "    if (compare_tags(" + containerName + "." + variableName + "[i]->intended_tag,", "                        inherited_min_intended_tag) < 0) {", "        inherited_min_intended_tag = " + containerName + "." + variableName + "[i]->intended_tag;", "    }", "}"));
                    } else
                        intendedTagInheritenceCode.pr(String.join("\n", "if (compare_tags(" + containerName + "." + variableName + "->intended_tag,", "                    inherited_min_intended_tag) < 0) {", "    inherited_min_intended_tag = " + containerName + "." + variableName + "->intended_tag;", "}"));
                } else if (variable instanceof Port) {
                    // Input port
                    Port inputPort = (Port) variable;
                    if (ASTUtils.isMultiport(inputPort)) {
                        intendedTagInheritenceCode.pr(String.join("\n", "for (int i=0; i < " + generateWidthVariable(variableName) + "; i++) {", "    if (compare_tags(" + variableName + "[i]->intended_tag, inherited_min_intended_tag) < 0) {", "        inherited_min_intended_tag = " + variableName + "[i]->intended_tag;", "    }", "}"));
                    } else {
                        intendedTagInheritenceCode.pr(String.join("\n", "if (compare_tags(" + variableName + "->intended_tag, inherited_min_intended_tag) < 0) {", "    inherited_min_intended_tag = " + variableName + "->intended_tag;", "}"));
                    }
                } else if (variable instanceof Action) {
                    intendedTagInheritenceCode.pr(String.join("\n", "if (compare_tags(" + variableName + "->trigger->intended_tag, inherited_min_intended_tag) < 0) {", "    inherited_min_intended_tag = " + variableName + "->trigger->intended_tag;", "}"));
                }
            }
        }
        if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
            // NOTE: this does not include contained outputs.
            for (Input input : ((Reactor) reaction.eContainer()).getInputs()) {
                intendedTagInheritenceCode.pr(String.join("\n", "if (compare_tags(" + input.getName() + "->intended_tag, inherited_min_intended_tag) > 0) {", "    inherited_min_intended_tag = " + input.getName() + "->intended_tag;", "}"));
            }
        }
        // Once the minimum intended tag has been found,
        // it will be passed down to the port effects
        // of the reaction. Note that the intended tag
        // will not pass on to actions downstream.
        // Last reaction that sets the intended tag for the effect
        // will be seen.
        intendedTagInheritenceCode.pr(String.join("\n", "// All effects inherit the minimum intended tag of input triggers", "if (inherited_min_intended_tag.time != NEVER) {"));
        intendedTagInheritenceCode.indent();
        for (VarRef effect : ASTUtils.convertToEmptyListIfNull(reaction.getEffects())) {
            Variable effectVar = effect.getVariable();
            Instantiation effContainer = effect.getContainer();
            if (effectVar instanceof Input) {
                if (ASTUtils.isMultiport((Port) effectVar)) {
                    intendedTagInheritenceCode.pr(String.join("\n", "for(int i=0; i < " + effContainer.getName() + "." + generateWidthVariable(effectVar.getName()) + "; i++) {", "    " + effContainer.getName() + "." + effectVar.getName() + "[i]->intended_tag = inherited_min_intended_tag;", "}"));
                } else {
                    if (effContainer.getWidthSpec() != null) {
                        // Contained reactor is a bank.
                        intendedTagInheritenceCode.pr(String.join("\n", "for (int bankIndex = 0; bankIndex < self->_lf_" + generateWidthVariable(effContainer.getName()) + "; bankIndex++) {", "    " + effContainer.getName() + "[bankIndex]." + effectVar.getName() + " = &(self->_lf_" + effContainer.getName() + "[bankIndex]." + effectVar.getName() + ");", "}"));
                    } else {
                        // Input to a contained reaction
                        intendedTagInheritenceCode.pr(String.join("\n", "// Don't reset the intended tag of the output port if it has already been set.", effContainer.getName() + "." + effectVar.getName() + "->intended_tag = inherited_min_intended_tag;"));
                    }
                }
            }
        }
        intendedTagInheritenceCode.unindent();
        intendedTagInheritenceCode.pr("}");
        intendedTagInheritenceCode.unindent();
        intendedTagInheritenceCode.pr("#pragma GCC diagnostic pop");
        intendedTagInheritenceCode.pr("}");
    }
    return intendedTagInheritenceCode.toString();
}
Also used : VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) Variable(org.lflang.lf.Variable) CUtil.generateWidthVariable(org.lflang.generator.c.CUtil.generateWidthVariable) Output(org.lflang.lf.Output) Port(org.lflang.lf.Port) TriggerRef(org.lflang.lf.TriggerRef) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 5 with TriggerRef

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

the class CReactionGenerator method generateInitializationForReaction.

/**
 * Generate necessary initialization code inside the body of the reaction that belongs to reactor decl.
 * @param body The body of the reaction. Used to check for the DISABLE_REACTION_INITIALIZATION_MARKER.
 * @param reaction The initialization code will be generated for this specific reaction
 * @param decl The reactor that has the reaction
 * @param reactionIndex The index of the reaction relative to other reactions in the reactor, starting from 0
 */
public static String generateInitializationForReaction(String body, Reaction reaction, ReactorDecl decl, int reactionIndex, CTypes types, ErrorReporter errorReporter, Instantiation mainDef, boolean isFederatedAndDecentralized, boolean requiresTypes) {
    Reactor reactor = ASTUtils.toDefinition(decl);
    // Construct the reactionInitialization code to go into
    // the body of the function before the verbatim code.
    CodeBuilder reactionInitialization = new CodeBuilder();
    CodeBuilder code = new CodeBuilder();
    // Define the "self" struct.
    String structType = CUtil.selfType(decl);
    // or anything else. No need to declare it.
    if (structType != null) {
        code.pr(String.join("\n", "#pragma GCC diagnostic push", "#pragma GCC diagnostic ignored \"-Wunused-variable\"", structType + "* self = (" + structType + "*)instance_args;"));
    }
    // to not generate it.
    if (body.startsWith(CGenerator.DISABLE_REACTION_INITIALIZATION_MARKER)) {
        code.pr("#pragma GCC diagnostic pop");
        return code.toString();
    }
    // A reaction may send to or receive from multiple ports of
    // a contained reactor. The variables for these ports need to
    // all be declared as fields of the same struct. Hence, we first
    // collect the fields to be defined in the structs and then
    // generate the structs.
    Map<Instantiation, CodeBuilder> fieldsForStructsForContainedReactors = new LinkedHashMap<>();
    // Actions may appear twice, first as a trigger, then with the outputs.
    // But we need to declare it only once. Collect in this data structure
    // the actions that are declared as triggered so that if they appear
    // again with the outputs, they are not defined a second time.
    // That second redefinition would trigger a compile error.
    Set<Action> actionsAsTriggers = new LinkedHashSet<>();
    // defined so that they can be used in the verbatim code.
    for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
        if (trigger instanceof VarRef) {
            VarRef triggerAsVarRef = (VarRef) trigger;
            if (triggerAsVarRef.getVariable() instanceof Port) {
                generatePortVariablesInReaction(reactionInitialization, fieldsForStructsForContainedReactors, triggerAsVarRef, decl, types);
            } else if (triggerAsVarRef.getVariable() instanceof Action) {
                reactionInitialization.pr(generateActionVariablesInReaction((Action) triggerAsVarRef.getVariable(), decl, types));
                actionsAsTriggers.add((Action) triggerAsVarRef.getVariable());
            }
        }
    }
    if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
        // NOTE: this does not include contained outputs.
        for (Input input : reactor.getInputs()) {
            reactionInitialization.pr(generateInputVariablesInReaction(input, decl, types));
        }
    }
    // Define argument for non-triggering inputs.
    for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
        if (src.getVariable() instanceof Port) {
            generatePortVariablesInReaction(reactionInitialization, fieldsForStructsForContainedReactors, src, decl, types);
        } else if (src.getVariable() instanceof Action) {
            // It's a bit odd to read but not be triggered by an action, but
            // OK, I guess we allow it.
            reactionInitialization.pr(generateActionVariablesInReaction((Action) src.getVariable(), decl, types));
            actionsAsTriggers.add((Action) src.getVariable());
        }
    }
    // value that may have been written to that output in an earlier reaction.
    if (reaction.getEffects() != null) {
        for (VarRef effect : reaction.getEffects()) {
            Variable variable = effect.getVariable();
            if (variable instanceof Action) {
                // If it has already appeared as trigger, do not redefine it.
                if (!actionsAsTriggers.contains(effect.getVariable())) {
                    reactionInitialization.pr(CGenerator.variableStructType(variable, decl) + "* " + variable.getName() + " = &self->_lf_" + variable.getName() + ";");
                }
            } else if (effect.getVariable() instanceof Mode) {
                // Mode change effect
                int idx = ASTUtils.allModes(reactor).indexOf((Mode) effect.getVariable());
                String name = effect.getVariable().getName();
                if (idx >= 0) {
                    reactionInitialization.pr("reactor_mode_t* " + name + " = &self->_lf__modes[" + idx + "];\n" + "char _lf_" + name + "_change_type = " + (ModeTransitionType.getModeTransitionType(effect) == ModeTransitionType.HISTORY ? 2 : 1) + ";");
                } else {
                    errorReporter.reportError(reaction, "In generateReaction(): " + name + " not a valid mode of this reactor.");
                }
            } else {
                if (variable instanceof Output) {
                    reactionInitialization.pr(generateOutputVariablesInReaction(effect, decl, errorReporter, requiresTypes));
                } else if (variable instanceof Input) {
                    // It is the input of a contained reactor.
                    generateVariablesForSendingToContainedReactors(reactionInitialization, fieldsForStructsForContainedReactors, effect.getContainer(), (Input) variable);
                } else {
                    errorReporter.reportError(reaction, "In generateReaction(): effect is neither an input nor an output.");
                }
            }
        }
    }
    // generate the structs used for communication to and from contained reactors.
    for (Instantiation containedReactor : fieldsForStructsForContainedReactors.keySet()) {
        String array = "";
        if (containedReactor.getWidthSpec() != null) {
            String containedReactorWidthVar = generateWidthVariable(containedReactor.getName());
            code.pr("int " + containedReactorWidthVar + " = self->_lf_" + containedReactorWidthVar + ";");
            // Windows does not support variables in arrays declared on the stack,
            // so we use the maximum size over all bank members.
            array = "[" + maxContainedReactorBankWidth(containedReactor, null, 0, mainDef) + "]";
        }
        code.pr(String.join("\n", "struct " + containedReactor.getName() + " {", "    " + fieldsForStructsForContainedReactors.get(containedReactor) + "", "} " + containedReactor.getName() + array + ";"));
    }
    // Next generate all the collected setup code.
    code.pr(reactionInitialization.toString());
    code.pr("#pragma GCC diagnostic pop");
    if (reaction.getStp() == null) {
        // Pass down the intended_tag to all input and output effects
        // downstream if the current reaction does not have a STP
        // handler.
        code.pr(generateIntendedTagInheritence(body, reaction, decl, reactionIndex, types, isFederatedAndDecentralized));
    }
    return code.toString();
}
Also used : LinkedHashSet(java.util.LinkedHashSet) VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) Variable(org.lflang.lf.Variable) CUtil.generateWidthVariable(org.lflang.generator.c.CUtil.generateWidthVariable) Port(org.lflang.lf.Port) Mode(org.lflang.lf.Mode) TriggerRef(org.lflang.lf.TriggerRef) CodeBuilder(org.lflang.generator.CodeBuilder) LinkedHashMap(java.util.LinkedHashMap) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation)

Aggregations

Input (org.lflang.lf.Input)5 Output (org.lflang.lf.Output)5 Reactor (org.lflang.lf.Reactor)5 TriggerRef (org.lflang.lf.TriggerRef)5 VarRef (org.lflang.lf.VarRef)5 LinkedHashSet (java.util.LinkedHashSet)4 Action (org.lflang.lf.Action)4 CodeBuilder (org.lflang.generator.CodeBuilder)3 Port (org.lflang.lf.Port)3 Variable (org.lflang.lf.Variable)3 CUtil.generateWidthVariable (org.lflang.generator.c.CUtil.generateWidthVariable)2 Instantiation (org.lflang.lf.Instantiation)2 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 Check (org.eclipse.xtext.validation.Check)1 NamedInstance (org.lflang.generator.NamedInstance)1 ImportedReactor (org.lflang.lf.ImportedReactor)1 Mode (org.lflang.lf.Mode)1 TypedVariable (org.lflang.lf.TypedVariable)1