Search in sources :

Example 1 with Output

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

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

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

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

the class CReactionGenerator method generateOutputVariablesInReaction.

/**
 * Generate into the specified string builder the code to
 * initialize local variables for outputs in a reaction function
 * from the "self" struct.
 * @param effect The effect declared by the reaction. This must refer to an output.
 * @param decl The reactor containing the reaction or the import statement.
 */
public static String generateOutputVariablesInReaction(VarRef effect, ReactorDecl decl, ErrorReporter errorReporter, boolean requiresTypes) {
    Output output = (Output) effect.getVariable();
    String outputName = output.getName();
    String outputWidth = generateWidthVariable(outputName);
    if (output.getType() == null && requiresTypes) {
        errorReporter.reportError(output, "Output is required to have a type: " + outputName);
        return "";
    } else {
        // The container of the output may be a contained reactor or
        // the reactor containing the reaction.
        String outputStructType = (effect.getContainer() == null) ? CGenerator.variableStructType(output, decl).toString() : CGenerator.variableStructType(output, effect.getContainer().getReactorClass()).toString();
        if (!ASTUtils.isMultiport(output)) {
            // Output port is not a multiport.
            return outputStructType + "* " + outputName + " = &self->_lf_" + outputName + ";";
        } else {
            // Set the _width variable.
            return String.join("\n", "int " + outputWidth + " = self->_lf_" + outputWidth + ";", outputStructType + "** " + outputName + " = self->_lf_" + outputName + "_pointers;");
        }
    }
}
Also used : Output(org.lflang.lf.Output)

Example 5 with Output

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

Aggregations

Output (org.lflang.lf.Output)10 Input (org.lflang.lf.Input)8 Action (org.lflang.lf.Action)7 Reactor (org.lflang.lf.Reactor)7 VarRef (org.lflang.lf.VarRef)7 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 TimeValue (org.lflang.TimeValue)2 ActionInstance (org.lflang.generator.ActionInstance)2 PortInstance (org.lflang.generator.PortInstance)2 ReactionInstance (org.lflang.generator.ReactionInstance)2 CUtil.generateWidthVariable (org.lflang.generator.c.CUtil.generateWidthVariable)2 ImportedReactor (org.lflang.lf.ImportedReactor)2 Reaction (org.lflang.lf.Reaction)2