Search in sources :

Example 1 with Parameter

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

the class FedASTUtils method findMaxSTP.

/**
 * Find the maximum STP offset for the given 'port'.
 *
 * An STP offset predicate can be nested in contained reactors in
 * the federate.
 * @param port The port to generate the STP list for.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param reactor The top-level reactor (not the federate reactor)
 * @return The maximum STP as a TimeValue
 */
private static TimeValue findMaxSTP(Variable port, FederateInstance instance, GeneratorBase generator, Reactor reactor) {
    // Find a list of STP offsets (if any exists)
    List<Value> STPList = new LinkedList<>();
    // First, check if there are any connections to contained reactors that
    // need to be handled
    List<Connection> connectionsWithPort = ASTUtils.allConnections(reactor).stream().filter(c -> c.getLeftPorts().stream().anyMatch((VarRef v) -> v.getVariable().equals(port))).collect(Collectors.toList());
    // Find the list of reactions that have the port as trigger or source
    // (could be a variable name)
    List<Reaction> reactionsWithPort = ASTUtils.allReactions(reactor).stream().filter(r -> {
        // Check the triggers of reaction r first
        return r.getTriggers().stream().anyMatch(t -> {
            if (t instanceof VarRef) {
                // Check if the variables match
                return ((VarRef) t).getVariable() == port;
            } else {
                // Not a network port (startup or shutdown)
                return false;
            }
        }) || // Then check the sources of reaction r
        r.getSources().stream().anyMatch(s -> s.getVariable() == port);
    }).collect(Collectors.toList());
    // Find a list of STP offsets (if any exists)
    if (generator.isFederatedAndDecentralized()) {
        for (Reaction r : safe(reactionsWithPort)) {
            if (!instance.contains(r)) {
                continue;
            }
            // If not, assume it is zero
            if (r.getStp() != null) {
                if (r.getStp().getValue().getParameter() != null) {
                    List<Instantiation> instantList = new ArrayList<>();
                    instantList.add(instance.instantiation);
                    STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
                } else {
                    STPList.add(r.getStp().getValue());
                }
            }
        }
        // Check the children for STPs as well
        for (Connection c : safe(connectionsWithPort)) {
            VarRef childPort = c.getRightPorts().get(0);
            Reactor childReactor = (Reactor) childPort.getVariable().eContainer();
            // Find the list of reactions that have the port as trigger or
            // source (could be a variable name)
            List<Reaction> childReactionsWithPort = ASTUtils.allReactions(childReactor).stream().filter(r -> r.getTriggers().stream().anyMatch(t -> {
                if (t instanceof VarRef) {
                    // Check if the variables match
                    return ((VarRef) t).getVariable() == childPort.getVariable();
                } else {
                    // Not a network port (startup or shutdown)
                    return false;
                }
            }) || r.getSources().stream().anyMatch(s -> s.getVariable() == childPort.getVariable())).collect(Collectors.toList());
            for (Reaction r : safe(childReactionsWithPort)) {
                if (!instance.contains(r)) {
                    continue;
                }
                // If not, assume it is zero
                if (r.getStp() != null) {
                    if (r.getStp().getValue() instanceof Parameter) {
                        List<Instantiation> instantList = new ArrayList<>();
                        instantList.add(childPort.getContainer());
                        STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
                    } else {
                        STPList.add(r.getStp().getValue());
                    }
                }
            }
        }
    }
    return STPList.stream().map(ASTUtils::getLiteralTimeValue).filter(Objects::nonNull).reduce(TimeValue.ZERO, TimeValue::max);
}
Also used : Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) Instantiation(org.lflang.lf.Instantiation) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Connection(org.lflang.lf.Connection) Type(org.lflang.lf.Type) GeneratorBase(org.lflang.generator.GeneratorBase) CoordinationType(org.lflang.TargetProperty.CoordinationType) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) PortInstance(org.lflang.generator.PortInstance) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) Optional(java.util.Optional) VarRef(org.lflang.lf.VarRef) Collections(java.util.Collections) ASTUtils(org.lflang.ASTUtils) VarRef(org.lflang.lf.VarRef) ASTUtils(org.lflang.ASTUtils) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Value(org.lflang.lf.Value) Parameter(org.lflang.lf.Parameter) Instantiation(org.lflang.lf.Instantiation) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 2 with Parameter

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

the class ModelInfo method detectOverflow.

/**
 * Given a parameter that is used in a deadline specification, recursively
 * track down its definition and check whether it is overflowing. Also
 * detect and report overrides that are overflowing.
 */
private boolean detectOverflow(Set<Instantiation> visited, Parameter current) {
    var overflow = false;
    // Determine whether the parameter's default value overflows or not.
    if (isTooLarge(ASTUtils.getDefaultAsTimeValue(current))) {
        this.overflowingParameters.add(current);
        overflow = true;
    }
    // Iterate over the instantiations of the reactor in which the
    // current parameter was found.
    Set<Instantiation> instantiations = this.instantiationGraph.getInstantiations((Reactor) current.eContainer());
    for (var instantiation : instantiations) {
        // Only visit each instantiation once per deadline to avoid cycles.
        if (!visited.contains(instantiation)) {
            visited.add(instantiation);
            // Find assignments that override the current parameter.
            for (var assignment : instantiation.getParameters()) {
                if (assignment.getLhs().equals(current)) {
                    Parameter parameter = assignment.getRhs().get(0).getParameter();
                    if (parameter != null) {
                        // Check for overflow in the referenced parameter.
                        overflow = detectOverflow(visited, parameter) || overflow;
                    } else {
                        // constant; check whether it is too large.
                        if (isTooLarge(ASTUtils.getLiteralTimeValue(assignment.getRhs().get(0)))) {
                            this.overflowingAssignments.add(assignment);
                            overflow = true;
                        }
                    }
                }
            }
        }
    }
    return overflow;
}
Also used : Parameter(org.lflang.lf.Parameter) Instantiation(org.lflang.lf.Instantiation)

Example 3 with Parameter

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

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

the class PythonParameterGenerator method generatePythonInstantiations.

/**
 * Generate Python code that instantiates and initializes parameters for a reactor 'decl'.
 *
 * @param decl The reactor declaration
 * @return The generated code as a StringBuilder
 */
public static String generatePythonInstantiations(ReactorDecl decl, PythonTypes types) {
    List<String> lines = new ArrayList<>();
    lines.add("# Define parameters and their default values");
    for (Parameter param : getAllParameters(decl)) {
        if (!types.getTargetType(param).equals("PyObject*")) {
            // If type is given, use it
            String type = types.getPythonType(ASTUtils.getInferredType(param));
            lines.add("self._" + param.getName() + ":" + type + " = " + generatePythonInitializer(param));
        } else {
            // If type is not given, just pass along the initialization
            lines.add("self._" + param.getName() + " = " + generatePythonInitializer(param));
        }
    }
    // Handle parameters that are set in instantiation
    lines.addAll(List.of("# Handle parameters that are set in instantiation", "self.__dict__.update(kwargs)", ""));
    return String.join("\n", lines);
}
Also used : ArrayList(java.util.ArrayList) Parameter(org.lflang.lf.Parameter)

Example 5 with Parameter

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

the class LinguaFrancaASTUtilsTest method initialValue.

/**
 * Test reading initial values of parameters.
 * This checks that the example given in the documentation of the
 * ASTUtils.initialValue() function behaves as stated in the docs.
 */
@Test
public void initialValue() throws Exception {
    // Java 17:
    // Model model = parser.parse("""
    // target C;
    // reactor A(x:int(1)) {}
    // reactor B(y:int(2)) {
    // a1 = new A(x = y);
    // a2 = new A(x = -1);
    // }
    // reactor C(z:int(3)) {
    // b1 = new B(y = z);
    // b2 = new B(y = -2);
    // }
    // """
    // Java 11:
    Model model = parser.parse(String.join(System.getProperty("line.separator"), "target C;", "reactor A(x:int(1)) {}", "reactor B(y:int(2)) {", "    a1 = new A(x = y);", "    a2 = new A(x = -1);", "}", "reactor C(z:int(3)) {", "    b1 = new B(y = z);", "    b2 = new B(y = -2);", "}"));
    Assertions.assertNotNull(model);
    Assertions.assertTrue(model.eResource().getErrors().isEmpty(), "Encountered unexpected error while parsing: " + model.eResource().getErrors());
    var map = getInsts(model);
    /* Check for this:
         *     initialValue(x, null) returns 1
         *     initialValue(x, [a1]) returns 2
         *     initialValue(x, [a2]) returns -1
         *     initialValue(x, [a1, b1]) returns 3
         *     initialValue(x, [a2, b1]) returns -1
         *     initialValue(x, [a1, b2]) returns -2
         *     initialValue(x, [a2, b2]) returns -1
         * 
         *     initialValue(y, null) returns 2
         *     initialValue(y, [a1]) throws an IllegalArgumentException
         *     initialValue(y, [b1]) returns 3
         *     initialValue(y, [b2]) returns -2
         */
    model.eAllContents().forEachRemaining((obj) -> {
        if (obj instanceof Parameter) {
            Parameter parameter = (Parameter) obj;
            if (parameter.getName() == "x") {
                var values = ASTUtils.initialValue(parameter, null);
                Assertions.assertEquals(values.get(0).getLiteral(), "1");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a1")));
                Assertions.assertEquals(values.get(0).getLiteral(), "2");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a2")));
                Assertions.assertEquals(values.get(0).getLiteral(), "-1");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a1"), map.get("b1")));
                Assertions.assertEquals(values.get(0).getLiteral(), "3");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a2"), map.get("b1")));
                Assertions.assertEquals(values.get(0).getLiteral(), "-1");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a1"), map.get("b2")));
                Assertions.assertEquals(values.get(0).getLiteral(), "-2");
                values = ASTUtils.initialValue(parameter, List.of(map.get("a2"), map.get("b2")));
                Assertions.assertEquals(values.get(0).getLiteral(), "-1");
            } else if (parameter.getName() == "y") {
                var values = ASTUtils.initialValue(parameter, null);
                Assertions.assertEquals(values.get(0).getLiteral(), "2");
                try {
                    values = ASTUtils.initialValue(parameter, List.of(map.get("a1")));
                } catch (IllegalArgumentException ex) {
                    Assertions.assertTrue(ex.getMessage().startsWith("Parameter y is not"));
                }
                values = ASTUtils.initialValue(parameter, List.of(map.get("b1")));
                Assertions.assertEquals(values.get(0).getLiteral(), "3");
                values = ASTUtils.initialValue(parameter, List.of(map.get("b2")));
                Assertions.assertEquals(values.get(0).getLiteral(), "-2");
            }
        }
    });
}
Also used : Model(org.lflang.lf.Model) Parameter(org.lflang.lf.Parameter) Test(org.junit.jupiter.api.Test)

Aggregations

Parameter (org.lflang.lf.Parameter)9 ArrayList (java.util.ArrayList)4 TimeValue (org.lflang.TimeValue)3 Instantiation (org.lflang.lf.Instantiation)3 Value (org.lflang.lf.Value)3 List (java.util.List)2 Collectors (java.util.stream.Collectors)2 ASTUtils (org.lflang.ASTUtils)2 Action (org.lflang.lf.Action)2 Delay (org.lflang.lf.Delay)2 Reaction (org.lflang.lf.Reaction)2 Reactor (org.lflang.lf.Reactor)2 Time (org.lflang.lf.Time)2 VarRef (org.lflang.lf.VarRef)2 Collections (java.util.Collections)1 LinkedList (java.util.LinkedList)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1 EcoreUtil (org.eclipse.emf.ecore.util.EcoreUtil)1 Test (org.junit.jupiter.api.Test)1