Search in sources :

Example 21 with VarRef

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

VarRef (org.lflang.lf.VarRef)21 Reactor (org.lflang.lf.Reactor)16 Action (org.lflang.lf.Action)10 Instantiation (org.lflang.lf.Instantiation)9 Reaction (org.lflang.lf.Reaction)8 Input (org.lflang.lf.Input)7 Output (org.lflang.lf.Output)7 Port (org.lflang.lf.Port)7 ArrayList (java.util.ArrayList)6 LinkedHashSet (java.util.LinkedHashSet)6 TriggerRef (org.lflang.lf.TriggerRef)6 Variable (org.lflang.lf.Variable)6 Connection (org.lflang.lf.Connection)5 ImportedReactor (org.lflang.lf.ImportedReactor)5 LfFactory (org.lflang.lf.LfFactory)5 TimeValue (org.lflang.TimeValue)4 Delay (org.lflang.lf.Delay)4 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Collectors (java.util.stream.Collectors)3