Search in sources :

Example 21 with Reactor

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

the class PortInstanceTests method createRange.

@Test
public void createRange() throws Exception {
    Reactor main = factory.createReactor();
    ReactorInstance maini = new ReactorInstance(main, reporter);
    ReactorInstance a = newReactor("A", maini);
    ReactorInstance b = newReactor("B", maini);
    ReactorInstance c = newReactor("C", maini);
    PortInstance p = newOutputPort("p", a);
    PortInstance q = newInputPort("q", b);
    PortInstance r = newInputPort("r", c);
    Assertions.assertEquals(".A.p", p.getFullName());
    connect(p, q);
    connect(p, r);
    List<SendRange> sr = p.eventualDestinations();
    // Destinations should be empty because there are no reactions.
    Assertions.assertEquals("[]", sr.toString());
    // Clear caches to make a mutation.
    maini.clearCaches();
    newReaction(q);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1)]]", sr.toString());
    maini.clearCaches();
    newReaction(r);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1), .C.r(0,1)]]", sr.toString());
    // Now test multiports.
    p.setWidth(3);
    r.setWidth(2);
    // Have to redo the connections.
    clearConnections(maini);
    maini.clearCaches();
    connect(p, 0, 1, q, 0, 1);
    connect(p, 1, 2, r, 0, 2);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1)], .A.p(1,2)->[.C.r(0,2)]]", sr.toString());
    // More complicated multiport connection.
    clearConnections(maini);
    maini.clearCaches();
    ReactorInstance d = newReactor("D", maini);
    PortInstance v = newOutputPort("v", d);
    v.setWidth(2);
    q.setWidth(3);
    connect(v, 0, 2, q, 0, 2);
    connect(p, 0, 1, q, 2, 1);
    connect(p, 1, 2, r, 0, 2);
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(2,1)], .A.p(1,2)->[.C.r(0,2)]]", sr.toString());
    // Additional multicast connection.
    maini.clearCaches();
    ReactorInstance e = newReactor("E", maini);
    PortInstance s = newPort("s", e);
    s.setWidth(3);
    newReaction(s);
    connect(p, s);
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(2,1), .E.s(0,1)], .A.p(1,2)->[.C.r(0,2), .E.s(1,2)]]", sr.toString());
    // Add hierarchical reactors that further split the ranges.
    maini.clearCaches();
    ReactorInstance f = newReactor("F", e);
    PortInstance t = newPort("t", f);
    newReaction(t);
    ReactorInstance g = newReactor("G", e);
    PortInstance u = newPort("u", g);
    u.setWidth(2);
    newReaction(u);
    connect(s, 0, 1, t, 0, 1);
    connect(s, 1, 2, u, 0, 2);
    sr = p.eventualDestinations();
    // FIXME: Multicast destinations should be able to be reported in arbitrary order.
    Assertions.assertEquals("[.A.p(0,1)->[.E.F.t(0,1), .E.s(0,1), .B.q(2,1)], .A.p(1,2)->[.E.G.u(0,2), .E.s(1,2), .C.r(0,2)]]", sr.toString());
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactorInstance(org.lflang.generator.ReactorInstance) Reactor(org.lflang.lf.Reactor) SendRange(org.lflang.generator.SendRange) Test(org.junit.jupiter.api.Test)

Example 22 with Reactor

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

the class RangeTests method createRange.

@Test
public void createRange() throws Exception {
    Reactor main = factory.createReactor();
    ReactorInstance maini = new ReactorInstance(main, reporter);
    Reactor a = factory.createReactor();
    a.setName("A");
    ReactorInstance ai = new ReactorInstance(a, maini, reporter);
    ai.setWidth(2);
    Reactor b = factory.createReactor();
    b.setName("B");
    ReactorInstance bi = new ReactorInstance(b, ai, reporter);
    bi.setWidth(2);
    Port p = factory.createPort();
    p.setName("P");
    PortInstance pi = new PortInstance(p, bi, reporter);
    pi.setWidth(2);
    Assertions.assertEquals(".A.B.P", pi.getFullName());
    RuntimeRange<PortInstance> range = new RuntimeRange.Port(pi, 3, 4, null);
    Assertions.assertEquals(8, range.maxWidth);
    Assertions.assertEquals(".A.B.P(3,4)", range.toString());
    // The results expected below are derived from the class comment for RuntimeRange,
    // which includes this example.
    List<Integer> instances = range.instances();
    Assertions.assertEquals(List.of(3, 4, 5, 6), instances);
    Set<Integer> parents = range.parentInstances(1);
    Assertions.assertEquals(Set.of(1, 2, 3), parents);
    parents = range.parentInstances(2);
    Assertions.assertEquals(Set.of(0, 1), parents);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 1, 0), range.startMR().getDigits());
    // Create a SendRange sending from and to this range.
    SendRange sendRange = new SendRange(pi, 3, 4, null, null);
    sendRange.destinations.add(range);
    // Test getNumberOfDestinationReactors.
    Assertions.assertEquals(3, sendRange.getNumberOfDestinationReactors());
    // Make first interleaved version.
    range = range.toggleInterleaved(bi);
    instances = range.instances();
    Assertions.assertEquals(List.of(3, 4, 6, 5), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 1, 0), range.startMR().getDigits());
    // Make second interleaved version.
    range = range.toggleInterleaved(ai);
    instances = range.instances();
    Assertions.assertEquals(List.of(6, 1, 5, 3), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(0, 1, 1), range.startMR().getDigits());
    // Test instances of the parent.
    Assertions.assertEquals(Set.of(3, 0, 2, 1), range.parentInstances(1));
    // Add this range to the sendRange destinations and verify
    // that the number of destination reactors becomes 4.
    sendRange.addDestination(range);
    Assertions.assertEquals(4, sendRange.getNumberOfDestinationReactors());
    // Make third interleaved version.
    range = range.toggleInterleaved(bi);
    instances = range.instances();
    Assertions.assertEquals(List.of(5, 2, 6, 3), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 0, 1), range.startMR().getDigits());
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactorInstance(org.lflang.generator.ReactorInstance) Port(org.lflang.lf.Port) Reactor(org.lflang.lf.Reactor) SendRange(org.lflang.generator.SendRange) Test(org.junit.jupiter.api.Test)

Example 23 with Reactor

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

the class ASTUtils method rerouteViaDelay.

/**
 * Take a connection and reroute it via an instance of a generated delay
 * reactor. This method returns a list to new connections to substitute
 * the original one.
 * @param connection The connection to reroute.
 * @param delayInstance The delay instance to route the connection through.
 */
private static List<Connection> rerouteViaDelay(Connection connection, Instantiation delayInstance) {
    List<Connection> connections = new ArrayList<>();
    Connection upstream = factory.createConnection();
    Connection downstream = factory.createConnection();
    VarRef input = factory.createVarRef();
    VarRef output = factory.createVarRef();
    Reactor delayClass = toDefinition(delayInstance.getReactorClass());
    // Establish references to the involved ports.
    input.setContainer(delayInstance);
    input.setVariable(delayClass.getInputs().get(0));
    output.setContainer(delayInstance);
    output.setVariable(delayClass.getOutputs().get(0));
    upstream.getLeftPorts().addAll(connection.getLeftPorts());
    upstream.getRightPorts().add(input);
    downstream.getLeftPorts().add(output);
    downstream.getRightPorts().addAll(connection.getRightPorts());
    downstream.setIterated(connection.isIterated());
    connections.add(upstream);
    connections.add(downstream);
    return connections;
}
Also used : VarRef(org.lflang.lf.VarRef) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor)

Example 24 with Reactor

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

the class ASTUtils method superClasses.

/**
 * Return all the superclasses of the specified reactor
 * in deepest-first order. For example, if A extends B and C, and
 * B and C both extend D, this will return the list [D, B, C, A].
 * Duplicates are removed. If the specified reactor does not extend
 * any other reactor, then return an empty list.
 * If a cycle is found, where X extends Y and Y extends X, or if
 * a superclass is declared that is not found, then return null.
 * @param reactor The specified reactor.
 * @param extensions A set of reactors extending the specified reactor
 *  (used to detect circular extensions).
 */
private static LinkedHashSet<Reactor> superClasses(Reactor reactor, Set<Reactor> extensions) {
    LinkedHashSet<Reactor> result = new LinkedHashSet<>();
    for (ReactorDecl superDecl : convertToEmptyListIfNull(reactor.getSuperClasses())) {
        Reactor r = toDefinition(superDecl);
        if (r == reactor || r == null)
            return null;
        // If r is in the extensions, then we have a circular inheritance structure.
        if (extensions.contains(r))
            return null;
        extensions.add(r);
        LinkedHashSet<Reactor> baseExtends = superClasses(r, extensions);
        extensions.remove(r);
        if (baseExtends == null)
            return null;
        result.addAll(baseExtends);
        result.add(r);
    }
    return result;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) ReactorDecl(org.lflang.lf.ReactorDecl)

Example 25 with Reactor

use of org.lflang.lf.Reactor 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);
    delayParameter.getInit().add(defaultTime);
    // Name the newly created action; set its delay and type.
    action.setName("act");
    var paramRef = factory.createParameterReference();
    paramRef.setParameter(delayParameter);
    action.setMinDelay(paramRef);
    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) 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)

Aggregations

Reactor (org.lflang.lf.Reactor)59 VarRef (org.lflang.lf.VarRef)22 ImportedReactor (org.lflang.lf.ImportedReactor)19 Action (org.lflang.lf.Action)18 ArrayList (java.util.ArrayList)17 Instantiation (org.lflang.lf.Instantiation)15 Reaction (org.lflang.lf.Reaction)15 EObject (org.eclipse.emf.ecore.EObject)12 LinkedHashSet (java.util.LinkedHashSet)11 LfFactory (org.lflang.lf.LfFactory)11 Connection (org.lflang.lf.Connection)10 Variable (org.lflang.lf.Variable)10 List (java.util.List)9 PortInstance (org.lflang.generator.PortInstance)9 ReactorInstance (org.lflang.generator.ReactorInstance)9 Input (org.lflang.lf.Input)9 Output (org.lflang.lf.Output)9 HashSet (java.util.HashSet)8 ReactorDecl (org.lflang.lf.ReactorDecl)8 Type (org.lflang.lf.Type)8