diff --git a/org.lflang/src/org/lflang/ASTUtils.xtend b/org.lflang/src/org/lflang/ASTUtils.xtend index 7afe6ba544..0e3f327b04 100644 --- a/org.lflang/src/org/lflang/ASTUtils.xtend +++ b/org.lflang/src/org/lflang/ASTUtils.xtend @@ -177,7 +177,7 @@ class ASTUtils { * if the port on the left or right of the connection involves a bank of reactors or a multiport. * @param connection The connection. */ - private static def boolean isWide(Connection connection) { + static def boolean hasMultipleConnections(Connection connection) { if (connection.leftPorts.size > 1 || connection.rightPorts.size > 1) { return true; } @@ -216,6 +216,7 @@ class ASTUtils { output.variable = delayClass.outputs.get(0) upstream.leftPorts.addAll(connection.leftPorts) upstream.rightPorts.add(input) + upstream.iterated = connection.iterated downstream.leftPorts.add(output) downstream.rightPorts.addAll(connection.rightPorts) @@ -256,7 +257,7 @@ class ASTUtils { typeParm.literal = generic delayInstance.typeParms.add(typeParm) } - if (connection.isWide) { + if (connection.hasMultipleConnections) { val widthSpec = factory.createWidthSpec if (defineWidthFromConnection) { // Add all right ports of the connection to the WidthSpec of the genertaed delay instance. diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index d6292e0cd9..f7e264d393 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -413,3 +413,5 @@ val Instantiation.reactor get() = this.reactorClass.toDefinition() /** Check if the receiver is a bank instantiation. */ val Instantiation.isBank: Boolean get() = this.widthSpec != null + +val Connection.hasMultipleConnections: Boolean get() = ASTUtils.hasMultipleConnections(this) diff --git a/org.lflang/src/org/lflang/LinguaFranca.xtext b/org.lflang/src/org/lflang/LinguaFranca.xtext index 9ad861332e..b7dfbeb46a 100644 --- a/org.lflang/src/org/lflang/LinguaFranca.xtext +++ b/org.lflang/src/org/lflang/LinguaFranca.xtext @@ -227,7 +227,7 @@ Instantiation: Connection: ((leftPorts += VarRef (',' leftPorts += VarRef)*) - | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' isIterated ?= '+'?)) + | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?)) ('->' | physical?='~>') rightPorts += VarRef (',' rightPorts += VarRef)* (delay=Delay)? diff --git a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 0f77215bf5..b9ac6cc00e 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -27,6 +27,7 @@ package org.lflang.generator.cpp import org.lflang.generator.PrependOperator import org.lflang.isBank import org.lflang.isMultiport +import org.lflang.hasMultipleConnections import org.lflang.lf.* /** @@ -131,29 +132,8 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { """.trimMargin() } - private val Connection.isMultiportConnection: Boolean - get() { - // if there are multiple ports listed on the left or right side, this is a multiport connection - if (leftPorts.size > 1 || rightPorts.size > 1) - return true - - // if the ports on either side are multiports, this is a multiport connection - val leftPort = leftPorts[0].variable as Port - val rightPort = rightPorts[0].variable as Port - if (leftPort.isMultiport || rightPort.isMultiport) - return true - - // if the containers on either side are banks, this is a multiport connection - val leftContainer = leftPorts[0].container - val rightContainer = rightPorts[0].container - if (leftContainer?.isBank == true || rightContainer?.isBank == true) - return true - - return false - } - private fun declareConnection(c: Connection, idx: Int): String { - return if (c.isMultiportConnection) { + return if (c.hasMultipleConnections) { declareMultiportConnection(c, idx) } else { val leftPort = c.leftPorts[0] @@ -198,7 +178,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { ${" |"..c.leftPorts.joinToString("\n") { addAllPortsToVector(it, "__lf_left_ports_$idx") }} |std::vector<$portType> __lf_right_ports_$idx; ${" |"..c.rightPorts.joinToString("\n") { addAllPortsToVector(it, "__lf_right_ports_$idx") }} - |lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIsIterated}); + |lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated}); """.trimMargin() } } diff --git a/test/Cpp/src/multiport/Broadcast.lf b/test/Cpp/src/multiport/Broadcast.lf new file mode 100644 index 0000000000..a1e7a8da0e --- /dev/null +++ b/test/Cpp/src/multiport/Broadcast.lf @@ -0,0 +1,27 @@ +target Cpp; + +reactor Source { + output out:unsigned; + + reaction (startup) -> out {= + out.set(42); + =} +} + +reactor Sink(bank_index:size_t(0)) { + input in:unsigned; + + reaction (in) {= + std::cout << "Received " << *in.get() << '\n'; + if (*in.get() != 42) { + std::cerr << "Error: expected " << 42 << "!\n"; + exit(1); + } + =} +} + +main reactor { + source = new Source(); + sink = new[4] Sink(); + (source.out)+ -> sink.in; +} \ No newline at end of file diff --git a/test/Cpp/src/multiport/BroadcastAfter.lf b/test/Cpp/src/multiport/BroadcastAfter.lf new file mode 100644 index 0000000000..ee8172fbd1 --- /dev/null +++ b/test/Cpp/src/multiport/BroadcastAfter.lf @@ -0,0 +1,43 @@ +target Cpp{ + fast: true +} + +reactor Source { + output out:unsigned; + + reaction (startup) -> out {= + out.set(42); + =} +} + +reactor Sink(bank_index: size_t(0)) { + input in:unsigned; + state received: bool{false}; + + reaction (in) {= + std::cout << bank_index << " received " << *in.get() << '\n'; + if (*in.get() != 42) { + std::cerr << "Error: expected " << 42 << "!\n"; + exit(1); + } + if (get_elapsed_logical_time() != 1s) { + std::cerr << "ERROR: Expected to receive input after one second.\n"; + exit(2); + } + received = true; + =} + + reaction(shutdown) {= + if (!received) { + std::cerr << "ERROR: Destination " << bank_index << " received no input!\n"; + exit(1); + } + std::cout << "Success.\n"; + =} +} + +main reactor { + source = new Source(); + sink = new[4] Sink(); + (source.out)+ -> sink.in after 1 sec; +} \ No newline at end of file