Search in sources :

Example 1 with Input

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

the class ASTUtils method getDelayClass.

/**
 * Return a synthesized AST node that represents the definition of a delay
 * reactor. Depending on whether the target supports generics, either this
 * method will synthesize a generic definition and keep returning it upon
 * subsequent calls, or otherwise, it will synthesize a new definition for
 * each new type it hasn't yet created a compatible delay reactor for.
 * @param type The type the delay class must be compatible with.
 * @param generator A code generator.
 */
private static Reactor getDelayClass(Type type, GeneratorBase generator) {
    String className;
    if (generator.getTargetTypes().supportsGenerics()) {
        className = GeneratorBase.GEN_DELAY_CLASS_NAME;
    } else {
        String id = Integer.toHexString(InferredType.fromAST(type).toText().hashCode());
        className = String.format("%s_%s", GeneratorBase.GEN_DELAY_CLASS_NAME, id);
    }
    // Only add class definition if it is not already there.
    Reactor classDef = generator.findDelayClass(className);
    if ((classDef != null)) {
        return classDef;
    }
    Reactor delayClass = factory.createReactor();
    Parameter delayParameter = factory.createParameter();
    Action action = factory.createAction();
    VarRef triggerRef = factory.createVarRef();
    VarRef effectRef = factory.createVarRef();
    Input input = factory.createInput();
    Output output = factory.createOutput();
    VarRef inRef = factory.createVarRef();
    VarRef outRef = factory.createVarRef();
    Reaction r1 = factory.createReaction();
    Reaction r2 = factory.createReaction();
    delayParameter.setName("delay");
    delayParameter.setType(factory.createType());
    delayParameter.getType().setId("time");
    delayParameter.getType().setTime(true);
    Time defaultTime = factory.createTime();
    defaultTime.setUnit(null);
    defaultTime.setInterval(0);
    Value defaultValue = factory.createValue();
    defaultValue.setTime(defaultTime);
    delayParameter.getInit().add(defaultValue);
    // Name the newly created action; set its delay and type.
    action.setName("act");
    action.setMinDelay(factory.createValue());
    action.getMinDelay().setParameter(delayParameter);
    action.setOrigin(ActionOrigin.LOGICAL);
    if (generator.getTargetTypes().supportsGenerics()) {
        action.setType(factory.createType());
        action.getType().setId("T");
    } else {
        action.setType(EcoreUtil.copy(type));
    }
    input.setName("inp");
    input.setType(EcoreUtil.copy(action.getType()));
    output.setName("out");
    output.setType(EcoreUtil.copy(action.getType()));
    // Establish references to the involved ports.
    inRef.setVariable(input);
    outRef.setVariable(output);
    // Establish references to the action.
    triggerRef.setVariable(action);
    effectRef.setVariable(action);
    // Add the action to the reactor.
    delayClass.setName(className);
    delayClass.getActions().add(action);
    // Configure the second reaction, which reads the input.
    r1.getTriggers().add(inRef);
    r1.getEffects().add(effectRef);
    r1.setCode(factory.createCode());
    r1.getCode().setBody(generator.generateDelayBody(action, inRef));
    // Configure the first reaction, which produces the output.
    r2.getTriggers().add(triggerRef);
    r2.getEffects().add(outRef);
    r2.setCode(factory.createCode());
    r2.getCode().setBody(generator.generateForwardBody(action, outRef));
    // Add the reactions to the newly created reactor class.
    // These need to go in the opposite order in case
    // a new input arrives at the same time the delayed
    // output is delivered!
    delayClass.getReactions().add(r2);
    delayClass.getReactions().add(r1);
    // Add a type parameter if the target supports it.
    if (generator.getTargetTypes().supportsGenerics()) {
        TypeParm parm = factory.createTypeParm();
        parm.setLiteral(generator.generateDelayGeneric());
        delayClass.getTypeParms().add(parm);
    }
    delayClass.getInputs().add(input);
    delayClass.getOutputs().add(output);
    delayClass.getParameters().add(delayParameter);
    generator.addDelayClass(delayClass);
    return delayClass;
}
Also used : VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) Value(org.lflang.lf.Value) Parameter(org.lflang.lf.Parameter) Time(org.lflang.lf.Time) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction) TypeParm(org.lflang.lf.TypeParm)

Example 2 with Input

use of org.lflang.lf.Input 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 3 with Input

use of org.lflang.lf.Input 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 4 with Input

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

the class CReactionGenerator method generatePortVariablesInReaction.

/**
 * Generate into the specified string builder the code to
 * initialize local variables for ports in a reaction function
 * from the "self" struct. The port may be an input of the
 * reactor or an output of a contained reactor. The second
 * argument provides, for each contained reactor, a place to
 * write the declaration of the output of that reactor that
 * is triggering reactions.
 * @param builder The place into which to write the code.
 * @param structs A map from reactor instantiations to a place to write
 *  struct fields.
 * @param port The port.
 * @param reactor The reactor or import statement.
 */
private static void generatePortVariablesInReaction(CodeBuilder builder, Map<Instantiation, CodeBuilder> structs, VarRef port, ReactorDecl decl, CTypes types) {
    if (port.getVariable() instanceof Input) {
        builder.pr(generateInputVariablesInReaction((Input) port.getVariable(), decl, types));
    } else {
        // port is an output of a contained reactor.
        Output output = (Output) port.getVariable();
        String portStructType = CGenerator.variableStructType(output, port.getContainer().getReactorClass()).toString();
        CodeBuilder structBuilder = structs.get(port.getContainer());
        if (structBuilder == null) {
            structBuilder = new CodeBuilder();
            structs.put(port.getContainer(), structBuilder);
        }
        String reactorName = port.getContainer().getName();
        String reactorWidth = generateWidthVariable(reactorName);
        String outputName = output.getName();
        String outputWidth = generateWidthVariable(outputName);
        // of its presence.
        if (!ASTUtils.isMultiport(output)) {
            // Output is not a multiport.
            structBuilder.pr(portStructType + "* " + outputName + ";");
        } else {
            // Output is a multiport.
            structBuilder.pr(String.join("\n", portStructType + "** " + outputName + ";", "int " + outputWidth + ";"));
        }
        // Next, initialize the struct with the current values.
        if (port.getContainer().getWidthSpec() != null) {
            // Output is in a bank.
            builder.pr(String.join("\n", "for (int i = 0; i < " + reactorWidth + "; i++) {", "    " + reactorName + "[i]." + outputName + " = self->_lf_" + reactorName + "[i]." + outputName + ";", "}"));
            if (ASTUtils.isMultiport(output)) {
                builder.pr(String.join("\n", "for (int i = 0; i < " + reactorWidth + "; i++) {", "    " + reactorName + "[i]." + outputWidth + " = self->_lf_" + reactorName + "[i]." + outputWidth + ";", "}"));
            }
        } else {
            // Output is not in a bank.
            builder.pr(reactorName + "." + outputName + " = self->_lf_" + reactorName + "." + outputName + ";");
            if (ASTUtils.isMultiport(output)) {
                builder.pr(reactorName + "." + outputWidth + " = self->_lf_" + reactorName + "." + outputWidth + ";");
            }
        }
    }
}
Also used : Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 5 with Input

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

Aggregations

Input (org.lflang.lf.Input)8 Output (org.lflang.lf.Output)8 Reactor (org.lflang.lf.Reactor)7 VarRef (org.lflang.lf.VarRef)7 Action (org.lflang.lf.Action)6 TriggerRef (org.lflang.lf.TriggerRef)6 LinkedHashSet (java.util.LinkedHashSet)5 CodeBuilder (org.lflang.generator.CodeBuilder)4 Variable (org.lflang.lf.Variable)4 Instantiation (org.lflang.lf.Instantiation)3 Port (org.lflang.lf.Port)3 ArrayList (java.util.ArrayList)2 LinkedHashMap (java.util.LinkedHashMap)2 CUtil.generateWidthVariable (org.lflang.generator.c.CUtil.generateWidthVariable)2 ImportedReactor (org.lflang.lf.ImportedReactor)2 Reaction (org.lflang.lf.Reaction)2 Objects (com.google.common.base.Objects)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Map (java.util.Map)1