From 4c9d15de1900935732b875cb7c45c90ed813e7c6 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 27 Mar 2023 10:16:09 -0700 Subject: [PATCH 001/142] Align transient-federates branches in lingua-franca and reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 08c1839210..8871b510e1 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 08c1839210435cdb2c812f2471e8cfd6c40c7a94 +Subproject commit 8871b510e1482fa59d2bd13ce9b83bf13d21da1f From 357ac7b4c8b4382410ad0694343f5afb5f678ab0 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 27 Mar 2023 11:19:58 -0700 Subject: [PATCH 002/142] Add support of @transient annotation (attribute) to federate instance, and propagate it to C generation. --- org.lflang/src/org/lflang/AttributeUtils.java | 13 ++++++++++++- .../org/lflang/federated/extensions/CExtension.java | 3 +++ .../federated/generator/FederateInstance.java | 8 +++++++- .../src/org/lflang/validation/AttributeSpec.java | 2 ++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/AttributeUtils.java b/org.lflang/src/org/lflang/AttributeUtils.java index ec5edc4b9d..6acc3dff20 100644 --- a/org.lflang/src/org/lflang/AttributeUtils.java +++ b/org.lflang/src/org/lflang/AttributeUtils.java @@ -32,7 +32,8 @@ import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; - +import org.lflang.federated.generator.FederateInstance; +import org.lflang.generator.ReactorInstance; import org.lflang.lf.Action; import org.lflang.lf.AttrParm; import org.lflang.lf.Attribute; @@ -191,6 +192,16 @@ public static boolean isSparse(EObject node) { return findAttributeByName(node, "sparse") != null; } + /** + * Return true if the specified node is an Instantiation and has an + * {@code @transient} attribute. + * + * @param node An AST node. + */ + public static boolean isTransient(EObject node) { + return findAttributeByName(node, "transient") != null; + } + /** * Return true if the reaction is unordered. * diff --git a/org.lflang/src/org/lflang/federated/extensions/CExtension.java b/org.lflang/src/org/lflang/federated/extensions/CExtension.java index fda727d735..abc0d2a112 100644 --- a/org.lflang/src/org/lflang/federated/extensions/CExtension.java +++ b/org.lflang/src/org/lflang/federated/extensions/CExtension.java @@ -632,6 +632,9 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo // Set global variable identifying the federate. code.pr("_lf_my_fed_id = "+ federate.id+";"); + // Set indicator variable that specify whether the federate is transient. + code.pr("_fed.is_transient = " + federate.isTransient + ";"); + // We keep separate record for incoming and outgoing p2p connections to allow incoming traffic to be processed in a separate // thread without requiring a mutex lock. var numberOfInboundConnections = federate.inboundP2PConnections.size(); diff --git a/org.lflang/src/org/lflang/federated/generator/FederateInstance.java b/org.lflang/src/org/lflang/federated/generator/FederateInstance.java index 92faefe400..efa9784ff1 100644 --- a/org.lflang/src/org/lflang/federated/generator/FederateInstance.java +++ b/org.lflang/src/org/lflang/federated/generator/FederateInstance.java @@ -45,6 +45,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY import org.lflang.TargetConfig; import org.lflang.TimeValue; import org.lflang.federated.serialization.SupportedSerializers; +import org.lflang.AttributeUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.PortInstance; @@ -107,7 +108,8 @@ public FederateInstance( this.bankIndex = bankIndex; this.errorReporter = errorReporter; this.targetConfig = targetConfig; - + this.isTransient = AttributeUtils.isTransient(instantiation); + if (instantiation != null) { this.name = instantiation.getName(); // If the instantiation is in a bank, then we have to append @@ -187,6 +189,10 @@ public Instantiation getInstantiation() { */ public int id = 0; + /** + * Type of the federate: transient if true, and peristent if false . + */ + public boolean isTransient = false; /** * The name of this federate instance. This will be the instantiation diff --git a/org.lflang/src/org/lflang/validation/AttributeSpec.java b/org.lflang/src/org/lflang/validation/AttributeSpec.java index c5a530581b..294805361f 100644 --- a/org.lflang/src/org/lflang/validation/AttributeSpec.java +++ b/org.lflang/src/org/lflang/validation/AttributeSpec.java @@ -211,6 +211,8 @@ enum AttrParamType { )); // @sparse ATTRIBUTE_SPECS_BY_NAME.put("sparse", new AttributeSpec(null)); + // @transient + ATTRIBUTE_SPECS_BY_NAME.put("transient", new AttributeSpec(null)); // @icon("value") ATTRIBUTE_SPECS_BY_NAME.put("icon", new AttributeSpec( List.of(new AttrParamSpec(VALUE_ATTR, AttrParamType.STRING, false)) From f6dec10fa72be6251ad20ef63b74f03a75840f1e Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 28 Mar 2023 15:08:33 -0700 Subject: [PATCH 003/142] Make federate launcher aware of number of persistent and transient federates. --- .../federated/launcher/FedLauncherGenerator.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/federated/launcher/FedLauncherGenerator.java b/org.lflang/src/org/lflang/federated/launcher/FedLauncherGenerator.java index 3ad08e2450..326d9bbfea 100644 --- a/org.lflang/src/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/org.lflang/src/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -308,6 +308,15 @@ private String getDistHeader() { private String getRtiCommand(List federates, boolean isRemote) { List commands = new ArrayList<>(); + + // Identify the transient federates number + int transientFederatesNumber = 0; + for (FederateInstance federate: federates) { + if (federate.isTransient) { + transientFederatesNumber++; + } + } + if (isRemote) { commands.add("RTI -i '${FEDERATION_ID}' \\"); } else { @@ -320,7 +329,8 @@ private String getRtiCommand(List federates, boolean isRemote) commands.add(" -t \\"); } commands.addAll(List.of( - " -n "+federates.size()+" \\", + " -n "+(federates.size() - transientFederatesNumber) +" \\", + " -nt "+transientFederatesNumber+" \\", " -c "+targetConfig.clockSync.toString()+" \\" )); if (targetConfig.clockSync.equals(ClockSyncMode.ON)) { From 96b50ed85adecb90c3a4ffc5695ce0a9629874ec Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 5 Apr 2023 03:26:43 -0700 Subject: [PATCH 004/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 9f5aca4ec9..190a211b55 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9f5aca4ec90c6e12bdd3e614056bbcc5ddef77f9 +Subproject commit 190a211b5568b63a6664f82c3756dcada70c51d7 From 5e380ff72998ac0acde93c8ecf36f4c2936044e6 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 12 Apr 2023 17:14:55 -0700 Subject: [PATCH 005/142] Align reactor-c and add Timers.lf test --- org.lflang/src/lib/c/reactor-c | 2 +- test/C/src/federated/transient/Timers.lf | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/C/src/federated/transient/Timers.lf diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 190a211b55..b570310c79 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 190a211b5568b63a6664f82c3756dcada70c51d7 +Subproject commit b570310c79ced4d834e329ac8d357c134b62c5e0 diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf new file mode 100644 index 0000000000..01bd24b34f --- /dev/null +++ b/test/C/src/federated/transient/Timers.lf @@ -0,0 +1,23 @@ +target C { + timeout: 10s, + tracing: true, + threading: true +} + +reactor Timer(period:time = 2s) { + output out: int + timer t(0, period) + state count: int = 0 + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d", self->count); + self->count++; + =} +} + +federated reactor { + @transient + t0 = new Timer(period = 1s) + t1 = new Timer() + t2 = new Timer() +} \ No newline at end of file From 9ad1339154dba67c019c1c9c920a23f2bc7d68d6 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 13 Apr 2023 19:33:44 -0700 Subject: [PATCH 006/142] Add a test LF program for where the transient federate has upstream and downstream federates + Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- .../federated/transient/ConnectedTransient.lf | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 test/C/src/federated/transient/ConnectedTransient.lf diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index b570310c79..86a1a473c3 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit b570310c79ced4d834e329ac8d357c134b62c5e0 +Subproject commit 86a1a473c33b7aea38ef4409e893204e764a9122 diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf new file mode 100644 index 0000000000..e19d77d0dd --- /dev/null +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -0,0 +1,53 @@ +target C { + timeout: 10s, + tracing: true, + threading: true +} + +reactor Up(period:time = 2s) { + output out: int + timer t(0, period) + state count: int = 0 + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d", self->count); + self->count++; + =} +} + +reactor Middle { + input in1: int + input in2: int + output out: int + state count: int=0 + reaction(in1) -> out {= + self->count += in1->value; + lf_set(out, self->count); + lf_print("Sending %d", self->count); + =} + reaction(in2) -> out {= + self->count += in2->value; + lf_set(out, self->count); + lf_print("Sending %d", self->count); + =} +} + +reactor Down{ + input in: int + reaction(in) {= + lf_print("Received %d at logical time %lld", in-> value, lf_time_logical_elapsed()); + =} +} + +federated reactor { + up1 = new Up(period = 2s) + up2 = new Up(period = 1s) + @transient + mid = new Middle() + down = new Down() + + // Connections + up1.out -> mid.in1 + up2.out -> mid.in2 + mid.out -> down.in +} \ No newline at end of file From 41e056432071ce0829aa15d416b394944545b452 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 14 Apr 2023 03:24:28 -0700 Subject: [PATCH 007/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 86a1a473c3..3f29f1d590 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 86a1a473c33b7aea38ef4409e893204e764a9122 +Subproject commit 3f29f1d59058fc0e3b39401b1a07e83b2e21c07c From d6692d14a64d1829d9727a11aafaa48b74c1ce54 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 18 Apr 2023 10:46:11 -0700 Subject: [PATCH 008/142] Add transient joining events + Align reactor-c. --- org.lflang/src/lib/c/reactor-c | 2 +- util/tracing/visualization/fedsd_helper.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 3f29f1d590..33191e943f 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 3f29f1d59058fc0e3b39401b1a07e83b2e21c07c +Subproject commit 33191e943ff68634fe1b725f9f3b536eb4919ad6 diff --git a/util/tracing/visualization/fedsd_helper.py b/util/tracing/visualization/fedsd_helper.py index 804341f117..a3dc7f0e19 100644 --- a/util/tracing/visualization/fedsd_helper.py +++ b/util/tracing/visualization/fedsd_helper.py @@ -44,7 +44,11 @@ "Receiving ADR_AD": "ADR_AD", "Receiving ADR_QR": "ADR_QR", "Receiving UNIDENTIFIED": "UNIDENTIFIED", - "Scheduler advancing time ends": "AdvLT" + "Scheduler advancing time ends": "AdvLT", + "Sending TAG_QR": "TAG_QR", + "Sending TAG_QR_RES": "TAG_QR_RES", + "Receiving TAG_QR": "TAG_QR", + "Receiving TAG_QR_RES": "TAG_QR_RES" } prune_event_name.setdefault(" ", "UNIDENTIFIED") From f8b1a5a716fafa635b66cff33b97d2c9c5c04274 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 25 Apr 2023 16:12:16 -0700 Subject: [PATCH 009/142] Add transient tests --- .../transient/ConnectedTransient_2L.lf | 64 +++++++++++++++++++ .../src/federated/transient/PingPong_Cycle.lf | 56 ++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 test/C/src/federated/transient/ConnectedTransient_2L.lf create mode 100644 test/C/src/federated/transient/PingPong_Cycle.lf diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf new file mode 100644 index 0000000000..b242275c3d --- /dev/null +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -0,0 +1,64 @@ +target C { + timeout: 20s, + tracing: true +} + +reactor Up(period:time = 2s) { + output out: int + timer t(0, period) + state count: int = 0 + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} +} + +reactor PassThrough { + input in: int + output out: int + reaction(in) -> out {= + lf_set(out, in->value); + lf_print("PassThrough :: Passing %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + =} +} + +reactor Middle { + input in1: int + input in2: int + output out: int + state count: int=0 + reaction(in1) -> out {= + self->count += in1->value; + lf_set(out, self->count); + lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} + reaction(in2) -> out {= + self->count += in2->value; + lf_set(out, self->count); + lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} +} + +reactor Down{ + input in: int + reaction(in) {= + lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + =} +} + +federated reactor { + up1 = new Up(period = 2s) + up2 = new Up(period = 1s) + @transient + pt = new PassThrough() + @transient + mid = new Middle() + down = new Down() + + // Connections + up1.out -> pt.in + pt.out -> mid.in1 + up2.out -> mid.in2 + mid.out -> down.in +} \ No newline at end of file diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf new file mode 100644 index 0000000000..1fad7fefa2 --- /dev/null +++ b/test/C/src/federated/transient/PingPong_Cycle.lf @@ -0,0 +1,56 @@ +target C { + timeout: 10 s, + tracing: true +} + +reactor Ping { + timer t(0, 1 s) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= + lf_set(out, self->counter++); + =} + + reaction(in) {= + self->received = true; + lf_print("Ping Received %d at %lld.", in->value, lf_time_logical_elapsed()); + =} + + reaction(shutdown) {= + if(!self->received) { + lf_print("Nothing received."); + exit(1); + } + =} +} + +reactor Pong { + input in: int + output out: int + state received: bool = false + + reaction(in) -> out {= + self->received = true; + lf_print("Pong Received %d at %lld.", in-> value, lf_time_logical_elapsed()); + lf_set(out, in->value); + =} + + reaction(shutdown) {= + if(!self->received) { + lf_print("Nothing received."); + exit(1); + } + =} +} + +federated reactor { + ping = new Ping() + @transient + pong = new Pong() + + ping.out -> pong.in + pong.out -> ping.in after 100 ms +} \ No newline at end of file From 364a3a0701c1877e09c254d4aa13b824ca4a0181 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 25 Apr 2023 16:34:40 -0700 Subject: [PATCH 010/142] Add a transient example with a deadline, derived from the fast and slow example. --- test/C/src/federated/transient/FastAndSlow.lf | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/C/src/federated/transient/FastAndSlow.lf diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf new file mode 100644 index 0000000000..558736a859 --- /dev/null +++ b/test/C/src/federated/transient/FastAndSlow.lf @@ -0,0 +1,39 @@ +// This example is derived from the C++ enclave test case, which says "This is a +// basic test for enclaved execution. The deadlines should never be +// violated for the test to pass.". +// Here, we transform it into a federated one, where the `fast` federate is +// transient. + +target C { + timeout: 20 sec +} + +reactor Slow { + timer t(0, 1 sec) + + reaction(t) {= + lf_print("Slow reaction starts"); + lf_sleep(700000000); + lf_print("Slow reaction ends"); + =} deadline(200 msec) {= + lf_print_error_and_exit("Slow deadline was violated!"); + =} +} + +reactor Fast { + timer t(0 msec, 100 msec) + + reaction(t) {= + lf_print("Fast reaction executes"); + =} deadline( + 200 msec + ) {= + lf_print_error_and_exit("Fast deadline was violated!"); + =} +} + +federated reactor { + slow = new Slow() + @transient + fast = new Fast() +} \ No newline at end of file From 3ac5aabd53f61b8dd7aff4e6e5ffc99b53ee5f8f Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 25 Apr 2023 18:19:27 -0700 Subject: [PATCH 011/142] Better trace points naming --- util/tracing/visualization/fedsd_helper.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/tracing/visualization/fedsd_helper.py b/util/tracing/visualization/fedsd_helper.py index a3dc7f0e19..06aa0c3289 100644 --- a/util/tracing/visualization/fedsd_helper.py +++ b/util/tracing/visualization/fedsd_helper.py @@ -45,10 +45,10 @@ "Receiving ADR_QR": "ADR_QR", "Receiving UNIDENTIFIED": "UNIDENTIFIED", "Scheduler advancing time ends": "AdvLT", - "Sending TAG_QR": "TAG_QR", - "Sending TAG_QR_RES": "TAG_QR_RES", - "Receiving TAG_QR": "TAG_QR", - "Receiving TAG_QR_RES": "TAG_QR_RES" + "Sending CuTAG_QR": "CuTAG_QR", + "Sending CuTAG_QR_RES": "CuTAG_QR_RES", + "Receiving CuTAG_QR": "CuTAG_QR", + "Receiving CuTAG_QR_RES": "CuTAG_QR_RES" } prune_event_name.setdefault(" ", "UNIDENTIFIED") From cb27df584a9bfc93828d63e54736bf52f514da3e Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 25 Apr 2023 18:43:35 -0700 Subject: [PATCH 012/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index df9bd413b5..9a788e9370 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit df9bd413b51c5cd150002cec3355c563d62fbb8b +Subproject commit 9a788e9370b2f91b4f06c1044259838e39c539ee From d7791fa78884011abf45bfd9d6fc0d83a9124862 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 27 Apr 2023 12:33:00 -0700 Subject: [PATCH 013/142] Include a special case for testing transients --- .../federated/transient/ConnectedTransient.lf | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index e19d77d0dd..e085f11f71 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -1,7 +1,6 @@ target C { - timeout: 10s, - tracing: true, - threading: true + timeout: 20s, + tracing: true } reactor Up(period:time = 2s) { @@ -10,7 +9,7 @@ reactor Up(period:time = 2s) { state count: int = 0 reaction(t) -> out {= lf_set(out, self->count); - lf_print("Count is = %d", self->count); + lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); self->count++; =} } @@ -23,19 +22,25 @@ reactor Middle { reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); - lf_print("Sending %d", self->count); + lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); - lf_print("Sending %d", self->count); + lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} } reactor Down{ + timer t(2s, 300ms) input in: int + reaction(t) {= + lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); + =} reaction(in) {= - lf_print("Received %d at logical time %lld", in-> value, lf_time_logical_elapsed()); + lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } From e8349ced2187d5e5d33657d2df1d3b21747838f3 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 3 May 2023 18:09:06 -0700 Subject: [PATCH 014/142] Merge master into transient-federates and Align reactor-c. --- .github/workflows/ci.yml | 2 - CONTRIBUTING.md | 15 +-- org.lflang/build.gradle | 6 - org.lflang/src/lib/c/reactor-c | 2 +- org.lflang/src/lib/ts/babel.config.js | 19 --- org.lflang/src/lib/ts/package.json | 24 +--- org.lflang/src/lib/ts/tsconfig.json | 7 +- org.lflang/src/org/lflang/FileConfig.java | 4 +- org.lflang/src/org/lflang/TargetConfig.java | 16 +-- org.lflang/src/org/lflang/TargetProperty.java | 6 +- .../federated/extensions/CExtension.java | 1 + .../federated/extensions/CExtensionUtils.java | 5 + .../federated/generator/FedFileConfig.java | 18 ++- .../org/lflang/generator/GeneratorBase.java | 5 +- .../lflang/generator/c/CCmakeGenerator.java | 5 +- .../src/org/lflang/generator/c/CCompiler.java | 19 ++- .../org/lflang/generator/c/CGenerator.java | 63 +++------- .../src/org/lflang/generator/c/CUtil.java | 110 ----------------- .../org/lflang/generator/ts/TSGenerator.kt | 54 ++++++--- org.lflang/src/org/lflang/util/FileUtil.java | 111 +++++++++++++++++- test/C/src/FileReader.lf | 46 ++++++++ test/C/src/federated/FederatedFileReader.lf | 57 +++++++++ test/C/src/lib/FileReader.txt | 1 + test/C/src/target/FederatedFiles.lf | 14 +++ util/RunZephyrTests.sh | 2 +- 25 files changed, 344 insertions(+), 268 deletions(-) delete mode 100644 org.lflang/src/lib/ts/babel.config.js create mode 100644 test/C/src/FileReader.lf create mode 100644 test/C/src/federated/FederatedFileReader.lf create mode 100644 test/C/src/lib/FileReader.txt create mode 100644 test/C/src/target/FederatedFiles.lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6dd56ae40..48110ac926 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,8 +51,6 @@ jobs: uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: 'C' - benchmarks-ref: main - compiler-ref: master needs: cancel # Run language server tests. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13d24c957c..55716f5b17 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,8 +25,7 @@ Test categories are declared in the [TestCategory enum in TestRegistry.java](htt ### Workflow All code contributions must go through a pull request (PR), pass all tests run in CI, and get an approving review before it is merged. Pushing to the `master` branch is restricted. All code review is conducted using the Github review system on PRs. Before requesting a code review, ensure that you have: -- applied the [code formatter](#code-style-and-formatting); -- [documented](#code-style-and-formatting) your code; +- documented your code; - written [tests](#writing-tests) that cover your code; and - accompanied any remaining `TODO`s or `FIXME`s with a link to an active [issue](#reporting-issues). @@ -73,18 +72,6 @@ Perform merges to bring your feature branch up-to-date with master locally (do n #### Addressing reviews To address feedback from code review, implement changes and push to your feature branch. If you are certain that a reviewer's concern has been addressed by your new changes, hit the `Resolve conversation` button. If you are unsure, ask for follow up in the conversation and let the reviewer determine whether the feedback was addressed accordingly. -### Code style and formatting -The Lingua Franca compiler is implemented in Java and Kotlin. The overarching advice is to use each language's most widely used idioms and conventions, which are fortunately very similar. The code base is shipped with a [Spotless](https://github.com/diffplug/spotless) configuration to check and enforce style compliance. Lingua Franca code (e.g., tests) in this repository is also automatically formatted via Spotless. - -- To check that modified files are formatted correctly, run: -``` -./gradlew spotlessCheck -``` -- To apply the changes recommended by the formatter, run: -``` -./gradlew spotlessApply -``` - #### General guidelines - _Do not copy-paste code._ If you want to reuse code, factor it out into a method and call it. - _Keep methods concise._ As a rule of thumb, a method should fit on your screen so that it can be read without scrolling. We impose no hard limit on method length, but anything above 40 lines should be considered for breaking up. diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index 00410d16f5..5155c0a6e2 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -174,12 +174,6 @@ task buildAll() { mainClassName = 'org.lflang.cli.Lfc' } -// define buildLfc as an alias to buildAll -task buildLfc { - dependsOn buildAll - doFirst({{logger.warn("The buildLfc task is deprecated! Please use buildAll instead.")}}) -} - task jarCliTools(type: ShadowJar) { manifest { attributes('Main-Class': 'org.lflang.cli.Lfc') diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index c35cfd167b..fababedeec 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit c35cfd167bb3f0560e05b6a967386672270a24f2 +Subproject commit fababedeec2925e996991a3d5b7a4b96e4af21c0 diff --git a/org.lflang/src/lib/ts/babel.config.js b/org.lflang/src/lib/ts/babel.config.js deleted file mode 100644 index 9fd078c1b2..0000000000 --- a/org.lflang/src/lib/ts/babel.config.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = function (api) { - api.cache(true); - - const presets = [ - "@babel/typescript" - ]; - - const plugins = [ - "@babel/proposal-class-properties", - "@babel/proposal-object-rest-spread", - "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-transform-modules-commonjs" - ]; - - return { - presets, - plugins - }; -} diff --git a/org.lflang/src/lib/ts/package.json b/org.lflang/src/lib/ts/package.json index a1d65a6403..fc063d791e 100644 --- a/org.lflang/src/lib/ts/package.json +++ b/org.lflang/src/lib/ts/package.json @@ -3,35 +3,23 @@ "type": "commonjs", "dependencies": { "@lf-lang/reactor-ts": "git://github.com/lf-lang/reactor-ts.git#master", - "@babel/cli": "^7.8.4", - "@babel/core": "^7.8.7", - "@babel/node": "^7.8.7", - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.8.3", - "@babel/plugin-proposal-optional-chaining": "^7.8.3", - "@babel/plugin-transform-modules-commonjs": "^7.8.3", - "@babel/preset-env": "^7.8.7", - "@babel/preset-typescript": "^7.8.3", - "command-line-usage": "^6.1.0", "command-line-args": "^5.1.1", - "rimraf": "^3.0.2" + "command-line-usage": "^6.1.3" }, "devDependencies": { "@types/command-line-args": "^5.2.0", "@types/command-line-usage": "^5.0.2", - "@types/jest": "^27.0.0", - "@types/microtime": "^2.1.0", - "@types/node": "^16.3.3", "@types/google-protobuf": "^3.7.4", - "@types/uuid": "^8.3.4", + "@types/microtime": "^2.1.0", + "@types/node": "^18.14.2", "@typescript-eslint/eslint-plugin": "5.33.0", "@typescript-eslint/parser": "^5.8.1", "eslint": "^8.5.0", "typescript": "~4.8.2", - "ts-protoc-gen": "^0.12.0" + "ts-protoc-gen": "^0.15.0", + "rimraf": "^3.0.2" }, "scripts": { - "check-types": "tsc", - "build": "npx rimraf dist && npx babel src --out-dir dist --extensions .ts,.js" + "build": "npx rimraf dist && npx tsc --outDir dist" } } diff --git a/org.lflang/src/lib/ts/tsconfig.json b/org.lflang/src/lib/ts/tsconfig.json index b771b75281..3d51d35052 100644 --- a/org.lflang/src/lib/ts/tsconfig.json +++ b/org.lflang/src/lib/ts/tsconfig.json @@ -1,19 +1,22 @@ { "compilerOptions": { "allowJs": true, - "noEmit": true, "target": "esnext", + "module": "CommonJS", "types": ["node", "@lf-lang/reactor-ts", "ulog", "microtime", "command-line-args", "command-line-usage"], + "typeRoots": ["./node_modules/@types/", "./node_modules/@lf-lang/reactor-ts/src/core/@types/"], "esModuleInterop": true, "isolatedModules": true, "lib": ["esnext", "dom"], "sourceMap": true, "strict": true, "moduleResolution": "node", + "skipLibCheck": true, "strictBindCallApply": true, "strictNullChecks": true, "strictFunctionTypes": true, - "typeRoots": ["./node_modules/@types/", "./node_modules/@lf-lang/reactor-ts/src/core/@types/"] + "noImplicitThis": true, + "outDir": "dist" }, "include": [ "src/**/*" diff --git a/org.lflang/src/org/lflang/FileConfig.java b/org.lflang/src/org/lflang/FileConfig.java index ed0f663ee9..91d681046a 100644 --- a/org.lflang/src/org/lflang/FileConfig.java +++ b/org.lflang/src/org/lflang/FileConfig.java @@ -1,6 +1,5 @@ package org.lflang; -import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; @@ -15,7 +14,6 @@ import org.eclipse.xtext.generator.IFileSystemAccess2; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.generator.GeneratorUtils; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -308,7 +306,7 @@ public LFCommand getCommand() { * Return the extension used for binaries on the platform on which compilation takes place. */ protected String getExecutableExtension() { - return (GeneratorUtils.isHostWindows() ? ".exe" : ""); + return GeneratorUtils.isHostWindows() ? ".exe" : ""; } /** diff --git a/org.lflang/src/org/lflang/TargetConfig.java b/org.lflang/src/org/lflang/TargetConfig.java index 23e99541da..845f214ec8 100644 --- a/org.lflang/src/org/lflang/TargetConfig.java +++ b/org.lflang/src/org/lflang/TargetConfig.java @@ -172,13 +172,6 @@ public TargetConfig( */ public List cmakeIncludes = new ArrayList<>(); - /** - * List of cmake-includes from the cmake-include target property with no path info. - * Useful for copying them to remote machines. This is needed because - * target cmake-includes can be resources with resource paths. - */ - public List cmakeIncludesWithoutPath = new ArrayList<>(); - /** * The compiler to invoke, unless a build command has been specified. */ @@ -237,14 +230,7 @@ public TargetConfig( /** * List of files to be copied to src-gen. */ - public List fileNames = new ArrayList<>(); - - /** - * List of file names from the files target property with no path info. - * Useful for copying them to remote machines. This is needed because - * target files can be resources with resource paths. - */ - public List filesNamesWithoutPath = new ArrayList<>(); + public List files = new ArrayList<>(); /** * If true, configure the execution environment to keep executing if there diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index 1bacb1f75e..61cda14431 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -276,16 +276,16 @@ public enum TargetProperty { * processed by the code generator. */ FILES("files", UnionType.FILE_OR_FILE_ARRAY, List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.fileNames), + (config) -> ASTUtils.toElement(config.files), (config, value, err) -> { - config.fileNames = ASTUtils.elementToListOfStrings(value); + config.files = ASTUtils.elementToListOfStrings(value); }, // FIXME: This merging of lists is potentially dangerous since // the incoming list of files can belong to a .lf file that is // located in a different location, and keeping just filename // strings like this without absolute paths is incorrect. (config, value, err) -> { - config.fileNames.addAll(ASTUtils.elementToListOfStrings(value)); + config.files.addAll(ASTUtils.elementToListOfStrings(value)); }), /** diff --git a/org.lflang/src/org/lflang/federated/extensions/CExtension.java b/org.lflang/src/org/lflang/federated/extensions/CExtension.java index a8127c33bc..676e3d8be1 100644 --- a/org.lflang/src/org/lflang/federated/extensions/CExtension.java +++ b/org.lflang/src/org/lflang/federated/extensions/CExtension.java @@ -498,6 +498,7 @@ public String generatePreamble( includes.pr("#include \"core/federated/federate.h\""); includes.pr("#include \"core/federated/net_common.h\""); includes.pr("#include \"core/federated/net_util.h\""); + includes.pr("#include \"core/federated/clock-sync.h\""); includes.pr("#include \"core/threaded/reactor_threaded.h\""); includes.pr("#include \"core/utils/util.h\""); includes.pr("extern federate_instance_t _fed;"); diff --git a/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java b/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java index c84bf36197..2ad19c64cc 100644 --- a/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java +++ b/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java @@ -361,6 +361,11 @@ public static void generateCMakeInclude( CodeBuilder cmakeIncludeCode = new CodeBuilder(); cmakeIncludeCode.pr(generateSerializationCMakeExtension(federate)); + cmakeIncludeCode.pr( + "add_compile_definitions(LF_SOURCE_DIRECTORY=\"" + + fileConfig.srcPath + + "\")" + ); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); diff --git a/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java b/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java index 42f5c60dc7..e434501825 100644 --- a/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java +++ b/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -110,7 +111,7 @@ public void doClean() throws IOException { */ public void relativizePaths(FedTargetConfig targetConfig) { relativizePathList(targetConfig.protoFiles); - relativizePathList(targetConfig.fileNames); + relativizePathList(targetConfig.files); relativizePathList(targetConfig.cmakeIncludes); } @@ -120,17 +121,22 @@ public void relativizePaths(FedTargetConfig targetConfig) { */ private void relativizePathList(List paths) { List tempList = new ArrayList<>(); - paths.forEach(f -> tempList.add(relativizePath(f))); + paths.forEach(f -> tempList.add(relativizePath(Paths.get(f)))); paths.clear(); paths.addAll(tempList); } /** - * Relativize a single path. + * Relativize a single path, but only if it points to a local resource in the project (i.e., not + * on the class path). * @param path The path to relativize. */ - private String relativizePath(String path) { - Path resolvedPath = this.srcPath.resolve(path).toAbsolutePath(); - return this.getSrcPath().relativize(resolvedPath).toString(); + private String relativizePath(Path path) { + if (FileUtil.findInPackage(path, this) == null) { + return String.valueOf(path); + } else { + Path resolvedPath = this.srcPath.resolve(path).toAbsolutePath(); + return this.getSrcPath().relativize(resolvedPath).toString(); + } } } diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index ba39a94d9f..15d703bcbf 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -56,6 +56,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; +import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; import com.google.common.base.Objects; @@ -348,7 +349,9 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param targetConfig The targetConfig to read the `files` from. * @param fileConfig The fileConfig used to make the copy and resolve paths. */ - protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) {} + protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { + FileUtil.copyFiles(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); + } /** * Return true if errors occurred in the last call to doGenerate(). diff --git a/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java b/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java index 3f5eb4a5b7..d158f7491b 100644 --- a/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java @@ -25,6 +25,7 @@ package org.lflang.generator.c; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -313,8 +314,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.cmakeIncludesWithoutPath) { - cMakeCode.pr("include(\""+includeFile+"\")"); + for (String includeFile : targetConfig.cmakeIncludes) { + cMakeCode.pr("include(\""+ Path.of(includeFile).getFileName()+"\")"); } cMakeCode.newLine(); diff --git a/org.lflang/src/org/lflang/generator/c/CCompiler.java b/org.lflang/src/org/lflang/generator/c/CCompiler.java index 06095f553d..f0860a0e91 100644 --- a/org.lflang/src/org/lflang/generator/c/CCompiler.java +++ b/org.lflang/src/org/lflang/generator/c/CCompiler.java @@ -25,6 +25,7 @@ package org.lflang.generator.c; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -222,6 +223,14 @@ static Stream cmakeCompileDefinitions(TargetConfig targetConfig) { private static List cmakeOptions(TargetConfig targetConfig, FileConfig fileConfig) { List arguments = new ArrayList<>(); cmakeCompileDefinitions(targetConfig).forEachOrdered(arguments::add); + String separator = File.separator; + String maybeQuote = ""; // Windows seems to require extra level of quoting. + String srcPath = fileConfig.srcPath.toString(); // Windows requires escaping the backslashes. + if (separator.equals("\\")) { + separator = "\\\\\\\\"; + maybeQuote = "\\\""; + srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); + } arguments.addAll(List.of( "-DCMAKE_BUILD_TYPE=" + ((targetConfig.cmakeBuildType!=null) ? targetConfig.cmakeBuildType.toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), @@ -230,8 +239,16 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f fileConfig.binPath ) ), - FileUtil.toUnixString(fileConfig.getSrcGenPath()) + "-DLF_FILE_SEPARATOR=\"" + maybeQuote + separator + maybeQuote + "\"" )); + // Add #define for source file directory. + // Do not do this for federated programs because for those, the definition is put + // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). + if (!fileConfig.srcPath.toString().contains("fed-gen")) { + // Do not convert to Unix path + arguments.add("-DLF_SOURCE_DIRECTORY=\"" + maybeQuote + srcPath + maybeQuote + "\""); + } + arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); if (GeneratorUtils.isHostWindows()) { arguments.add("-DCMAKE_SYSTEM_VERSION=\"10.0\""); diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index f598219ddd..fbedb23253 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -37,7 +37,6 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.HashSet; import java.util.LinkedHashSet; @@ -610,7 +609,9 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { GeneratorResult.Status.COMPILED, null ); } - System.out.println("Compiled binary is in " + fileConfig.binPath); + if (!errorsOccurred()){ + System.out.println("Compiled binary is in " + fileConfig.binPath); + } } else { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, null)); } @@ -803,9 +804,15 @@ private void inspectReactorEResource(ReactorDecl reactor) { break; } } - // Copy the user files and cmake-includes to the src-gen path of the main .lf file if (lfResource != null) { + // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); + // Merge the CMake includes from the imported file into the target config + lfResource.getTargetConfig().cmakeIncludes.forEach(incl -> { + if (!this.targetConfig.cmakeIncludes.contains(incl)) { + this.targetConfig.cmakeIncludes.add(incl); + } + }); } } } @@ -818,56 +825,18 @@ private void inspectReactorEResource(ReactorDecl reactor) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ @Override - public void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { + protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { super.copyUserFiles(targetConfig, fileConfig); - // Make sure the target directory exists. - var targetDir = this.fileConfig.getSrcGenPath(); - try { - Files.createDirectories(targetDir); - } catch (IOException e) { - //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored - Exceptions.sneakyThrow(e); - } - - for (String filename : targetConfig.fileNames) { - var relativeFileName = CUtil.copyFileOrResource( - filename, - fileConfig.srcFile.getParent(), - targetDir); - if (StringExtensions.isNullOrEmpty(relativeFileName)) { - errorReporter.reportError( - "Failed to find file " + filename + " specified in the" + - " files target property." - ); - } else { - targetConfig.filesNamesWithoutPath.add( - relativeFileName - ); - } - } + // Must use class variable to determine destination! + var destination = this.fileConfig.getSrcGenPath(); - for (String filename : targetConfig.cmakeIncludes) { - var relativeCMakeIncludeFileName = - CUtil.copyFileOrResource( - filename, - fileConfig.srcFile.getParent(), - targetDir); - // Check if the file exists - if (StringExtensions.isNullOrEmpty(relativeCMakeIncludeFileName)) { - errorReporter.reportError( - "Failed to find cmake-include file " + filename - ); - } else { - this.targetConfig.cmakeIncludesWithoutPath.add( - relativeCMakeIncludeFileName - ); - } - } + FileUtil.copyFiles(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); + // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { try { FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(targetConfig.fedSetupPreamble), - targetDir.resolve(targetConfig.fedSetupPreamble)); + destination.resolve(targetConfig.fedSetupPreamble)); } catch (IOException e) { errorReporter.reportError("Failed to find _fed_setup file " + targetConfig.fedSetupPreamble); } diff --git a/org.lflang/src/org/lflang/generator/c/CUtil.java b/org.lflang/src/org/lflang/generator/c/CUtil.java index 69e9ec30ae..ce1c83d87d 100644 --- a/org.lflang/src/org/lflang/generator/c/CUtil.java +++ b/org.lflang/src/org/lflang/generator/c/CUtil.java @@ -26,12 +26,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY package org.lflang.generator.c; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -54,7 +49,6 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY import org.lflang.lf.Parameter; import org.lflang.lf.Port; import org.lflang.lf.Reactor; -import org.lflang.lf.ReactorDecl; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; import org.lflang.lf.WidthTerm; @@ -575,69 +569,6 @@ public static String triggerRefNested(PortInstance port, String runtimeIndex, St return reactorRefNested(port.getParent(), runtimeIndex, bankIndex) + "." + port.getName() + "_trigger"; } - /** - * Copy the 'fileName' (which also could be a directory name) from the - * 'srcDirectory' to the 'destinationDirectory'. This function has a - * fallback search mechanism, where if `fileName` is not found in the - * `srcDirectory`, it will try to find `fileName` via the following - * procedure: - * 1- Search in LF_CLASSPATH. @see findFile() - * 2- Search in CLASSPATH. @see findFile() - * 3- Search for 'fileName' as a resource. That means the `fileName` - * can be '/path/to/class/resource'. @see java.lang.Class.getResourceAsStream() - * - * @param fileName Name of the file or directory. - * @param srcDir Where the file or directory is currently located. - * @param dstDir Where the file or directory should be placed. - * @return The name of the file or directory in destinationDirectory or an empty string on failure. - */ - public static String copyFileOrResource(String fileName, Path srcDir, - Path dstDir) { - // Try to copy the file or directory from the file system. - Path file = findFileOrDirectory(fileName, srcDir); - if (file != null) { - Path target = dstDir.resolve(file.getFileName()); - try { - if (Files.isDirectory(file)) { - FileUtil.copyDirectory(file, target); - } else if (Files.isRegularFile(file)) { - Files.copy(file, target, - StandardCopyOption.REPLACE_EXISTING); - } - return file.getFileName().toString(); - } catch (IOException e) { - // Failed to copy the file or directory, most likely - // because it doesn't exist. Will try to find it as a - // resource before giving up. - } - } - - String filenameWithoutPath = fileName; - int lastSeparator = fileName.lastIndexOf(File.separator); - if (lastSeparator > 0) { - // FIXME: Brittle. What if the file is in a subdirectory? - filenameWithoutPath = fileName.substring(lastSeparator + 1); - } - // Try to copy the file or directory as a resource. - try { - FileUtil.copyFileFromClassPath(fileName, - dstDir.resolve(filenameWithoutPath)); - return filenameWithoutPath; - } catch (IOException ex) { - // Will try one more time as a directory - } - - try { - FileUtil.copyDirectoryFromClassPath(fileName, - dstDir.resolve(filenameWithoutPath), false); - return filenameWithoutPath; - } catch (IOException ex) { - System.err.println( - "WARNING: Failed to find file or directory " + fileName); - } - - return ""; - } ////////////////////////////////////////////////////// //// FIXME: Not clear what the strategy is with the following inner interface. @@ -661,47 +592,6 @@ public interface ReportCommandErrors { void report(String errors); } - /** - * Search for a given file or directory name in the given directory. - * If not found, search in directories in LF_CLASSPATH. - * If there is no LF_CLASSPATH environment variable, use CLASSPATH, - * if it is defined. The first file or directory that is found will - * be returned. Otherwise, null is returned. - * - * @param fileName The file or directory name or relative path + name - * as a String. - * @param directory String representation of the directory to search in. - * @return A Java Path or null if not found. - */ - public static Path findFileOrDirectory(String fileName, Path directory) { - Path foundFile; - - // Check in local directory - foundFile = directory.resolve(fileName); - if (Files.exists(foundFile)) { - return foundFile; - } - - // Check in LF_CLASSPATH - // Load all the resources in LF_CLASSPATH if it is set. - String classpathLF = System.getenv("LF_CLASSPATH"); - if (classpathLF == null) { - classpathLF = System.getenv("CLASSPATH"); - } - if (classpathLF != null) { - String[] paths = classpathLF.split(System.getProperty("path.separator")); - for (String path : paths) { - foundFile = Paths.get(path).resolve(fileName); - if (Files.exists(foundFile)) { - return foundFile; - } - } - } - // Not found. - return null; - } - - /** * Run the custom build command specified with the "build" parameter. * This command is executed in the same directory as the source file. diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 9262e44e64..bd92a144ce 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -61,8 +61,10 @@ class TSGenerator( val fileConfig: TSFileConfig = context.fileConfig as TSFileConfig + var devMode = false; companion object { + /** Path to the TS lib directory (relative to class path) */ const val LIB_PATH = "/lib/ts" @@ -70,7 +72,9 @@ class TSGenerator( * Names of the configuration files to check for and copy to the generated * source package root if they cannot be found in the source directory. */ - val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", "babel.config.js", ".eslintrc.json") + val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", ".eslintrc.json") + + const val RUNTIME_URL = "git://github.com/lf-lang/reactor-ts.git" fun timeInTargetLanguage(value: TimeValue): String { return if (value.unit != null) { @@ -145,14 +149,16 @@ class TSGenerator( println("No .proto files have been imported. Skipping protocol buffer compilation.") } val parsingContext = SubContext(context, COLLECTED_DEPENDENCIES_PERCENT_PROGRESS, 100) - if ( - !context.cancelIndicator.isCanceled - && passesChecks(TSValidator(fileConfig, errorReporter, codeMaps), parsingContext) - ) { + val validator = TSValidator(fileConfig, errorReporter, codeMaps) + if (!context.cancelIndicator.isCanceled) { if (context.mode == LFGeneratorContext.Mode.LSP_MEDIUM) { + if (!passesChecks(validator, parsingContext)) { + context.unsuccessfulFinish(); + return; + } context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) } else { - compile(resource, parsingContext) + compile(validator, resource, parsingContext) concludeCompilation(context, codeMaps) } } else { @@ -184,12 +190,18 @@ class TSGenerator( if (rtPath != null) rtPath = formatRuntimePath(rtPath) // FIXME: do better CLI arg validation upstream // https://github.com/lf-lang/lingua-franca/issues/1429 + if (rtPath != null || rtVersion != null) { + devMode = true; + } manifest.toFile().forEachLine { var line = it.replace("\"LinguaFrancaDefault\"", "\"${fileConfig.name}\""); + if (line.contains(rtRegex) && line.contains(RUNTIME_URL)) { + devMode = true; + } if (rtPath != null) { line = line.replace(rtRegex, "$1: \"$rtPath\",") } else if (rtVersion != null) { - line = line.replace(rtRegex, "$1: \"git://github.com/lf-lang/reactor-ts.git#$rtVersion\",") + line = line.replace(rtRegex, "$1: \"$RUNTIME_URL#$rtVersion\",") } sb.appendLine(line) } @@ -263,13 +275,13 @@ class TSGenerator( } - private fun compile(resource: Resource, parsingContext: LFGeneratorContext) { + private fun compile(validator: TSValidator, resource: Resource, parsingContext: LFGeneratorContext) { GeneratorUtils.refreshProject(resource, parsingContext.mode) if (parsingContext.cancelIndicator.isCanceled) return parsingContext.reportProgress("Transpiling to JavaScript...", 70) - transpile(parsingContext.cancelIndicator) + transpile(validator, parsingContext.cancelIndicator) if (parsingContext.cancelIndicator.isCanceled) return } @@ -309,6 +321,7 @@ class TSGenerator( errorReporter.reportWarning( "Falling back on npm. To prevent an accumulation of replicated dependencies, " + "it is highly recommended to install pnpm globally (npm install -g pnpm).") + val npmInstall = commandFactory.createCommand("npm", if (production) listOf("install", "--production") else listOf("install"), path) if (npmInstall == null) { @@ -325,6 +338,19 @@ class TSGenerator( "\nFor installation instructions, see: https://www.npmjs.com/get-npm") return } + + // If reactor-ts is pulled from GitHub and building is done using npm, + // first build reactor-ts (pnpm does this automatically). + if (devMode) { + val rtPath = path.resolve("node_modules").resolve("@lf-lang").resolve("reactor-ts") + val buildRuntime = commandFactory.createCommand("npm", listOf("run", "prepublish"), rtPath) + if (buildRuntime.run(context.cancelIndicator) != 0) { + errorReporter.reportError( + GeneratorUtils.findTargetDecl(resource), + "ERROR: unable to build runtime in dev mode: " + buildRuntime.errors.toString()) + } + } + installProtoBufsIfNeeded(false, path, context.cancelIndicator) } } @@ -397,19 +423,19 @@ class TSGenerator( /** * Transpile TypeScript to JavaScript. */ - private fun transpile(cancelIndicator: CancelIndicator) { + private fun transpile(validator: TSValidator, cancelIndicator: CancelIndicator) { println("Compiling") - val babel = commandFactory.createCommand("npm", listOf("run", "build"), fileConfig.srcGenPkgPath) + val tsc = commandFactory.createCommand("npm", listOf("run", "build"), fileConfig.srcGenPkgPath) - if (babel == null) { + if (tsc == null) { errorReporter.reportError(NO_NPM_MESSAGE) return } - if (babel.run(cancelIndicator) == 0) { + if (validator.run(tsc, cancelIndicator) == 0) { println("SUCCESS (compiling generated TypeScript code)") } else { - errorReporter.reportError("Compiler failed with the following errors:\n${babel.errors}") + errorReporter.reportError("Compiler failed with the following errors:\n${tsc.errors}") } } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index d4d34c7b08..a2cfb81e4d 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -36,7 +36,9 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.util.RuntimeIOException; +import org.lflang.ErrorReporter; import org.lflang.FileConfig; +import org.lflang.generator.LFGeneratorContext; public class FileUtil { @@ -150,7 +152,7 @@ public static java.net.URI locateFile(String path, Resource resource) { sourceURI = iFile != null ? iFile.getRawLocation().toFile().getParentFile().toURI() : null; } if (sourceURI != null) { - return sourceURI.resolve(path.toString()); + return sourceURI.resolve(path); } } catch (Exception e) { // nothing @@ -239,6 +241,68 @@ public static void copyFile(Path source, Path destination) throws IOException { copyFile(source, destination, false); } + /** + * Given a list of files or directories, attempt to find them based on the given generator + * context, and copy then to the destination. Files are searched for in the file system first. + * Files that cannot be found in the file system are looked for on the class path. + * + * @param filesOrDirectories The files or directories to copy. + * @param destination The location to copy them to. + * @param fileConfig The file configuration that specifies where the files must be found. + * @param errorReporter An error reporter to report problems. + */ + public static void copyFiles( + List filesOrDirectories, + Path destination, + FileConfig fileConfig, + ErrorReporter errorReporter + ) { + for (String fileOrDirectory : filesOrDirectories) { + var path = Paths.get(fileOrDirectory); + var found = FileUtil.findInPackage(path, fileConfig); + if (found != null) { + try { + FileUtil.copyFileOrDirectory(found, destination.resolve(found.getFileName())); + } catch (IOException e) { + errorReporter.reportError( + "Unable to copy '" + fileOrDirectory + "' from the file system." + ); + } + } else { + // Attempt to copy from the classpath instead. + // If the filename is not a directory, it will + // just be copied without further recursion. + try { + FileUtil.copyDirectoryFromClassPath( + fileOrDirectory, + destination, + false + ); + } catch (IOException e) { + errorReporter.reportError( + "Unable to copy '" + fileOrDirectory + "' from the class path." + ); + } + } + } + } + + /** + * If the source is a directory, then copy the contents of the directory to the destination. + * If the source is a file, then copy the file to the destination. + * @param source A file or directory to copy to the destination. + * @param destination A directory to copy the file(s) at the source to. + * @throws IOException + */ + public static void copyFileOrDirectory(Path source, Path destination) throws IOException { + if (Files.isDirectory(source)) { + copyDirectory(source, destination); + } else if (Files.isRegularFile(source)) { + copyFile(source, destination); + } else { + throw new IllegalArgumentException("Source is neither a directory nor a regular file."); + } + } /** * Copy a given input stream to a destination file. * @@ -359,6 +423,7 @@ private static boolean copyDirectoryFromJar(JarURLConnection connection, final P final String connectionEntryName = connection.getEntryName(); boolean copiedFiles = false; + // Iterate all entries in the jar file. for (Enumeration e = jar.entries(); e.hasMoreElements(); ) { final JarEntry entry = e.nextElement(); @@ -366,9 +431,10 @@ private static boolean copyDirectoryFromJar(JarURLConnection connection, final P // Extract files only if they match the given source path. if (entryName.startsWith(connectionEntryName)) { - String filename = entry.getName().substring(connectionEntryName.length() + 1); + String filename = entryName.equals(connectionEntryName) ? + connectionEntryName : + entryName.substring(connectionEntryName.length() + 1); Path currentFile = destination.resolve(filename); - if (entry.isDirectory()) { Files.createDirectories(currentFile); } else { @@ -511,6 +577,45 @@ public static void deleteDirectory(Path dir) throws IOException { } } + /** + * Return an absolute path to the given file or directory if it can be found within the package. + * Otherwise, return null. + * + * NOTE: If the given file or directory is given as an absolute path but cannot be found, it is + * interpreted as a relative path with respect to the project root. + * + * @param fileOrDirectory The file or directory to look for. + * @param fileConfig A file configuration that determines where the package is located. + * @return An absolute path of the file or directory was found; null otherwise. + */ + public static Path findInPackage(Path fileOrDirectory, FileConfig fileConfig) { + if (fileOrDirectory.isAbsolute() && Files.exists(fileOrDirectory)) { + return fileOrDirectory; + } else { + Path relPath; + // Disregard root and interpret as relative path + if (fileOrDirectory.isAbsolute()) { + relPath = Paths.get( + String.valueOf(fileOrDirectory).replaceFirst( + String.valueOf(fileOrDirectory.getRoot()), + "") + ); + } else { + relPath = fileOrDirectory; + } + + // Look relative to the source file and relative to the package root. + var locations = List.of(fileConfig.srcPath, fileConfig.srcPkgPath); + var found = locations.stream().filter( + loc -> Files.exists(loc.resolve(relPath)) + ).findFirst(); + if (found.isPresent()) { + return found.get().resolve(relPath); + } + } + return null; + } + /** * Get the iResource corresponding to the provided resource if it can be * found. diff --git a/test/C/src/FileReader.lf b/test/C/src/FileReader.lf new file mode 100644 index 0000000000..10be772fb7 --- /dev/null +++ b/test/C/src/FileReader.lf @@ -0,0 +1,46 @@ +/** Test reading a file at a location relative to the source file. */ +target C + +reactor Source { + output out: char* // Use char*, not string, so memory is freed. + + reaction(startup) -> out {= + char* file_path = + LF_SOURCE_DIRECTORY + LF_FILE_SEPARATOR "lib" + LF_FILE_SEPARATOR "FileReader.txt"; + + FILE* file = fopen(file_path, "rb"); + if (file == NULL) lf_print_error_and_exit("Error opening file at path %s.", file_path); + + // Determine the file size + fseek(file, 0, SEEK_END); + long file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + // Allocate memory for the buffer + char* buffer = (char *) malloc(file_size + 1); + if (buffer == NULL) lf_print_error_and_exit("Out of memory."); + + // Read the file into the buffer + fread(buffer, file_size, 1, file); + buffer[file_size] = '\0'; + fclose(file); + + lf_set(out, buffer); + =} +} + +main reactor { + preamble {= + #include + =} + s = new Source() + + reaction(s.out) {= + printf("Received: %s\n", s.out->value); + if (strcmp("Hello World", s.out->value) != 0) { + lf_print_error_and_exit("Expected 'Hello World'"); + } + =} +} diff --git a/test/C/src/federated/FederatedFileReader.lf b/test/C/src/federated/FederatedFileReader.lf new file mode 100644 index 0000000000..6ba2da763f --- /dev/null +++ b/test/C/src/federated/FederatedFileReader.lf @@ -0,0 +1,57 @@ +/** Test reading a file at a location relative to the source file. */ +target C { + timeout: 0 s +} + +reactor Source { + output out: char* // Use char*, not string, so memory is freed. + + reaction(startup) -> out {= + char* file_path = + LF_SOURCE_DIRECTORY + LF_FILE_SEPARATOR ".." + LF_FILE_SEPARATOR "lib" + LF_FILE_SEPARATOR "FileReader.txt"; + + FILE* file = fopen(file_path, "rb"); + if (file == NULL) lf_print_error_and_exit("Error opening file at path %s.", file_path); + + // Determine the file size + fseek(file, 0, SEEK_END); + long file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + // Allocate memory for the buffer + char* buffer = (char *) malloc(file_size + 1); + if (buffer == NULL) lf_print_error_and_exit("Out of memory."); + + // Read the file into the buffer + fread(buffer, file_size, 1, file); + buffer[file_size] = '\0'; + fclose(file); + + // For federated version, have to use lf_set_array so array size is know + // to the serializer. + lf_set_array(out, buffer, file_size + 1); + =} +} + +reactor Check { + preamble {= + #include + =} + input in: char* + + reaction(in) {= + printf("Received: %s\n", in->value); + if (strcmp("Hello World", in->value) != 0) { + lf_print_error_and_exit("Expected 'Hello World'"); + } + =} +} + +federated reactor { + s = new Source() + c = new Check() + s.out -> c.in +} diff --git a/test/C/src/lib/FileReader.txt b/test/C/src/lib/FileReader.txt new file mode 100644 index 0000000000..5e1c309dae --- /dev/null +++ b/test/C/src/lib/FileReader.txt @@ -0,0 +1 @@ +Hello World \ No newline at end of file diff --git a/test/C/src/target/FederatedFiles.lf b/test/C/src/target/FederatedFiles.lf new file mode 100644 index 0000000000..ebc1ff210e --- /dev/null +++ b/test/C/src/target/FederatedFiles.lf @@ -0,0 +1,14 @@ +// This test references a header file in reactor-c, which has to be obtained +// from the class path. This test is successful if it compiles. +target C { + files: "/lib/c/reactor-c/util/sensor_simulator.h", + timeout: 1 s +} + +reactor Foo { + reaction(startup) {= lf_print("Hello World"); =} +} + +federated reactor { + f = new Foo() +} diff --git a/util/RunZephyrTests.sh b/util/RunZephyrTests.sh index 66dcd10ffa..cabbbec0b2 100755 --- a/util/RunZephyrTests.sh +++ b/util/RunZephyrTests.sh @@ -9,7 +9,7 @@ num_failures=0 failed_tests="" # Skip -skip=() +skip=("FileReader") find_kconfig_folders() { if [ -f "$folder/CMakeLists.txt" ]; then From 53443e79093390ac2dacfae10dc985948db8f857 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 4 May 2023 08:52:50 -0700 Subject: [PATCH 015/142] Wrong merge! Revert "Merge master into transient-federates and Align reactor-c." This reverts commit e8349ced2187d5e5d33657d2df1d3b21747838f3. --- .github/workflows/ci.yml | 2 + CONTRIBUTING.md | 15 ++- org.lflang/build.gradle | 6 + org.lflang/src/lib/c/reactor-c | 2 +- org.lflang/src/lib/ts/babel.config.js | 19 +++ org.lflang/src/lib/ts/package.json | 24 +++- org.lflang/src/lib/ts/tsconfig.json | 7 +- org.lflang/src/org/lflang/FileConfig.java | 4 +- org.lflang/src/org/lflang/TargetConfig.java | 16 ++- org.lflang/src/org/lflang/TargetProperty.java | 6 +- .../federated/extensions/CExtension.java | 1 - .../federated/extensions/CExtensionUtils.java | 5 - .../federated/generator/FedFileConfig.java | 18 +-- .../org/lflang/generator/GeneratorBase.java | 5 +- .../lflang/generator/c/CCmakeGenerator.java | 5 +- .../src/org/lflang/generator/c/CCompiler.java | 19 +-- .../org/lflang/generator/c/CGenerator.java | 63 +++++++--- .../src/org/lflang/generator/c/CUtil.java | 110 +++++++++++++++++ .../org/lflang/generator/ts/TSGenerator.kt | 54 +++------ org.lflang/src/org/lflang/util/FileUtil.java | 111 +----------------- test/C/src/FileReader.lf | 46 -------- test/C/src/federated/FederatedFileReader.lf | 57 --------- test/C/src/lib/FileReader.txt | 1 - test/C/src/target/FederatedFiles.lf | 14 --- util/RunZephyrTests.sh | 2 +- 25 files changed, 268 insertions(+), 344 deletions(-) create mode 100644 org.lflang/src/lib/ts/babel.config.js delete mode 100644 test/C/src/FileReader.lf delete mode 100644 test/C/src/federated/FederatedFileReader.lf delete mode 100644 test/C/src/lib/FileReader.txt delete mode 100644 test/C/src/target/FederatedFiles.lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48110ac926..f6dd56ae40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,8 @@ jobs: uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: 'C' + benchmarks-ref: main + compiler-ref: master needs: cancel # Run language server tests. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55716f5b17..13d24c957c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,8 @@ Test categories are declared in the [TestCategory enum in TestRegistry.java](htt ### Workflow All code contributions must go through a pull request (PR), pass all tests run in CI, and get an approving review before it is merged. Pushing to the `master` branch is restricted. All code review is conducted using the Github review system on PRs. Before requesting a code review, ensure that you have: -- documented your code; +- applied the [code formatter](#code-style-and-formatting); +- [documented](#code-style-and-formatting) your code; - written [tests](#writing-tests) that cover your code; and - accompanied any remaining `TODO`s or `FIXME`s with a link to an active [issue](#reporting-issues). @@ -72,6 +73,18 @@ Perform merges to bring your feature branch up-to-date with master locally (do n #### Addressing reviews To address feedback from code review, implement changes and push to your feature branch. If you are certain that a reviewer's concern has been addressed by your new changes, hit the `Resolve conversation` button. If you are unsure, ask for follow up in the conversation and let the reviewer determine whether the feedback was addressed accordingly. +### Code style and formatting +The Lingua Franca compiler is implemented in Java and Kotlin. The overarching advice is to use each language's most widely used idioms and conventions, which are fortunately very similar. The code base is shipped with a [Spotless](https://github.com/diffplug/spotless) configuration to check and enforce style compliance. Lingua Franca code (e.g., tests) in this repository is also automatically formatted via Spotless. + +- To check that modified files are formatted correctly, run: +``` +./gradlew spotlessCheck +``` +- To apply the changes recommended by the formatter, run: +``` +./gradlew spotlessApply +``` + #### General guidelines - _Do not copy-paste code._ If you want to reuse code, factor it out into a method and call it. - _Keep methods concise._ As a rule of thumb, a method should fit on your screen so that it can be read without scrolling. We impose no hard limit on method length, but anything above 40 lines should be considered for breaking up. diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index 5155c0a6e2..00410d16f5 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -174,6 +174,12 @@ task buildAll() { mainClassName = 'org.lflang.cli.Lfc' } +// define buildLfc as an alias to buildAll +task buildLfc { + dependsOn buildAll + doFirst({{logger.warn("The buildLfc task is deprecated! Please use buildAll instead.")}}) +} + task jarCliTools(type: ShadowJar) { manifest { attributes('Main-Class': 'org.lflang.cli.Lfc') diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index fababedeec..c35cfd167b 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit fababedeec2925e996991a3d5b7a4b96e4af21c0 +Subproject commit c35cfd167bb3f0560e05b6a967386672270a24f2 diff --git a/org.lflang/src/lib/ts/babel.config.js b/org.lflang/src/lib/ts/babel.config.js new file mode 100644 index 0000000000..9fd078c1b2 --- /dev/null +++ b/org.lflang/src/lib/ts/babel.config.js @@ -0,0 +1,19 @@ +module.exports = function (api) { + api.cache(true); + + const presets = [ + "@babel/typescript" + ]; + + const plugins = [ + "@babel/proposal-class-properties", + "@babel/proposal-object-rest-spread", + "@babel/plugin-proposal-optional-chaining", + "@babel/plugin-transform-modules-commonjs" + ]; + + return { + presets, + plugins + }; +} diff --git a/org.lflang/src/lib/ts/package.json b/org.lflang/src/lib/ts/package.json index fc063d791e..a1d65a6403 100644 --- a/org.lflang/src/lib/ts/package.json +++ b/org.lflang/src/lib/ts/package.json @@ -3,23 +3,35 @@ "type": "commonjs", "dependencies": { "@lf-lang/reactor-ts": "git://github.com/lf-lang/reactor-ts.git#master", + "@babel/cli": "^7.8.4", + "@babel/core": "^7.8.7", + "@babel/node": "^7.8.7", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/preset-env": "^7.8.7", + "@babel/preset-typescript": "^7.8.3", + "command-line-usage": "^6.1.0", "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.3" + "rimraf": "^3.0.2" }, "devDependencies": { "@types/command-line-args": "^5.2.0", "@types/command-line-usage": "^5.0.2", - "@types/google-protobuf": "^3.7.4", + "@types/jest": "^27.0.0", "@types/microtime": "^2.1.0", - "@types/node": "^18.14.2", + "@types/node": "^16.3.3", + "@types/google-protobuf": "^3.7.4", + "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "5.33.0", "@typescript-eslint/parser": "^5.8.1", "eslint": "^8.5.0", "typescript": "~4.8.2", - "ts-protoc-gen": "^0.15.0", - "rimraf": "^3.0.2" + "ts-protoc-gen": "^0.12.0" }, "scripts": { - "build": "npx rimraf dist && npx tsc --outDir dist" + "check-types": "tsc", + "build": "npx rimraf dist && npx babel src --out-dir dist --extensions .ts,.js" } } diff --git a/org.lflang/src/lib/ts/tsconfig.json b/org.lflang/src/lib/ts/tsconfig.json index 3d51d35052..b771b75281 100644 --- a/org.lflang/src/lib/ts/tsconfig.json +++ b/org.lflang/src/lib/ts/tsconfig.json @@ -1,22 +1,19 @@ { "compilerOptions": { "allowJs": true, + "noEmit": true, "target": "esnext", - "module": "CommonJS", "types": ["node", "@lf-lang/reactor-ts", "ulog", "microtime", "command-line-args", "command-line-usage"], - "typeRoots": ["./node_modules/@types/", "./node_modules/@lf-lang/reactor-ts/src/core/@types/"], "esModuleInterop": true, "isolatedModules": true, "lib": ["esnext", "dom"], "sourceMap": true, "strict": true, "moduleResolution": "node", - "skipLibCheck": true, "strictBindCallApply": true, "strictNullChecks": true, "strictFunctionTypes": true, - "noImplicitThis": true, - "outDir": "dist" + "typeRoots": ["./node_modules/@types/", "./node_modules/@lf-lang/reactor-ts/src/core/@types/"] }, "include": [ "src/**/*" diff --git a/org.lflang/src/org/lflang/FileConfig.java b/org.lflang/src/org/lflang/FileConfig.java index 91d681046a..ed0f663ee9 100644 --- a/org.lflang/src/org/lflang/FileConfig.java +++ b/org.lflang/src/org/lflang/FileConfig.java @@ -1,5 +1,6 @@ package org.lflang; +import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; @@ -14,6 +15,7 @@ import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.lflang.federated.generator.FedFileConfig; import org.lflang.generator.GeneratorUtils; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -306,7 +308,7 @@ public LFCommand getCommand() { * Return the extension used for binaries on the platform on which compilation takes place. */ protected String getExecutableExtension() { - return GeneratorUtils.isHostWindows() ? ".exe" : ""; + return (GeneratorUtils.isHostWindows() ? ".exe" : ""); } /** diff --git a/org.lflang/src/org/lflang/TargetConfig.java b/org.lflang/src/org/lflang/TargetConfig.java index 845f214ec8..23e99541da 100644 --- a/org.lflang/src/org/lflang/TargetConfig.java +++ b/org.lflang/src/org/lflang/TargetConfig.java @@ -172,6 +172,13 @@ public TargetConfig( */ public List cmakeIncludes = new ArrayList<>(); + /** + * List of cmake-includes from the cmake-include target property with no path info. + * Useful for copying them to remote machines. This is needed because + * target cmake-includes can be resources with resource paths. + */ + public List cmakeIncludesWithoutPath = new ArrayList<>(); + /** * The compiler to invoke, unless a build command has been specified. */ @@ -230,7 +237,14 @@ public TargetConfig( /** * List of files to be copied to src-gen. */ - public List files = new ArrayList<>(); + public List fileNames = new ArrayList<>(); + + /** + * List of file names from the files target property with no path info. + * Useful for copying them to remote machines. This is needed because + * target files can be resources with resource paths. + */ + public List filesNamesWithoutPath = new ArrayList<>(); /** * If true, configure the execution environment to keep executing if there diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index 61cda14431..1bacb1f75e 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -276,16 +276,16 @@ public enum TargetProperty { * processed by the code generator. */ FILES("files", UnionType.FILE_OR_FILE_ARRAY, List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.files), + (config) -> ASTUtils.toElement(config.fileNames), (config, value, err) -> { - config.files = ASTUtils.elementToListOfStrings(value); + config.fileNames = ASTUtils.elementToListOfStrings(value); }, // FIXME: This merging of lists is potentially dangerous since // the incoming list of files can belong to a .lf file that is // located in a different location, and keeping just filename // strings like this without absolute paths is incorrect. (config, value, err) -> { - config.files.addAll(ASTUtils.elementToListOfStrings(value)); + config.fileNames.addAll(ASTUtils.elementToListOfStrings(value)); }), /** diff --git a/org.lflang/src/org/lflang/federated/extensions/CExtension.java b/org.lflang/src/org/lflang/federated/extensions/CExtension.java index 676e3d8be1..a8127c33bc 100644 --- a/org.lflang/src/org/lflang/federated/extensions/CExtension.java +++ b/org.lflang/src/org/lflang/federated/extensions/CExtension.java @@ -498,7 +498,6 @@ public String generatePreamble( includes.pr("#include \"core/federated/federate.h\""); includes.pr("#include \"core/federated/net_common.h\""); includes.pr("#include \"core/federated/net_util.h\""); - includes.pr("#include \"core/federated/clock-sync.h\""); includes.pr("#include \"core/threaded/reactor_threaded.h\""); includes.pr("#include \"core/utils/util.h\""); includes.pr("extern federate_instance_t _fed;"); diff --git a/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java b/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java index 2ad19c64cc..c84bf36197 100644 --- a/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java +++ b/org.lflang/src/org/lflang/federated/extensions/CExtensionUtils.java @@ -361,11 +361,6 @@ public static void generateCMakeInclude( CodeBuilder cmakeIncludeCode = new CodeBuilder(); cmakeIncludeCode.pr(generateSerializationCMakeExtension(federate)); - cmakeIncludeCode.pr( - "add_compile_definitions(LF_SOURCE_DIRECTORY=\"" - + fileConfig.srcPath - + "\")" - ); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); diff --git a/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java b/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java index e434501825..42f5c60dc7 100644 --- a/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java +++ b/org.lflang/src/org/lflang/federated/generator/FedFileConfig.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -111,7 +110,7 @@ public void doClean() throws IOException { */ public void relativizePaths(FedTargetConfig targetConfig) { relativizePathList(targetConfig.protoFiles); - relativizePathList(targetConfig.files); + relativizePathList(targetConfig.fileNames); relativizePathList(targetConfig.cmakeIncludes); } @@ -121,22 +120,17 @@ public void relativizePaths(FedTargetConfig targetConfig) { */ private void relativizePathList(List paths) { List tempList = new ArrayList<>(); - paths.forEach(f -> tempList.add(relativizePath(Paths.get(f)))); + paths.forEach(f -> tempList.add(relativizePath(f))); paths.clear(); paths.addAll(tempList); } /** - * Relativize a single path, but only if it points to a local resource in the project (i.e., not - * on the class path). + * Relativize a single path. * @param path The path to relativize. */ - private String relativizePath(Path path) { - if (FileUtil.findInPackage(path, this) == null) { - return String.valueOf(path); - } else { - Path resolvedPath = this.srcPath.resolve(path).toAbsolutePath(); - return this.getSrcPath().relativize(resolvedPath).toString(); - } + private String relativizePath(String path) { + Path resolvedPath = this.srcPath.resolve(path).toAbsolutePath(); + return this.getSrcPath().relativize(resolvedPath).toString(); } } diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 15d703bcbf..ba39a94d9f 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -56,7 +56,6 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; -import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; import com.google.common.base.Objects; @@ -349,9 +348,7 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param targetConfig The targetConfig to read the `files` from. * @param fileConfig The fileConfig used to make the copy and resolve paths. */ - protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - FileUtil.copyFiles(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); - } + protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) {} /** * Return true if errors occurred in the last call to doGenerate(). diff --git a/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java b/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java index d158f7491b..3f5eb4a5b7 100644 --- a/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CCmakeGenerator.java @@ -25,7 +25,6 @@ package org.lflang.generator.c; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -314,8 +313,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.cmakeIncludes) { - cMakeCode.pr("include(\""+ Path.of(includeFile).getFileName()+"\")"); + for (String includeFile : targetConfig.cmakeIncludesWithoutPath) { + cMakeCode.pr("include(\""+includeFile+"\")"); } cMakeCode.newLine(); diff --git a/org.lflang/src/org/lflang/generator/c/CCompiler.java b/org.lflang/src/org/lflang/generator/c/CCompiler.java index f0860a0e91..06095f553d 100644 --- a/org.lflang/src/org/lflang/generator/c/CCompiler.java +++ b/org.lflang/src/org/lflang/generator/c/CCompiler.java @@ -25,7 +25,6 @@ package org.lflang.generator.c; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -223,14 +222,6 @@ static Stream cmakeCompileDefinitions(TargetConfig targetConfig) { private static List cmakeOptions(TargetConfig targetConfig, FileConfig fileConfig) { List arguments = new ArrayList<>(); cmakeCompileDefinitions(targetConfig).forEachOrdered(arguments::add); - String separator = File.separator; - String maybeQuote = ""; // Windows seems to require extra level of quoting. - String srcPath = fileConfig.srcPath.toString(); // Windows requires escaping the backslashes. - if (separator.equals("\\")) { - separator = "\\\\\\\\"; - maybeQuote = "\\\""; - srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); - } arguments.addAll(List.of( "-DCMAKE_BUILD_TYPE=" + ((targetConfig.cmakeBuildType!=null) ? targetConfig.cmakeBuildType.toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), @@ -239,16 +230,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f fileConfig.binPath ) ), - "-DLF_FILE_SEPARATOR=\"" + maybeQuote + separator + maybeQuote + "\"" + FileUtil.toUnixString(fileConfig.getSrcGenPath()) )); - // Add #define for source file directory. - // Do not do this for federated programs because for those, the definition is put - // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). - if (!fileConfig.srcPath.toString().contains("fed-gen")) { - // Do not convert to Unix path - arguments.add("-DLF_SOURCE_DIRECTORY=\"" + maybeQuote + srcPath + maybeQuote + "\""); - } - arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); if (GeneratorUtils.isHostWindows()) { arguments.add("-DCMAKE_SYSTEM_VERSION=\"10.0\""); diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index fbedb23253..f598219ddd 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -37,6 +37,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.HashSet; import java.util.LinkedHashSet; @@ -609,9 +610,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { GeneratorResult.Status.COMPILED, null ); } - if (!errorsOccurred()){ - System.out.println("Compiled binary is in " + fileConfig.binPath); - } + System.out.println("Compiled binary is in " + fileConfig.binPath); } else { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, null)); } @@ -804,15 +803,9 @@ private void inspectReactorEResource(ReactorDecl reactor) { break; } } + // Copy the user files and cmake-includes to the src-gen path of the main .lf file if (lfResource != null) { - // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); - // Merge the CMake includes from the imported file into the target config - lfResource.getTargetConfig().cmakeIncludes.forEach(incl -> { - if (!this.targetConfig.cmakeIncludes.contains(incl)) { - this.targetConfig.cmakeIncludes.add(incl); - } - }); } } } @@ -825,18 +818,56 @@ private void inspectReactorEResource(ReactorDecl reactor) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ @Override - protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { + public void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { super.copyUserFiles(targetConfig, fileConfig); - // Must use class variable to determine destination! - var destination = this.fileConfig.getSrcGenPath(); + // Make sure the target directory exists. + var targetDir = this.fileConfig.getSrcGenPath(); + try { + Files.createDirectories(targetDir); + } catch (IOException e) { + //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored + Exceptions.sneakyThrow(e); + } + + for (String filename : targetConfig.fileNames) { + var relativeFileName = CUtil.copyFileOrResource( + filename, + fileConfig.srcFile.getParent(), + targetDir); + if (StringExtensions.isNullOrEmpty(relativeFileName)) { + errorReporter.reportError( + "Failed to find file " + filename + " specified in the" + + " files target property." + ); + } else { + targetConfig.filesNamesWithoutPath.add( + relativeFileName + ); + } + } - FileUtil.copyFiles(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); + for (String filename : targetConfig.cmakeIncludes) { + var relativeCMakeIncludeFileName = + CUtil.copyFileOrResource( + filename, + fileConfig.srcFile.getParent(), + targetDir); + // Check if the file exists + if (StringExtensions.isNullOrEmpty(relativeCMakeIncludeFileName)) { + errorReporter.reportError( + "Failed to find cmake-include file " + filename + ); + } else { + this.targetConfig.cmakeIncludesWithoutPath.add( + relativeCMakeIncludeFileName + ); + } + } - // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { try { FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(targetConfig.fedSetupPreamble), - destination.resolve(targetConfig.fedSetupPreamble)); + targetDir.resolve(targetConfig.fedSetupPreamble)); } catch (IOException e) { errorReporter.reportError("Failed to find _fed_setup file " + targetConfig.fedSetupPreamble); } diff --git a/org.lflang/src/org/lflang/generator/c/CUtil.java b/org.lflang/src/org/lflang/generator/c/CUtil.java index ce1c83d87d..69e9ec30ae 100644 --- a/org.lflang/src/org/lflang/generator/c/CUtil.java +++ b/org.lflang/src/org/lflang/generator/c/CUtil.java @@ -26,7 +26,12 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY package org.lflang.generator.c; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -49,6 +54,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY import org.lflang.lf.Parameter; import org.lflang.lf.Port; import org.lflang.lf.Reactor; +import org.lflang.lf.ReactorDecl; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; import org.lflang.lf.WidthTerm; @@ -569,6 +575,69 @@ public static String triggerRefNested(PortInstance port, String runtimeIndex, St return reactorRefNested(port.getParent(), runtimeIndex, bankIndex) + "." + port.getName() + "_trigger"; } + /** + * Copy the 'fileName' (which also could be a directory name) from the + * 'srcDirectory' to the 'destinationDirectory'. This function has a + * fallback search mechanism, where if `fileName` is not found in the + * `srcDirectory`, it will try to find `fileName` via the following + * procedure: + * 1- Search in LF_CLASSPATH. @see findFile() + * 2- Search in CLASSPATH. @see findFile() + * 3- Search for 'fileName' as a resource. That means the `fileName` + * can be '/path/to/class/resource'. @see java.lang.Class.getResourceAsStream() + * + * @param fileName Name of the file or directory. + * @param srcDir Where the file or directory is currently located. + * @param dstDir Where the file or directory should be placed. + * @return The name of the file or directory in destinationDirectory or an empty string on failure. + */ + public static String copyFileOrResource(String fileName, Path srcDir, + Path dstDir) { + // Try to copy the file or directory from the file system. + Path file = findFileOrDirectory(fileName, srcDir); + if (file != null) { + Path target = dstDir.resolve(file.getFileName()); + try { + if (Files.isDirectory(file)) { + FileUtil.copyDirectory(file, target); + } else if (Files.isRegularFile(file)) { + Files.copy(file, target, + StandardCopyOption.REPLACE_EXISTING); + } + return file.getFileName().toString(); + } catch (IOException e) { + // Failed to copy the file or directory, most likely + // because it doesn't exist. Will try to find it as a + // resource before giving up. + } + } + + String filenameWithoutPath = fileName; + int lastSeparator = fileName.lastIndexOf(File.separator); + if (lastSeparator > 0) { + // FIXME: Brittle. What if the file is in a subdirectory? + filenameWithoutPath = fileName.substring(lastSeparator + 1); + } + // Try to copy the file or directory as a resource. + try { + FileUtil.copyFileFromClassPath(fileName, + dstDir.resolve(filenameWithoutPath)); + return filenameWithoutPath; + } catch (IOException ex) { + // Will try one more time as a directory + } + + try { + FileUtil.copyDirectoryFromClassPath(fileName, + dstDir.resolve(filenameWithoutPath), false); + return filenameWithoutPath; + } catch (IOException ex) { + System.err.println( + "WARNING: Failed to find file or directory " + fileName); + } + + return ""; + } ////////////////////////////////////////////////////// //// FIXME: Not clear what the strategy is with the following inner interface. @@ -592,6 +661,47 @@ public interface ReportCommandErrors { void report(String errors); } + /** + * Search for a given file or directory name in the given directory. + * If not found, search in directories in LF_CLASSPATH. + * If there is no LF_CLASSPATH environment variable, use CLASSPATH, + * if it is defined. The first file or directory that is found will + * be returned. Otherwise, null is returned. + * + * @param fileName The file or directory name or relative path + name + * as a String. + * @param directory String representation of the directory to search in. + * @return A Java Path or null if not found. + */ + public static Path findFileOrDirectory(String fileName, Path directory) { + Path foundFile; + + // Check in local directory + foundFile = directory.resolve(fileName); + if (Files.exists(foundFile)) { + return foundFile; + } + + // Check in LF_CLASSPATH + // Load all the resources in LF_CLASSPATH if it is set. + String classpathLF = System.getenv("LF_CLASSPATH"); + if (classpathLF == null) { + classpathLF = System.getenv("CLASSPATH"); + } + if (classpathLF != null) { + String[] paths = classpathLF.split(System.getProperty("path.separator")); + for (String path : paths) { + foundFile = Paths.get(path).resolve(fileName); + if (Files.exists(foundFile)) { + return foundFile; + } + } + } + // Not found. + return null; + } + + /** * Run the custom build command specified with the "build" parameter. * This command is executed in the same directory as the source file. diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index bd92a144ce..9262e44e64 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -61,10 +61,8 @@ class TSGenerator( val fileConfig: TSFileConfig = context.fileConfig as TSFileConfig - var devMode = false; companion object { - /** Path to the TS lib directory (relative to class path) */ const val LIB_PATH = "/lib/ts" @@ -72,9 +70,7 @@ class TSGenerator( * Names of the configuration files to check for and copy to the generated * source package root if they cannot be found in the source directory. */ - val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", ".eslintrc.json") - - const val RUNTIME_URL = "git://github.com/lf-lang/reactor-ts.git" + val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", "babel.config.js", ".eslintrc.json") fun timeInTargetLanguage(value: TimeValue): String { return if (value.unit != null) { @@ -149,16 +145,14 @@ class TSGenerator( println("No .proto files have been imported. Skipping protocol buffer compilation.") } val parsingContext = SubContext(context, COLLECTED_DEPENDENCIES_PERCENT_PROGRESS, 100) - val validator = TSValidator(fileConfig, errorReporter, codeMaps) - if (!context.cancelIndicator.isCanceled) { + if ( + !context.cancelIndicator.isCanceled + && passesChecks(TSValidator(fileConfig, errorReporter, codeMaps), parsingContext) + ) { if (context.mode == LFGeneratorContext.Mode.LSP_MEDIUM) { - if (!passesChecks(validator, parsingContext)) { - context.unsuccessfulFinish(); - return; - } context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) } else { - compile(validator, resource, parsingContext) + compile(resource, parsingContext) concludeCompilation(context, codeMaps) } } else { @@ -190,18 +184,12 @@ class TSGenerator( if (rtPath != null) rtPath = formatRuntimePath(rtPath) // FIXME: do better CLI arg validation upstream // https://github.com/lf-lang/lingua-franca/issues/1429 - if (rtPath != null || rtVersion != null) { - devMode = true; - } manifest.toFile().forEachLine { var line = it.replace("\"LinguaFrancaDefault\"", "\"${fileConfig.name}\""); - if (line.contains(rtRegex) && line.contains(RUNTIME_URL)) { - devMode = true; - } if (rtPath != null) { line = line.replace(rtRegex, "$1: \"$rtPath\",") } else if (rtVersion != null) { - line = line.replace(rtRegex, "$1: \"$RUNTIME_URL#$rtVersion\",") + line = line.replace(rtRegex, "$1: \"git://github.com/lf-lang/reactor-ts.git#$rtVersion\",") } sb.appendLine(line) } @@ -275,13 +263,13 @@ class TSGenerator( } - private fun compile(validator: TSValidator, resource: Resource, parsingContext: LFGeneratorContext) { + private fun compile(resource: Resource, parsingContext: LFGeneratorContext) { GeneratorUtils.refreshProject(resource, parsingContext.mode) if (parsingContext.cancelIndicator.isCanceled) return parsingContext.reportProgress("Transpiling to JavaScript...", 70) - transpile(validator, parsingContext.cancelIndicator) + transpile(parsingContext.cancelIndicator) if (parsingContext.cancelIndicator.isCanceled) return } @@ -321,7 +309,6 @@ class TSGenerator( errorReporter.reportWarning( "Falling back on npm. To prevent an accumulation of replicated dependencies, " + "it is highly recommended to install pnpm globally (npm install -g pnpm).") - val npmInstall = commandFactory.createCommand("npm", if (production) listOf("install", "--production") else listOf("install"), path) if (npmInstall == null) { @@ -338,19 +325,6 @@ class TSGenerator( "\nFor installation instructions, see: https://www.npmjs.com/get-npm") return } - - // If reactor-ts is pulled from GitHub and building is done using npm, - // first build reactor-ts (pnpm does this automatically). - if (devMode) { - val rtPath = path.resolve("node_modules").resolve("@lf-lang").resolve("reactor-ts") - val buildRuntime = commandFactory.createCommand("npm", listOf("run", "prepublish"), rtPath) - if (buildRuntime.run(context.cancelIndicator) != 0) { - errorReporter.reportError( - GeneratorUtils.findTargetDecl(resource), - "ERROR: unable to build runtime in dev mode: " + buildRuntime.errors.toString()) - } - } - installProtoBufsIfNeeded(false, path, context.cancelIndicator) } } @@ -423,19 +397,19 @@ class TSGenerator( /** * Transpile TypeScript to JavaScript. */ - private fun transpile(validator: TSValidator, cancelIndicator: CancelIndicator) { + private fun transpile(cancelIndicator: CancelIndicator) { println("Compiling") - val tsc = commandFactory.createCommand("npm", listOf("run", "build"), fileConfig.srcGenPkgPath) + val babel = commandFactory.createCommand("npm", listOf("run", "build"), fileConfig.srcGenPkgPath) - if (tsc == null) { + if (babel == null) { errorReporter.reportError(NO_NPM_MESSAGE) return } - if (validator.run(tsc, cancelIndicator) == 0) { + if (babel.run(cancelIndicator) == 0) { println("SUCCESS (compiling generated TypeScript code)") } else { - errorReporter.reportError("Compiler failed with the following errors:\n${tsc.errors}") + errorReporter.reportError("Compiler failed with the following errors:\n${babel.errors}") } } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index a2cfb81e4d..d4d34c7b08 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -36,9 +36,7 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.util.RuntimeIOException; -import org.lflang.ErrorReporter; import org.lflang.FileConfig; -import org.lflang.generator.LFGeneratorContext; public class FileUtil { @@ -152,7 +150,7 @@ public static java.net.URI locateFile(String path, Resource resource) { sourceURI = iFile != null ? iFile.getRawLocation().toFile().getParentFile().toURI() : null; } if (sourceURI != null) { - return sourceURI.resolve(path); + return sourceURI.resolve(path.toString()); } } catch (Exception e) { // nothing @@ -241,68 +239,6 @@ public static void copyFile(Path source, Path destination) throws IOException { copyFile(source, destination, false); } - /** - * Given a list of files or directories, attempt to find them based on the given generator - * context, and copy then to the destination. Files are searched for in the file system first. - * Files that cannot be found in the file system are looked for on the class path. - * - * @param filesOrDirectories The files or directories to copy. - * @param destination The location to copy them to. - * @param fileConfig The file configuration that specifies where the files must be found. - * @param errorReporter An error reporter to report problems. - */ - public static void copyFiles( - List filesOrDirectories, - Path destination, - FileConfig fileConfig, - ErrorReporter errorReporter - ) { - for (String fileOrDirectory : filesOrDirectories) { - var path = Paths.get(fileOrDirectory); - var found = FileUtil.findInPackage(path, fileConfig); - if (found != null) { - try { - FileUtil.copyFileOrDirectory(found, destination.resolve(found.getFileName())); - } catch (IOException e) { - errorReporter.reportError( - "Unable to copy '" + fileOrDirectory + "' from the file system." - ); - } - } else { - // Attempt to copy from the classpath instead. - // If the filename is not a directory, it will - // just be copied without further recursion. - try { - FileUtil.copyDirectoryFromClassPath( - fileOrDirectory, - destination, - false - ); - } catch (IOException e) { - errorReporter.reportError( - "Unable to copy '" + fileOrDirectory + "' from the class path." - ); - } - } - } - } - - /** - * If the source is a directory, then copy the contents of the directory to the destination. - * If the source is a file, then copy the file to the destination. - * @param source A file or directory to copy to the destination. - * @param destination A directory to copy the file(s) at the source to. - * @throws IOException - */ - public static void copyFileOrDirectory(Path source, Path destination) throws IOException { - if (Files.isDirectory(source)) { - copyDirectory(source, destination); - } else if (Files.isRegularFile(source)) { - copyFile(source, destination); - } else { - throw new IllegalArgumentException("Source is neither a directory nor a regular file."); - } - } /** * Copy a given input stream to a destination file. * @@ -423,7 +359,6 @@ private static boolean copyDirectoryFromJar(JarURLConnection connection, final P final String connectionEntryName = connection.getEntryName(); boolean copiedFiles = false; - // Iterate all entries in the jar file. for (Enumeration e = jar.entries(); e.hasMoreElements(); ) { final JarEntry entry = e.nextElement(); @@ -431,10 +366,9 @@ private static boolean copyDirectoryFromJar(JarURLConnection connection, final P // Extract files only if they match the given source path. if (entryName.startsWith(connectionEntryName)) { - String filename = entryName.equals(connectionEntryName) ? - connectionEntryName : - entryName.substring(connectionEntryName.length() + 1); + String filename = entry.getName().substring(connectionEntryName.length() + 1); Path currentFile = destination.resolve(filename); + if (entry.isDirectory()) { Files.createDirectories(currentFile); } else { @@ -577,45 +511,6 @@ public static void deleteDirectory(Path dir) throws IOException { } } - /** - * Return an absolute path to the given file or directory if it can be found within the package. - * Otherwise, return null. - * - * NOTE: If the given file or directory is given as an absolute path but cannot be found, it is - * interpreted as a relative path with respect to the project root. - * - * @param fileOrDirectory The file or directory to look for. - * @param fileConfig A file configuration that determines where the package is located. - * @return An absolute path of the file or directory was found; null otherwise. - */ - public static Path findInPackage(Path fileOrDirectory, FileConfig fileConfig) { - if (fileOrDirectory.isAbsolute() && Files.exists(fileOrDirectory)) { - return fileOrDirectory; - } else { - Path relPath; - // Disregard root and interpret as relative path - if (fileOrDirectory.isAbsolute()) { - relPath = Paths.get( - String.valueOf(fileOrDirectory).replaceFirst( - String.valueOf(fileOrDirectory.getRoot()), - "") - ); - } else { - relPath = fileOrDirectory; - } - - // Look relative to the source file and relative to the package root. - var locations = List.of(fileConfig.srcPath, fileConfig.srcPkgPath); - var found = locations.stream().filter( - loc -> Files.exists(loc.resolve(relPath)) - ).findFirst(); - if (found.isPresent()) { - return found.get().resolve(relPath); - } - } - return null; - } - /** * Get the iResource corresponding to the provided resource if it can be * found. diff --git a/test/C/src/FileReader.lf b/test/C/src/FileReader.lf deleted file mode 100644 index 10be772fb7..0000000000 --- a/test/C/src/FileReader.lf +++ /dev/null @@ -1,46 +0,0 @@ -/** Test reading a file at a location relative to the source file. */ -target C - -reactor Source { - output out: char* // Use char*, not string, so memory is freed. - - reaction(startup) -> out {= - char* file_path = - LF_SOURCE_DIRECTORY - LF_FILE_SEPARATOR "lib" - LF_FILE_SEPARATOR "FileReader.txt"; - - FILE* file = fopen(file_path, "rb"); - if (file == NULL) lf_print_error_and_exit("Error opening file at path %s.", file_path); - - // Determine the file size - fseek(file, 0, SEEK_END); - long file_size = ftell(file); - fseek(file, 0, SEEK_SET); - - // Allocate memory for the buffer - char* buffer = (char *) malloc(file_size + 1); - if (buffer == NULL) lf_print_error_and_exit("Out of memory."); - - // Read the file into the buffer - fread(buffer, file_size, 1, file); - buffer[file_size] = '\0'; - fclose(file); - - lf_set(out, buffer); - =} -} - -main reactor { - preamble {= - #include - =} - s = new Source() - - reaction(s.out) {= - printf("Received: %s\n", s.out->value); - if (strcmp("Hello World", s.out->value) != 0) { - lf_print_error_and_exit("Expected 'Hello World'"); - } - =} -} diff --git a/test/C/src/federated/FederatedFileReader.lf b/test/C/src/federated/FederatedFileReader.lf deleted file mode 100644 index 6ba2da763f..0000000000 --- a/test/C/src/federated/FederatedFileReader.lf +++ /dev/null @@ -1,57 +0,0 @@ -/** Test reading a file at a location relative to the source file. */ -target C { - timeout: 0 s -} - -reactor Source { - output out: char* // Use char*, not string, so memory is freed. - - reaction(startup) -> out {= - char* file_path = - LF_SOURCE_DIRECTORY - LF_FILE_SEPARATOR ".." - LF_FILE_SEPARATOR "lib" - LF_FILE_SEPARATOR "FileReader.txt"; - - FILE* file = fopen(file_path, "rb"); - if (file == NULL) lf_print_error_and_exit("Error opening file at path %s.", file_path); - - // Determine the file size - fseek(file, 0, SEEK_END); - long file_size = ftell(file); - fseek(file, 0, SEEK_SET); - - // Allocate memory for the buffer - char* buffer = (char *) malloc(file_size + 1); - if (buffer == NULL) lf_print_error_and_exit("Out of memory."); - - // Read the file into the buffer - fread(buffer, file_size, 1, file); - buffer[file_size] = '\0'; - fclose(file); - - // For federated version, have to use lf_set_array so array size is know - // to the serializer. - lf_set_array(out, buffer, file_size + 1); - =} -} - -reactor Check { - preamble {= - #include - =} - input in: char* - - reaction(in) {= - printf("Received: %s\n", in->value); - if (strcmp("Hello World", in->value) != 0) { - lf_print_error_and_exit("Expected 'Hello World'"); - } - =} -} - -federated reactor { - s = new Source() - c = new Check() - s.out -> c.in -} diff --git a/test/C/src/lib/FileReader.txt b/test/C/src/lib/FileReader.txt deleted file mode 100644 index 5e1c309dae..0000000000 --- a/test/C/src/lib/FileReader.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World \ No newline at end of file diff --git a/test/C/src/target/FederatedFiles.lf b/test/C/src/target/FederatedFiles.lf deleted file mode 100644 index ebc1ff210e..0000000000 --- a/test/C/src/target/FederatedFiles.lf +++ /dev/null @@ -1,14 +0,0 @@ -// This test references a header file in reactor-c, which has to be obtained -// from the class path. This test is successful if it compiles. -target C { - files: "/lib/c/reactor-c/util/sensor_simulator.h", - timeout: 1 s -} - -reactor Foo { - reaction(startup) {= lf_print("Hello World"); =} -} - -federated reactor { - f = new Foo() -} diff --git a/util/RunZephyrTests.sh b/util/RunZephyrTests.sh index cabbbec0b2..66dcd10ffa 100755 --- a/util/RunZephyrTests.sh +++ b/util/RunZephyrTests.sh @@ -9,7 +9,7 @@ num_failures=0 failed_tests="" # Skip -skip=("FileReader") +skip=() find_kconfig_folders() { if [ -f "$folder/CMakeLists.txt" ]; then From 841943cedbecf98d99dfb01a659a895df5363746 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 4 May 2023 09:00:19 -0700 Subject: [PATCH 016/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index c35cfd167b..fababedeec 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit c35cfd167bb3f0560e05b6a967386672270a24f2 +Subproject commit fababedeec2925e996991a3d5b7a4b96e4af21c0 From 3db843501d301eb280322dbf30c07c00409991f7 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 5 May 2023 16:07:27 -0700 Subject: [PATCH 017/142] Better trace visualization. --- org.lflang/src/lib/c/reactor-c | 2 +- util/tracing/visualization/fedsd.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index fababedeec..82cfe8cf48 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit fababedeec2925e996991a3d5b7a4b96e4af21c0 +Subproject commit 82cfe8cf48a35fbf4a365f7cc6d1db5f1db7c4a5 diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index 3eb13d11bc..2ad5261e24 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -26,6 +26,8 @@ .TAG { stroke: #08a578; fill: #08a578} \ .TIMESTAMP { stroke: grey; fill: grey } \ .FED_ID {stroke: #80DD99; fill: #80DD99 } \ + .CuTAG_RQ {stroke: #d0b7eb; fill: #d0b7eb} \ + .CuTAG_RQ_RES {stroke: #d0b7eb; fill: #d0b7eb} \ .ADV {stroke-linecap="round" ; stroke: "red" ; fill: "red"} \ text { \ font-size: smaller; \ @@ -275,7 +277,7 @@ def load_and_process_csv_file(csv_file) : # FIXME: Using microseconds is hardwired here. physical_time = f'{int(row["physical_time"]/1000):,}' - if (row['event'] in {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG'}): + if (row['event'] in {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG', 'CuTAG_QR'}): label = row['event'] elif (row['logical_time'] == -1678240241788173894) : # FIXME: This isn't right. NEVER == -9223372036854775808. From ca4dca411c5f6c80a6dc6ba18cd95973f61a9c33 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 5 May 2023 16:31:09 -0700 Subject: [PATCH 018/142] Make trabsients joining and leaving several times appear in one same lifeline in the visualization. --- util/tracing/visualization/fedsd.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index 2ad5261e24..36737fdebf 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -129,11 +129,16 @@ def load_and_process_csv_file(csv_file) : if (not fed_df.empty): # Get the federate id number fed_id = fed_df.iloc[-1]['self_id'] - # Add to the list of sequence diagram actors and add the name - actors.append(fed_id) - actors_names[fed_id] = Path(fed_trace).stem - # Derive the x coordinate of the actor - x_coor[fed_id] = (padding * 2) + (spacing * (len(actors)-1)) + ### Check that the federate id have not been entrered yet. + ### This is particlurly useful for transient actors, when + ### they leave and join several times + if (actors.count(fed_id) == 0): + # Add to the list of sequence diagram actors and add the name + actors.append(fed_id) + actors_names[fed_id] = Path(fed_trace).stem + # Derive the x coordinate of the actor + x_coor[fed_id] = (padding * 2) + (spacing * (len(actors)-1)) + fed_df['x1'] = x_coor[fed_id] # Append into trace_df trace_df = trace_df.append(fed_df, sort=False, ignore_index=True) From 5bfe2654377188b4d648f39f760c0b4e6ee4fdfb Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 5 May 2023 17:43:50 -0700 Subject: [PATCH 019/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 82cfe8cf48..79a67ff829 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 82cfe8cf48a35fbf4a365f7cc6d1db5f1db7c4a5 +Subproject commit 79a67ff829f7c4c63a0104c99d6206f056eb105e From 31fb9135f361001a442f6800aab33a0b62eb6f43 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 23 May 2023 16:22:56 -0700 Subject: [PATCH 020/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index dc6b138746..9e2613f961 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit dc6b13874697315859cd75e26ddd82f9c0d83643 +Subproject commit 9e2613f9617577825533a1640beb55c5a95d325a From aad29f025af8e6d152f952c2aadbf32f73910aa4 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 25 May 2023 13:34:17 -0700 Subject: [PATCH 021/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index f60135799b..2a9e2e9a4f 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit f60135799b23bc4d4adb51b7fd65de8744fa565c +Subproject commit 2a9e2e9a4ff207c46d3cb6c14a081be0c15d25cc From 5c2b46c41ff8c4f46670db2ffc3cca4cbe5d8c71 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 25 May 2023 17:33:54 -0700 Subject: [PATCH 022/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 2a9e2e9a4f..9a7296373c 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 2a9e2e9a4ff207c46d3cb6c14a081be0c15d25cc +Subproject commit 9a7296373c417c16bfefc2535593b853dcc9479c From c4194f29009035ed8a9ff27487ee7c7378f6a069 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 25 May 2023 18:27:37 -0700 Subject: [PATCH 023/142] Align reactor-c, after fixing the segmentation faults and the wrong iterator variable. --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 9a7296373c..d918168fe5 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9a7296373c417c16bfefc2535593b853dcc9479c +Subproject commit d918168fe50c5dc27a9f27c61979fc139c4b859d From bc5ed4b139abba9576b32a20a0a5ea50810a1953 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 26 May 2023 11:57:45 -0700 Subject: [PATCH 024/142] Align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index d918168fe5..1068a4cab2 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit d918168fe50c5dc27a9f27c61979fc139c4b859d +Subproject commit 1068a4cab21a2cd31e5a945b817a19de79149be1 From c24cfc05f131b6c1538525bb8f9556758fe797fb Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 26 May 2023 12:01:00 -0700 Subject: [PATCH 025/142] Re-align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 1068a4cab2..1b47b3239d 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 1068a4cab21a2cd31e5a945b817a19de79149be1 +Subproject commit 1b47b3239d958714a6af9c2ebabb86e8cf09b1fb From a6e614532ae2783171b59b96e7245ed4d6290ec5 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 26 May 2023 12:03:45 -0700 Subject: [PATCH 026/142] Re-align reactor-c --- org.lflang/src/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/c/reactor-c b/org.lflang/src/lib/c/reactor-c index 1b47b3239d..0343ab6dc6 160000 --- a/org.lflang/src/lib/c/reactor-c +++ b/org.lflang/src/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 1b47b3239d958714a6af9c2ebabb86e8cf09b1fb +Subproject commit 0343ab6dc6a41559870fd92abd3855a523c4f65e From 535bbbb1f2bd97b2b0c33e21e3f196ead74fcaf5 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 6 Jun 2023 18:22:00 -0700 Subject: [PATCH 027/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index d6f4fb6037..a11c1b03a1 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit d6f4fb6037e243c967c30de2be93e680107104c2 +Subproject commit a11c1b03a135056550eb64c3a110ee56f8fa0c42 From 29a1881180faaf1bd6a03c115901004fd75078e3 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 7 Jun 2023 09:47:56 -0700 Subject: [PATCH 028/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 79a67ff829..a11c1b03a1 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 79a67ff829f7c4c63a0104c99d6206f056eb105e +Subproject commit a11c1b03a135056550eb64c3a110ee56f8fa0c42 From 84c4311e729293d39ab2f39b779cbe3ddb996655 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 7 Jun 2023 10:24:52 -0700 Subject: [PATCH 029/142] Manual merge of the lost commit (add @transient annotations + set transient attribute in a federate + update the laucher). Here, the number of federates is the total of transient and pesistent federates. --- core/src/main/java/org/lflang/AttributeUtils.java | 12 ++++++++++++ .../org/lflang/federated/extensions/CExtension.java | 3 +++ .../lflang/federated/generator/FederateInstance.java | 7 +++++++ .../federated/launcher/FedLauncherGenerator.java | 10 ++++++++++ .../java/org/lflang/validation/AttributeSpec.java | 2 ++ 5 files changed, 34 insertions(+) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 6703df2d0e..3ffbfb04cd 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -31,6 +31,8 @@ import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; +import org.lflang.federated.generator.FederateInstance; +import org.lflang.generator.ReactorInstance; import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.AttrParm; @@ -196,6 +198,16 @@ public static boolean isSparse(EObject node) { return findAttributeByName(node, "sparse") != null; } + /** + * Return true if the specified node is an Instantiation and has an + * {@code @transient} attribute. + * + * @param node An AST node. + */ + public static boolean isTransient(EObject node) { + return findAttributeByName(node, "transient") != null; + } + /** * Return true if the reaction is unordered. * diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index 121cf5d817..9c56951cd6 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -673,6 +673,9 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo // Set global variable identifying the federate. code.pr("_lf_my_fed_id = " + federate.id + ";"); + // Set indicator variable that specify whether the federate is transient. + code.pr("_fed.is_transient = " + federate.isTransient + ";"); + // We keep separate record for incoming and outgoing p2p connections to allow incoming traffic // to be processed in a separate // thread without requiring a mutex lock. diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index ee3c0a46f0..9141b4503a 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -41,6 +41,7 @@ import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; +import org.lflang.AttributeUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.PortInstance; import org.lflang.generator.ReactionInstance; @@ -96,6 +97,7 @@ public FederateInstance( this.bankIndex = bankIndex; this.errorReporter = errorReporter; this.targetConfig = targetConfig; + this.isTransient = AttributeUtils.isTransient(instantiation); if (instantiation != null) { // If the instantiation is in a bank, then we have to append @@ -159,6 +161,11 @@ public Instantiation getInstantiation() { /** The integer ID of this federate. */ public int id = 0; + /** + * Type of the federate: transient if true, and peristent if false . + */ + public boolean isTransient = false; + /** * The name of this federate instance. This will be the instantiation name, possibly appended with * "__n", where n is the bank position of this instance if the instantiation is of a bank of diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index b3be6acad0..1d21c0f35f 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -314,6 +314,15 @@ private String getDistHeader() { private String getRtiCommand(List federates, boolean isRemote) { List commands = new ArrayList<>(); + + // Identify the transient federates number + int transientFederatesNumber = 0; + for (FederateInstance federate: federates) { + if (federate.isTransient) { + transientFederatesNumber++; + } + } + if (isRemote) { commands.add("RTI -i '${FEDERATION_ID}' \\"); } else { @@ -328,6 +337,7 @@ private String getRtiCommand(List federates, boolean isRemote) commands.addAll( List.of( " -n " + federates.size() + " \\", + " -nt "+ transientFederatesNumber + " \\", " -c " + targetConfig.clockSync.toString() + " \\")); if (targetConfig.clockSync.equals(ClockSyncMode.ON)) { commands.add("period " + targetConfig.clockSyncOptions.period.toNanoSeconds() + " \\"); diff --git a/core/src/main/java/org/lflang/validation/AttributeSpec.java b/core/src/main/java/org/lflang/validation/AttributeSpec.java index 45c984204e..dd9bbac9e2 100644 --- a/core/src/main/java/org/lflang/validation/AttributeSpec.java +++ b/core/src/main/java/org/lflang/validation/AttributeSpec.java @@ -205,6 +205,8 @@ enum AttrParamType { new AttributeSpec(List.of(new AttrParamSpec(VALUE_ATTR, AttrParamType.STRING, false)))); // @sparse ATTRIBUTE_SPECS_BY_NAME.put("sparse", new AttributeSpec(null)); + // @transient + ATTRIBUTE_SPECS_BY_NAME.put("transient", new AttributeSpec(null)); // @icon("value") ATTRIBUTE_SPECS_BY_NAME.put( "icon", From 059f05242a122e0634c3100ed5547375be324482 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 8 Jun 2023 14:07:10 -0700 Subject: [PATCH 030/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index a11c1b03a1..64c34bd29b 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit a11c1b03a135056550eb64c3a110ee56f8fa0c42 +Subproject commit 64c34bd29b38751568c68b636dad4062efa481ed From 2488dac0cee54d1876ed0165e17a87c52d671a6e Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 8 Jun 2023 16:00:32 -0700 Subject: [PATCH 031/142] Apply formatting to transient federates exmaples and align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../federated/transient/ConnectedTransient.lf | 28 +++++++++++-------- .../transient/ConnectedTransient_2L.lf | 22 +++++++++------ test/C/src/federated/transient/FastAndSlow.lf | 18 ++++-------- .../src/federated/transient/PingPong_Cycle.lf | 8 ++---- test/C/src/federated/transient/Timers.lf | 11 ++++---- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 64c34bd29b..cd0a9925ae 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 64c34bd29b38751568c68b636dad4062efa481ed +Subproject commit cd0a9925ae135435b92f6138a7036767d4901906 diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index e085f11f71..6ecf19f3d9 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -1,12 +1,13 @@ target C { - timeout: 20s, + timeout: 20 s, tracing: true } -reactor Up(period:time = 2s) { +reactor Up(period: time = 2 s) { output out: int timer t(0, period) state count: int = 0 + reaction(t) -> out {= lf_set(out, self->count); lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); @@ -18,13 +19,15 @@ reactor Middle { input in1: int input in2: int output out: int - state count: int=0 + state count: int = 0 + reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} + reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); @@ -33,26 +36,27 @@ reactor Middle { =} } -reactor Down{ - timer t(2s, 300ms) +reactor Down { + timer t(2 s, 300 ms) input in: int + reaction(t) {= - lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); =} + reaction(in) {= - lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } federated reactor { - up1 = new Up(period = 2s) - up2 = new Up(period = 1s) + up1 = new Up(period = 2 s) + up2 = new Up(period = 1 s) @transient mid = new Middle() down = new Down() - // Connections - up1.out -> mid.in1 + up1.out -> mid.in1 // Connections up2.out -> mid.in2 mid.out -> down.in -} \ No newline at end of file +} diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index b242275c3d..1eb30bb091 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -1,12 +1,13 @@ target C { - timeout: 20s, + timeout: 20 s, tracing: true } -reactor Up(period:time = 2s) { +reactor Up(period: time = 2 s) { output out: int timer t(0, period) state count: int = 0 + reaction(t) -> out {= lf_set(out, self->count); lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); @@ -17,6 +18,7 @@ reactor Up(period:time = 2s) { reactor PassThrough { input in: int output out: int + reaction(in) -> out {= lf_set(out, in->value); lf_print("PassThrough :: Passing %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); @@ -27,12 +29,14 @@ reactor Middle { input in1: int input in2: int output out: int - state count: int=0 + state count: int = 0 + reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} + reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); @@ -40,25 +44,25 @@ reactor Middle { =} } -reactor Down{ +reactor Down { input in: int + reaction(in) {= lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } federated reactor { - up1 = new Up(period = 2s) - up2 = new Up(period = 1s) + up1 = new Up(period = 2 s) + up2 = new Up(period = 1 s) @transient pt = new PassThrough() @transient mid = new Middle() down = new Down() - // Connections - up1.out -> pt.in + up1.out -> pt.in // Connections pt.out -> mid.in1 up2.out -> mid.in2 mid.out -> down.in -} \ No newline at end of file +} diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf index 558736a859..c51c1b5fa8 100644 --- a/test/C/src/federated/transient/FastAndSlow.lf +++ b/test/C/src/federated/transient/FastAndSlow.lf @@ -1,9 +1,7 @@ -// This example is derived from the C++ enclave test case, which says "This is a -// basic test for enclaved execution. The deadlines should never be -// violated for the test to pass.". -// Here, we transform it into a federated one, where the `fast` federate is -// transient. - +// This example is derived from the C++ enclave test case, which says "This is a +// basic test for enclaved execution. The deadlines should never be violated for +// the test to pass.". Here, we transform it into a federated one, where the +// `fast` federate is transient. target C { timeout: 20 sec } @@ -23,11 +21,7 @@ reactor Slow { reactor Fast { timer t(0 msec, 100 msec) - reaction(t) {= - lf_print("Fast reaction executes"); - =} deadline( - 200 msec - ) {= + reaction(t) {= lf_print("Fast reaction executes"); =} deadline(200 msec) {= lf_print_error_and_exit("Fast deadline was violated!"); =} } @@ -36,4 +30,4 @@ federated reactor { slow = new Slow() @transient fast = new Fast() -} \ No newline at end of file +} diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf index 1fad7fefa2..c8d0f27e0c 100644 --- a/test/C/src/federated/transient/PingPong_Cycle.lf +++ b/test/C/src/federated/transient/PingPong_Cycle.lf @@ -10,9 +10,7 @@ reactor Ping { state counter: int = 0 state received: bool = false - reaction(t) -> out {= - lf_set(out, self->counter++); - =} + reaction(t) -> out {= lf_set(out, self->counter++); =} reaction(in) {= self->received = true; @@ -48,9 +46,9 @@ reactor Pong { federated reactor { ping = new Ping() - @transient + @transient pong = new Pong() ping.out -> pong.in pong.out -> ping.in after 100 ms -} \ No newline at end of file +} diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf index 01bd24b34f..c1bef66257 100644 --- a/test/C/src/federated/transient/Timers.lf +++ b/test/C/src/federated/transient/Timers.lf @@ -1,13 +1,14 @@ target C { - timeout: 10s, + timeout: 10 s, tracing: true, - threading: true + threading: true } -reactor Timer(period:time = 2s) { +reactor Timer(period: time = 2 s) { output out: int timer t(0, period) state count: int = 0 + reaction(t) -> out {= lf_set(out, self->count); lf_print("Count is = %d", self->count); @@ -17,7 +18,7 @@ reactor Timer(period:time = 2s) { federated reactor { @transient - t0 = new Timer(period = 1s) + t0 = new Timer(period = 1 s) t1 = new Timer() t2 = new Timer() -} \ No newline at end of file +} From 6eb0fb4f3f31d0e3058cb7184d64d06e5506ae6a Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 8 Jun 2023 16:07:31 -0700 Subject: [PATCH 032/142] Apply formatting --- .../main/java/org/lflang/AttributeUtils.java | 17 +++++++---------- .../federated/generator/FederateInstance.java | 6 ++---- .../launcher/FedLauncherGenerator.java | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 3ffbfb04cd..ec7a59b13a 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -31,8 +31,6 @@ import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; -import org.lflang.federated.generator.FederateInstance; -import org.lflang.generator.ReactorInstance; import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.AttrParm; @@ -199,14 +197,13 @@ public static boolean isSparse(EObject node) { } /** - * Return true if the specified node is an Instantiation and has an - * {@code @transient} attribute. - * - * @param node An AST node. - */ - public static boolean isTransient(EObject node) { - return findAttributeByName(node, "transient") != null; - } + * Return true if the specified node is an Instantiation and has an {@code @transient} attribute. + * + * @param node An AST node. + */ + public static boolean isTransient(EObject node) { + return findAttributeByName(node, "transient") != null; + } /** * Return true if the reaction is unordered. diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 9141b4503a..7b3dd3040a 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -36,12 +36,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.emf.ecore.EObject; +import org.lflang.AttributeUtils; import org.lflang.ErrorReporter; import org.lflang.TargetConfig; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; -import org.lflang.AttributeUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.PortInstance; import org.lflang.generator.ReactionInstance; @@ -161,9 +161,7 @@ public Instantiation getInstantiation() { /** The integer ID of this federate. */ public int id = 0; - /** - * Type of the federate: transient if true, and peristent if false . - */ + /** Type of the federate: transient if true, and peristent if false . */ public boolean isTransient = false; /** diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 1d21c0f35f..76566f92ea 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -317,7 +317,7 @@ private String getRtiCommand(List federates, boolean isRemote) // Identify the transient federates number int transientFederatesNumber = 0; - for (FederateInstance federate: federates) { + for (FederateInstance federate : federates) { if (federate.isTransient) { transientFederatesNumber++; } @@ -337,7 +337,7 @@ private String getRtiCommand(List federates, boolean isRemote) commands.addAll( List.of( " -n " + federates.size() + " \\", - " -nt "+ transientFederatesNumber + " \\", + " -nt " + transientFederatesNumber + " \\", " -c " + targetConfig.clockSync.toString() + " \\")); if (targetConfig.clockSync.equals(ClockSyncMode.ON)) { commands.add("period " + targetConfig.clockSyncOptions.period.toNanoSeconds() + " \\"); From ab0a39728e219f7e0de95cba6deade6e642d63bd Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 8 Jun 2023 17:05:48 -0700 Subject: [PATCH 033/142] Apply the updated format --- .../federated/transient/ConnectedTransient.lf | 92 +++++++++---------- .../transient/ConnectedTransient_2L.lf | 90 +++++++++--------- test/C/src/federated/transient/FastAndSlow.lf | 37 ++++---- .../src/federated/transient/PingPong_Cycle.lf | 84 ++++++++--------- test/C/src/federated/transient/Timers.lf | 30 +++--- 5 files changed, 165 insertions(+), 168 deletions(-) diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index 6ecf19f3d9..786f10ddf4 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -1,62 +1,62 @@ target C { - timeout: 20 s, - tracing: true + timeout: 20 s, + tracing: true } reactor Up(period: time = 2 s) { - output out: int - timer t(0, period) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} + output out: int + timer t(0, period) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} } reactor Middle { - input in1: int - input in2: int - output out: int - state count: int = 0 - - reaction(in1) -> out {= - self->count += in1->value; - lf_set(out, self->count); - lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} - - reaction(in2) -> out {= - self->count += in2->value; - lf_set(out, self->count); - lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - // lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} + input in1: int + input in2: int + output out: int + state count: int = 0 + + reaction(in1) -> out {= + self->count += in1->value; + lf_set(out, self->count); + lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} + + reaction(in2) -> out {= + self->count += in2->value; + lf_set(out, self->count); + lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} } reactor Down { - timer t(2 s, 300 ms) - input in: int + timer t(2 s, 300 ms) + input in: int - reaction(t) {= - lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(t) {= + lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); + =} - reaction(in) {= - lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(in) {= + lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + =} } federated reactor { - up1 = new Up(period = 2 s) - up2 = new Up(period = 1 s) - @transient - mid = new Middle() - down = new Down() - - up1.out -> mid.in1 // Connections - up2.out -> mid.in2 - mid.out -> down.in + up1 = new Up(period = 2 s) + up2 = new Up(period = 1 s) + @transient + mid = new Middle() + down = new Down() + + up1.out -> mid.in1 // Connections + up2.out -> mid.in2 + mid.out -> down.in } diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index 1eb30bb091..d5ceafe2f1 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -1,68 +1,68 @@ target C { - timeout: 20 s, - tracing: true + timeout: 20 s, + tracing: true } reactor Up(period: time = 2 s) { - output out: int - timer t(0, period) - state count: int = 0 + output out: int + timer t(0, period) + state count: int = 0 - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} } reactor PassThrough { - input in: int - output out: int + input in: int + output out: int - reaction(in) -> out {= - lf_set(out, in->value); - lf_print("PassThrough :: Passing %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(in) -> out {= + lf_set(out, in->value); + lf_print("PassThrough :: Passing %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + =} } reactor Middle { - input in1: int - input in2: int - output out: int - state count: int = 0 + input in1: int + input in2: int + output out: int + state count: int = 0 - reaction(in1) -> out {= - self->count += in1->value; - lf_set(out, self->count); - lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(in1) -> out {= + self->count += in1->value; + lf_set(out, self->count); + lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} - reaction(in2) -> out {= - self->count += in2->value; - lf_set(out, self->count); - lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(in2) -> out {= + self->count += in2->value; + lf_set(out, self->count); + lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + =} } reactor Down { - input in: int + input in: int - reaction(in) {= - lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} + reaction(in) {= + lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + =} } federated reactor { - up1 = new Up(period = 2 s) - up2 = new Up(period = 1 s) - @transient - pt = new PassThrough() - @transient - mid = new Middle() - down = new Down() + up1 = new Up(period = 2 s) + up2 = new Up(period = 1 s) + @transient + pt = new PassThrough() + @transient + mid = new Middle() + down = new Down() - up1.out -> pt.in // Connections - pt.out -> mid.in1 - up2.out -> mid.in2 - mid.out -> down.in + up1.out -> pt.in // Connections + pt.out -> mid.in1 + up2.out -> mid.in2 + mid.out -> down.in } diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf index c51c1b5fa8..08b6f9669c 100644 --- a/test/C/src/federated/transient/FastAndSlow.lf +++ b/test/C/src/federated/transient/FastAndSlow.lf @@ -1,33 +1,30 @@ -// This example is derived from the C++ enclave test case, which says "This is a -// basic test for enclaved execution. The deadlines should never be violated for -// the test to pass.". Here, we transform it into a federated one, where the -// `fast` federate is transient. +// This example is derived from the C++ enclave test case, which says "This is a basic test for +// enclaved execution. The deadlines should never be violated for the test to pass.". Here, we +// transform it into a federated one, where the `fast` federate is transient. target C { - timeout: 20 sec + timeout: 20 sec } reactor Slow { - timer t(0, 1 sec) + timer t(0, 1 sec) - reaction(t) {= - lf_print("Slow reaction starts"); - lf_sleep(700000000); - lf_print("Slow reaction ends"); - =} deadline(200 msec) {= - lf_print_error_and_exit("Slow deadline was violated!"); - =} + reaction(t) {= + lf_print("Slow reaction starts"); + lf_sleep(700000000); + lf_print("Slow reaction ends"); + =} deadline(200 msec) {= lf_print_error_and_exit("Slow deadline was violated!"); =} } reactor Fast { - timer t(0 msec, 100 msec) + timer t(0 msec, 100 msec) - reaction(t) {= lf_print("Fast reaction executes"); =} deadline(200 msec) {= - lf_print_error_and_exit("Fast deadline was violated!"); - =} + reaction(t) {= lf_print("Fast reaction executes"); =} deadline(200 msec) {= + lf_print_error_and_exit("Fast deadline was violated!"); + =} } federated reactor { - slow = new Slow() - @transient - fast = new Fast() + slow = new Slow() + @transient + fast = new Fast() } diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf index c8d0f27e0c..c41824b3d7 100644 --- a/test/C/src/federated/transient/PingPong_Cycle.lf +++ b/test/C/src/federated/transient/PingPong_Cycle.lf @@ -1,54 +1,54 @@ target C { - timeout: 10 s, - tracing: true + timeout: 10 s, + tracing: true } reactor Ping { - timer t(0, 1 s) - input in: int - output out: int - state counter: int = 0 - state received: bool = false - - reaction(t) -> out {= lf_set(out, self->counter++); =} - - reaction(in) {= - self->received = true; - lf_print("Ping Received %d at %lld.", in->value, lf_time_logical_elapsed()); - =} - - reaction(shutdown) {= - if(!self->received) { - lf_print("Nothing received."); - exit(1); - } - =} + timer t(0, 1 s) + input in: int + output out: int + state counter: int = 0 + state received: bool = false + + reaction(t) -> out {= lf_set(out, self->counter++); =} + + reaction(in) {= + self->received = true; + lf_print("Ping Received %d at %lld.", in->value, lf_time_logical_elapsed()); + =} + + reaction(shutdown) {= + if(!self->received) { + lf_print("Nothing received."); + exit(1); + } + =} } reactor Pong { - input in: int - output out: int - state received: bool = false - - reaction(in) -> out {= - self->received = true; - lf_print("Pong Received %d at %lld.", in-> value, lf_time_logical_elapsed()); - lf_set(out, in->value); - =} - - reaction(shutdown) {= - if(!self->received) { - lf_print("Nothing received."); - exit(1); - } - =} + input in: int + output out: int + state received: bool = false + + reaction(in) -> out {= + self->received = true; + lf_print("Pong Received %d at %lld.", in-> value, lf_time_logical_elapsed()); + lf_set(out, in->value); + =} + + reaction(shutdown) {= + if(!self->received) { + lf_print("Nothing received."); + exit(1); + } + =} } federated reactor { - ping = new Ping() - @transient - pong = new Pong() + ping = new Ping() + @transient + pong = new Pong() - ping.out -> pong.in - pong.out -> ping.in after 100 ms + ping.out -> pong.in + pong.out -> ping.in after 100 ms } diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf index c1bef66257..961413ce8e 100644 --- a/test/C/src/federated/transient/Timers.lf +++ b/test/C/src/federated/transient/Timers.lf @@ -1,24 +1,24 @@ target C { - timeout: 10 s, - tracing: true, - threading: true + timeout: 10 s, + tracing: true, + threading: true } reactor Timer(period: time = 2 s) { - output out: int - timer t(0, period) - state count: int = 0 + output out: int + timer t(0, period) + state count: int = 0 - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d", self->count); - self->count++; - =} + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d", self->count); + self->count++; + =} } federated reactor { - @transient - t0 = new Timer(period = 1 s) - t1 = new Timer() - t2 = new Timer() + @transient + t0 = new Timer(period = 1 s) + t1 = new Timer() + t2 = new Timer() } From a5bdaf87057b66161d84069a242213f5f35b8845 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 9 Jun 2023 09:47:18 -0700 Subject: [PATCH 034/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index cd0a9925ae..f6970198ad 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit cd0a9925ae135435b92f6138a7036767d4901906 +Subproject commit f6970198ad6b61bc5288c9110896b85fabc6abe5 From d55462544b3f782fe08ec9d2b6e892dea63c3a34 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Jun 2023 08:38:45 -0700 Subject: [PATCH 035/142] Check to avoid repeated CI runs --- .github/workflows/all-misc.yml | 5 +++++ .github/workflows/all-targets.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 7efaee5131..2a7c22cc59 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -19,8 +19,13 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: + check-redundant: + uses: fkirc/skip-duplicate-actions@v5.3.0 + if: ${{ github.ref == 'refs/heads/master' }} + check-diff: uses: ./.github/workflows/check-diff.yml + needs: check-redundant # Test the Gradle build. building: diff --git a/.github/workflows/all-targets.yml b/.github/workflows/all-targets.yml index bc740a36b9..25fb5dfde8 100644 --- a/.github/workflows/all-targets.yml +++ b/.github/workflows/all-targets.yml @@ -19,8 +19,13 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: + check-redundant: + uses: fkirc/skip-duplicate-actions@v5.3.0 + if: ${{ github.ref == 'refs/heads/master' }} + check-diff: uses: ./.github/workflows/check-diff.yml + needs: check-redundant c: uses: ./.github/workflows/only-c.yml From ab85faacad8fa431bcaa8ab828f6742cb5278f98 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Jun 2023 10:07:13 -0700 Subject: [PATCH 036/142] Run skip-duplicate-actions in check-diff workflow --- .github/scripts/check-diff.sh | 2 +- .github/workflows/all-misc.yml | 4 ---- .github/workflows/all-targets.yml | 5 ----- .github/workflows/check-diff.yml | 5 +++++ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/scripts/check-diff.sh b/.github/scripts/check-diff.sh index c7bdda6d5f..29dab281f9 100644 --- a/.github/scripts/check-diff.sh +++ b/.github/scripts/check-diff.sh @@ -3,7 +3,7 @@ changes() { } if changes | grep -q $1; then - echo "CHANGED_$2=1" >> $GITHUB_OUTPUT + echo "CHANGED_$2=${{ steps.check.outputs.should_skip != 'true' }}" >> $GITHUB_OUTPUT else echo "CHANGED_$2=0" >> $GITHUB_OUTPUT fi diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 2a7c22cc59..8dea3460f0 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -19,10 +19,6 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: - check-redundant: - uses: fkirc/skip-duplicate-actions@v5.3.0 - if: ${{ github.ref == 'refs/heads/master' }} - check-diff: uses: ./.github/workflows/check-diff.yml needs: check-redundant diff --git a/.github/workflows/all-targets.yml b/.github/workflows/all-targets.yml index 25fb5dfde8..bc740a36b9 100644 --- a/.github/workflows/all-targets.yml +++ b/.github/workflows/all-targets.yml @@ -19,13 +19,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: - check-redundant: - uses: fkirc/skip-duplicate-actions@v5.3.0 - if: ${{ github.ref == 'refs/heads/master' }} - check-diff: uses: ./.github/workflows/check-diff.yml - needs: check-redundant c: uses: ./.github/workflows/only-c.yml diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 3633344d5d..92ef7bff5b 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -33,6 +33,10 @@ jobs: repository: lf-lang/lingua-franca submodules: true fetch-depth: 0 + - name: Check for redundant runs + id: check + uses: fkirc/skip-duplicate-actions@v5.3.0 + if: ${{ github.ref == 'refs/heads/master' }} - id: do run: | wget https://raw.githubusercontent.com/lf-lang/lingua-franca/master/.github/scripts/check-diff.sh @@ -43,3 +47,4 @@ jobs: source check-diff.sh "core/src/main/kotlin/org/lflang/generator/ts\|core/src/main/java/org/lflang/generator/ts\|core/src/main/resources/lib/ts\|test/TypeScript" TS source check-diff.sh "util/tracing" TRACING shell: bash + if: ${{ steps.check.outputs.should_skip != 'true' }} From 7393614b70e63e21153a3a8b3fa657cf18afd577 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 00:26:08 -0700 Subject: [PATCH 037/142] Augment diff checks and allow skipping if redundant --- .github/scripts/check-diff.sh | 8 +- .github/workflows/all-misc.yml | 13 ++-- .github/workflows/all-targets.yml | 12 +-- .github/workflows/check-diff.yml | 121 ++++++++++++++++++++---------- 4 files changed, 101 insertions(+), 53 deletions(-) mode change 100644 => 100755 .github/scripts/check-diff.sh diff --git a/.github/scripts/check-diff.sh b/.github/scripts/check-diff.sh old mode 100644 new mode 100755 index 29dab281f9..5be32c9c17 --- a/.github/scripts/check-diff.sh +++ b/.github/scripts/check-diff.sh @@ -1,9 +1,11 @@ +#!/bin/bash + changes() { git diff --name-only HEAD $(git merge-base HEAD origin/master) } -if changes | grep -q $1; then - echo "CHANGED_$2=${{ steps.check.outputs.should_skip != 'true' }}" >> $GITHUB_OUTPUT +if changes | grep $1 | grep -q -v '^.*md\|txt$'; then + echo "changed_$2=1" >> $GITHUB_OUTPUT else - echo "CHANGED_$2=0" >> $GITHUB_OUTPUT + echo "changed_$2=0" >> $GITHUB_OUTPUT fi diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 8dea3460f0..8a891b65cb 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -21,32 +21,35 @@ concurrency: jobs: check-diff: uses: ./.github/workflows/check-diff.yml - needs: check-redundant # Test the Gradle build. building: + needs: check-diff uses: ./.github/workflows/build.yml with: all-platforms: ${{ !github.event.pull_request.draft }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' }} # Build the tools used for processing execution traces tracing: - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-tracing == 1 }} - uses: ./.github/workflows/build-trace-tools.yml needs: check-diff + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_tracing == 'true' }} + uses: ./.github/workflows/build-trace-tools.yml with: all-platforms: ${{ !github.event.pull_request.draft }} # Run tests for the standalone compiler. cli: - if: ${{ !github.event.pull_request.draft }} + if: ${{ !github.event.pull_request.draft && needs.check-diff.outputs.skip_all != 'true' }} + needs: check-diff uses: ./.github/workflows/cli-tests.yml with: all-platforms: ${{ !github.event.pull_request.draft }} # Run language server tests. lsp: - if: ${{ !github.event.pull_request.draft }} + if: ${{ !github.event.pull_request.draft && needs.check-diff.outputs.skip_all != 'true' }} + needs: check-diff uses: ./.github/workflows/lsp-tests.yml with: all-platforms: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/all-targets.yml b/.github/workflows/all-targets.yml index bc740a36b9..c11c64a589 100644 --- a/.github/workflows/all-targets.yml +++ b/.github/workflows/all-targets.yml @@ -25,29 +25,29 @@ jobs: c: uses: ./.github/workflows/only-c.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-c == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' }} cpp: uses: ./.github/workflows/only-cpp.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-cpp == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_cpp == 'true' }} py: uses: ./.github/workflows/only-py.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-py == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_py == 'true' }} rs: uses: ./.github/workflows/only-rs.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-rs == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_rs == 'true' }} ts: uses: ./.github/workflows/only-ts.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-ts == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_ts == 'true' }} serialization: - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.changed-c == 1 || needs.check-diff.outputs.changed-py == 1 || needs.check-diff.outputs.changed-ts == 1 }} + if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true' }} needs: check-diff uses: ./.github/workflows/serialization-tests.yml diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 92ef7bff5b..a8bb15f35a 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -3,48 +3,91 @@ name: Check diff from master on: workflow_call: outputs: - changed-c: - value: ${{ jobs.check.outputs.changed-c }} - changed-cpp: - value: ${{ jobs.check.outputs.changed-cpp }} - changed-py: - value: ${{ jobs.check.outputs.changed-py }} - changed-rs: - value: ${{ jobs.check.outputs.changed-rs }} - changed-ts: - value: ${{ jobs.check.outputs.changed-ts }} - changed-tracing: - value: ${{ jobs.check.outputs.changed-tracing }} + run_c: + description: 'Return true if C tests should be run' + value: ${{ jobs.check.outputs.changed_c == 1 && jobs.check.outputs.skip_all != 'true' }} + run_cpp: + description: 'Return true if C++ tests should be run' + value: ${{ jobs.check.outputs.changed_cpp == 1 && jobs.check.outputs.skip_all != 'true' }} + run_py: + description: 'Return true if Python tests should be run' + value: ${{ (jobs.check.outputs.changed_py == 1 || jobs.check.outputs.changed_c == 1) && jobs.check.outputs.skip_all != 'true' }} + run_rs: + description: 'Return true if Rust tests should be run' + value: ${{ jobs.check.outputs.changed_rs == 1 && jobs.check.outputs.skip_all != 'true' }} + run_ts: + description: 'Return true if TypeScript tests should be run' + value: ${{ jobs.check.outputs.changed_ts == 1 && jobs.check.outputs.skip_all != 'true' }} + run_tracing: + description: 'Return true if tracing tests should be run' + value: ${{ jobs.check.outputs.changed_tracing == 1 && jobs.check.outputs.skip_all != 'true' }} + skip_all: + description: 'Return true if tests should not be run' + value: ${{ jobs.check.outputs.skip_all == 'true' }} jobs: check: runs-on: ubuntu-latest outputs: - changed-c: ${{ steps.do.outputs.CHANGED_C }} - changed-cpp: ${{ steps.do.outputs.CHANGED_CPP }} - changed-py: ${{ steps.do.outputs.CHANGED_PY }} - changed-rs: ${{ steps.do.outputs.CHANGED_RS }} - changed-ts: ${{ steps.do.outputs.CHANGED_TS }} - changed-tracing: ${{ steps.do.outputs.CHANGED_TRACING }} + changed_c: ${{ steps.do.outputs.changed_c }} + changed_cpp: ${{ steps.do.outputs.changed_cpp }} + changed_py: ${{ steps.do.outputs.changed_py }} + changed_rs: ${{ steps.do.outputs.changed_rs }} + changed_ts: ${{ steps.do.outputs.changed_ts }} + changed_tracing: ${{ steps.do.outputs.changed_tracing }} + skip_all: ${{ steps.duplicate.outputs.should_skip }} steps: - - name: Check out lingua-franca repository - uses: actions/checkout@v3 - with: - repository: lf-lang/lingua-franca - submodules: true - fetch-depth: 0 - - name: Check for redundant runs - id: check - uses: fkirc/skip-duplicate-actions@v5.3.0 - if: ${{ github.ref == 'refs/heads/master' }} - - id: do - run: | - wget https://raw.githubusercontent.com/lf-lang/lingua-franca/master/.github/scripts/check-diff.sh - source check-diff.sh "core/src/main/java/org/lflang/generator/c\|core/src/main/resources/lib/c\|core/src/main/resources/lib/platform\|test/C" C - source check-diff.sh "core/src/main/kotlin/org/lflang/generator/cpp\|core/src/main/resources/lib/cpp\|test/Cpp" CPP - source check-diff.sh "core/src/main/java/org/lflang/generator/python\|core/src/main/resources/lib/py\|test/Python" PY - source check-diff.sh "core/src/main/kotlin/org/lflang/generator/rust\|core/src/main/java/org/lflang/generator/rust\|core/src/main/resources/lib/rs\|test/Rust" RS - source check-diff.sh "core/src/main/kotlin/org/lflang/generator/ts\|core/src/main/java/org/lflang/generator/ts\|core/src/main/resources/lib/ts\|test/TypeScript" TS - source check-diff.sh "util/tracing" TRACING - shell: bash - if: ${{ steps.check.outputs.should_skip != 'true' }} + - name: Check out lingua-franca repository + uses: actions/checkout@v3 + with: + repository: lf-lang/lingua-franca + submodules: true + fetch-depth: 0 + - name: Check for redundant runs + id: duplicate + uses: fkirc/skip-duplicate-actions@v5.3.0 + - id: do + name: Check which targets have changes + run: | + ./check-diff.sh "lflang/generator/c\|resources/lib/c\|resources/lib/platform\|test/C" c + ./check-diff.sh "lflang/generator/cpp\|resources/lib/cpp\|test/Cpp" cpp + ./check-diff.sh "lflang/generator/python\|resources/lib/py\|test/Python" py + ./check-diff.sh "lflang/generator/rust\|resources/lib/rs\|test/Rust" rs + ./check-diff.sh "lflang/generator/ts\|resources/lib/ts\|test/TypeScript" ts + ./check-diff.sh "util/tracing" tracing + shell: bash + working-directory: .github/scripts + - id: summarize + name: "Create summary" + run: | + echo '## Summary' > $GITHUB_STEP_SUMMARY + - id: skip-all + name: "Explain skipping all checks" + run: | + echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY + echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY + echo ":heavy_check_mark: Skipping tests." >> $GITHUB_STEP_SUMMARY + if: ${{ steps.do.outputs.skip_all == 'true' }} + - id: run-some + name: "Explain running some checks" + run: | + echo ":hourglass: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY + if: ${{ steps.do.outputs.skip_all != 'true' }} + - id: ready-mode + name: 'Report on full test run' + run: | + echo ":heavy_check_mark: Performing all tests." >> $GITHUB_STEP_SUMMARY + if: ${{ !github.event.pull_request.draft }} + - id: draft-mode + name: 'Report on partial test run' + run: | + echo ":heavy_check_mark: Performing tests affected by detected changes." >> $GITHUB_STEP_SUMMARY + echo '| | running |' >> $GITHUB_STEP_SUMMARY + echo '|---------|-------------------------------------------|' >> $GITHUB_STEP_SUMMARY + echo '| c | `${{ steps.do.outputs.changed_c == 1 }}` |' >> $GITHUB_STEP_SUMMARY + echo '| cpp | `${{ steps.do.outputs.changed_cpp == 1 }}` |' >> $GITHUB_STEP_SUMMARY + echo '| py | `${{ steps.do.outputs.changed_py == 1 }}` |' >> $GITHUB_STEP_SUMMARY + echo '| rs | `${{ steps.do.outputs.changed_rs == 1 }}` |' >> $GITHUB_STEP_SUMMARY + echo '| ts | `${{ steps.do.outputs.changed_ts == 1 }}` |' >> $GITHUB_STEP_SUMMARY + echo '| tracing | `${{ steps.do.outputs.changed_tracing == 1 }}` |' >> $GITHUB_STEP_SUMMARY + if: ${{ github.event.pull_request.draft }} From 5cb581db396d5cd99fd52ddf244056df2271d3db Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 00:59:42 -0700 Subject: [PATCH 038/142] Also do no run checks in master if changes are inconsequential --- .github/workflows/all-misc.yml | 6 +++--- .github/workflows/all-targets.yml | 12 ++++++------ .github/workflows/check-diff.yml | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 8a891b65cb..4764f02219 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -33,14 +33,14 @@ jobs: # Build the tools used for processing execution traces tracing: needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_tracing == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (needs.check-diff.outputs.run_tracing == 'true' || !github.event.pull_request.draft) }} uses: ./.github/workflows/build-trace-tools.yml with: all-platforms: ${{ !github.event.pull_request.draft }} # Run tests for the standalone compiler. cli: - if: ${{ !github.event.pull_request.draft && needs.check-diff.outputs.skip_all != 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && !github.event.pull_request.draft }} needs: check-diff uses: ./.github/workflows/cli-tests.yml with: @@ -48,7 +48,7 @@ jobs: # Run language server tests. lsp: - if: ${{ !github.event.pull_request.draft && needs.check-diff.outputs.skip_all != 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && !github.event.pull_request.draft }} needs: check-diff uses: ./.github/workflows/lsp-tests.yml with: diff --git a/.github/workflows/all-targets.yml b/.github/workflows/all-targets.yml index c11c64a589..ef880cc0c0 100644 --- a/.github/workflows/all-targets.yml +++ b/.github/workflows/all-targets.yml @@ -25,29 +25,29 @@ jobs: c: uses: ./.github/workflows/only-c.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true') }} cpp: uses: ./.github/workflows/only-cpp.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_cpp == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_cpp == 'true') }} py: uses: ./.github/workflows/only-py.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_py == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_py == 'true') }} rs: uses: ./.github/workflows/only-rs.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_rs == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_rs == 'true') }} ts: uses: ./.github/workflows/only-ts.yml needs: check-diff - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_ts == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_ts == 'true') }} serialization: - if: ${{ !github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true') }} needs: check-diff uses: ./.github/workflows/serialization-tests.yml diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index a8bb15f35a..3232b22d25 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -35,7 +35,7 @@ jobs: changed_rs: ${{ steps.do.outputs.changed_rs }} changed_ts: ${{ steps.do.outputs.changed_ts }} changed_tracing: ${{ steps.do.outputs.changed_tracing }} - skip_all: ${{ steps.duplicate.outputs.should_skip }} + skip_all: ${{ steps.duplicate.outputs.should_skip == 'true' || steps.do.outputs.changed_any == 0 }} steps: - name: Check out lingua-franca repository uses: actions/checkout@v3 @@ -55,6 +55,7 @@ jobs: ./check-diff.sh "lflang/generator/rust\|resources/lib/rs\|test/Rust" rs ./check-diff.sh "lflang/generator/ts\|resources/lib/ts\|test/TypeScript" ts ./check-diff.sh "util/tracing" tracing + ./check-diff.sh "*" any shell: bash working-directory: .github/scripts - id: summarize From d6d13e71767759190fd61c6f6846f8e047ec0732 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 01:01:17 -0700 Subject: [PATCH 039/142] Consistent ordering of terms --- .github/workflows/all-misc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 4764f02219..0ad64bbc8f 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -33,7 +33,7 @@ jobs: # Build the tools used for processing execution traces tracing: needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (needs.check-diff.outputs.run_tracing == 'true' || !github.event.pull_request.draft) }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_tracing == 'true') }} uses: ./.github/workflows/build-trace-tools.yml with: all-platforms: ${{ !github.event.pull_request.draft }} From c21334d67c61f1a598ab4d0aad47199c533a80b5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 01:04:17 -0700 Subject: [PATCH 040/142] Regex --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 3232b22d25..4b23a4260a 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -55,7 +55,7 @@ jobs: ./check-diff.sh "lflang/generator/rust\|resources/lib/rs\|test/Rust" rs ./check-diff.sh "lflang/generator/ts\|resources/lib/ts\|test/TypeScript" ts ./check-diff.sh "util/tracing" tracing - ./check-diff.sh "*" any + ./check-diff.sh ".+" any shell: bash working-directory: .github/scripts - id: summarize From 2472febb1256ac0b1a142c478ac12027d196d850 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 01:06:53 -0700 Subject: [PATCH 041/142] Fix grep --- .github/workflows/check-diff.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 4b23a4260a..1f495c5a43 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -35,7 +35,7 @@ jobs: changed_rs: ${{ steps.do.outputs.changed_rs }} changed_ts: ${{ steps.do.outputs.changed_ts }} changed_tracing: ${{ steps.do.outputs.changed_tracing }} - skip_all: ${{ steps.duplicate.outputs.should_skip == 'true' || steps.do.outputs.changed_any == 0 }} + skip_all: ${{ steps.duplicate.outputs.should_skip == 'true' && steps.do.outputs.changed_any == 0 }} steps: - name: Check out lingua-franca repository uses: actions/checkout@v3 @@ -55,7 +55,7 @@ jobs: ./check-diff.sh "lflang/generator/rust\|resources/lib/rs\|test/Rust" rs ./check-diff.sh "lflang/generator/ts\|resources/lib/ts\|test/TypeScript" ts ./check-diff.sh "util/tracing" tracing - ./check-diff.sh ".+" any + ./check-diff.sh "" any shell: bash working-directory: .github/scripts - id: summarize From 8d8786f638327bb9591e31063997247327d41914 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 09:18:16 -0700 Subject: [PATCH 042/142] Add logic to handle build_anyway --- .github/workflows/all-misc.yml | 2 +- .github/workflows/check-diff.yml | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 0ad64bbc8f..481c651aa1 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -28,7 +28,7 @@ jobs: uses: ./.github/workflows/build.yml with: all-platforms: ${{ !github.event.pull_request.draft }} - if: ${{ needs.check-diff.outputs.skip_all != 'true' }} + if: ${{ needs.check-diff.outputs.skip_all != 'true' || needs.check-diff.outputs.build_anyway == 'true' }} # Build the tools used for processing execution traces tracing: diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 1f495c5a43..31f0d9668b 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -3,6 +3,9 @@ name: Check diff from master on: workflow_call: outputs: + build_anyway: + description: 'Return true if building is still needed when skipping tests' + value: ${{ jobs.check.outputs.build_anyway == 1 }} run_c: description: 'Return true if C tests should be run' value: ${{ jobs.check.outputs.changed_c == 1 && jobs.check.outputs.skip_all != 'true' }} @@ -29,6 +32,7 @@ jobs: check: runs-on: ubuntu-latest outputs: + build_anyway: ${{ steps.skip-ignore.outputs.changed_build }} changed_c: ${{ steps.do.outputs.changed_c }} changed_cpp: ${{ steps.do.outputs.changed_cpp }} changed_py: ${{ steps.do.outputs.changed_py }} @@ -62,13 +66,20 @@ jobs: name: "Create summary" run: | echo '## Summary' > $GITHUB_STEP_SUMMARY - - id: skip-all - name: "Explain skipping all checks" + - id: skip-redundant + name: "Explain skipping all checks due to a prior run" run: | echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY - echo ":heavy_check_mark: Skipping tests." >> $GITHUB_STEP_SUMMARY + echo ":heavy_check_mark: Skipping all tests." >> $GITHUB_STEP_SUMMARY if: ${{ steps.do.outputs.skip_all == 'true' }} + - id: skip-ignore + name: "Explain skipping all checks due to inconsequential changes" + run: | + echo "The detected changes did not affect any code." >> $GITHUB_STEP_SUMMARY + echo ":heavy_check_mark: Skipping tests. Only running build." >> $GITHUB_STEP_SUMMARY + echo "build_anyway=1" >> $GITHUB_OUTPUT + if: ${{ steps.do.outputs.skip_all != 'true' && steps.do.outputs.changed_any == 0 }} - id: run-some name: "Explain running some checks" run: | From 14f7ef6671e17c644cb70898b80f5f515dbbaa55 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 12:48:14 -0700 Subject: [PATCH 043/142] Simplifications --- .github/workflows/all-misc.yml | 8 ++-- .github/workflows/all-targets.yml | 12 +++--- .github/workflows/check-diff.yml | 61 +++++++++++++++---------------- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/.github/workflows/all-misc.yml b/.github/workflows/all-misc.yml index 481c651aa1..0cbdd2a21d 100644 --- a/.github/workflows/all-misc.yml +++ b/.github/workflows/all-misc.yml @@ -28,19 +28,19 @@ jobs: uses: ./.github/workflows/build.yml with: all-platforms: ${{ !github.event.pull_request.draft }} - if: ${{ needs.check-diff.outputs.skip_all != 'true' || needs.check-diff.outputs.build_anyway == 'true' }} + if: ${{ needs.check-diff.outputs.run_build == 'true' }} # Build the tools used for processing execution traces tracing: needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_tracing == 'true') }} + if: ${{ needs.check-diff.outputs.run_tracing == 'true' }} uses: ./.github/workflows/build-trace-tools.yml with: all-platforms: ${{ !github.event.pull_request.draft }} # Run tests for the standalone compiler. cli: - if: ${{ needs.check-diff.outputs.skip_all != 'true' && !github.event.pull_request.draft }} + if: ${{ needs.check-diff.outputs.run_misc == 'true' }} needs: check-diff uses: ./.github/workflows/cli-tests.yml with: @@ -48,7 +48,7 @@ jobs: # Run language server tests. lsp: - if: ${{ needs.check-diff.outputs.skip_all != 'true' && !github.event.pull_request.draft }} + if: ${{ needs.check-diff.outputs.run_misc == 'true' }} needs: check-diff uses: ./.github/workflows/lsp-tests.yml with: diff --git a/.github/workflows/all-targets.yml b/.github/workflows/all-targets.yml index ef880cc0c0..4068bc2576 100644 --- a/.github/workflows/all-targets.yml +++ b/.github/workflows/all-targets.yml @@ -25,29 +25,29 @@ jobs: c: uses: ./.github/workflows/only-c.yml needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true') }} + if: ${{ needs.check-diff.outputs.run_c == 'true' }} cpp: uses: ./.github/workflows/only-cpp.yml needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_cpp == 'true') }} + if: ${{ needs.check-diff.outputs.run_cpp == 'true' }} py: uses: ./.github/workflows/only-py.yml needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_py == 'true') }} + if: ${{ needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_c == 'true' }} rs: uses: ./.github/workflows/only-rs.yml needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_rs == 'true') }} + if: ${{ needs.check-diff.outputs.run_rs == 'true' }} ts: uses: ./.github/workflows/only-ts.yml needs: check-diff - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_ts == 'true') }} + if: ${{ needs.check-diff.outputs.run_ts == 'true' }} serialization: - if: ${{ needs.check-diff.outputs.skip_all != 'true' && (!github.event.pull_request.draft || needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true') }} + if: ${{ needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true' }} needs: check-diff uses: ./.github/workflows/serialization-tests.yml diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 31f0d9668b..fc3e38277f 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -3,43 +3,43 @@ name: Check diff from master on: workflow_call: outputs: - build_anyway: - description: 'Return true if building is still needed when skipping tests' - value: ${{ jobs.check.outputs.build_anyway == 1 }} run_c: description: 'Return true if C tests should be run' - value: ${{ jobs.check.outputs.changed_c == 1 && jobs.check.outputs.skip_all != 'true' }} + value: ${{ jobs.check.outputs.run_c == 'true' && jobs.check.outputs.skip != 'true' }} run_cpp: description: 'Return true if C++ tests should be run' - value: ${{ jobs.check.outputs.changed_cpp == 1 && jobs.check.outputs.skip_all != 'true' }} + value: ${{ jobs.check.outputs.run_cpp == 'true' && jobs.check.outputs.skip != 'true' }} run_py: description: 'Return true if Python tests should be run' - value: ${{ (jobs.check.outputs.changed_py == 1 || jobs.check.outputs.changed_c == 1) && jobs.check.outputs.skip_all != 'true' }} + value: ${{ jobs.check.outputs.run_py == 'true' && jobs.check.outputs.skip != 'true' }} run_rs: description: 'Return true if Rust tests should be run' - value: ${{ jobs.check.outputs.changed_rs == 1 && jobs.check.outputs.skip_all != 'true' }} + value: ${{ jobs.check.outputs.run_rs == 'true' && jobs.check.outputs.skip != 'true' }} run_ts: description: 'Return true if TypeScript tests should be run' - value: ${{ jobs.check.outputs.changed_ts == 1 && jobs.check.outputs.skip_all != 'true' }} + value: ${{ jobs.check.outputs.run_ts == 'true' && jobs.check.outputs.skip != 'true' }} run_tracing: description: 'Return true if tracing tests should be run' - value: ${{ jobs.check.outputs.changed_tracing == 1 && jobs.check.outputs.skip_all != 'true' }} - skip_all: - description: 'Return true if tests should not be run' - value: ${{ jobs.check.outputs.skip_all == 'true' }} + value: ${{ jobs.check.outputs.run_tracing == 'true' && jobs.check.outputs.skip != 'true' }} + run_build: + description: 'Return true if the build should be run' + value: ${{ jobs.check.outputs.skip != 'true' }} + run_misc: + description: 'Return true if the build should be run' + value: ${{ jobs.check.outputs.run_misc == 'true' && jobs.check.outputs.skip != 'true' }} jobs: check: runs-on: ubuntu-latest outputs: - build_anyway: ${{ steps.skip-ignore.outputs.changed_build }} - changed_c: ${{ steps.do.outputs.changed_c }} - changed_cpp: ${{ steps.do.outputs.changed_cpp }} - changed_py: ${{ steps.do.outputs.changed_py }} - changed_rs: ${{ steps.do.outputs.changed_rs }} - changed_ts: ${{ steps.do.outputs.changed_ts }} - changed_tracing: ${{ steps.do.outputs.changed_tracing }} - skip_all: ${{ steps.duplicate.outputs.should_skip == 'true' && steps.do.outputs.changed_any == 0 }} + skip: ${{ steps.duplicate.outputs.should_skip == 'true' }} + run_c: ${{ steps.do.outputs.changed_c == 1 || !github.event.pull_request.draft }} + run_cpp: ${{ steps.do.outputs.changed_cpp == 1 || !github.event.pull_request.draft }} + run_misc: ${{ steps.do.outputs.changed_any == 1 || !github.event.pull_request.draft }} + run_py: ${{ steps.do.outputs.changed_py == 1 || !github.event.pull_request.draft }} + run_rs: ${{ steps.do.outputs.changed_rs == 1 || !github.event.pull_request.draft }} + run_ts: ${{ steps.do.outputs.changed_ts == 1|| !github.event.pull_request.draft }} + run_tracing: ${{ steps.do.outputs.changed_tracing == 1 || !github.event.pull_request.draft }} steps: - name: Check out lingua-franca repository uses: actions/checkout@v3 @@ -67,28 +67,27 @@ jobs: run: | echo '## Summary' > $GITHUB_STEP_SUMMARY - id: skip-redundant - name: "Explain skipping all checks due to a prior run" + name: "Explain skipping checks due to a prior run" run: | echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY - echo ":heavy_check_mark: Skipping all tests." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.do.outputs.skip_all == 'true' }} + echo ":heavy_check_mark: Skipping all tests. Only building." >> $GITHUB_STEP_SUMMARY + if: ${{ steps.duplicate.outputs.should_skip == 'true' }} - id: skip-ignore - name: "Explain skipping all checks due to inconsequential changes" + name: "Explain skipping checks due to inconsequential changes" run: | - echo "The detected changes did not affect any code." >> $GITHUB_STEP_SUMMARY - echo ":heavy_check_mark: Skipping tests. Only running build." >> $GITHUB_STEP_SUMMARY - echo "build_anyway=1" >> $GITHUB_OUTPUT - if: ${{ steps.do.outputs.skip_all != 'true' && steps.do.outputs.changed_any == 0 }} + echo ":octopus: The detected changes did not affect any code." >> $GITHUB_STEP_SUMMARY + echo ":heavy_check_mark: Skipping tests. Only building." >> $GITHUB_STEP_SUMMARY + if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any == 0 }} - id: run-some name: "Explain running some checks" run: | - echo ":hourglass: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.do.outputs.skip_all != 'true' }} + echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY + if: ${{ steps.duplicate.outputs.should_skip != 'true' }} - id: ready-mode name: 'Report on full test run' run: | - echo ":heavy_check_mark: Performing all tests." >> $GITHUB_STEP_SUMMARY + echo ":hourglass: Performing all tests." >> $GITHUB_STEP_SUMMARY if: ${{ !github.event.pull_request.draft }} - id: draft-mode name: 'Report on partial test run' From 98559ab33f7d6202f906c5aa0fd202843ce6de46 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 13:17:36 -0700 Subject: [PATCH 044/142] Updated reporting --- .github/workflows/check-diff.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index fc3e38277f..d5e77e757f 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -67,32 +67,32 @@ jobs: run: | echo '## Summary' > $GITHUB_STEP_SUMMARY - id: skip-redundant - name: "Explain skipping checks due to a prior run" + name: "Report skipping checks due to a prior run" run: | echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY - echo ":heavy_check_mark: Skipping all tests. Only building." >> $GITHUB_STEP_SUMMARY + echo ":heavy_check_mark: Skipping all tests." >> $GITHUB_STEP_SUMMARY if: ${{ steps.duplicate.outputs.should_skip == 'true' }} - id: skip-ignore - name: "Explain skipping checks due to inconsequential changes" + name: "Report skipping checks due to inconsequential changes" run: | echo ":octopus: The detected changes did not affect any code." >> $GITHUB_STEP_SUMMARY echo ":heavy_check_mark: Skipping tests. Only building." >> $GITHUB_STEP_SUMMARY if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any == 0 }} - id: run-some - name: "Explain running some checks" + name: "Report running some checks" run: | echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' }} - - id: ready-mode + if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0}} + - id: run-ready-mode name: 'Report on full test run' run: | echo ":hourglass: Performing all tests." >> $GITHUB_STEP_SUMMARY - if: ${{ !github.event.pull_request.draft }} - - id: draft-mode + if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0 && !github.event.pull_request.draft}} + - id: run-draft-mode name: 'Report on partial test run' run: | - echo ":heavy_check_mark: Performing tests affected by detected changes." >> $GITHUB_STEP_SUMMARY + echo ":hourglass: Performing tests affected by detected changes." >> $GITHUB_STEP_SUMMARY echo '| | running |' >> $GITHUB_STEP_SUMMARY echo '|---------|-------------------------------------------|' >> $GITHUB_STEP_SUMMARY echo '| c | `${{ steps.do.outputs.changed_c == 1 }}` |' >> $GITHUB_STEP_SUMMARY @@ -101,4 +101,4 @@ jobs: echo '| rs | `${{ steps.do.outputs.changed_rs == 1 }}` |' >> $GITHUB_STEP_SUMMARY echo '| ts | `${{ steps.do.outputs.changed_ts == 1 }}` |' >> $GITHUB_STEP_SUMMARY echo '| tracing | `${{ steps.do.outputs.changed_tracing == 1 }}` |' >> $GITHUB_STEP_SUMMARY - if: ${{ github.event.pull_request.draft }} + if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0 && github.event.pull_request.draft}} From f8ecb86ab8b3867d863d20ab14282aae680c4be1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 13:20:34 -0700 Subject: [PATCH 045/142] Indentation --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index d5e77e757f..2b7cf982a7 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -83,7 +83,7 @@ jobs: name: "Report running some checks" run: | echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0}} + if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0}} - id: run-ready-mode name: 'Report on full test run' run: | From 5c4635019418c1439212a3b7deee8f71ac99ca95 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 13:30:15 -0700 Subject: [PATCH 046/142] Minor tweaks --- .github/workflows/check-diff.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 2b7cf982a7..2859713497 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -25,8 +25,8 @@ on: description: 'Return true if the build should be run' value: ${{ jobs.check.outputs.skip != 'true' }} run_misc: - description: 'Return true if the build should be run' - value: ${{ jobs.check.outputs.run_misc == 'true' && jobs.check.outputs.skip != 'true' }} + description: 'Return true if the build should be run' + value: ${{ jobs.check.outputs.run_misc == 'true' && jobs.check.outputs.skip != 'true' }} jobs: check: @@ -67,7 +67,7 @@ jobs: run: | echo '## Summary' > $GITHUB_STEP_SUMMARY - id: skip-redundant - name: "Report skipping checks due to a prior run" + name: "Report on skipping checks (prior run found)" run: | echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY @@ -80,7 +80,7 @@ jobs: echo ":heavy_check_mark: Skipping tests. Only building." >> $GITHUB_STEP_SUMMARY if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any == 0 }} - id: run-some - name: "Report running some checks" + name: "Report on running checks (no prior run found)" run: | echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0}} From 54ad2b63b6a7cced4ae7ec85b40ce443520f59e0 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 13:41:12 -0700 Subject: [PATCH 047/142] Fix quotation problem --- .github/scripts/check-diff.sh | 2 +- .github/workflows/check-diff.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/check-diff.sh b/.github/scripts/check-diff.sh index 5be32c9c17..dad8d5c909 100755 --- a/.github/scripts/check-diff.sh +++ b/.github/scripts/check-diff.sh @@ -4,7 +4,7 @@ changes() { git diff --name-only HEAD $(git merge-base HEAD origin/master) } -if changes | grep $1 | grep -q -v '^.*md\|txt$'; then +if changes | grep "$1" | grep -q -v "^.*md\|txt$"; then echo "changed_$2=1" >> $GITHUB_OUTPUT else echo "changed_$2=0" >> $GITHUB_OUTPUT diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 2859713497..5e933733f0 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -59,7 +59,7 @@ jobs: ./check-diff.sh "lflang/generator/rust\|resources/lib/rs\|test/Rust" rs ./check-diff.sh "lflang/generator/ts\|resources/lib/ts\|test/TypeScript" ts ./check-diff.sh "util/tracing" tracing - ./check-diff.sh "" any + ./check-diff.sh ".*" any shell: bash working-directory: .github/scripts - id: summarize From b0430fe81bbbde732882eecc746e04da13b6b401 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 14:55:19 -0700 Subject: [PATCH 048/142] Do not skip checks upon ready_for_review event --- .github/workflows/check-diff.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 5e933733f0..32c8dc4b20 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -66,29 +66,33 @@ jobs: name: "Create summary" run: | echo '## Summary' > $GITHUB_STEP_SUMMARY + - id: should-skip + name: "Determine whether to skip checks" + run: | + echo "skip=${{ steps.duplicate.outputs.should_skip == 'true' && github.event.action != 'ready_for_review' }}" >> $GITHUB_OUTPUT - id: skip-redundant name: "Report on skipping checks (prior run found)" run: | echo ":tada: A successful prior run has been found:" >> $GITHUB_STEP_SUMMARY echo "${{ steps.duplicate.outputs.skipped_by }}" >> $GITHUB_STEP_SUMMARY echo ":heavy_check_mark: Skipping all tests." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip == 'true' }} + if: ${{ steps.should-skip.outputs.skip == 'true' }} - id: skip-ignore name: "Report skipping checks due to inconsequential changes" run: | echo ":octopus: The detected changes did not affect any code." >> $GITHUB_STEP_SUMMARY echo ":heavy_check_mark: Skipping tests. Only building." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any == 0 }} + if: ${{ steps.should-skip.outputs.skip != 'true' && steps.do.outputs.changed_any == 0 }} - id: run-some name: "Report on running checks (no prior run found)" run: | echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0}} + if: ${{ steps.should-skip.outputs.skip != 'true' && steps.do.outputs.changed_any != 0}} - id: run-ready-mode name: 'Report on full test run' run: | echo ":hourglass: Performing all tests." >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0 && !github.event.pull_request.draft}} + if: ${{ steps.should-skip.outputs.skip != 'true' && steps.do.outputs.changed_any != 0 && !github.event.pull_request.draft}} - id: run-draft-mode name: 'Report on partial test run' run: | @@ -101,4 +105,4 @@ jobs: echo '| rs | `${{ steps.do.outputs.changed_rs == 1 }}` |' >> $GITHUB_STEP_SUMMARY echo '| ts | `${{ steps.do.outputs.changed_ts == 1 }}` |' >> $GITHUB_STEP_SUMMARY echo '| tracing | `${{ steps.do.outputs.changed_tracing == 1 }}` |' >> $GITHUB_STEP_SUMMARY - if: ${{ steps.duplicate.outputs.should_skip != 'true' && steps.do.outputs.changed_any != 0 && github.event.pull_request.draft}} + if: ${{ steps.should-skip.outputs.skip != 'true' && steps.do.outputs.changed_any != 0 && github.event.pull_request.draft}} From ad83284fa99d15444a187341b4bdc78bd6804c51 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 14:57:50 -0700 Subject: [PATCH 049/142] Bugfix --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 32c8dc4b20..f122db7d3c 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -32,7 +32,7 @@ jobs: check: runs-on: ubuntu-latest outputs: - skip: ${{ steps.duplicate.outputs.should_skip == 'true' }} + skip: ${{ steps.should-skip.outputs.skip == 'true' }} run_c: ${{ steps.do.outputs.changed_c == 1 || !github.event.pull_request.draft }} run_cpp: ${{ steps.do.outputs.changed_cpp == 1 || !github.event.pull_request.draft }} run_misc: ${{ steps.do.outputs.changed_any == 1 || !github.event.pull_request.draft }} From 6ba9ca8d1dfc21bf3f7c24bf1181d442e6779e51 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 15:03:58 -0700 Subject: [PATCH 050/142] Wording --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index f122db7d3c..f455692275 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -96,7 +96,7 @@ jobs: - id: run-draft-mode name: 'Report on partial test run' run: | - echo ":hourglass: Performing tests affected by detected changes." >> $GITHUB_STEP_SUMMARY + echo ":hourglass: Performing tests potentially affected by detected changes." >> $GITHUB_STEP_SUMMARY echo '| | running |' >> $GITHUB_STEP_SUMMARY echo '|---------|-------------------------------------------|' >> $GITHUB_STEP_SUMMARY echo '| c | `${{ steps.do.outputs.changed_c == 1 }}` |' >> $GITHUB_STEP_SUMMARY From 53d0a68da299201fd23180f7e18d817bea03f56f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 15:17:17 -0700 Subject: [PATCH 051/142] Wording --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index f455692275..55f5f404e8 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -86,7 +86,7 @@ jobs: - id: run-some name: "Report on running checks (no prior run found)" run: | - echo ":octopus: No successful prior run has been found." >> $GITHUB_STEP_SUMMARY + echo ":octopus: No (complete) successful prior run has been found." >> $GITHUB_STEP_SUMMARY if: ${{ steps.should-skip.outputs.skip != 'true' && steps.do.outputs.changed_any != 0}} - id: run-ready-mode name: 'Report on full test run' From 24dede8d8a4603643c48e5667ee21fe6a7126a63 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Jun 2023 16:23:10 -0700 Subject: [PATCH 052/142] Point to main branch for benchmarks --- .github/workflows/only-c.yml | 2 +- .github/workflows/only-cpp.yml | 2 +- .github/workflows/only-rs.yml | 2 +- .github/workflows/only-ts.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/only-c.yml b/.github/workflows/only-c.yml index 2d12dd9da8..9b457b6d01 100644 --- a/.github/workflows/only-c.yml +++ b/.github/workflows/only-c.yml @@ -21,7 +21,7 @@ jobs: # Run the C benchmark tests. benchmarking: - uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@gradle + uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: "C" diff --git a/.github/workflows/only-cpp.yml b/.github/workflows/only-cpp.yml index fdac226930..b30f079657 100644 --- a/.github/workflows/only-cpp.yml +++ b/.github/workflows/only-cpp.yml @@ -15,7 +15,7 @@ concurrency: jobs: # Run the C++ benchmark tests. cpp-benchmark-tests: - uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@gradle + uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: "Cpp" diff --git a/.github/workflows/only-rs.yml b/.github/workflows/only-rs.yml index ef3f31e7d9..149978d820 100644 --- a/.github/workflows/only-rs.yml +++ b/.github/workflows/only-rs.yml @@ -21,6 +21,6 @@ jobs: # Run the Rust benchmark tests. rs-benchmark-tests: - uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@gradle + uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: "Rust" diff --git a/.github/workflows/only-ts.yml b/.github/workflows/only-ts.yml index 131c06ab17..0059a4ec49 100644 --- a/.github/workflows/only-ts.yml +++ b/.github/workflows/only-ts.yml @@ -15,7 +15,7 @@ concurrency: jobs: # Run the TypeScript benchmark tests. benchmarking: - uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@gradle + uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main with: target: "TS" From 0f32bc9a18e2a7401e5357fc4305a4e1893af496 Mon Sep 17 00:00:00 2001 From: Alexander Schulz-Rosengarten Date: Thu, 1 Jun 2023 10:31:00 +0200 Subject: [PATCH 053/142] Added annotation to influence port side or switch to free port placement --- .../main/java/org/lflang/AttributeUtils.java | 5 + .../synthesis/LinguaFrancaSynthesis.java | 96 +++++++--- .../synthesis/SynthesisRegistration.java | 12 +- .../postprocessor/ReactionPortAdjustment.java | 7 +- .../styles/LinguaFrancaShapeExtensions.java | 14 +- .../org/lflang/validation/AttributeSpec.java | 4 + .../postprocessor/ReactorPortAdjustment.java | 172 ++++++++++++++++++ 7 files changed, 270 insertions(+), 40 deletions(-) create mode 100644 org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index ec7a59b13a..2b35571c6b 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -239,6 +239,11 @@ public static String getLabel(EObject node) { public static String getIconPath(EObject node) { return getAttributeValue(node, "icon"); } + + /** Return the declared side of the port, as given by the @side annotation. */ + public static String getPortSide(EObject node) { + return getAttributeValue(node, "side"); + } /** * Return the {@code @enclave} attribute annotated on the given node. diff --git a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java index 45f3342a0a..cdea160a53 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java @@ -102,6 +102,7 @@ import org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction; import org.lflang.diagram.synthesis.action.ShowCycleAction; import org.lflang.diagram.synthesis.postprocessor.ReactionPortAdjustment; +import org.lflang.diagram.synthesis.postprocessor.ReactorPortAdjustment; import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; import org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions; import org.lflang.diagram.synthesis.styles.ReactorFigureComponents; @@ -163,6 +164,8 @@ public class LinguaFrancaSynthesis extends AbstractDiagramSynthesis { "org.lflang.linguafranca.diagram.synthesis.reactor.recursive.instantiation", false); public static final Property REACTOR_HAS_BANK_PORT_OFFSET = new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.bank.offset", false); + public static final Property REACTOR_MULTIPORT = + new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.multiport", false); public static final Property REACTOR_INPUT = new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.input", false); public static final Property REACTOR_OUTPUT = @@ -244,6 +247,8 @@ public class LinguaFrancaSynthesis extends AbstractDiagramSynthesis { SynthesisOption.createRangeOption("Reactor Parameter/Variable Columns", 1, 10, 1) .setCategory(APPEARANCE); + public static final SynthesisOption FIXED_PORT_SIDE = + SynthesisOption.createCheckOption("Fixed Port Sides", true).setCategory(LAYOUT); public static final SynthesisOption SPACING = SynthesisOption.createRangeOption("Spacing (%)", 0, 150, 5, 75).setCategory(LAYOUT); @@ -280,6 +285,7 @@ public List getDisplayedSynthesisOptions() { SHOW_STATE_VARIABLES, REACTOR_BODY_TABLE_COLS, LAYOUT, + FIXED_PORT_SIDE, LayoutPostProcessing.MODEL_ORDER, SPACING); } @@ -481,6 +487,11 @@ private Collection createReactorNode( _kRenderingExtensions.addDoubleClickAction(figure, MemorizingExpandCollapseAction.ID); } _reactorIcons.handleIcon(comps.getReactor(), reactor, false); + + if (!getBooleanValue(FIXED_PORT_SIDE)) { + // Port figures will need post-processing to fix IO indication if portside is not fixed + ReactorPortAdjustment.apply(node, comps.getFigures()); + } if (getBooleanValue(SHOW_HYPERLINKS)) { // Collapse button @@ -607,6 +618,11 @@ private Collection createReactorNode( } } _reactorIcons.handleIcon(comps.getReactor(), reactor, true); + + if (!getBooleanValue(FIXED_PORT_SIDE)) { + // Port figures will need post-processing to fix IO indication if portside is not fixed + ReactorPortAdjustment.apply(node, comps.getFigures()); + } if (getBooleanValue(SHOW_HYPERLINKS)) { // Expand button @@ -728,16 +744,24 @@ public KNode configureReactorNodeLayout(KNode node, boolean main) { node, CoreOptions.NODE_SIZE_CONSTRAINTS, EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.PORTS)); - - // Allows to freely shuffle ports on each side - setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE); - // Adjust port label spacing to be closer to edge but not overlap with port figure - // TODO: Add PortLabelPlacement.NEXT_TO_PORT_IF_POSSIBLE back into the configuration, as soon as - // ELK provides a fix for LF issue #1273 + + + if (getBooleanValue(FIXED_PORT_SIDE)) { + // Allows to freely shuffle ports on each side + setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE); + } else { + // Ports are no longer fixed based on input or output + setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FREE); + } + setLayoutOption( node, CoreOptions.PORT_LABELS_PLACEMENT, EnumSet.of(PortLabelPlacement.ALWAYS_OTHER_SAME_SIDE, PortLabelPlacement.OUTSIDE)); + // TODO: Add PortLabelPlacement.NEXT_TO_PORT_IF_POSSIBLE back into the configuration, as soon as + // ELK provides a fix for LF issue #1273 + + // Adjust port label spacing to be closer to edge but not overlap with port figure setLayoutOption(node, CoreOptions.SPACING_LABEL_PORT_HORIZONTAL, 2.0); setLayoutOption(node, CoreOptions.SPACING_LABEL_PORT_VERTICAL, -3.0); @@ -1034,8 +1058,8 @@ private Collection transformReactorNetwork( int outputSize = reaction.effects.size(); if (!getBooleanValue(REACTIONS_USE_HYPEREDGES) && (inputSize > 1 || outputSize > 1)) { // If this node will have more than one input/output port, the port positions must be - // adjusted to the - // pointy shape. However, this is only possible after the layout. + // adjusted to the pointy shape. + // However, this is only possible after the layout. ReactionPortAdjustment.apply(node, figure); } @@ -1577,27 +1601,32 @@ private KEdge connect(KEdge edge, KPort src, KPort dst) { } /** Translate an input/output into a port. */ - private KPort addIOPort( - KNode node, PortInstance lfPort, boolean input, boolean multiport, boolean bank) { + private KPort addIOPort(KNode node, PortInstance lfPort, + boolean input, boolean multiport, boolean bank) { KPort port = _kPortExtensions.createPort(); node.getPorts().add(port); associateWith(port, lfPort.getDefinition()); NamedInstanceUtil.linkInstance(port, lfPort); _kPortExtensions.setPortSize(port, 6, 6); - - if (input) { - // multiports are smaller by an offset at the right, hence compensate in inputs - double offset = multiport ? -3.4 : -3.3; - setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST); - setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, offset); - } else { - double offset = multiport ? -2.6 : -3.3; // multiports are smaller - offset = - bank - ? offset - LinguaFrancaShapeExtensions.BANK_FIGURE_X_OFFSET_SUM - : offset; // compensate bank figure width - setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.EAST); - setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, offset); + + var side = input ? PortSide.WEST : PortSide.EAST; + var userSideAttr = AttributeUtils.getPortSide(lfPort.getDefinition()); + if (userSideAttr != null) { + try { + var userSide = PortSide.valueOf(userSideAttr.toUpperCase()); + if (userSide != null) { + side = userSide; + } + } catch(Exception e) { + // ignore and use default + } + } + double offset = getReactorPortOffset(side == PortSide.WEST, multiport, bank); + setLayoutOption(port, CoreOptions.PORT_SIDE, side); + setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, offset); + + if (multiport) { + node.setProperty(REACTOR_MULTIPORT, true); } if (bank && !node.getProperty(REACTOR_HAS_BANK_PORT_OFFSET)) { // compensate bank figure height @@ -1608,7 +1637,9 @@ private KPort addIOPort( node.setProperty(REACTOR_HAS_BANK_PORT_OFFSET, true); // only once } - _linguaFrancaShapeExtensions.addTrianglePort(port, multiport); + // If fixed port sides are active and the port is put on the opposite side, reverse it + var reverse = getBooleanValue(FIXED_PORT_SIDE) && input != (side == PortSide.WEST); + _linguaFrancaShapeExtensions.addTrianglePort(port, multiport, reverse); String label = lfPort.getName(); if (!getBooleanValue(SHOW_PORT_NAMES)) { @@ -1622,6 +1653,21 @@ private KPort addIOPort( associateWith(_kLabelExtensions.addOutsidePortLabel(port, label, 8), lfPort.getDefinition()); return port; } + + public static double getReactorPortOffset(boolean sideLeft, boolean multiport, boolean bank) { + var offset = -3.3; + + if (multiport) { + offset = sideLeft ? -3.4 : -2.6; + } + + if (bank && !sideLeft) { + // compensate bank figure width + offset -= LinguaFrancaShapeExtensions.BANK_FIGURE_X_OFFSET_SUM; + } + + return offset; + } private KPort addInvisiblePort(KNode node) { KPort port = _kPortExtensions.createPort(); diff --git a/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java b/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java index c48d2e59ee..bf78f2862d 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java @@ -1,17 +1,19 @@ package org.lflang.diagram.synthesis; -import de.cau.cs.kieler.klighd.IKlighdStartupHook; -import de.cau.cs.kieler.klighd.KlighdDataManager; import org.lflang.diagram.synthesis.action.CollapseAllReactorsAction; import org.lflang.diagram.synthesis.action.ExpandAllReactorsAction; import org.lflang.diagram.synthesis.action.FilterCycleAction; import org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction; import org.lflang.diagram.synthesis.action.ShowCycleAction; import org.lflang.diagram.synthesis.postprocessor.ReactionPortAdjustment; +import org.lflang.diagram.synthesis.postprocessor.ReactorPortAdjustment; import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; import org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions; import org.lflang.diagram.synthesis.util.NamedInstanceUtil; +import de.cau.cs.kieler.klighd.IKlighdStartupHook; +import de.cau.cs.kieler.klighd.KlighdDataManager; + /** * Registration of all diagram synthesis related classes in Klighd. * @@ -35,6 +37,7 @@ public void execute() { // Style Mod reg.registerStyleModifier(ReactionPortAdjustment.ID, new ReactionPortAdjustment()); + reg.registerStyleModifier(ReactorPortAdjustment.ID, new ReactorPortAdjustment()); // Blacklist LF-specific properties that should be removed when a diagram is sent from the // diagram server to a client. @@ -46,8 +49,7 @@ public void execute() { reg.registerBlacklistedProperty(ReactionPortAdjustment.PROCESSED); reg.registerBlacklistedProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER); reg.registerBlacklistedProperty(LinguaFrancaStyleExtensions.LABEL_PARENT_BACKGROUND); - reg.registerBlacklistedProperty( - NamedInstanceUtil - .LINKED_INSTANCE); // Very important since its values can not be synthesized easily! + // Very important since its values can not be synthesized easily! + reg.registerBlacklistedProperty(NamedInstanceUtil.LINKED_INSTANCE); } } diff --git a/core/src/main/java/org/lflang/diagram/synthesis/postprocessor/ReactionPortAdjustment.java b/core/src/main/java/org/lflang/diagram/synthesis/postprocessor/ReactionPortAdjustment.java index 4507039b28..64c517a336 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/postprocessor/ReactionPortAdjustment.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/postprocessor/ReactionPortAdjustment.java @@ -66,9 +66,10 @@ public class ReactionPortAdjustment implements IStyleModifier { public static void apply(KNode node, KRendering rendering) { // Add modifier that fixes port positions such that edges are properly attached to the shape var invisible = _kRenderingFactory.createKInvisibility(); - invisible.setInvisible(false); // make it ineffective (just for purpose of holding modifier) - invisible.setModifierId( - ReactionPortAdjustment.ID); // Add modifier to receive callback after layout + // make it ineffective (just for purpose of holding modifier) + invisible.setInvisible(false); + // Add modifier to receive callback after layout + invisible.setModifierId(ReactionPortAdjustment.ID); rendering.getStyles().add(invisible); node.setProperty(PROCESSED, false); } diff --git a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java index efdc2ff4d5..3d7d45e86b 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java @@ -802,7 +802,7 @@ public KEllipse addResetFigure(KNode node) { } /** Creates the visual representation of a reactor port. */ - public KPolygon addTrianglePort(KPort port, boolean multiport) { + public KPolygon addTrianglePort(KPort port, boolean multiport, boolean reverse) { port.setSize(8, 8); // Create triangle port @@ -822,15 +822,15 @@ public KPolygon addTrianglePort(KPort port, boolean multiport) { // between parallel connections pointsToAdd = List.of( - _kRenderingExtensions.createKPosition(LEFT, 0, 0, TOP, 0.6f, 0), - _kRenderingExtensions.createKPosition(RIGHT, 1.2f, 0, TOP, 0, 0.5f), - _kRenderingExtensions.createKPosition(LEFT, 0, 0, BOTTOM, 0.6f, 0)); + _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, TOP, 0.6f, 0), + _kRenderingExtensions.createKPosition(reverse ? LEFT: RIGHT, 1.2f, 0, TOP, 0, 0.5f), + _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, BOTTOM, 0.6f, 0)); } else { pointsToAdd = List.of( - _kRenderingExtensions.createKPosition(LEFT, 0, 0, TOP, 0, 0), - _kRenderingExtensions.createKPosition(RIGHT, 0, 0, TOP, 0, 0.5f), - _kRenderingExtensions.createKPosition(LEFT, 0, 0, BOTTOM, 0, 0)); + _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, TOP, 0, 0), + _kRenderingExtensions.createKPosition(reverse ? LEFT: RIGHT, 0, 0, TOP, 0, 0.5f), + _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, BOTTOM, 0, 0)); } trianglePort.getPoints().addAll(pointsToAdd); return trianglePort; diff --git a/core/src/main/java/org/lflang/validation/AttributeSpec.java b/core/src/main/java/org/lflang/validation/AttributeSpec.java index dd9bbac9e2..6f2d31e222 100644 --- a/core/src/main/java/org/lflang/validation/AttributeSpec.java +++ b/core/src/main/java/org/lflang/validation/AttributeSpec.java @@ -211,6 +211,10 @@ enum AttrParamType { ATTRIBUTE_SPECS_BY_NAME.put( "icon", new AttributeSpec(List.of(new AttrParamSpec(VALUE_ATTR, AttrParamType.STRING, false)))); + // @side("value") + ATTRIBUTE_SPECS_BY_NAME.put( + "side", + new AttributeSpec(List.of(new AttrParamSpec(VALUE_ATTR, AttrParamType.STRING, false)))); // @enclave(each=boolean) ATTRIBUTE_SPECS_BY_NAME.put( "enclave", diff --git a/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java b/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java new file mode 100644 index 0000000000..3548fd5aa1 --- /dev/null +++ b/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java @@ -0,0 +1,172 @@ +/************* + * Copyright (c) 2023, Kiel University. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************/ +package org.lflang.diagram.synthesis.postprocessor; + +import java.util.List; + +import javax.inject.Inject; + +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.graph.properties.Property; +import org.eclipse.xtext.xbase.lib.Extension; +import org.lflang.diagram.synthesis.LinguaFrancaSynthesis; +import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; + +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; + +import de.cau.cs.kieler.klighd.IStyleModifier; +import de.cau.cs.kieler.klighd.IViewer; +import de.cau.cs.kieler.klighd.internal.ILayoutRecorder; +import de.cau.cs.kieler.klighd.kgraph.KGraphElement; +import de.cau.cs.kieler.klighd.kgraph.KGraphFactory; +import de.cau.cs.kieler.klighd.kgraph.KNode; +import de.cau.cs.kieler.klighd.krendering.KRendering; +import de.cau.cs.kieler.klighd.krendering.KRenderingFactory; +import de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared; +import de.cau.cs.kieler.klighd.syntheses.AbstractDiagramSynthesis; + +/** + * Adjusts the port figures of reactors when fixed side are off to keep the input output indication correct. + * + * @author Alexander Schulz-Rosengarten + */ +public class ReactorPortAdjustment implements IStyleModifier { + + public static final String ID = + "org.lflang.diagram.synthesis.postprocessor.ReactorPortAdjustment"; + + /** INTERNAL property to mark node as flipped. */ + public static final Property FLIPPED = + new Property<>("org.lflang.diagram.synthesis.postprocessor.reactor.ports.flipped", false); + + @Inject @Extension private LinguaFrancaShapeExtensions _linguaFrancaShapeExtensions; + @Extension private KGraphFactory _kGraphFactory = KGraphFactory.eINSTANCE; + private static KRenderingFactory _kRenderingFactory = KRenderingFactory.eINSTANCE; + + /** Register this modifier on a reaction rendering. */ + public static void apply(KNode node, List renderings) { + var rendering = renderings.get(0); // Get first in bank + // Add modifier that fixes port positions such that edges are properly attached to the shape + var invisible = _kRenderingFactory.createKRotation(); + // make it ineffective (just for purpose of holding modifier) + invisible.setRotation(0); + // Add modifier to receive callback after layout + invisible.setModifierId(ID); + rendering.getStyles().add(invisible); + } + + public ReactorPortAdjustment() { + // Inject extension + if (_linguaFrancaShapeExtensions == null) { + var injector = Guice.createInjector(new com.google.inject.Module() { + // This Module is created to satisfy ViewSynthesisShared scope of used synthesis-extensions + public void configure(Binder binder) { + binder.bindScope(ViewSynthesisShared.class, Scopes.SINGLETON); + binder.bind(new TypeLiteral>(){}).toInstance(new LinguaFrancaSynthesis()); + } + }); + _linguaFrancaShapeExtensions = injector.getInstance(LinguaFrancaShapeExtensions.class); + } + } + + @Override + public boolean modify(IStyleModifier.StyleModificationContext context) { + try { + KGraphElement node = context.getGraphElement(); + if (node instanceof KNode) { + KNode knode = (KNode) node; + + // Find root node + KNode parent = knode; + while (parent.eContainer() != null) { + parent = (KNode) parent.eContainer(); + } + + // Get viewer (this is a bit brittle because it fetches the viewer from some internal + // property) + Object viewer = + parent.getAllProperties().entrySet().stream() + .filter( + entry -> + entry.getKey().getId().equals("de.cau.cs.kieler.klighd.viewer") + || entry.getKey().getId().equals("klighd.layout.viewer")) + .findAny() + .map(entry -> entry.getValue()) + .orElse(null); + + ILayoutRecorder recorder = null; + if (viewer instanceof IViewer) { + recorder = ((IViewer) viewer).getViewContext().getLayoutRecorder(); + } + + if (recorder != null) { + recorder.startRecording(); + } + for (var port : knode.getPorts()) { + var isInput = port.getProperty(LinguaFrancaSynthesis.REACTOR_INPUT).booleanValue(); + if (!isInput && !port.getProperty(LinguaFrancaSynthesis.REACTOR_OUTPUT)) { + continue; // skip + } + + var xPos = port.getXpos(); + var isLeft = xPos < 0; + var flip = isInput != isLeft; + var isFlipped = port.getProperty(FLIPPED).booleanValue(); + var needsUpdate = flip != isFlipped; + + if (needsUpdate) { + // Remove figure + port.getData().removeIf(it -> it instanceof KRendering); + + // Get port type + var isMultiport = port.getProperty(LinguaFrancaSynthesis.REACTOR_MULTIPORT); + var isBank = port.getProperty(LinguaFrancaSynthesis.REACTOR_HAS_BANK_PORT_OFFSET); + + // Add new figure + _linguaFrancaShapeExtensions.addTrianglePort(port, isMultiport, flip); + port.setProperty(FLIPPED, flip); + + // Compute new offset + var oldOffset = port.getProperty(CoreOptions.PORT_BORDER_OFFSET); + var newOffset = LinguaFrancaSynthesis.getReactorPortOffset(!isLeft, isMultiport, isBank); + + // Apply offset directly + port.setPos((float) (port.getXpos() + (oldOffset - newOffset)), port.getYpos()); + } + } + if (recorder != null) { + recorder.stopRecording(0); + } + } + } catch (Exception e) { + e.printStackTrace(); + // do not disturb rendering process + } + return false; + } +} From 58c15fdfb9ef78a6d5d0454a45011e187f085849 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 1 Jun 2023 15:41:53 -0700 Subject: [PATCH 054/142] Apply formatter. --- .../main/java/org/lflang/AttributeUtils.java | 2 +- .../synthesis/LinguaFrancaSynthesis.java | 39 ++++++------ .../synthesis/SynthesisRegistration.java | 7 +-- .../styles/LinguaFrancaShapeExtensions.java | 4 +- .../postprocessor/ReactorPortAdjustment.java | 61 ++++++++++--------- 5 files changed, 57 insertions(+), 56 deletions(-) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 2b35571c6b..73756c11ed 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -239,7 +239,7 @@ public static String getLabel(EObject node) { public static String getIconPath(EObject node) { return getAttributeValue(node, "icon"); } - + /** Return the declared side of the port, as given by the @side annotation. */ public static String getPortSide(EObject node) { return getAttributeValue(node, "side"); diff --git a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java index cdea160a53..060e73507d 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java @@ -165,7 +165,7 @@ public class LinguaFrancaSynthesis extends AbstractDiagramSynthesis { public static final Property REACTOR_HAS_BANK_PORT_OFFSET = new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.bank.offset", false); public static final Property REACTOR_MULTIPORT = - new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.multiport", false); + new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.multiport", false); public static final Property REACTOR_INPUT = new Property<>("org.lflang.linguafranca.diagram.synthesis.reactor.input", false); public static final Property REACTOR_OUTPUT = @@ -247,8 +247,8 @@ public class LinguaFrancaSynthesis extends AbstractDiagramSynthesis { SynthesisOption.createRangeOption("Reactor Parameter/Variable Columns", 1, 10, 1) .setCategory(APPEARANCE); - public static final SynthesisOption FIXED_PORT_SIDE = - SynthesisOption.createCheckOption("Fixed Port Sides", true).setCategory(LAYOUT); + public static final SynthesisOption FIXED_PORT_SIDE = + SynthesisOption.createCheckOption("Fixed Port Sides", true).setCategory(LAYOUT); public static final SynthesisOption SPACING = SynthesisOption.createRangeOption("Spacing (%)", 0, 150, 5, 75).setCategory(LAYOUT); @@ -487,7 +487,7 @@ private Collection createReactorNode( _kRenderingExtensions.addDoubleClickAction(figure, MemorizingExpandCollapseAction.ID); } _reactorIcons.handleIcon(comps.getReactor(), reactor, false); - + if (!getBooleanValue(FIXED_PORT_SIDE)) { // Port figures will need post-processing to fix IO indication if portside is not fixed ReactorPortAdjustment.apply(node, comps.getFigures()); @@ -618,7 +618,7 @@ private Collection createReactorNode( } } _reactorIcons.handleIcon(comps.getReactor(), reactor, true); - + if (!getBooleanValue(FIXED_PORT_SIDE)) { // Port figures will need post-processing to fix IO indication if portside is not fixed ReactorPortAdjustment.apply(node, comps.getFigures()); @@ -744,8 +744,7 @@ public KNode configureReactorNodeLayout(KNode node, boolean main) { node, CoreOptions.NODE_SIZE_CONSTRAINTS, EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.PORTS)); - - + if (getBooleanValue(FIXED_PORT_SIDE)) { // Allows to freely shuffle ports on each side setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE); @@ -753,14 +752,14 @@ public KNode configureReactorNodeLayout(KNode node, boolean main) { // Ports are no longer fixed based on input or output setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FREE); } - + setLayoutOption( node, CoreOptions.PORT_LABELS_PLACEMENT, EnumSet.of(PortLabelPlacement.ALWAYS_OTHER_SAME_SIDE, PortLabelPlacement.OUTSIDE)); // TODO: Add PortLabelPlacement.NEXT_TO_PORT_IF_POSSIBLE back into the configuration, as soon as // ELK provides a fix for LF issue #1273 - + // Adjust port label spacing to be closer to edge but not overlap with port figure setLayoutOption(node, CoreOptions.SPACING_LABEL_PORT_HORIZONTAL, 2.0); setLayoutOption(node, CoreOptions.SPACING_LABEL_PORT_VERTICAL, -3.0); @@ -1601,30 +1600,30 @@ private KEdge connect(KEdge edge, KPort src, KPort dst) { } /** Translate an input/output into a port. */ - private KPort addIOPort(KNode node, PortInstance lfPort, - boolean input, boolean multiport, boolean bank) { + private KPort addIOPort( + KNode node, PortInstance lfPort, boolean input, boolean multiport, boolean bank) { KPort port = _kPortExtensions.createPort(); node.getPorts().add(port); associateWith(port, lfPort.getDefinition()); NamedInstanceUtil.linkInstance(port, lfPort); _kPortExtensions.setPortSize(port, 6, 6); - + var side = input ? PortSide.WEST : PortSide.EAST; var userSideAttr = AttributeUtils.getPortSide(lfPort.getDefinition()); if (userSideAttr != null) { try { var userSide = PortSide.valueOf(userSideAttr.toUpperCase()); if (userSide != null) { - side = userSide; + side = userSide; } - } catch(Exception e) { + } catch (Exception e) { // ignore and use default } } double offset = getReactorPortOffset(side == PortSide.WEST, multiport, bank); setLayoutOption(port, CoreOptions.PORT_SIDE, side); setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, offset); - + if (multiport) { node.setProperty(REACTOR_MULTIPORT, true); } @@ -1653,19 +1652,19 @@ private KPort addIOPort(KNode node, PortInstance lfPort, associateWith(_kLabelExtensions.addOutsidePortLabel(port, label, 8), lfPort.getDefinition()); return port; } - + public static double getReactorPortOffset(boolean sideLeft, boolean multiport, boolean bank) { var offset = -3.3; - + if (multiport) { - offset = sideLeft ? -3.4 : -2.6; + offset = sideLeft ? -3.4 : -2.6; } - + if (bank && !sideLeft) { // compensate bank figure width offset -= LinguaFrancaShapeExtensions.BANK_FIGURE_X_OFFSET_SUM; } - + return offset; } diff --git a/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java b/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java index bf78f2862d..577e0c26ba 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/SynthesisRegistration.java @@ -1,5 +1,7 @@ package org.lflang.diagram.synthesis; +import de.cau.cs.kieler.klighd.IKlighdStartupHook; +import de.cau.cs.kieler.klighd.KlighdDataManager; import org.lflang.diagram.synthesis.action.CollapseAllReactorsAction; import org.lflang.diagram.synthesis.action.ExpandAllReactorsAction; import org.lflang.diagram.synthesis.action.FilterCycleAction; @@ -11,9 +13,6 @@ import org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions; import org.lflang.diagram.synthesis.util.NamedInstanceUtil; -import de.cau.cs.kieler.klighd.IKlighdStartupHook; -import de.cau.cs.kieler.klighd.KlighdDataManager; - /** * Registration of all diagram synthesis related classes in Klighd. * @@ -50,6 +49,6 @@ public void execute() { reg.registerBlacklistedProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER); reg.registerBlacklistedProperty(LinguaFrancaStyleExtensions.LABEL_PARENT_BACKGROUND); // Very important since its values can not be synthesized easily! - reg.registerBlacklistedProperty(NamedInstanceUtil.LINKED_INSTANCE); + reg.registerBlacklistedProperty(NamedInstanceUtil.LINKED_INSTANCE); } } diff --git a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java index 3d7d45e86b..b8ee69fa1c 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java @@ -823,13 +823,13 @@ public KPolygon addTrianglePort(KPort port, boolean multiport, boolean reverse) pointsToAdd = List.of( _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, TOP, 0.6f, 0), - _kRenderingExtensions.createKPosition(reverse ? LEFT: RIGHT, 1.2f, 0, TOP, 0, 0.5f), + _kRenderingExtensions.createKPosition(reverse ? LEFT : RIGHT, 1.2f, 0, TOP, 0, 0.5f), _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, BOTTOM, 0.6f, 0)); } else { pointsToAdd = List.of( _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, TOP, 0, 0), - _kRenderingExtensions.createKPosition(reverse ? LEFT: RIGHT, 0, 0, TOP, 0, 0.5f), + _kRenderingExtensions.createKPosition(reverse ? LEFT : RIGHT, 0, 0, TOP, 0, 0.5f), _kRenderingExtensions.createKPosition(reverse ? RIGHT : LEFT, 0, 0, BOTTOM, 0, 0)); } trianglePort.getPoints().addAll(pointsToAdd); diff --git a/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java b/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java index 3548fd5aa1..315eb0ebf4 100644 --- a/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java +++ b/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java @@ -24,21 +24,10 @@ ***************/ package org.lflang.diagram.synthesis.postprocessor; -import java.util.List; - -import javax.inject.Inject; - -import org.eclipse.elk.core.options.CoreOptions; -import org.eclipse.elk.graph.properties.Property; -import org.eclipse.xtext.xbase.lib.Extension; -import org.lflang.diagram.synthesis.LinguaFrancaSynthesis; -import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; - import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; - import de.cau.cs.kieler.klighd.IStyleModifier; import de.cau.cs.kieler.klighd.IViewer; import de.cau.cs.kieler.klighd.internal.ILayoutRecorder; @@ -49,9 +38,17 @@ import de.cau.cs.kieler.klighd.krendering.KRenderingFactory; import de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared; import de.cau.cs.kieler.klighd.syntheses.AbstractDiagramSynthesis; +import java.util.List; +import javax.inject.Inject; +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.graph.properties.Property; +import org.eclipse.xtext.xbase.lib.Extension; +import org.lflang.diagram.synthesis.LinguaFrancaSynthesis; +import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; /** - * Adjusts the port figures of reactors when fixed side are off to keep the input output indication correct. + * Adjusts the port figures of reactors when fixed side are off to keep the input output indication + * correct. * * @author Alexander Schulz-Rosengarten */ @@ -63,7 +60,7 @@ public class ReactorPortAdjustment implements IStyleModifier { /** INTERNAL property to mark node as flipped. */ public static final Property FLIPPED = new Property<>("org.lflang.diagram.synthesis.postprocessor.reactor.ports.flipped", false); - + @Inject @Extension private LinguaFrancaShapeExtensions _linguaFrancaShapeExtensions; @Extension private KGraphFactory _kGraphFactory = KGraphFactory.eINSTANCE; private static KRenderingFactory _kRenderingFactory = KRenderingFactory.eINSTANCE; @@ -79,17 +76,22 @@ public static void apply(KNode node, List renderings) { invisible.setModifierId(ID); rendering.getStyles().add(invisible); } - + public ReactorPortAdjustment() { // Inject extension if (_linguaFrancaShapeExtensions == null) { - var injector = Guice.createInjector(new com.google.inject.Module() { - // This Module is created to satisfy ViewSynthesisShared scope of used synthesis-extensions - public void configure(Binder binder) { - binder.bindScope(ViewSynthesisShared.class, Scopes.SINGLETON); - binder.bind(new TypeLiteral>(){}).toInstance(new LinguaFrancaSynthesis()); - } - }); + var injector = + Guice.createInjector( + new com.google.inject.Module() { + // This Module is created to satisfy ViewSynthesisShared scope of used + // synthesis-extensions + public void configure(Binder binder) { + binder.bindScope(ViewSynthesisShared.class, Scopes.SINGLETON); + binder + .bind(new TypeLiteral>() {}) + .toInstance(new LinguaFrancaSynthesis()); + } + }); _linguaFrancaShapeExtensions = injector.getInstance(LinguaFrancaShapeExtensions.class); } } @@ -130,31 +132,32 @@ public boolean modify(IStyleModifier.StyleModificationContext context) { for (var port : knode.getPorts()) { var isInput = port.getProperty(LinguaFrancaSynthesis.REACTOR_INPUT).booleanValue(); if (!isInput && !port.getProperty(LinguaFrancaSynthesis.REACTOR_OUTPUT)) { - continue; // skip + continue; // skip } - + var xPos = port.getXpos(); var isLeft = xPos < 0; var flip = isInput != isLeft; var isFlipped = port.getProperty(FLIPPED).booleanValue(); var needsUpdate = flip != isFlipped; - + if (needsUpdate) { // Remove figure port.getData().removeIf(it -> it instanceof KRendering); - + // Get port type var isMultiport = port.getProperty(LinguaFrancaSynthesis.REACTOR_MULTIPORT); var isBank = port.getProperty(LinguaFrancaSynthesis.REACTOR_HAS_BANK_PORT_OFFSET); - + // Add new figure _linguaFrancaShapeExtensions.addTrianglePort(port, isMultiport, flip); port.setProperty(FLIPPED, flip); - + // Compute new offset var oldOffset = port.getProperty(CoreOptions.PORT_BORDER_OFFSET); - var newOffset = LinguaFrancaSynthesis.getReactorPortOffset(!isLeft, isMultiport, isBank); - + var newOffset = + LinguaFrancaSynthesis.getReactorPortOffset(!isLeft, isMultiport, isBank); + // Apply offset directly port.setPos((float) (port.getXpos() + (oldOffset - newOffset)), port.getYpos()); } From 61dfa835c5e60baf88b9c375a69e846f3b906279 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 1 Jun 2023 23:24:38 -0700 Subject: [PATCH 055/142] Update org.lflang/src/org/lflang/AttributeUtils.java Co-authored-by: Edward A. Lee --- core/src/main/java/org/lflang/AttributeUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 73756c11ed..582e5a4b0a 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -240,7 +240,10 @@ public static String getIconPath(EObject node) { return getAttributeValue(node, "icon"); } - /** Return the declared side of the port, as given by the @side annotation. */ + /** + * Return the {@code @side} annotation for the given node (presumably a port) + * or null if there is no such annotation. + */ public static String getPortSide(EObject node) { return getAttributeValue(node, "side"); } From 5f967ba16ed6529fcdb7b8b8bbd15be4df811c61 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 6 Jun 2023 22:24:44 -0700 Subject: [PATCH 056/142] Fix formatting --- core/src/main/java/org/lflang/AttributeUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 582e5a4b0a..42d139e8f3 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -241,8 +241,8 @@ public static String getIconPath(EObject node) { } /** - * Return the {@code @side} annotation for the given node (presumably a port) - * or null if there is no such annotation. + * Return the {@code @side} annotation for the given node (presumably a port) or null if there is + * no such annotation. */ public static String getPortSide(EObject node) { return getAttributeValue(node, "side"); From 33cd91b66e8eb6b825b734fa67ccc38f11f94143 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 9 Jun 2023 13:47:32 -0700 Subject: [PATCH 057/142] Fix for #1834 --- util/tracing/visualization/fedsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index 36737fdebf..b463b21b05 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -141,7 +141,7 @@ def load_and_process_csv_file(csv_file) : fed_df['x1'] = x_coor[fed_id] # Append into trace_df - trace_df = trace_df.append(fed_df, sort=False, ignore_index=True) + trace_df = pd.concat([trace_df, fed_df]) fed_df = fed_df[0:0] # Sort all traces by physical time and then reset the index From efbc87ec3c9d18afd7b908bab56189d353504073 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 9 Jun 2023 14:02:16 -0700 Subject: [PATCH 058/142] Remove no more relevant FIXMEs --- util/tracing/visualization/fedsd.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index b463b21b05..07c5e93f89 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -53,15 +53,6 @@ help='List of the federates csv trace files.') -''' Clock synchronization error ''' -''' FIXME: There should be a value for each communicating pair ''' -clock_sync_error = 0 - -''' Bound on the network latency ''' -''' FIXME: There should be a value for each communicating pair ''' -network_latency = 100000000 # That is 100us - - def load_and_process_csv_file(csv_file) : ''' Loads and processes the csv entries, based on the type of the actor (if RTI @@ -148,11 +139,6 @@ def load_and_process_csv_file(csv_file) : trace_df = trace_df.sort_values(by=['physical_time']) trace_df = trace_df.reset_index(drop=True) - # FIXME: For now, we need to remove the rows with negative physical time values... - # Until the reason behinf such values is investigated. The negative physical - # time is when federates are still in the process of joining - # trace_df = trace_df[trace_df['physical_time'] >= 0] - # Add the Y column and initialize it with the padding value trace_df['y1'] = math.ceil(padding * 3 / 2) # Or set a small shift @@ -220,9 +206,7 @@ def load_and_process_csv_file(csv_file) : trace_df.loc[index, 'arrow'] = 'dot' else: # If there is one or more matching rows, then consider - # the first one, since it is an out -> in arrow, and - # since it is the closet in time - # FIXME: What other possible choices to consider? + # the first one if (inout == 'out'): matching_index = matching_df.index[0] matching_row = matching_df.loc[matching_index] From 5d33d6decd96dfea7509833aa2aaff785f26244b Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 9 Jun 2023 14:29:31 -0700 Subject: [PATCH 059/142] fedsd: Add support for physical connections matching --- util/tracing/visualization/fedsd.py | 35 +++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index 07c5e93f89..12656bf5fc 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -52,6 +52,10 @@ parser.add_argument('-f','--federates', nargs='+', action='append', help='List of the federates csv trace files.') +# Events matching at the sender and receiver ends depend on whether they are tagged +# (the elapsed logical time and microstep have to be the same) or not. +# Set of tagged events (messages) +non_tagged_messages = {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG'} def load_and_process_csv_file(csv_file) : ''' @@ -190,15 +194,25 @@ def load_and_process_csv_file(csv_file) : inout = trace_df.at[index, 'inout'] # Match tracepoints - matching_df = trace_df[\ - (trace_df['inout'] != inout) & \ - (trace_df['self_id'] == partner_id) & \ - (trace_df['partner_id'] == self_id) & \ - (trace_df['arrow'] == 'pending') & \ - (trace_df['event'] == event) & \ - (trace_df['logical_time'] == logical_time) & \ - (trace_df['microstep'] == microstep) \ - ] + # Depends on whether the event is tagged or not + if (trace_df.at[index,'event'] not in non_tagged_messages): + matching_df = trace_df[\ + (trace_df['inout'] != inout) & \ + (trace_df['self_id'] == partner_id) & \ + (trace_df['partner_id'] == self_id) & \ + (trace_df['arrow'] == 'pending') & \ + (trace_df['event'] == event) & \ + (trace_df['logical_time'] == logical_time) & \ + (trace_df['microstep'] == microstep) \ + ] + else : + matching_df = trace_df[\ + (trace_df['inout'] != inout) & \ + (trace_df['self_id'] == partner_id) & \ + (trace_df['partner_id'] == self_id) & \ + (trace_df['arrow'] == 'pending') & \ + (trace_df['event'] == event) + ] if (matching_df.empty) : # If no matching receiver, than set the arrow to 'dot', @@ -268,9 +282,6 @@ def load_and_process_csv_file(csv_file) : if (row['event'] in {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG', 'CuTAG_QR'}): label = row['event'] - elif (row['logical_time'] == -1678240241788173894) : - # FIXME: This isn't right. NEVER == -9223372036854775808. - label = row['event'] + '(NEVER)' else: label = row['event'] + '(' + f'{int(row["logical_time"]):,}' + ', ' + str(row['microstep']) + ')' From cfa12d5e04d7e362017ef2a18cba8777c12bf387 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 12 Jun 2023 15:14:52 +0200 Subject: [PATCH 060/142] Fix ROS2 test configuration --- .../org/lflang/tests/runtime/CppRos2Test.java | 6 +++-- .../main/java/org/lflang/ast/ASTUtils.java | 22 ------------------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index dc2612c14b..4b0dc28cec 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.LfFactory; import org.lflang.tests.TestBase; @@ -30,7 +29,10 @@ public void runWithRos2() { runTestsForTargets( Message.DESC_ROS2, it -> true, - it -> ASTUtils.addTargetProperty(it.getFileConfig().resource, "ros2", trueLiteral), + it -> { + it.getContext().getTargetConfig().ros2 = true; + return true; + }, TestLevel.EXECUTION, true); } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 60b5538372..4489b1523b 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -265,28 +265,6 @@ public static Target getTarget(EObject object) { return Target.fromDecl(targetDecl); } - /** - * Add a new target property to the given resource. This also creates a config object if the - * resource does not yey have one. - * - * @param resource The resource to modify - * @param name Name of the property to add - * @param value Value to be assigned to the property - */ - public static boolean addTargetProperty( - final Resource resource, final String name, final Element value) { - var config = targetDecl(resource).getConfig(); - if (config == null) { - config = LfFactory.eINSTANCE.createKeyValuePairs(); - targetDecl(resource).setConfig(config); - } - final var newProperty = LfFactory.eINSTANCE.createKeyValuePair(); - newProperty.setName(name); - newProperty.setValue(value); - config.getPairs().add(newProperty); - return true; - } - /** * Return true if the connection involves multiple ports on the left or right side of the * connection, or if the port on the left or right of the connection involves a bank of reactors From cba86392a7503b57d79632c1da00089aaf8eab8a Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Sun, 11 Jun 2023 12:38:13 +0200 Subject: [PATCH 061/142] fix ROS2 compilation --- .../kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index 22e3c3045a..f3fac39e42 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -79,7 +79,7 @@ class CppRos2NodeGenerator( |} | |$nodeName::~$nodeName() { - | if (lf_env->phase() == reactor::Environment::Phase::Execution) { + | if (lf_env->phase() == reactor::Phase::Execution) { | lf_env->async_shutdown(); | } | lf_shutdown_thread.join(); From 48e512811d84598f693817f28e7df37dce24e93a Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 12 Jun 2023 15:55:00 +0200 Subject: [PATCH 062/142] also pass cmake arguments in ros2 compilation --- .../org/lflang/generator/cpp/CppPlatformGenerator.kt | 10 ++++++++++ .../org/lflang/generator/cpp/CppRos2Generator.kt | 3 +-- .../org/lflang/generator/cpp/CppStandaloneGenerator.kt | 9 ++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 102657522b..09296cfe36 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -22,4 +22,14 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { abstract fun generatePlatformFiles() abstract fun doCompile(context: LFGeneratorContext, onlyGenerateBuildFiles: Boolean = false): Boolean + + protected val cmakeArgs: List + get() = listOf( + "-DCMAKE_BUILD_TYPE=${targetConfig.cmakeBuildType}", + "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation) "OFF" else "ON"}", + "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics) "ON" else "OFF"}", + "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", + "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.severity}", + "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", + ) } \ No newline at end of file diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt index a689a53c88..17c2c70315 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2Generator.kt @@ -54,8 +54,7 @@ class CppRos2Generator(generator: CppGenerator) : CppPlatformGenerator(generator packageGenerator.reactorCppName, "--cmake-args", "-DLF_REACTOR_CPP_SUFFIX=${packageGenerator.reactorCppSuffix}", - "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}" - ), + ) + cmakeArgs, fileConfig.outPath ) val returnCode = colconCommand?.run(context.cancelIndicator); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index f307559d9e..8e6e60227a 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -160,15 +160,10 @@ class CppStandaloneGenerator(generator: CppGenerator) : private fun createCmakeCommand(buildPath: Path, outPath: Path): LFCommand { val cmd = commandFactory.createCommand( - "cmake", listOf( - "-DCMAKE_BUILD_TYPE=${targetConfig.cmakeBuildType}", + "cmake", + cmakeArgs + listOf( "-DCMAKE_INSTALL_PREFIX=${outPath.toUnixString()}", "-DCMAKE_INSTALL_BINDIR=${outPath.relativize(fileConfig.binPath).toUnixString()}", - "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation) "OFF" else "ON"}", - "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics) "ON" else "OFF"}", - "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", - "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.severity}", - "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", fileConfig.srcGenBasePath.toUnixString() ), buildPath From 734e76048e769e9dd02cd3404ded3bb14afc104f Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 12 Jun 2023 16:07:22 +0200 Subject: [PATCH 063/142] also clean the install directory --- core/src/main/kotlin/org/lflang/generator/cpp/CppFileConfig.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppFileConfig.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppFileConfig.kt index ec4ad15713..42a5e0ab10 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppFileConfig.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppFileConfig.kt @@ -49,7 +49,8 @@ class CppFileConfig(resource: Resource, srcGenBasePath: Path, useHierarchicalBin this.outPath.resolve("build"), this.outPath.resolve("lib"), this.outPath.resolve("include"), - this.outPath.resolve("share") + this.outPath.resolve("share"), + this.outPath.resolve("install") ) /** Relative path to the directory where all source files for this resource should be generated in. */ From 2da47693a5d868f3f845cc2051a92e662a06bdc6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 12 Jun 2023 17:13:12 +0200 Subject: [PATCH 064/142] update reactor-cpp --- core/src/main/resources/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/cpp/reactor-cpp b/core/src/main/resources/lib/cpp/reactor-cpp index b607f1f640..e3564782f0 160000 --- a/core/src/main/resources/lib/cpp/reactor-cpp +++ b/core/src/main/resources/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit b607f1f64083ab531e7a676b29de75f076aa1cde +Subproject commit e3564782f0e1a2bc427e5932a88ff8f87dacd50c From 3c67317acbf1ce9c61b4718eae7ee33a5f5c21f8 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 12 Jun 2023 21:53:53 -0700 Subject: [PATCH 065/142] Attempt to make merge queue work again --- .github/workflows/check-diff.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 55f5f404e8..31a9a174db 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -69,7 +69,8 @@ jobs: - id: should-skip name: "Determine whether to skip checks" run: | - echo "skip=${{ steps.duplicate.outputs.should_skip == 'true' && github.event.action != 'ready_for_review' }}" >> $GITHUB_OUTPUT + echo "skip=${{ steps.duplicate.outputs.should_skip == 'true' && github.event.action != 'ready_for_review' && github.event.sender.login != 'github-merge-queue' }}" >> $GITHUB_OUTPUT + echo "(Run initiated by ${{ github.event.sender.login }} )" - id: skip-redundant name: "Report on skipping checks (prior run found)" run: | From 387bb93f51cb3fd172d87174447b2d9e6b961cfc Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 13 Jun 2023 10:06:05 +0200 Subject: [PATCH 066/142] Detect if we are running on a merge queue commit --- .github/workflows/check-diff.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index 31a9a174db..e67c36bb01 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -69,8 +69,14 @@ jobs: - id: should-skip name: "Determine whether to skip checks" run: | - echo "skip=${{ steps.duplicate.outputs.should_skip == 'true' && github.event.action != 'ready_for_review' && github.event.sender.login != 'github-merge-queue' }}" >> $GITHUB_OUTPUT - echo "(Run initiated by ${{ github.event.sender.login }} )" + echo ${{ github.ref_name }} + if echo ${{ github.ref_name }} | grep 'gh-readonly-queues'; then + echo "Don't skip, because this is a merge queue commit." + echo "skip=false" >> $GITHUB_OUTPUT + else + echo "skip=${{ steps.duplicate.outputs.should_skip == 'true' && github.event.action != 'ready_for_review' }}" >> $GITHUB_OUTPUT + fi + shell: bash - id: skip-redundant name: "Report on skipping checks (prior run found)" run: | From 97759a3f552df82770e6dd5acf85f9540715eca6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 13 Jun 2023 17:42:11 +0200 Subject: [PATCH 067/142] fix typo --- .github/workflows/check-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-diff.yml b/.github/workflows/check-diff.yml index e67c36bb01..40fe15834d 100644 --- a/.github/workflows/check-diff.yml +++ b/.github/workflows/check-diff.yml @@ -70,7 +70,7 @@ jobs: name: "Determine whether to skip checks" run: | echo ${{ github.ref_name }} - if echo ${{ github.ref_name }} | grep 'gh-readonly-queues'; then + if echo ${{ github.ref_name }} | grep 'gh-readonly-queue'; then echo "Don't skip, because this is a merge queue commit." echo "skip=false" >> $GITHUB_OUTPUT else From 4fa589c83295864cc4838dfd6279e721d86095ef Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 17:27:36 -0700 Subject: [PATCH 068/142] Fix comment duplication issue. --- core/src/main/java/org/lflang/ast/ToLf.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 9505c57478..4066dfd3bc 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -111,7 +111,9 @@ public MalleableString doSwitch(EObject eObject) { var ancestorComments = getAncestorComments(node); Predicate doesNotBelongToAncestor = n -> !ancestorComments.contains(n); List followingComments = - getFollowingComments(node, ASTUtils.sameLine(node).and(doesNotBelongToAncestor)).toList(); + getFollowingComments( + node, ASTUtils.sameLine(node).and(doesNotBelongToAncestor), doesNotBelongToAncestor) + .toList(); var previous = getNextCompositeSibling(node, INode::getPreviousSibling); Predicate doesNotBelongToPrevious = doesNotBelongToAncestor.and( @@ -174,12 +176,17 @@ private static Stream getFollowingNonCompositeSiblings(ICompositeNode nod * Return comments that follow {@code node} in the source code and that either satisfy {@code * filter} or that cannot belong to any following sibling of {@code node}. */ - private static Stream getFollowingComments(ICompositeNode node, Predicate filter) { + private static Stream getFollowingComments( + ICompositeNode node, Predicate precedingFilter, Predicate followingFilter) { ICompositeNode sibling = getNextCompositeSibling(node, INode::getNextSibling); Stream followingSiblingComments = - getFollowingNonCompositeSiblings(node).filter(ASTUtils::isComment).map(INode::getText); + getFollowingNonCompositeSiblings(node) + .filter(ASTUtils::isComment) + .filter(followingFilter) + .map(INode::getText); if (sibling == null) return followingSiblingComments; - return Stream.concat(followingSiblingComments, ASTUtils.getPrecedingComments(sibling, filter)); + return Stream.concat( + followingSiblingComments, ASTUtils.getPrecedingComments(sibling, precedingFilter)); } /** From f89061adb26c7bf6897d601407bf314ddd02c392 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 17:59:42 -0700 Subject: [PATCH 069/142] Do not destructively modify Ecore model. --- core/src/main/java/org/lflang/ast/ToLf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 4066dfd3bc..7748c1909b 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -908,7 +908,7 @@ private MalleableString initializer(Initializer init) { // This turns C array initializers into a braced expression. // C++ variants are not converted. BracedListExpression list = LfFactory.eINSTANCE.createBracedListExpression(); - list.getItems().addAll(init.getExprs()); + init.getExprs().forEach(it -> list.getItems().add(it)); return new Builder().append(" = ").append(doSwitch(list)).get(); } String prefix; From b68fbd2f1ec21ca597341335c83f77df39116d42 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 19:22:04 -0700 Subject: [PATCH 070/142] Do not skip doSwitch. doSwitch is what finds the comments. If you skip doSwitch and call directly into the code that is specific to the given EObject, you will drop comments. --- core/src/main/java/org/lflang/ast/ToLf.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 7748c1909b..693a81eb3b 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -488,7 +488,7 @@ public MalleableString caseStateVar(StateVar object) { } msb.append("state ").append(object.getName()); msb.append(typeAnnotationFor(object.getType())); - msb.append(initializer(object.getInit())); + msb.append(doSwitch(object.getInit())); return msb.get(); } @@ -877,15 +877,10 @@ public MalleableString caseAssignment(Assignment object) { // )); Builder msb = new Builder(); msb.append(object.getLhs().getName()); - msb.append(initializer(object.getRhs())); + msb.append(doSwitch(object.getRhs())); return msb.get(); } - @Override - public MalleableString caseInitializer(Initializer object) { - return initializer(object); - } - /** * Return true if the initializer should be output with an equals initializer. Old-style * assignments with parentheses are also output that way to help with the transition. @@ -895,7 +890,8 @@ private boolean shouldOutputAsAssignment(Initializer init) { || init.getExprs().size() == 1 && ASTUtils.getTarget(init).mandatesEqualsInitializers(); } - private MalleableString initializer(Initializer init) { + @Override + public MalleableString caseInitializer(Initializer init) { if (init == null) { return MalleableString.anyOf(""); } @@ -935,7 +931,7 @@ public MalleableString caseParameter(Parameter object) { return builder .append(object.getName()) .append(typeAnnotationFor(object.getType())) - .append(initializer(object.getInit())) + .append(doSwitch(object.getInit())) .get(); } From be759c2d279f4bc7bfa16e6f85699bb7ffdc1e07 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 23:11:59 -0700 Subject: [PATCH 071/142] Try again to fix destructive reads of init list. --- core/src/main/java/org/lflang/ast/ToLf.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 693a81eb3b..8899642956 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -904,7 +904,11 @@ public MalleableString caseInitializer(Initializer init) { // This turns C array initializers into a braced expression. // C++ variants are not converted. BracedListExpression list = LfFactory.eINSTANCE.createBracedListExpression(); - init.getExprs().forEach(it -> list.getItems().add(it)); + var list2 = new ArrayList(); + for (var expr : init.getExprs()) { + list2.add(expr); + } + list.getItems().addAll(list2); return new Builder().append(" = ").append(doSwitch(list)).get(); } String prefix; From b66723664d0f9a3b96195d958d6672a15a410e2d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 23:46:57 -0700 Subject: [PATCH 072/142] Fix NPE. --- core/src/main/java/org/lflang/ast/ToLf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 8899642956..d0de40a650 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -488,7 +488,7 @@ public MalleableString caseStateVar(StateVar object) { } msb.append("state ").append(object.getName()); msb.append(typeAnnotationFor(object.getType())); - msb.append(doSwitch(object.getInit())); + if (object.getInit() != null) msb.append(doSwitch(object.getInit())); return msb.get(); } From d25b58157c10ed507cf50c882edfe5c7bf9014ed Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 10 Jun 2023 23:47:55 -0700 Subject: [PATCH 073/142] Really fix the destructive copying this time. There is some black magic happening in the implementation of EList::add that removes EObjects from their containers when they are added to a new container. This works around that by just not adding the EObjects to a container. --- core/src/main/java/org/lflang/ast/ToLf.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index d0de40a650..9ca4c124dc 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -47,7 +47,6 @@ import org.lflang.lf.Instantiation; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; -import org.lflang.lf.LfFactory; import org.lflang.lf.Literal; import org.lflang.lf.Method; import org.lflang.lf.MethodArgument; @@ -818,9 +817,17 @@ public MalleableString caseBracedListExpression(BracedListExpression object) { if (object.getItems().isEmpty()) { return MalleableString.anyOf("{}"); } + return bracedListExpression(object.getItems()); + } + + /** + * Represent a braced list expression. Do not invoke on expressions that may have comments + * attached. + */ + private MalleableString bracedListExpression(List items) { // Note that this strips the trailing comma. There is no way // to implement trailing commas with the current set of list() methods AFAIU. - return list(", ", "{", "}", false, false, object.getItems()); + return list(", ", "{", "}", false, false, items); } @Override @@ -903,13 +910,7 @@ public MalleableString caseInitializer(Initializer init) { if (ASTUtils.getTarget(init) == Target.C) { // This turns C array initializers into a braced expression. // C++ variants are not converted. - BracedListExpression list = LfFactory.eINSTANCE.createBracedListExpression(); - var list2 = new ArrayList(); - for (var expr : init.getExprs()) { - list2.add(expr); - } - list.getItems().addAll(list2); - return new Builder().append(" = ").append(doSwitch(list)).get(); + return new Builder().append(" = ").append(bracedListExpression(init.getExprs())).get(); } String prefix; String suffix; From 3d83bbc4f68c81e9060986255680416a8fc3a77d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 12 Jun 2023 17:26:12 -0700 Subject: [PATCH 074/142] Do not extract comments that are in code blocks. This only applies when the comment is in the body of the code block. According to the grammar, the body does not start until some tokens appear -- that means non-whitespace, non-comment characters. --- core/src/main/java/org/lflang/ast/ToLf.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 9ca4c124dc..fe4912459b 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -16,6 +16,7 @@ import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.impl.ParserRuleImpl; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; @@ -205,6 +206,10 @@ private static List getContainedComments(INode node) { && (child.getText().contains("\n") || child.getText().contains("\r")) && !inSemanticallyInsignificantLeadingRubbish) { break; + } else if (child instanceof ICompositeNode compositeNode + && compositeNode.getGrammarElement().eContainer() instanceof ParserRuleImpl pri + && pri.getName().equals("Body")) { + break; } } return ret; From f56bcd78993ca2cc53df19c7a84bec8760a3aa2c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 12 Jun 2023 17:53:09 -0700 Subject: [PATCH 075/142] Add semicolon. --- core/src/main/java/org/lflang/ast/ToLf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index fe4912459b..1a6e6bd4be 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -743,7 +743,7 @@ public MalleableString caseInstantiation(Instantiation object) { msb.append(list(", ", "<", ">", true, false, object.getTypeArgs())); msb.append(list(false, object.getParameters())); // TODO: Delete the following case when the corresponding feature is removed - if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); + if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())).append(";"); return msb.get(); } From c538063fdf4eb63c51421b117e390b932e2b8490 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 12 Jun 2023 18:05:18 -0700 Subject: [PATCH 076/142] Make formatter check itself at runtime. This may slow down the formatter. It also is not certain to work because isEqual could contain mistakes. However, it may substantially reduce the likelihood that the formatter silently produces wrong results. It is hard to be sure about this, however, because it is already rare for the formatter to produce wrong results. --- cli/lff/src/main/java/org/lflang/cli/Lff.java | 10 +++ .../java/org/lflang/ast/ParsingUtils.java | 65 ++++++++++++++++++ .../java/org/lflang/tests/LfParsingUtil.java | 66 +------------------ .../lflang/tests/compiler/RoundTripTests.java | 6 +- 4 files changed, 82 insertions(+), 65 deletions(-) create mode 100644 core/src/main/java/org/lflang/ast/ParsingUtils.java diff --git a/cli/lff/src/main/java/org/lflang/cli/Lff.java b/cli/lff/src/main/java/org/lflang/cli/Lff.java index 21a72fad16..e987a8a6d4 100644 --- a/cli/lff/src/main/java/org/lflang/cli/Lff.java +++ b/cli/lff/src/main/java/org/lflang/cli/Lff.java @@ -10,6 +10,8 @@ import java.util.List; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.ast.FormattingUtils; +import org.lflang.ast.IsEqual; +import org.lflang.ast.ParsingUtils; import org.lflang.util.FileUtil; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -171,8 +173,16 @@ private void formatSingleFile(Path path, Path inputRoot, Path outputRoot) { if (!ignoreErrors) { exitIfCollectedErrors(); } + final String formattedFileContents = FormattingUtils.render(resource.getContents().get(0), lineLength); + if (!new IsEqual(resource.getContents().get(0)) + .doSwitch( + ParsingUtils.parseSourceAsIfInDirectory(path.getParent(), formattedFileContents))) { + reporter.printFatalErrorAndExit( + "The formatter failed to produce output that is semantically equivalent to its input." + + " Please file a bug report with Lingua Franca."); + } try { if (check) { diff --git a/core/src/main/java/org/lflang/ast/ParsingUtils.java b/core/src/main/java/org/lflang/ast/ParsingUtils.java new file mode 100644 index 0000000000..0b638b656d --- /dev/null +++ b/core/src/main/java/org/lflang/ast/ParsingUtils.java @@ -0,0 +1,65 @@ +package org.lflang.ast; + +import com.google.inject.Injector; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.resource.XtextResourceSet; +import org.lflang.LFStandaloneSetup; +import org.lflang.lf.Model; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ParsingUtils { + public static Model parse(Path file) { + // Source: + // https://wiki.eclipse.org/Xtext/FAQ#How_do_I_load_my_model_in_a_standalone_Java_application_.3F + Injector injector = new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); + XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class); + resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); + Resource resource = + resourceSet.getResource(URI.createFileURI(file.toFile().getAbsolutePath()), true); + return (Model) resource.getContents().get(0); + } + + public static Model parse(String fileContents) { + Path file = null; + try { + file = Files.createTempFile("lftests", ".lf"); + Files.writeString(file, fileContents); + return parse(file); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + if (file != null) { + try { + Files.deleteIfExists(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + + public static Model parseSourceAsIfInDirectory(Path directory, String sourceText) { + int num = 0; + while (Files.exists(directory.resolve("file" + num + ".lf"))) { + num++; + } + Path file = directory.resolve("file" + num + ".lf"); + try { + Files.writeString(file, sourceText); + return parse(file); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + Files.deleteIfExists(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/core/src/test/java/org/lflang/tests/LfParsingUtil.java b/core/src/test/java/org/lflang/tests/LfParsingUtil.java index ae45bf4e7c..6f00d61129 100644 --- a/core/src/test/java/org/lflang/tests/LfParsingUtil.java +++ b/core/src/test/java/org/lflang/tests/LfParsingUtil.java @@ -1,15 +1,7 @@ package org.lflang.tests; -import com.google.inject.Injector; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.resource.XtextResourceSet; import org.junit.jupiter.api.Assertions; -import org.lflang.LFStandaloneSetup; +import org.lflang.ast.ParsingUtils; import org.lflang.lf.Model; /** @@ -19,12 +11,12 @@ public class LfParsingUtil { /** Parse the given file, asserts that there are no parsing errors. */ public static Model parseValidModel(String fileName, String reformattedTestCase) { - Model resultingModel = parse(reformattedTestCase); + Model resultingModel = ParsingUtils.parse(reformattedTestCase); checkValid(fileName, resultingModel); return resultingModel; } - private static void checkValid(String fileName, Model resultingModel) { + public static void checkValid(String fileName, Model resultingModel) { Assertions.assertNotNull(resultingModel); if (!resultingModel.eResource().getErrors().isEmpty()) { resultingModel.eResource().getErrors().forEach(System.err::println); @@ -32,56 +24,4 @@ private static void checkValid(String fileName, Model resultingModel) { resultingModel.eResource().getErrors().isEmpty(), "Parsing errors in " + fileName); } } - - public static Model parseSourceAsIfInDirectory(Path directory, String sourceText) { - int num = 0; - while (Files.exists(directory.resolve("file" + num + ".lf"))) { - num++; - } - Path file = directory.resolve("file" + num + ".lf"); - try { - Files.writeString(file, sourceText); - Model resultingModel = parse(file); - checkValid("file in " + directory, resultingModel); - return resultingModel; - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - try { - Files.deleteIfExists(file); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - public static Model parse(String fileContents) { - Path file = null; - try { - file = Files.createTempFile("lftests", ".lf"); - Files.writeString(file, fileContents); - return parse(file); - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - if (file != null) { - try { - Files.deleteIfExists(file); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - } - - public static Model parse(Path file) { - // Source: - // https://wiki.eclipse.org/Xtext/FAQ#How_do_I_load_my_model_in_a_standalone_Java_application_.3F - Injector injector = new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); - XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class); - resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); - Resource resource = - resourceSet.getResource(URI.createFileURI(file.toFile().getAbsolutePath()), true); - return (Model) resource.getContents().get(0); - } } diff --git a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java index 1beb54b81a..9987ead64d 100644 --- a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java +++ b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java @@ -14,6 +14,7 @@ import org.lflang.Target; import org.lflang.ast.FormattingUtils; import org.lflang.ast.IsEqual; +import org.lflang.ast.ParsingUtils; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; @@ -41,14 +42,15 @@ public void roundTripTest() { } private void run(Path file) throws Exception { - Model originalModel = LfParsingUtil.parse(file); + Model originalModel = ParsingUtils.parse(file); System.out.println(file); assertThat(originalModel.eResource().getErrors(), equalTo(emptyList())); // TODO: Check that the output is a fixed point final int smallLineLength = 20; final String squishedTestCase = FormattingUtils.render(originalModel, smallLineLength); final Model resultingModel = - LfParsingUtil.parseSourceAsIfInDirectory(file.getParent(), squishedTestCase); + ParsingUtils.parseSourceAsIfInDirectory(file.getParent(), squishedTestCase); + LfParsingUtil.checkValid("file in " + file.getParent(), resultingModel); assertThat(resultingModel.eResource().getErrors(), equalTo(emptyList())); Assertions.assertTrue( From 40588f263b91c63eb64d67384a906b302fb80d1c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 12 Jun 2023 19:21:29 -0700 Subject: [PATCH 077/142] Equality is symmetric. --- cli/lff/src/main/java/org/lflang/cli/Lff.java | 6 ++- .../src/main/java/org/lflang/ast/IsEqual.java | 44 ++++++++++++------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/cli/lff/src/main/java/org/lflang/cli/Lff.java b/cli/lff/src/main/java/org/lflang/cli/Lff.java index e987a8a6d4..adfb23bada 100644 --- a/cli/lff/src/main/java/org/lflang/cli/Lff.java +++ b/cli/lff/src/main/java/org/lflang/cli/Lff.java @@ -180,8 +180,10 @@ private void formatSingleFile(Path path, Path inputRoot, Path outputRoot) { .doSwitch( ParsingUtils.parseSourceAsIfInDirectory(path.getParent(), formattedFileContents))) { reporter.printFatalErrorAndExit( - "The formatter failed to produce output that is semantically equivalent to its input." - + " Please file a bug report with Lingua Franca."); + "The formatter failed to produce output that is semantically equivalent to its input when" + + " executed on the file " + + path + + ". Please file a bug report with Lingua Franca."); } try { diff --git a/core/src/main/java/org/lflang/ast/IsEqual.java b/core/src/main/java/org/lflang/ast/IsEqual.java index bc0fc31abf..a79d1c71fa 100644 --- a/core/src/main/java/org/lflang/ast/IsEqual.java +++ b/core/src/main/java/org/lflang/ast/IsEqual.java @@ -7,6 +7,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.eclipse.emf.ecore.EObject; +import org.lflang.Target; import org.lflang.TimeUnit; import org.lflang.lf.Action; import org.lflang.lf.Array; @@ -174,13 +175,22 @@ public Boolean caseStateVar(StateVar object) { public Boolean caseInitializer(Initializer object) { // Empty braces are not equivalent to no init. return new ComparisonMachine<>(object, Initializer.class) - .equalAsObjects(Initializer::isBraces) - // An initializer with no parens is equivalent to one with parens, - // if the list has a single element. This is probably going to change - // when we introduce equals initializers. - // .equalAsObjects(Initializer::isParens) - .listsEquivalent(Initializer::getExprs) - .conclusion; + .equalAsObjects(Initializer::isBraces) + // An initializer with no parens is equivalent to one with parens, + // if the list has a single element. This is probably going to change + // when we introduce equals initializers. +// .equalAsObjects(Initializer::isParens) + .listsEquivalent(Initializer::getExprs) + .conclusion + || otherObject instanceof Initializer i && i.getExprs().size() == 1 && i.getExprs().get(0) instanceof BracedListExpression ble + && initializerAndBracedListExpression(object, ble) + || otherObject instanceof Initializer i2 && object.getExprs().size() == 1 && object.getExprs().get(0) instanceof BracedListExpression ble2 + && initializerAndBracedListExpression(i2, ble2); + } + + private static boolean initializerAndBracedListExpression(Initializer object, BracedListExpression otherObject) { + return ASTUtils.getTarget(object) == Target.C + && listsEqualish(otherObject.getItems(), object.getExprs(), (a, b) -> new IsEqual(a).doSwitch(b)); } @Override @@ -583,6 +593,17 @@ private UnsupportedOperationException thereIsAMoreSpecificCase( .collect(Collectors.joining(" or ")))); } + private static boolean listsEqualish(List list0, List list1, BiPredicate equalish) { + if (list0 == list1) return true; // e.g., they are both null + if (list0.size() != list1.size()) return false; + for (int i = 0; i < list0.size(); i++) { + if (!equalish.test(list0.get(i), list1.get(i))) { + return false; + } + } + return true; + } + /** Fluently compare a pair of parse tree nodes for equivalence. */ private class ComparisonMachine { private final E object; @@ -613,14 +634,7 @@ boolean listsEqualish( if (!conclusion) return false; List list0 = listGetter.apply(object); List list1 = listGetter.apply(other); - if (list0 == list1) return true; // e.g., they are both null - if (list0.size() != list1.size()) return false; - for (int i = 0; i < list0.size(); i++) { - if (!equalish.test(list0.get(i), list1.get(i))) { - return false; - } - } - return true; + return IsEqual.listsEqualish(list0, list1, equalish); } /** Conclude false if the two properties are not equal as objects. */ From 1a165b6fe27d20e0347eb509ce6aedc5dfb0db0d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Tue, 13 Jun 2023 16:29:04 -0700 Subject: [PATCH 078/142] Fixes in isEqual. --- .../src/main/java/org/lflang/ast/IsEqual.java | 21 ++++++++++++------- .../java/org/lflang/ast/ParsingUtils.java | 7 +++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/IsEqual.java b/core/src/main/java/org/lflang/ast/IsEqual.java index a79d1c71fa..af06923d35 100644 --- a/core/src/main/java/org/lflang/ast/IsEqual.java +++ b/core/src/main/java/org/lflang/ast/IsEqual.java @@ -179,18 +179,24 @@ public Boolean caseInitializer(Initializer object) { // An initializer with no parens is equivalent to one with parens, // if the list has a single element. This is probably going to change // when we introduce equals initializers. -// .equalAsObjects(Initializer::isParens) + // .equalAsObjects(Initializer::isParens) .listsEquivalent(Initializer::getExprs) .conclusion - || otherObject instanceof Initializer i && i.getExprs().size() == 1 && i.getExprs().get(0) instanceof BracedListExpression ble + || otherObject instanceof Initializer i + && i.getExprs().size() == 1 + && i.getExprs().get(0) instanceof BracedListExpression ble && initializerAndBracedListExpression(object, ble) - || otherObject instanceof Initializer i2 && object.getExprs().size() == 1 && object.getExprs().get(0) instanceof BracedListExpression ble2 - && initializerAndBracedListExpression(i2, ble2); + || otherObject instanceof Initializer i2 + && object.getExprs().size() == 1 + && object.getExprs().get(0) instanceof BracedListExpression ble2 + && initializerAndBracedListExpression(i2, ble2); } - private static boolean initializerAndBracedListExpression(Initializer object, BracedListExpression otherObject) { + private static boolean initializerAndBracedListExpression( + Initializer object, BracedListExpression otherObject) { return ASTUtils.getTarget(object) == Target.C - && listsEqualish(otherObject.getItems(), object.getExprs(), (a, b) -> new IsEqual(a).doSwitch(b)); + && listsEqualish( + otherObject.getItems(), object.getExprs(), (a, b) -> new IsEqual(a).doSwitch(b)); } @Override @@ -593,7 +599,8 @@ private UnsupportedOperationException thereIsAMoreSpecificCase( .collect(Collectors.joining(" or ")))); } - private static boolean listsEqualish(List list0, List list1, BiPredicate equalish) { + private static boolean listsEqualish( + List list0, List list1, BiPredicate equalish) { if (list0 == list1) return true; // e.g., they are both null if (list0.size() != list1.size()) return false; for (int i = 0; i < list0.size(); i++) { diff --git a/core/src/main/java/org/lflang/ast/ParsingUtils.java b/core/src/main/java/org/lflang/ast/ParsingUtils.java index 0b638b656d..caa0bb0174 100644 --- a/core/src/main/java/org/lflang/ast/ParsingUtils.java +++ b/core/src/main/java/org/lflang/ast/ParsingUtils.java @@ -1,6 +1,9 @@ package org.lflang.ast; import com.google.inject.Injector; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.resource.XtextResource; @@ -8,10 +11,6 @@ import org.lflang.LFStandaloneSetup; import org.lflang.lf.Model; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - public class ParsingUtils { public static Model parse(Path file) { // Source: From a9a34db552daba6609069c660198b2121b9f897f Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Tue, 13 Jun 2023 17:39:52 -0700 Subject: [PATCH 079/142] Do not capture certain comments in toText. --- core/src/main/java/org/lflang/ast/ToText.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToText.java b/core/src/main/java/org/lflang/ast/ToText.java index f1d47b7c69..0c001ad67e 100644 --- a/core/src/main/java/org/lflang/ast/ToText.java +++ b/core/src/main/java/org/lflang/ast/ToText.java @@ -47,21 +47,15 @@ public String caseCode(Code code) { ICompositeNode node = NodeModelUtils.getNode(code); if (node != null) { StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); + boolean started = false; for (ILeafNode leaf : node.getLeafNodes()) { - builder.append(leaf.getText()); + if (!leaf.getText().contains("{=") + && (leaf.getText().contains("\n") && !ASTUtils.isComment(leaf))) { + started = true; + } + if (started && !leaf.getText().contains("=}")) builder.append(leaf.getText()); } String str = builder.toString().trim(); - // Remove the code delimiters (and any surrounding comments). - // This assumes any comment before {= does not include {=. - int start = str.indexOf("{="); - int end = str.lastIndexOf("=}"); - if (start == -1 || end == -1) { - // Silent failure is needed here because toText is needed to create the intermediate - // representation, - // which the validator uses. - return str; - } - str = str.substring(start + 2, end); if (str.split("\n").length > 1) { // multi line code return StringUtil.trimCodeBlock(str, 1); From 444fcf3c19a5d9cd790f74e0438198595d327f53 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Tue, 13 Jun 2023 18:30:41 -0700 Subject: [PATCH 080/142] More tinkering with comments around Code eObjects. --- core/src/main/java/org/lflang/ast/ToLf.java | 7 ++++--- core/src/main/java/org/lflang/ast/ToText.java | 17 ++++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index 1a6e6bd4be..bc5808e925 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -206,9 +206,10 @@ private static List getContainedComments(INode node) { && (child.getText().contains("\n") || child.getText().contains("\r")) && !inSemanticallyInsignificantLeadingRubbish) { break; - } else if (child instanceof ICompositeNode compositeNode - && compositeNode.getGrammarElement().eContainer() instanceof ParserRuleImpl pri - && pri.getName().equals("Body")) { + } else if (child.getParent() != null + && child.getParent().getGrammarElement().eContainer() instanceof ParserRuleImpl pri + && pri.getName().equals("Body") + && !child.getText().isBlank()) { break; } } diff --git a/core/src/main/java/org/lflang/ast/ToText.java b/core/src/main/java/org/lflang/ast/ToText.java index 0c001ad67e..103303f51e 100644 --- a/core/src/main/java/org/lflang/ast/ToText.java +++ b/core/src/main/java/org/lflang/ast/ToText.java @@ -49,16 +49,19 @@ public String caseCode(Code code) { StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); boolean started = false; for (ILeafNode leaf : node.getLeafNodes()) { - if (!leaf.getText().contains("{=") - && (leaf.getText().contains("\n") && !ASTUtils.isComment(leaf))) { - started = true; + if (!leaf.getText().equals("{=") && !leaf.getText().equals("=}")) { + var nothing = leaf.getText().isBlank() || ASTUtils.isComment(leaf); + if (!nothing || started || leaf.getText().startsWith("\n")) + builder.append(leaf.getText()); + if ((leaf.getText().contains("\n") || (!nothing))) { + started = true; + } } - if (started && !leaf.getText().contains("=}")) builder.append(leaf.getText()); } - String str = builder.toString().trim(); - if (str.split("\n").length > 1) { + String str = builder.toString(); + if (str.contains("\n")) { // multi line code - return StringUtil.trimCodeBlock(str, 1); + return StringUtil.trimCodeBlock(str, 0); } else { // single line code return str.trim(); From c811b07346b0e6c13b5e3a393dedfdab15f9380a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 12:42:57 -0700 Subject: [PATCH 081/142] Reduce comment inlining. This avoids inlining comments when the target syntactic element is multiple lines long. In such cases the comment instead gets its own line. --- .../java/org/lflang/ast/FormattingUtils.java | 1 + test/C/all.csv | 29 ++++ test/C/federate__receiver.csv | 11 ++ test/C/federate__receiver_summary.csv | 16 +++ test/C/federate__sender.csv | 20 +++ test/C/federate__sender_summary.csv | 27 ++++ test/C/rti.csv | 15 +++ test/C/rti_summary.csv | 16 +++ test/C/src/ActionWithNoReaction.lf | 3 +- test/C/src/ArrayAsType.lf | 3 +- test/C/src/ArrayPrint.lf | 3 +- test/C/src/DelayArray.lf | 3 +- test/C/src/DelayArrayWithAfter.lf | 3 +- test/C/src/DelayStruct.lf | 3 +- test/C/src/DelayStructWithAfter.lf | 3 +- test/C/src/DelayStructWithAfterOverlapped.lf | 3 +- test/C/src/FloatLiteral.lf | 3 +- test/C/src/HelloWorld.lf | 3 +- test/C/src/ManualDelayedReaction.lf | 3 +- test/C/src/MethodsRecursive.lf | 3 +- test/C/src/NativeListsAndTimes.lf | 3 +- test/C/src/SendsPointerTest.lf | 3 +- test/C/src/SetArray.lf | 3 +- test/C/src/SetToken.lf | 3 +- test/C/src/StructAsType.lf | 3 +- test/C/src/StructAsTypeDirect.lf | 3 +- test/C/src/StructPrint.lf | 3 +- test/C/src/StructScale.lf | 3 +- test/C/src/docker/HelloWorldContainerized.lf | 3 +- .../DistributedLoopedPhysicalAction.lf | 3 +- .../modal_models/BanksCount3ModesComplex.lf | 3 +- .../modal_models/BanksCount3ModesSimple.lf | 3 +- .../src/modal_models/BanksModalStateReset.lf | 3 +- test/C/src/modal_models/ConvertCaseTest.lf | 3 +- test/C/src/modal_models/Count3Modes.lf | 3 +- test/C/src/modal_models/ModalCycleBreaker.lf | 3 +- .../src/modal_models/ModalNestedReactions.lf | 3 +- .../src/modal_models/ModalStartupShutdown.lf | 3 +- test/C/src/multiport/MultiportMutableInput.lf | 3 +- .../multiport/MultiportMutableInputArray.lf | 3 +- test/C/src/multiport/MultiportToBank.lf | 4 +- test/C/src/multiport/MultiportToBankDouble.lf | 4 +- test/C/src/no_inlining/IntPrint.lf | 3 +- test/C/temp.txt | 124 ++++++++++++++++++ test/C/trace_svg.html | 97 ++++++++++++++ test/Cpp/src/FloatLiteral.lf | 3 +- test/Cpp/src/ManualDelayedReaction.lf | 3 +- test/Cpp/src/NativeListsAndTimes.lf | 7 +- test/Python/src/ActionWithNoReaction.lf | 3 +- test/Python/src/ArrayAsType.lf | 3 +- test/Python/src/ArrayPrint.lf | 3 +- test/Python/src/DelayArray.lf | 3 +- test/Python/src/DelayArrayWithAfter.lf | 3 +- test/Python/src/DelayStruct.lf | 3 +- test/Python/src/DelayStructWithAfter.lf | 3 +- .../src/DelayStructWithAfterOverlapped.lf | 3 +- test/Python/src/FloatLiteral.lf | 3 +- test/Python/src/ManualDelayedReaction.lf | 3 +- test/Python/src/MethodsRecursive.lf | 3 +- test/Python/src/NativeListsAndTimes.lf | 3 +- test/Python/src/SetArray.lf | 3 +- test/Python/src/StructAsType.lf | 3 +- test/Python/src/StructAsTypeDirect.lf | 3 +- test/Python/src/StructPrint.lf | 3 +- test/Python/src/StructScale.lf | 3 +- test/Python/src/lib/ImportedAgain.lf | 3 +- .../modal_models/BanksCount3ModesComplex.lf | 3 +- .../modal_models/BanksCount3ModesSimple.lf | 3 +- .../src/modal_models/BanksModalStateReset.lf | 3 +- .../src/modal_models/ConvertCaseTest.lf | 3 +- test/Python/src/modal_models/Count3Modes.lf | 3 +- .../src/modal_models/ModalCycleBreaker.lf | 3 +- .../src/modal_models/ModalNestedReactions.lf | 3 +- .../src/modal_models/ModalStartupShutdown.lf | 3 +- .../src/multiport/MultiportMutableInput.lf | 3 +- .../multiport/MultiportMutableInputArray.lf | 3 +- test/Rust/src/FloatLiteral.lf | 3 +- test/Rust/src/NativeListsAndTimes.lf | 3 +- test/Rust/src/StructAsType.lf | 3 +- test/TypeScript/src/ArrayAsType.lf | 3 +- test/TypeScript/src/ArrayPrint.lf | 3 +- test/TypeScript/src/Deadline.lf | 3 +- test/TypeScript/src/FloatLiteral.lf | 3 +- test/TypeScript/src/NativeListsAndTimes.lf | 3 +- test/TypeScript/src/StructAsType.lf | 3 +- test/TypeScript/src/StructAsTypeDirect.lf | 3 +- test/TypeScript/src/StructPrint.lf | 3 +- test/TypeScript/src/TimeLimit.lf | 3 +- .../src/multiport/MultiportMutableInput.lf | 3 +- .../multiport/MultiportMutableInputArray.lf | 3 +- .../src/multiport/MultiportToBankDouble.lf | 4 +- 91 files changed, 522 insertions(+), 84 deletions(-) create mode 100644 test/C/all.csv create mode 100644 test/C/federate__receiver.csv create mode 100644 test/C/federate__receiver_summary.csv create mode 100644 test/C/federate__sender.csv create mode 100644 test/C/federate__sender_summary.csv create mode 100644 test/C/rti.csv create mode 100644 test/C/rti_summary.csv create mode 100644 test/C/temp.txt create mode 100644 test/C/trace_svg.html diff --git a/core/src/main/java/org/lflang/ast/FormattingUtils.java b/core/src/main/java/org/lflang/ast/FormattingUtils.java index 7ec3d7d59a..500edc465d 100644 --- a/core/src/main/java/org/lflang/ast/FormattingUtils.java +++ b/core/src/main/java/org/lflang/ast/FormattingUtils.java @@ -220,6 +220,7 @@ static boolean placeComment( for (int j = 0; j < components.size(); j++) { String current = components.get(j); if (j >= i && current.contains("\n")) { + if (components.get(j).lines().filter(it -> !it.isBlank()).count() > 1) break; components.set( j, components diff --git a/test/C/all.csv b/test/C/all.csv new file mode 100644 index 0000000000..4705d450d4 --- /dev/null +++ b/test/C/all.csv @@ -0,0 +1,29 @@ +,event,self_id,partner_id,logical_time,microstep,physical_time,inout,x1,y1,arrow,x2,y2 +0,FED_ID,1,-1,-1686279803405901114,0,-1041305535,out,300,75,arrow,100,96 +1,FED_ID,-1,1,-1686279803405901114,0,-1041279256,in,100,96,marked,-1,-1 +2,ACK,-1,1,-1686279803405901114,0,-1041277413,out,100,116,arrow,300,137 +3,ACK,1,-1,-1686279803405901114,0,-1041236205,in,300,137,marked,-1,-1 +4,TIMESTAMP,1,-1,-1041185840,0,-1041181933,out,300,158,arrow,100,245 +5,FED_ID,0,-1,-1686279803405901114,0,-1040825162,out,500,180,arrow,100,204 +6,FED_ID,-1,0,-1686279803405901114,0,-1000243598,in,100,204,marked,-1,-1 +7,ACK,-1,0,-1686279803405901114,0,-1000241414,out,100,224,arrow,500,266 +8,TIMESTAMP,-1,1,-1041185840,0,-1000221006,in,100,245,marked,-1,-1 +9,ACK,0,-1,-1686279803405901114,0,-1000187212,in,500,266,marked,-1,-1 +10,TIMESTAMP,0,-1,-1000000000,0,-999986915,out,500,288,arrow,100,309 +11,TIMESTAMP,-1,0,-1000000000,0,-999957680,in,100,309,marked,-1,-1 +12,TIMESTAMP,-1,0,0,0,-999953903,out,100,329,arrow,500,371 +13,TIMESTAMP,-1,1,0,0,-999941831,out,100,350,arrow,300,391 +14,TIMESTAMP,0,-1,0,0,-999913577,in,500,371,marked,-1,-1 +15,TIMESTAMP,1,-1,0,0,-999906524,in,300,391,marked,-1,-1 +16,NET,1,-1,0,0,87819,out,300,416,arrow,100,477 +17,NET,0,-1,0,0,88491,out,500,435,arrow,100,456 +18,NET,-1,0,0,0,136240,in,100,456,marked,-1,-1 +19,NET,-1,1,0,0,168822,in,100,477,marked,-1,-1 +20,PTAG,-1,1,0,0,182147,out,100,498,arrow,300,539 +21,PTAG,-1,0,0,0,201463,out,100,519,arrow,500,559 +22,PTAG,1,-1,0,0,208607,in,300,539,marked,-1,-1 +23,PTAG,0,-1,0,0,216271,in,500,559,marked,-1,-1 +24,T_MSG,0,-1,0,0,446263,out,500,581,arrow,100,605 +25,T_MSG,-1,0,0,0,43615435,in,100,605,marked,-1,-1 +26,T_MSG,-1,1,0,0,43618230,out,100,625,arrow,300,646 +27,T_MSG,1,-1,0,0,43665168,in,300,646,marked,-1,-1 diff --git a/test/C/federate__receiver.csv b/test/C/federate__receiver.csv new file mode 100644 index 0000000000..f6a261ca92 --- /dev/null +++ b/test/C/federate__receiver.csv @@ -0,0 +1,11 @@ +Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay +Worker wait starts, NO REACTOR, 1, -1, 0, 0, 341276, NO TRIGGER, 0 +Worker wait starts, NO REACTOR, 2, -1, 0, 0, 376362, NO TRIGGER, 0 +Sending FED_ID, NO REACTOR, 1, -1, -1686279803405901114, 0, -1041305535, NO TRIGGER, 0 +Receiving ACK, NO REACTOR, 1, -1, -1686279803405901114, 0, -1041236205, NO TRIGGER, 0 +Sending TIMESTAMP, NO REACTOR, 1, -1, -1041185840, 0, -1041181933, NO TRIGGER, 0 +Receiving TIMESTAMP, NO REACTOR, 1, -1, 0, 0, -999906524, NO TRIGGER, 0 +Sending NET, NO REACTOR, 1, -1, 0, 0, 87819, NO TRIGGER, 0 +Receiving PTAG, NO REACTOR, 1, -1, 0, 0, 208607, NO TRIGGER, 0 +Worker wait starts, NO REACTOR, 0, -1, 0, 0, 326138, NO TRIGGER, 0 +Receiving TAGGED_MSG, NO REACTOR, 1, -1, 0, 0, 43665168, NO TRIGGER, 0 diff --git a/test/C/federate__receiver_summary.csv b/test/C/federate__receiver_summary.csv new file mode 100644 index 0000000000..da8d04534b --- /dev/null +++ b/test/C/federate__receiver_summary.csv @@ -0,0 +1,16 @@ +Start time:, 1686279803405901114 +End time:, 1686279803449566282 +Total time:, 43665168 + +Total Event Occurrences +Worker wait starts, 3 +Sending TIMESTAMP, 1 +Sending NET, 1 +Sending FED_ID, 1 +Receiving ACK, 1 +Receiving TIMESTAMP, 1 +Receiving PTAG, 1 +Receiving TAGGED_MSG, 1 + +Reaction Executions +Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time diff --git a/test/C/federate__sender.csv b/test/C/federate__sender.csv new file mode 100644 index 0000000000..ea34698814 --- /dev/null +++ b/test/C/federate__sender.csv @@ -0,0 +1,20 @@ +Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay +Worker wait starts, NO REACTOR, 1, -1, 0, 0, 326829, NO TRIGGER, 0 +Worker wait starts, NO REACTOR, 2, -1, 0, 0, 377073, NO TRIGGER, 0 +Sending FED_ID, NO REACTOR, 0, -1, -1686279803405901114, 0, -1040825162, NO TRIGGER, 0 +Receiving ACK, NO REACTOR, 0, -1, -1686279803405901114, 0, -1000187212, NO TRIGGER, 0 +Sending TIMESTAMP, NO REACTOR, 0, -1, -1000000000, 0, -999986915, NO TRIGGER, 0 +Receiving TIMESTAMP, NO REACTOR, 0, -1, 0, 0, -999913577, NO TRIGGER, 0 +Schedule called, sender, 0, 0, 0, 0, -999848234, sender.t, 0 +Schedule called, sender, 0, 0, 0, 0, -999845519, sender.t, 1000 +Sending NET, NO REACTOR, 0, -1, 0, 0, 88491, NO TRIGGER, 0 +Receiving PTAG, NO REACTOR, 0, -1, 0, 0, 216271, NO TRIGGER, 0 +Reaction starts, sender, 0, 0, 0, 0, 274490, NO TRIGGER, 0 +Schedule called, sender, 0, 0, 0, 0, 411548, sender.act, 0 +Reaction ends, sender, 0, 0, 0, 0, 413973, NO TRIGGER, 0 +Worker wait starts, NO REACTOR, 0, -1, 0, 0, 429051, NO TRIGGER, 0 +Worker wait ends, NO REACTOR, 0, -1, 0, 0, 434481, NO TRIGGER, 0 +Reaction starts, ns_federate__receiver, 0, 0, 0, 0, 442847, NO TRIGGER, 0 +Sending TAGGED_MSG, NO REACTOR, 0, -1, 0, 0, 446263, NO TRIGGER, 0 +Reaction ends, ns_federate__receiver, 0, 0, 0, 0, 463346, NO TRIGGER, 0 +Worker wait starts, NO REACTOR, 0, -1, 0, 0, 469397, NO TRIGGER, 0 diff --git a/test/C/federate__sender_summary.csv b/test/C/federate__sender_summary.csv new file mode 100644 index 0000000000..c3c8a72e1b --- /dev/null +++ b/test/C/federate__sender_summary.csv @@ -0,0 +1,27 @@ +Start time:, 1686279803405901114 +End time:, 1686279803406370511 +Total time:, 469397 + +Total Event Occurrences +Reaction starts, 2 +Reaction ends, 2 +Schedule called, 3 +Worker wait starts, 4 +Worker wait ends, 1 +Sending TIMESTAMP, 1 +Sending NET, 1 +Sending FED_ID, 1 +Sending TAGGED_MSG, 1 +Receiving ACK, 1 +Receiving TIMESTAMP, 1 +Receiving PTAG, 1 + +Reaction Executions +Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time +sender, 0, 1, 139483, 29.715358, 139483, 139483, 139483 +ns_federate__receiver, 0, 1, 20499, 4.367092, 20499, 20499, 20499 + +Schedule calls +Trigger, Occurrences +sender.act, 1 +sender.t, 2 diff --git a/test/C/rti.csv b/test/C/rti.csv new file mode 100644 index 0000000000..8bd2112691 --- /dev/null +++ b/test/C/rti.csv @@ -0,0 +1,15 @@ +Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay +Receiving FED_ID, NO REACTOR, -1, 1, -1686279803405901114, 0, -1041279256, NO TRIGGER, 0 +Sending ACK, NO REACTOR, -1, 1, -1686279803405901114, 0, -1041277413, NO TRIGGER, 0 +Receiving TIMESTAMP, NO REACTOR, -1, 1, -1041185840, 0, -1000221006, NO TRIGGER, 0 +Sending TIMESTAMP, NO REACTOR, -1, 1, 0, 0, -999941831, NO TRIGGER, 0 +Receiving NET, NO REACTOR, -1, 1, 0, 0, 168822, NO TRIGGER, 0 +Sending PTAG, NO REACTOR, -1, 1, 0, 0, 182147, NO TRIGGER, 0 +Sending TAGGED_MSG, NO REACTOR, -1, 1, 0, 0, 43618230, NO TRIGGER, 0 +Receiving FED_ID, NO REACTOR, -1, 0, -1686279803405901114, 0, -1000243598, NO TRIGGER, 0 +Sending ACK, NO REACTOR, -1, 0, -1686279803405901114, 0, -1000241414, NO TRIGGER, 0 +Receiving TIMESTAMP, NO REACTOR, -1, 0, -1000000000, 0, -999957680, NO TRIGGER, 0 +Sending TIMESTAMP, NO REACTOR, -1, 0, 0, 0, -999953903, NO TRIGGER, 0 +Receiving NET, NO REACTOR, -1, 0, 0, 0, 136240, NO TRIGGER, 0 +Sending PTAG, NO REACTOR, -1, 0, 0, 0, 201463, NO TRIGGER, 0 +Receiving TAGGED_MSG, NO REACTOR, -1, 0, 0, 0, 43615435, NO TRIGGER, 0 diff --git a/test/C/rti_summary.csv b/test/C/rti_summary.csv new file mode 100644 index 0000000000..31fcc3dc4a --- /dev/null +++ b/test/C/rti_summary.csv @@ -0,0 +1,16 @@ +Start time:, 1686279803405901114 +End time:, 1686279803449519344 +Total time:, 43618230 + +Total Event Occurrences +Sending ACK, 2 +Sending TIMESTAMP, 2 +Sending PTAG, 2 +Sending TAGGED_MSG, 1 +Receiving TIMESTAMP, 2 +Receiving NET, 2 +Receiving FED_ID, 2 +Receiving TAGGED_MSG, 1 + +Reaction Executions +Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time diff --git a/test/C/src/ActionWithNoReaction.lf b/test/C/src/ActionWithNoReaction.lf index 87f1c707c2..0143d67cce 100644 --- a/test/C/src/ActionWithNoReaction.lf +++ b/test/C/src/ActionWithNoReaction.lf @@ -10,7 +10,8 @@ reactor foo { output y: int logical action a: int* - reaction(x) -> y, a {= // reaction(a) {= =} + // reaction(a) {= =} + reaction(x) -> y, a {= lf_set(y, 2*x->value); lf_schedule(a, MSEC(500)); =} diff --git a/test/C/src/ArrayAsType.lf b/test/C/src/ArrayAsType.lf index 07dc9d1843..8339c6f9c2 100644 --- a/test/C/src/ArrayAsType.lf +++ b/test/C/src/ArrayAsType.lf @@ -13,7 +13,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input in: int[3] reaction(in) {= diff --git a/test/C/src/ArrayPrint.lf b/test/C/src/ArrayPrint.lf index 9cbf0e2fd6..49aaca5c12 100644 --- a/test/C/src/ArrayPrint.lf +++ b/test/C/src/ArrayPrint.lf @@ -24,7 +24,8 @@ reactor Source(size: int = 3) { =} } -reactor Print(scale: int = 1, size: int = 3) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1, size: int = 3) { input in: int[] state count: int = 0 diff --git a/test/C/src/DelayArray.lf b/test/C/src/DelayArray.lf index 62f36b059e..f818446991 100644 --- a/test/C/src/DelayArray.lf +++ b/test/C/src/DelayArray.lf @@ -29,7 +29,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input in: int[] reaction(in) {= diff --git a/test/C/src/DelayArrayWithAfter.lf b/test/C/src/DelayArrayWithAfter.lf index 094d264b08..3c3866b00c 100644 --- a/test/C/src/DelayArrayWithAfter.lf +++ b/test/C/src/DelayArrayWithAfter.lf @@ -22,7 +22,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input in: int[] state iteration: int = 1 state inputs_received: int = 0 diff --git a/test/C/src/DelayStruct.lf b/test/C/src/DelayStruct.lf index 6394ddbc1f..3d8ca9c665 100644 --- a/test/C/src/DelayStruct.lf +++ b/test/C/src/DelayStruct.lf @@ -39,7 +39,8 @@ reactor Source { =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: hello_t* reaction(in) {= diff --git a/test/C/src/DelayStructWithAfter.lf b/test/C/src/DelayStructWithAfter.lf index e3cf5b5b59..0207ba3ea2 100644 --- a/test/C/src/DelayStructWithAfter.lf +++ b/test/C/src/DelayStructWithAfter.lf @@ -20,7 +20,8 @@ reactor Source { =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: hello_t* reaction(in) {= diff --git a/test/C/src/DelayStructWithAfterOverlapped.lf b/test/C/src/DelayStructWithAfterOverlapped.lf index d10772a964..b098e9ecf1 100644 --- a/test/C/src/DelayStructWithAfterOverlapped.lf +++ b/test/C/src/DelayStructWithAfterOverlapped.lf @@ -25,7 +25,8 @@ reactor Source { =} } -reactor Print { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print { input in: hello_t* state s: int = 0 diff --git a/test/C/src/FloatLiteral.lf b/test/C/src/FloatLiteral.lf index dd6a39fc95..0179275083 100644 --- a/test/C/src/FloatLiteral.lf +++ b/test/C/src/FloatLiteral.lf @@ -1,6 +1,7 @@ target C -main reactor { // This test verifies that floating-point literals are handled correctly. +// This test verifies that floating-point literals are handled correctly. +main reactor { preamble {= #include =} diff --git a/test/C/src/HelloWorld.lf b/test/C/src/HelloWorld.lf index 07b49b0afd..470ebabb6b 100644 --- a/test/C/src/HelloWorld.lf +++ b/test/C/src/HelloWorld.lf @@ -1,5 +1,6 @@ target C { - tracing: { // To test generating a custom trace file name. + // To test generating a custom trace file name. + tracing: { trace-file-name: "HelloWorldTrace" }, logging: error, diff --git a/test/C/src/ManualDelayedReaction.lf b/test/C/src/ManualDelayedReaction.lf index 61e2519fc3..3432f15ec2 100644 --- a/test/C/src/ManualDelayedReaction.lf +++ b/test/C/src/ManualDelayedReaction.lf @@ -5,7 +5,8 @@ target C { keepalive: false } -reactor GeneratedDelay { // That's the stuff that shall be generated for the after +// That's the stuff that shall be generated for the after +reactor GeneratedDelay { input y_in: int output y_out: int state y_state: int = 0 diff --git a/test/C/src/MethodsRecursive.lf b/test/C/src/MethodsRecursive.lf index 3f2ec1fd00..8ba8a5627b 100644 --- a/test/C/src/MethodsRecursive.lf +++ b/test/C/src/MethodsRecursive.lf @@ -4,7 +4,8 @@ target C main reactor { state foo: int = 2 - method fib(n: int): int {= // Return the n-th Fibonacci number. + // Return the n-th Fibonacci number. + method fib(n: int): int {= if (n <= 1) return 1; return add(fib(n-1), fib(n-2)); =} diff --git a/test/C/src/NativeListsAndTimes.lf b/test/C/src/NativeListsAndTimes.lf index fa82f181a1..cbb1a6d861 100644 --- a/test/C/src/NativeListsAndTimes.lf +++ b/test/C/src/NativeListsAndTimes.lf @@ -1,6 +1,7 @@ target C -main reactor( // This test passes if it is successfully compiled into valid target code. +// This test passes if it is successfully compiled into valid target code. +main reactor( x: int = 0, y: time = 0, // Units are missing but not required z = 1 msec, // Type is missing but not required diff --git a/test/C/src/SendsPointerTest.lf b/test/C/src/SendsPointerTest.lf index 0ec366cadb..639798709f 100644 --- a/test/C/src/SendsPointerTest.lf +++ b/test/C/src/SendsPointerTest.lf @@ -13,7 +13,8 @@ reactor SendsPointer { =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: int_pointer reaction(in) {= diff --git a/test/C/src/SetArray.lf b/test/C/src/SetArray.lf index 72c2e938de..8926144e62 100644 --- a/test/C/src/SetArray.lf +++ b/test/C/src/SetArray.lf @@ -17,7 +17,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input in: int[] reaction(in) {= diff --git a/test/C/src/SetToken.lf b/test/C/src/SetToken.lf index 3ac1958b83..ff5e63066b 100644 --- a/test/C/src/SetToken.lf +++ b/test/C/src/SetToken.lf @@ -10,7 +10,8 @@ reactor Source { reaction(a) -> out {= lf_set_token(out, a->token); =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: int* reaction(in) {= diff --git a/test/C/src/StructAsType.lf b/test/C/src/StructAsType.lf index eded331cb9..bf7efbae41 100644 --- a/test/C/src/StructAsType.lf +++ b/test/C/src/StructAsType.lf @@ -23,7 +23,8 @@ reactor Source { =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: hello_t reaction(in) {= diff --git a/test/C/src/StructAsTypeDirect.lf b/test/C/src/StructAsTypeDirect.lf index b12e46b08e..4a7832ec68 100644 --- a/test/C/src/StructAsTypeDirect.lf +++ b/test/C/src/StructAsTypeDirect.lf @@ -17,7 +17,8 @@ reactor Source { =} } -reactor Print(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: int = 42) { input in: hello_t reaction(in) {= diff --git a/test/C/src/StructPrint.lf b/test/C/src/StructPrint.lf index 43d699860b..10bea74d49 100644 --- a/test/C/src/StructPrint.lf +++ b/test/C/src/StructPrint.lf @@ -20,7 +20,8 @@ reactor Print { =} } -reactor Check(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Check(expected: int = 42) { input in: hello_t* reaction(in) {= diff --git a/test/C/src/StructScale.lf b/test/C/src/StructScale.lf index bbc4d5d078..39293c2503 100644 --- a/test/C/src/StructScale.lf +++ b/test/C/src/StructScale.lf @@ -21,7 +21,8 @@ reactor Source { =} } -reactor TestInput(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor TestInput(expected: int = 42) { input in: hello_t* state invoked: bool = false diff --git a/test/C/src/docker/HelloWorldContainerized.lf b/test/C/src/docker/HelloWorldContainerized.lf index f486c7bb9a..d63ea45f93 100644 --- a/test/C/src/docker/HelloWorldContainerized.lf +++ b/test/C/src/docker/HelloWorldContainerized.lf @@ -1,5 +1,6 @@ target C { - tracing: { // To test generating a custom trace file name. + // To test generating a custom trace file name. + tracing: { trace-file-name: "HelloWorldTrace" }, logging: error, diff --git a/test/C/src/federated/DistributedLoopedPhysicalAction.lf b/test/C/src/federated/DistributedLoopedPhysicalAction.lf index dd7375cdb7..ace74a219f 100644 --- a/test/C/src/federated/DistributedLoopedPhysicalAction.lf +++ b/test/C/src/federated/DistributedLoopedPhysicalAction.lf @@ -10,7 +10,8 @@ */ target C { timeout: 1 sec, - coordination-options: { // Silences warning. + // Silences warning. + coordination-options: { advance-message-interval: 10 msec } } diff --git a/test/C/src/modal_models/BanksCount3ModesComplex.lf b/test/C/src/modal_models/BanksCount3ModesComplex.lf index b8afa7064f..220f63c949 100644 --- a/test/C/src/modal_models/BanksCount3ModesComplex.lf +++ b/test/C/src/modal_models/BanksCount3ModesComplex.lf @@ -70,7 +70,8 @@ main reactor { counters.always, counters.mode1, counters.mode2, counters.never -> test.events - reaction(stepper) -> counters.next {= // Trigger + // Trigger + reaction(stepper) -> counters.next {= for(int i = 0; i < 2; i++) { lf_set(counters[i].next, true); } diff --git a/test/C/src/modal_models/BanksCount3ModesSimple.lf b/test/C/src/modal_models/BanksCount3ModesSimple.lf index 8ca84403c9..e4f9ea6ec6 100644 --- a/test/C/src/modal_models/BanksCount3ModesSimple.lf +++ b/test/C/src/modal_models/BanksCount3ModesSimple.lf @@ -24,7 +24,8 @@ main reactor { counters.count -> test.events - reaction(stepper) -> counters.next {= // Trigger + // Trigger + reaction(stepper) -> counters.next {= for(int i = 0; i < 3; i++) { lf_set(counters[i].next, true); } diff --git a/test/C/src/modal_models/BanksModalStateReset.lf b/test/C/src/modal_models/BanksModalStateReset.lf index d8130611c7..57228081c2 100644 --- a/test/C/src/modal_models/BanksModalStateReset.lf +++ b/test/C/src/modal_models/BanksModalStateReset.lf @@ -45,7 +45,8 @@ main reactor { reset2.count2 -> test.events - reaction(stepper) -> reset1.next {= // Trigger mode change (separately because of #1278) + // Trigger mode change (separately because of #1278) + reaction(stepper) -> reset1.next {= for(int i = 0; i < reset1_width; i++) { lf_set(reset1[i].next, true); } diff --git a/test/C/src/modal_models/ConvertCaseTest.lf b/test/C/src/modal_models/ConvertCaseTest.lf index 24afa7439e..400c40e9ad 100644 --- a/test/C/src/modal_models/ConvertCaseTest.lf +++ b/test/C/src/modal_models/ConvertCaseTest.lf @@ -122,7 +122,8 @@ main reactor { reset_processor.converted, history_processor.converted -> test.events - reaction(stepper) -> reset_processor.discard, history_processor.discard {= // Trigger mode change + // Trigger mode change + reaction(stepper) -> reset_processor.discard, history_processor.discard {= lf_set(reset_processor.discard, true); lf_set(history_processor.discard, true); =} diff --git a/test/C/src/modal_models/Count3Modes.lf b/test/C/src/modal_models/Count3Modes.lf index 93e5119759..dc4063d865 100644 --- a/test/C/src/modal_models/Count3Modes.lf +++ b/test/C/src/modal_models/Count3Modes.lf @@ -38,7 +38,8 @@ main reactor { reaction(stepper) -> counter.next {= lf_set(counter.next, true); =} // Trigger - reaction(stepper) counter.count {= // Check + // Check + reaction(stepper) counter.count {= printf("%d\n", counter.count->value); if (!counter.count->is_present) { diff --git a/test/C/src/modal_models/ModalCycleBreaker.lf b/test/C/src/modal_models/ModalCycleBreaker.lf index c411fcbe3b..4ac9f509a7 100644 --- a/test/C/src/modal_models/ModalCycleBreaker.lf +++ b/test/C/src/modal_models/ModalCycleBreaker.lf @@ -16,7 +16,8 @@ reactor Modal { input in2: int output out: int - mode Two { // Defining reaction to in2 before in1 would cause cycle if no mode were present + // Defining reaction to in2 before in1 would cause cycle if no mode were present + mode Two { timer wait(150 msec, 1 sec) reaction(in2) {= // lf_set(out, in2->value); diff --git a/test/C/src/modal_models/ModalNestedReactions.lf b/test/C/src/modal_models/ModalNestedReactions.lf index f42ad4573f..be7d19fe7c 100644 --- a/test/C/src/modal_models/ModalNestedReactions.lf +++ b/test/C/src/modal_models/ModalNestedReactions.lf @@ -46,7 +46,8 @@ main reactor { reaction(stepper) -> counter.next {= lf_set(counter.next, true); =} // Trigger - reaction(stepper) counter.count, counter.only_in_two {= // Check + // Check + reaction(stepper) counter.count, counter.only_in_two {= printf("%d\n", counter.count->value); if (!counter.count->is_present) { diff --git a/test/C/src/modal_models/ModalStartupShutdown.lf b/test/C/src/modal_models/ModalStartupShutdown.lf index 389856c9e7..3a93cebfdd 100644 --- a/test/C/src/modal_models/ModalStartupShutdown.lf +++ b/test/C/src/modal_models/ModalStartupShutdown.lf @@ -88,7 +88,8 @@ reactor Modal { =} } - mode Five { // Unreachable! + // Unreachable! + mode Five { reaction(startup) -> startup5 {= printf("Startup 5 at (%lld, %u).\n", lf_time_logical_elapsed(), lf_tag().microstep); lf_set(startup5, 1); diff --git a/test/C/src/multiport/MultiportMutableInput.lf b/test/C/src/multiport/MultiportMutableInput.lf index 187b4d47be..50de03cc4d 100644 --- a/test/C/src/multiport/MultiportMutableInput.lf +++ b/test/C/src/multiport/MultiportMutableInput.lf @@ -11,7 +11,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input[2] in: int reaction(in) {= diff --git a/test/C/src/multiport/MultiportMutableInputArray.lf b/test/C/src/multiport/MultiportMutableInputArray.lf index 07f8a97365..f38eb78af1 100644 --- a/test/C/src/multiport/MultiportMutableInputArray.lf +++ b/test/C/src/multiport/MultiportMutableInputArray.lf @@ -25,7 +25,8 @@ reactor Source { =} } -reactor Print(scale: int = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: int = 1) { input[2] in: int[] reaction(in) {= diff --git a/test/C/src/multiport/MultiportToBank.lf b/test/C/src/multiport/MultiportToBank.lf index 4e0e89d05e..3249f3f61e 100644 --- a/test/C/src/multiport/MultiportToBank.lf +++ b/test/C/src/multiport/MultiportToBank.lf @@ -16,7 +16,9 @@ reactor Source(width: int = 2) { // Test also that multiple appearances of the same effect port do not result in multiple // allocations of memory for the port. - reaction(dummy) -> out {= // Contents of the reactions does not matter (either could be empty) + reaction(dummy) -> + // Contents of the reactions does not matter (either could be empty) + out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i); } diff --git a/test/C/src/multiport/MultiportToBankDouble.lf b/test/C/src/multiport/MultiportToBankDouble.lf index baf752b338..0fd905379d 100644 --- a/test/C/src/multiport/MultiportToBankDouble.lf +++ b/test/C/src/multiport/MultiportToBankDouble.lf @@ -16,7 +16,9 @@ reactor Source { // Test also that multiple appearances of the same effect port do not result in multiple // allocations of memory for the port. - reaction(startup) -> out {= // Contents of the reactions does not matter (either could be empty) + reaction(startup) -> + // Contents of the reactions does not matter (either could be empty) + out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i * 2); } diff --git a/test/C/src/no_inlining/IntPrint.lf b/test/C/src/no_inlining/IntPrint.lf index fd7639d45d..fd9f7d1e04 100644 --- a/test/C/src/no_inlining/IntPrint.lf +++ b/test/C/src/no_inlining/IntPrint.lf @@ -9,7 +9,8 @@ reactor Print { reaction(startup) -> out named send } -reactor Check(expected: int = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Check(expected: int = 42) { input in: int reaction(in) named receive diff --git a/test/C/temp.txt b/test/C/temp.txt new file mode 100644 index 0000000000..6e6a4106e0 --- /dev/null +++ b/test/C/temp.txt @@ -0,0 +1,124 @@ +Federate DistributedStop in Federation ID 'f4c5b423c156433c8b908f3c6595eb9aafd814168075d202' +#### Launching the federate federate__sender. +#### Launching the federate federate__receiver. +#### Bringing the RTI back to foreground so it can receive Control-C. +RTI -i ${FEDERATION_ID} -n 2 -c init exchanges-per-interval 10 +Federation ID for executable /home/peter/vscode-lingua-franca/lingua-franca/test/C/fed-gen/DistributedStop/bin/federate__sender: f4c5b423c156433c8b908f3c6595eb9aafd814168075d202 +DEBUG: _lf_new_token: Allocated memory for token: 0x55d77b60dab0 +DEBUG: _lf_new_token: Allocated memory for token: 0x55d77b60dec0 +DEBUG: Scheduler: Initializing with 3 workers +DEBUG: Scheduler: Max reaction level: 2 +DEBUG: Scheduler: Initialized vector of reactions for level 0 with size 1 +DEBUG: Scheduler: Initialized vector of reactions for level 1 with size 2 +DEBUG: Scheduler: Initialized vector of reactions for level 2 with size 1 +Federate 0: LOG: Connecting to the RTI. +Federate 0: LOG: Connected to an RTI. Sending federation ID for authentication. +Federate 0: DEBUG: Waiting for response to federation ID from the RTI. +Federate 0: LOG: Received acknowledgment from the RTI. +Federate 0: Connected to RTI at localhost:15045. +Federate 0: DEBUG: Physical time: 1686279449775465785. Elapsed: -7537092587079310023. Offset: 0 +Federate 0: DEBUG: Start time: 1686279449775465785ns +---- Start execution at time Thu Jun 8 19:57:29 2023 +---- plus 775465785 nanoseconds. +Federate 0: ---- Using 3 workers. +Federate 0: DEBUG: Scheduler: Initializing with 3 workers +Federate 0: DEBUG: Synchronizing with other federates. +Federate 0: DEBUG: Physical time: 1686279449775522231. Elapsed: 56446. Offset: 0 +Federate 0: DEBUG: Sending time 1686279449775522231 to the RTI. +Federate 0: DEBUG: Read 9 bytes. +Federate 0: Starting timestamp is: 1686279450818001739. +Federate 0: DEBUG: Physical time: 1686279449818147343. Elapsed: 42681558. Offset: 0 +Federate 0: LOG: Current physical time is: 1686279449818147343. +Federate 0: DEBUG: Scheduler: Enqueing reaction federate__sender.sender reaction 0, which has level 0. +Federate 0: DEBUG: Scheduler: Trying to lock the mutex for level 0. +Federate 0: DEBUG: Scheduler: Locked the mutex for level 0. +Federate 0: DEBUG: Scheduler: Accessing triggered reactions at the level 0 with index 0. +Federate 0: DEBUG: Scheduler: Index for level 0 is at 0. +Federate 0: LOG: Waiting for start time 1686279450818001739 plus STA 0. +Federate 0: DEBUG: -------- Waiting until physical time matches logical time 1686279450818001739 +Federate 0: DEBUG: Physical time: 1686279449818230780. Elapsed: -999770959. Offset: 0 +Federate 0: DEBUG: -------- Clock offset is 0 ns. +Federate 0: DEBUG: -------- Waiting 999770959 ns for physical time to match logical time 0. +Federate 0: DEBUG: Physical time: 1686279450818067383. Elapsed: 65644. Offset: 0 +Federate 0: DEBUG: Done waiting for start time 1686279450818001739. +Federate 0: DEBUG: Physical time: 1686279450818079496. Elapsed: 77757. Offset: 0 +Federate 0: DEBUG: Physical time is ahead of current time by 77757. This should be small. +Federate 0: DEBUG: Checking NET to see whether it should be bounded by physical time. Min delay from physical action: -9223372036854775808. +Federate 0: DEBUG: Sending tag (0, 0) to the RTI. +Federate 0: LOG: Sent next event tag (NET) (0, 0) to RTI. +Federate 0: DEBUG: Not waiting for reply to NET (0, 0) because I have no upstream federates. +Federate 0: DEBUG: Executing output control reactions. +Federate 0: LOG: Starting 3 worker threads. +Federate 0: DEBUG: Waiting for worker threads to exit. +Federate 0: DEBUG: Number of threads: 3. +Federate 0: LOG: Worker thread 0 started. +Federate 0: DEBUG: Scheduler: Worker 0 popping reaction with level 0, index for level: 0. +Federate 0: DEBUG: Worker 0: Got from scheduler reaction federate__sender.sender reaction 0: level: 0, is control reaction: 0, chain ID: 1, and deadline -9223372036854775808. +Federate 0: LOG: Worker 0: Invoking reaction federate__sender.sender reaction 0 at elapsed tag (0, 0). +Federate 0: DEBUG: _lf_replace_template_token: template: 0x55d77b60d5e0 newtoken: 0x55d77b60dab0. +Federate 0: DEBUG: _lf_replace_template_token: Incremented ref_count of 0x55d77b60dab0 to 2. +Federate 0: Sending 42 at (0, 0). +Federate 0: DEBUG: _lf_schedule: scheduling trigger 0x55d77b60d910 with delay 0 and token (nil). +Federate 0: DEBUG: _lf_schedule: current_tag.time = 168627Federation ID for executable /home/peter/vscode-lingua-franca/lingua-franca/test/C/fed-gen/DistributedStop/bin/federate__receiver: f4c5b423c156433c8b908f3c6595eb9aafd814168075d202 +DEBUG: _lf_new_token: Allocated memory for token: 0x55c15e3ebc00 +DEBUG: Scheduler: Initializing with 3 workers +DEBUG: Scheduler: Max reaction level: 2 +DEBUG: Scheduler: Initialized vector of reactions for level 0 with size 1 +DEBUG: Scheduler: Initialized vector of reactions for level 1 with size 1 +DEBUG: Scheduler: Initialized vector of reactions for level 2 with size 1 +Federate 1: LOG: Connecting to the RTI. +Federate 1: LOG: Connected to an RTI. Sending federation ID for authentication. +Federate 1: DEBUG: Waiting for response to federation ID from the RTI. +Federate 1: LOG: Received acknowledgment from the RTI. +Federate 1: Connected to RTI at localhost:15045. +Federate 1: DEBUG: Physical time: 1686279449817891932. Elapsed: -7537092587036883876. Offset: 0 +Federate 1: DEBUG: Start time: 1686279449817891932ns +---- Start execution at time Thu Jun 8 19:57:29 2023 +---- plus 817891932 nanoseconds. +Federate 1: ---- Using 3 workers. +Federate 1: DEBUG: Scheduler: Initializing with 3 workers +Federate 1: DEBUG: Synchronizing with other federates. +Federate 1: DEBUG: Physical time: 1686279449818001739. Elapsed: 109807. Offset: 0 +Federate 1: DEBUG: Sending time 1686279449818001739 to the RTI. +Federate 1: DEBUG: Read 9 bytes. +Federate 1: Starting timestamp is: 1686279450818001739. +Federate 1: DEBUG: Physical time: 1686279449818123568. Elapsed: 231636. Offset: 0 +Federate 1: LOG: Current physical time is: 1686279449818123568. +Federate 1: LOG: Waiting for start time 1686279450818001739 plus STA 0. +Federate 1: DEBUG: -------- Waiting until physical time matches logical time 1686279450818001739 +Federate 1: DEBUG: Physical time: 1686279449818218526. Elapsed: -999783213. Offset: 0 +Federate 1: DEBUG: -------- Clock offset is 0 ns. +Federate 1: DEBUG: -------- Waiting 999783213 ns for physical time to match logical time 0. +Federate 1: DEBUG: Physical time: 1686279450818074676. Elapsed: 72937. Offset: 0 +Federate 1: DEBUG: Done waiting for start time 1686279450818001739. +Federate 1: DEBUG: Physical time: 1686279450818083933. Elapsed: 82194. Offset: 0 +Federate 1: DEBUG: Physical time is ahead of current time by 82194. This should be small. +Federate 1: DEBUG: Checking NET to see whether it should be bounded by physical time. Min delay from physical action: -9223372036854775808. +Federate 1: DEBUG: Sending tag (0, 0) to the RTI. +Federate 1: LOG: Sent next event tag (NET) (0, 0) to RTI. +Federate 1: DEBUG: Waiting for a TAG from the RTI. +Federate 1: LOG: At tag (0, 0), received Provisional Tag Advance Grant (PTAG): (0, 0). +Federate 1: LOG: Starting 3 worker threads. +Federate 1: DEBUG: Waiting for worker threads to exit. +Federate 1: DEBUG: Number of threads: 3. +Federate 1: LOG: Worker thread 0 started. +Federate 1: DEBUG: Worker 0 is out of ready reactions. +Federate 1: DEBUG: Scheduler: Worker 0 is trying to acquire the scheduling semaphore. +Federate 1: LOG: Worker thread 1 started. +Federate 1: DEBUG: Worker 1 is out of ready reactions. +Federate 1: DEBUG: Scheduler: Worker 1 is trying to acquire the scheduling semaphore. +Federate 1: LOG: Worker thread 2 started. +Federate 1: DEBUG: Worker 2 is out of ready reactions. +Federate 1: DEBUG: Scheduler: Worker 2 is the last idle thread. +Federate 1: DEBUG: Receiving message to port 0 of length 4. +Federate 1: DEBUG: Physical time: 1686279450861618465. Elapsed: 43616726. Offset: 0 +Federate 1: LOG: Received message with tag: (0, 0), Current tag: (0, 0). +Federate 1: DEBUG: _lf_new_token: Allocated memory for token: 0x7f1664000ce0 +Federate 1: DEBUG: Updating the last known status tag of port 0 to (0, 0). +Federate 1: LOG: Inserting reactions directly at tag (0, 0). Intended tag: (0, 0). +Federate 1: DEBUG: _lf_replace_template_token: template: 0x55c15e3eba68 newtoken: 0x7f1664000ce0. +Federate 1: DEBUG: _lf_done_using: token = 0x55c15e3ebc00, ref_count = 1. +Federate 1: DEBUG: _lf_free_token: Putting token on the recycling bin: 0x55c15e3ebc00 +FedeKilling federate 66286. +Killing federate 66288. +#### Killing RTI 66280. diff --git a/test/C/trace_svg.html b/test/C/trace_svg.html new file mode 100644 index 0000000000..f2ceb2f918 --- /dev/null +++ b/test/C/trace_svg.html @@ -0,0 +1,97 @@ + + + + + + + + + + RTI + + + + + federate__receiver + + + + + federate__sender + + + + + FED_ID + -1,041,305 + -1,041,279 + + + ACK + -1,041,277 + -1,041,236 + + + TIMESTAMP(-1,041,185,840, 0) + -1,041,181 + + + FED_ID + -1,040,825 + -1,000,243 + + + ACK + -1,000,241 + -1,000,221 + -1,000,187 + + + TIMESTAMP(-1,000,000,000, 0) + -999,986 + -999,957 + + + TIMESTAMP(0, 0) + -999,953 + + + TIMESTAMP(0, 0) + -999,941 + -999,913 + -999,906 + + + NET(0, 0) + 87 + + + NET(0, 0) + 88 + 136 + 168 + + + PTAG(0, 0) + 182 + + + PTAG(0, 0) + 201 + 208 + 216 + + + T_MSG(0, 0) + 446 + 43,615 + + + T_MSG(0, 0) + 43,618 + 43,665 + + + + + diff --git a/test/Cpp/src/FloatLiteral.lf b/test/Cpp/src/FloatLiteral.lf index 4f57e36caa..f66aacbb12 100644 --- a/test/Cpp/src/FloatLiteral.lf +++ b/test/Cpp/src/FloatLiteral.lf @@ -1,6 +1,7 @@ target Cpp -main reactor { // This test verifies that floating-point literals are handled correctly. +// This test verifies that floating-point literals are handled correctly. +main reactor { state N: double = 6.0221409e+23 state charge: double = -1.6021766E-19 state minus_epsilon: double = -.01e0 diff --git a/test/Cpp/src/ManualDelayedReaction.lf b/test/Cpp/src/ManualDelayedReaction.lf index f3b8991136..f1917be62f 100644 --- a/test/Cpp/src/ManualDelayedReaction.lf +++ b/test/Cpp/src/ManualDelayedReaction.lf @@ -1,6 +1,7 @@ target Cpp -reactor GeneratedDelay { // That's the stuff that shall be generated for the after +// That's the stuff that shall be generated for the after +reactor GeneratedDelay { input y_in: int output y_out: int state y_state: int = 0 diff --git a/test/Cpp/src/NativeListsAndTimes.lf b/test/Cpp/src/NativeListsAndTimes.lf index 59d0101087..7320f5acc5 100644 --- a/test/Cpp/src/NativeListsAndTimes.lf +++ b/test/Cpp/src/NativeListsAndTimes.lf @@ -1,6 +1,7 @@ target Cpp -reactor Foo( // This test passes if it is successfully compiled into valid target code. +// This test passes if it is successfully compiled into valid target code. +reactor Foo( x: int = 0, y: time = 0, // Units are missing but not required z = 1 msec, // Type is missing but not required @@ -18,9 +19,7 @@ reactor Foo( // This test passes if it is successfully compiled into valid targ timer toe(z) // Implicit type time state baz = p // Implicit type int[] state period = z // Implicit type time - state times: std::vector< // a list of lists - std::vector<{= reactor::Duration =}> - >{q, g} + state times: std::vector>{q, g} // a list of lists state empty_list: int[] = {} reaction(tick) {= diff --git a/test/Python/src/ActionWithNoReaction.lf b/test/Python/src/ActionWithNoReaction.lf index a219377e6e..5e9456356d 100644 --- a/test/Python/src/ActionWithNoReaction.lf +++ b/test/Python/src/ActionWithNoReaction.lf @@ -10,7 +10,8 @@ reactor foo { output y logical action a - reaction(x) -> y, a {= # reaction(a) {= =} + # reaction(a) {= =} + reaction(x) -> y, a {= y.set(2*x.value) a.schedule(MSEC(500)) =} diff --git a/test/Python/src/ArrayAsType.lf b/test/Python/src/ArrayAsType.lf index de1490d332..554293a623 100644 --- a/test/Python/src/ArrayAsType.lf +++ b/test/Python/src/ArrayAsType.lf @@ -11,7 +11,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input _in reaction(_in) {= diff --git a/test/Python/src/ArrayPrint.lf b/test/Python/src/ArrayPrint.lf index f13d44c7bf..3d77584d1d 100644 --- a/test/Python/src/ArrayPrint.lf +++ b/test/Python/src/ArrayPrint.lf @@ -11,7 +11,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input _in reaction(_in) {= diff --git a/test/Python/src/DelayArray.lf b/test/Python/src/DelayArray.lf index b931821682..fd2c113c0f 100644 --- a/test/Python/src/DelayArray.lf +++ b/test/Python/src/DelayArray.lf @@ -24,7 +24,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input _in reaction(_in) {= diff --git a/test/Python/src/DelayArrayWithAfter.lf b/test/Python/src/DelayArrayWithAfter.lf index 1567074c22..a13dbe1c2d 100644 --- a/test/Python/src/DelayArrayWithAfter.lf +++ b/test/Python/src/DelayArrayWithAfter.lf @@ -17,7 +17,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input _in state iteration = 1 state inputs_received = 0 diff --git a/test/Python/src/DelayStruct.lf b/test/Python/src/DelayStruct.lf index 94d232011b..d02f43ce58 100644 --- a/test/Python/src/DelayStruct.lf +++ b/test/Python/src/DelayStruct.lf @@ -25,7 +25,8 @@ reactor Source { reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -reactor Print(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor Print(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/DelayStructWithAfter.lf b/test/Python/src/DelayStructWithAfter.lf index b7d34f127a..4ea5827157 100644 --- a/test/Python/src/DelayStructWithAfter.lf +++ b/test/Python/src/DelayStructWithAfter.lf @@ -11,7 +11,8 @@ reactor Source { reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -reactor Print(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor Print(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/DelayStructWithAfterOverlapped.lf b/test/Python/src/DelayStructWithAfterOverlapped.lf index ed9270de31..1137efeb22 100644 --- a/test/Python/src/DelayStructWithAfterOverlapped.lf +++ b/test/Python/src/DelayStructWithAfterOverlapped.lf @@ -18,7 +18,8 @@ reactor Source { =} } -reactor Print { # expected parameter is for testing. +# expected parameter is for testing. +reactor Print { input _in state s = 0 diff --git a/test/Python/src/FloatLiteral.lf b/test/Python/src/FloatLiteral.lf index 8d1edd93f1..2f029996f4 100644 --- a/test/Python/src/FloatLiteral.lf +++ b/test/Python/src/FloatLiteral.lf @@ -1,6 +1,7 @@ target Python -main reactor { # This test verifies that floating-point literals are handled correctly. +# This test verifies that floating-point literals are handled correctly. +main reactor { state N = 6.0221409e+23 state charge = -1.6021766E-19 state minus_epsilon = -.01e0 diff --git a/test/Python/src/ManualDelayedReaction.lf b/test/Python/src/ManualDelayedReaction.lf index 573c588b67..645c58f6ea 100644 --- a/test/Python/src/ManualDelayedReaction.lf +++ b/test/Python/src/ManualDelayedReaction.lf @@ -5,7 +5,8 @@ target Python { keepalive: false } -reactor GeneratedDelay { # That's the stuff that shall be generated for the after +# That's the stuff that shall be generated for the after +reactor GeneratedDelay { input y_in output y_out state y_state = 0 diff --git a/test/Python/src/MethodsRecursive.lf b/test/Python/src/MethodsRecursive.lf index a1fa182792..bc3cedb8cd 100644 --- a/test/Python/src/MethodsRecursive.lf +++ b/test/Python/src/MethodsRecursive.lf @@ -4,7 +4,8 @@ target Python main reactor { state foo = 2 - method fib(n) {= # Return the n-th Fibonacci number. + # Return the n-th Fibonacci number. + method fib(n) {= if n <= 1: return 1 return self.add(self.fib(n-1), self.fib(n-2)) diff --git a/test/Python/src/NativeListsAndTimes.lf b/test/Python/src/NativeListsAndTimes.lf index 775d074343..28a7d5c015 100644 --- a/test/Python/src/NativeListsAndTimes.lf +++ b/test/Python/src/NativeListsAndTimes.lf @@ -1,6 +1,7 @@ target Python -main reactor( # This test passes if it is successfully compiled into valid target code. +# This test passes if it is successfully compiled into valid target code. +main reactor( x = 0, y = 0, # Units are missing but not required z = 1 msec, # Type is missing but not required diff --git a/test/Python/src/SetArray.lf b/test/Python/src/SetArray.lf index c27408647b..2e7e504836 100644 --- a/test/Python/src/SetArray.lf +++ b/test/Python/src/SetArray.lf @@ -8,7 +8,8 @@ reactor Source { reaction(startup) -> out {= out.set([0,1,2]) =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input _in reaction(_in) {= diff --git a/test/Python/src/StructAsType.lf b/test/Python/src/StructAsType.lf index cd200a86ff..a16831f641 100644 --- a/test/Python/src/StructAsType.lf +++ b/test/Python/src/StructAsType.lf @@ -13,7 +13,8 @@ reactor Source { =} } -reactor Print(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor Print(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/StructAsTypeDirect.lf b/test/Python/src/StructAsTypeDirect.lf index 9e44cc6f34..7b903272a8 100644 --- a/test/Python/src/StructAsTypeDirect.lf +++ b/test/Python/src/StructAsTypeDirect.lf @@ -16,7 +16,8 @@ reactor Source { =} } -reactor Print(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor Print(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/StructPrint.lf b/test/Python/src/StructPrint.lf index 191f72bc6d..e4303e1d09 100644 --- a/test/Python/src/StructPrint.lf +++ b/test/Python/src/StructPrint.lf @@ -12,7 +12,8 @@ reactor Print { reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -reactor Check(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor Check(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/StructScale.lf b/test/Python/src/StructScale.lf index ce4a25bc67..fa650211d8 100644 --- a/test/Python/src/StructScale.lf +++ b/test/Python/src/StructScale.lf @@ -12,7 +12,8 @@ reactor Source { reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -reactor TestInput(expected = 42) { # expected parameter is for testing. +# expected parameter is for testing. +reactor TestInput(expected = 42) { input _in reaction(_in) {= diff --git a/test/Python/src/lib/ImportedAgain.lf b/test/Python/src/lib/ImportedAgain.lf index 9371712337..cabbf73f0a 100644 --- a/test/Python/src/lib/ImportedAgain.lf +++ b/test/Python/src/lib/ImportedAgain.lf @@ -2,7 +2,8 @@ # reactor definition. target Python -reactor ImportedAgain { # import Imported from "Imported.lf" +# import Imported from "Imported.lf" +reactor ImportedAgain { input x # y = new Imported(); // FIXME: Address this bug reaction(x) {= diff --git a/test/Python/src/modal_models/BanksCount3ModesComplex.lf b/test/Python/src/modal_models/BanksCount3ModesComplex.lf index 97447dc0b5..af97eec07b 100644 --- a/test/Python/src/modal_models/BanksCount3ModesComplex.lf +++ b/test/Python/src/modal_models/BanksCount3ModesComplex.lf @@ -67,7 +67,8 @@ main reactor { counters.always, counters.mode1, counters.mode2, counters.never -> test.events - reaction(stepper) -> counters.next {= # Trigger + # Trigger + reaction(stepper) -> counters.next {= for i in range(len(counters)): counters[i].next.set(True) =} diff --git a/test/Python/src/modal_models/BanksCount3ModesSimple.lf b/test/Python/src/modal_models/BanksCount3ModesSimple.lf index f36a82178a..503a5b99eb 100644 --- a/test/Python/src/modal_models/BanksCount3ModesSimple.lf +++ b/test/Python/src/modal_models/BanksCount3ModesSimple.lf @@ -24,7 +24,8 @@ main reactor { counters.count -> test.events - reaction(stepper) -> counters.next {= # Trigger + # Trigger + reaction(stepper) -> counters.next {= for counter in counters: counter.next.set(True) =} diff --git a/test/Python/src/modal_models/BanksModalStateReset.lf b/test/Python/src/modal_models/BanksModalStateReset.lf index 65080b5da9..d127288e0b 100644 --- a/test/Python/src/modal_models/BanksModalStateReset.lf +++ b/test/Python/src/modal_models/BanksModalStateReset.lf @@ -45,7 +45,8 @@ main reactor { reset2.count2 -> test.events - reaction(stepper) -> reset1.next {= # Trigger mode change (separately because of #1278) + # Trigger mode change (separately because of #1278) + reaction(stepper) -> reset1.next {= for i in range(len(reset1)): reset1[i].next.set(True) =} diff --git a/test/Python/src/modal_models/ConvertCaseTest.lf b/test/Python/src/modal_models/ConvertCaseTest.lf index 85e6c6f5e9..b6723f12d8 100644 --- a/test/Python/src/modal_models/ConvertCaseTest.lf +++ b/test/Python/src/modal_models/ConvertCaseTest.lf @@ -107,7 +107,8 @@ main reactor { reset_processor.converted, history_processor.converted -> test.events - reaction(stepper) -> reset_processor.discard, history_processor.discard {= # Trigger mode change + # Trigger mode change + reaction(stepper) -> reset_processor.discard, history_processor.discard {= reset_processor.discard.set(True) history_processor.discard.set(True) =} diff --git a/test/Python/src/modal_models/Count3Modes.lf b/test/Python/src/modal_models/Count3Modes.lf index 77fb09d1c0..5815c0bb99 100644 --- a/test/Python/src/modal_models/Count3Modes.lf +++ b/test/Python/src/modal_models/Count3Modes.lf @@ -38,7 +38,8 @@ main reactor { reaction(stepper) -> counter.next {= counter.next.set(True) =} # Trigger - reaction(stepper) counter.count {= # Check + # Check + reaction(stepper) counter.count {= print(f"{counter.count.value}") if counter.count.is_present is not True: diff --git a/test/Python/src/modal_models/ModalCycleBreaker.lf b/test/Python/src/modal_models/ModalCycleBreaker.lf index 97155b1534..f790373131 100644 --- a/test/Python/src/modal_models/ModalCycleBreaker.lf +++ b/test/Python/src/modal_models/ModalCycleBreaker.lf @@ -16,7 +16,8 @@ reactor Modal { input in2 output out - mode Two { # Defining reaction to in2 before in1 would cause cycle if no mode were present + # Defining reaction to in2 before in1 would cause cycle if no mode were present + mode Two { timer wait(150 msec, 1 sec) reaction(in2) {= =} diff --git a/test/Python/src/modal_models/ModalNestedReactions.lf b/test/Python/src/modal_models/ModalNestedReactions.lf index 2a9dc780f0..82fbbd5275 100644 --- a/test/Python/src/modal_models/ModalNestedReactions.lf +++ b/test/Python/src/modal_models/ModalNestedReactions.lf @@ -46,7 +46,8 @@ main reactor { reaction(stepper) -> counter.next {= counter.next.set(True) =} # Trigger - reaction(stepper) counter.count, counter.only_in_two {= # Check + # Check + reaction(stepper) counter.count, counter.only_in_two {= print(counter.count.value) if counter.count.is_present is not True: diff --git a/test/Python/src/modal_models/ModalStartupShutdown.lf b/test/Python/src/modal_models/ModalStartupShutdown.lf index cd0770ef5f..f5210580d1 100644 --- a/test/Python/src/modal_models/ModalStartupShutdown.lf +++ b/test/Python/src/modal_models/ModalStartupShutdown.lf @@ -88,7 +88,8 @@ reactor Modal { =} } - mode Five { # Unreachable! + # Unreachable! + mode Five { reaction(startup) -> startup5 {= print(f"Startup 5 at ({lf.time.logical_elapsed()}, {lf.tag().microstep}).") startup5.set(1) diff --git a/test/Python/src/multiport/MultiportMutableInput.lf b/test/Python/src/multiport/MultiportMutableInput.lf index a8e15b8bd6..bfc691d1c2 100644 --- a/test/Python/src/multiport/MultiportMutableInput.lf +++ b/test/Python/src/multiport/MultiportMutableInput.lf @@ -11,7 +11,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input[2] _in reaction(_in) {= diff --git a/test/Python/src/multiport/MultiportMutableInputArray.lf b/test/Python/src/multiport/MultiportMutableInputArray.lf index 9e6a7630de..a936910ddd 100644 --- a/test/Python/src/multiport/MultiportMutableInputArray.lf +++ b/test/Python/src/multiport/MultiportMutableInputArray.lf @@ -12,7 +12,8 @@ reactor Source { =} } -reactor Print(scale = 1) { # The scale parameter is just for testing. +# The scale parameter is just for testing. +reactor Print(scale = 1) { input[2] _in reaction(_in) {= diff --git a/test/Rust/src/FloatLiteral.lf b/test/Rust/src/FloatLiteral.lf index a0d61c9fdf..072e896779 100644 --- a/test/Rust/src/FloatLiteral.lf +++ b/test/Rust/src/FloatLiteral.lf @@ -1,6 +1,7 @@ target Rust -main reactor { // This test verifies that floating-point literals are handled correctly. +// This test verifies that floating-point literals are handled correctly. +main reactor { state N: f64 = 6.0221409e+23 state charge: f64 = -1.6021766E-19 state minus_epsilon: f64 = -.01e0 diff --git a/test/Rust/src/NativeListsAndTimes.lf b/test/Rust/src/NativeListsAndTimes.lf index 21c44e17d8..5d95f2fa07 100644 --- a/test/Rust/src/NativeListsAndTimes.lf +++ b/test/Rust/src/NativeListsAndTimes.lf @@ -1,6 +1,7 @@ target Rust -reactor Foo( // This test passes if it is successfully compiled into valid target code. +// This test passes if it is successfully compiled into valid target code. +reactor Foo( x: i32 = 0, y: time = 0, // Units are missing but not required z = 1 msec, // Type is missing but not required diff --git a/test/Rust/src/StructAsType.lf b/test/Rust/src/StructAsType.lf index 93450959b5..38242be033 100644 --- a/test/Rust/src/StructAsType.lf +++ b/test/Rust/src/StructAsType.lf @@ -18,7 +18,8 @@ reactor Source { =} } -reactor Print(expected: i32 = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: i32 = 42) { input inp: {= super::source::Hello =} state expected: i32 = expected diff --git a/test/TypeScript/src/ArrayAsType.lf b/test/TypeScript/src/ArrayAsType.lf index 45df34464c..fdeb482535 100644 --- a/test/TypeScript/src/ArrayAsType.lf +++ b/test/TypeScript/src/ArrayAsType.lf @@ -14,7 +14,8 @@ reactor Source { =} } -reactor Print(scale: number = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: number = 1) { input x: {= Array =} reaction(x) {= diff --git a/test/TypeScript/src/ArrayPrint.lf b/test/TypeScript/src/ArrayPrint.lf index 8eff86be03..f072536b91 100644 --- a/test/TypeScript/src/ArrayPrint.lf +++ b/test/TypeScript/src/ArrayPrint.lf @@ -14,7 +14,8 @@ reactor Source { =} } -reactor Print(scale: number = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: number = 1) { input x: {= Array =} reaction(x) {= diff --git a/test/TypeScript/src/Deadline.lf b/test/TypeScript/src/Deadline.lf index f83647dbf3..e6a6037090 100644 --- a/test/TypeScript/src/Deadline.lf +++ b/test/TypeScript/src/Deadline.lf @@ -4,7 +4,8 @@ target TypeScript { timeout: 4 sec } -reactor Source(period: time = 2 sec) { // run = "bin/Deadline -timeout 4 sec" +// run = "bin/Deadline -timeout 4 sec" +reactor Source(period: time = 2 sec) { output y: number timer t(0, period) state count: number = 0 diff --git a/test/TypeScript/src/FloatLiteral.lf b/test/TypeScript/src/FloatLiteral.lf index 42c9edf35a..a7c57397d4 100644 --- a/test/TypeScript/src/FloatLiteral.lf +++ b/test/TypeScript/src/FloatLiteral.lf @@ -1,6 +1,7 @@ target TypeScript -main reactor { // This test verifies that floating-point literals are handled correctly. +// This test verifies that floating-point literals are handled correctly. +main reactor { state N: number = 6.0221409e+23 state charge: number = -1.6021766E-19 state minus_epsilon: number = -.01e0 diff --git a/test/TypeScript/src/NativeListsAndTimes.lf b/test/TypeScript/src/NativeListsAndTimes.lf index 3e28688c79..393d7873b9 100644 --- a/test/TypeScript/src/NativeListsAndTimes.lf +++ b/test/TypeScript/src/NativeListsAndTimes.lf @@ -1,6 +1,7 @@ target TypeScript -main reactor( // This test passes if it is successfully compiled into valid target code. +// This test passes if it is successfully compiled into valid target code. +main reactor( x: number = 0, y: time = 0, // Units are missing but not required z = 1 msec, // Type is missing but not required diff --git a/test/TypeScript/src/StructAsType.lf b/test/TypeScript/src/StructAsType.lf index 117f760536..bef058e295 100644 --- a/test/TypeScript/src/StructAsType.lf +++ b/test/TypeScript/src/StructAsType.lf @@ -18,7 +18,8 @@ reactor Source { =} } -reactor Print(expected: number = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: number = 42) { input x: hello_t reaction(x) {= diff --git a/test/TypeScript/src/StructAsTypeDirect.lf b/test/TypeScript/src/StructAsTypeDirect.lf index 70b8d4b681..a2e6425172 100644 --- a/test/TypeScript/src/StructAsTypeDirect.lf +++ b/test/TypeScript/src/StructAsTypeDirect.lf @@ -18,7 +18,8 @@ reactor Source { =} } -reactor Print(expected: number = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: number = 42) { input x: hello_t reaction(x) {= diff --git a/test/TypeScript/src/StructPrint.lf b/test/TypeScript/src/StructPrint.lf index 4a79efb807..9268100161 100644 --- a/test/TypeScript/src/StructPrint.lf +++ b/test/TypeScript/src/StructPrint.lf @@ -17,7 +17,8 @@ reactor Source { =} } -reactor Print(expected: number = 42) { // expected parameter is for testing. +// expected parameter is for testing. +reactor Print(expected: number = 42) { input x: hello_t reaction(x) {= diff --git a/test/TypeScript/src/TimeLimit.lf b/test/TypeScript/src/TimeLimit.lf index 030879b594..c0b818c2e9 100644 --- a/test/TypeScript/src/TimeLimit.lf +++ b/test/TypeScript/src/TimeLimit.lf @@ -29,7 +29,8 @@ reactor Destination { =} } -main reactor TimeLimit(period: time = 1 msec) { // usecs take a little too long +// usecs take a little too long +main reactor TimeLimit(period: time = 1 msec) { timer stop(10 sec) c = new Clock(period = period) diff --git a/test/TypeScript/src/multiport/MultiportMutableInput.lf b/test/TypeScript/src/multiport/MultiportMutableInput.lf index bfab84c4a2..aad2281b3d 100644 --- a/test/TypeScript/src/multiport/MultiportMutableInput.lf +++ b/test/TypeScript/src/multiport/MultiportMutableInput.lf @@ -11,7 +11,8 @@ reactor Source { =} } -reactor Print(scale: number = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: number = 1) { input[2] inp: number reaction(inp) {= diff --git a/test/TypeScript/src/multiport/MultiportMutableInputArray.lf b/test/TypeScript/src/multiport/MultiportMutableInputArray.lf index ab863f8f1d..3450885edf 100644 --- a/test/TypeScript/src/multiport/MultiportMutableInputArray.lf +++ b/test/TypeScript/src/multiport/MultiportMutableInputArray.lf @@ -25,7 +25,8 @@ reactor Source { =} } -reactor Print(scale: number = 1) { // The scale parameter is just for testing. +// The scale parameter is just for testing. +reactor Print(scale: number = 1) { input[2] inp: {= Array =} reaction(inp) {= diff --git a/test/TypeScript/src/multiport/MultiportToBankDouble.lf b/test/TypeScript/src/multiport/MultiportToBankDouble.lf index 9f5ccf62ad..966fdf3b32 100644 --- a/test/TypeScript/src/multiport/MultiportToBankDouble.lf +++ b/test/TypeScript/src/multiport/MultiportToBankDouble.lf @@ -15,7 +15,9 @@ reactor Source { // Test also that multiple appearances of the same effect port do not result in multiple // allocations of memory for the port. - reaction(startup) -> out {= // Contents of the reactions does not matter (either could be empty) + reaction(startup) -> + // Contents of the reactions does not matter (either could be empty) + out {= for (let i = 0; i < out.length; i++) { out[i] = i * 2; } From b4c269b6e93648656ee473eb0d013d5dfd2bc408 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 12:46:43 -0700 Subject: [PATCH 082/142] Rename Utils -> Util. --- cli/lff/src/main/java/org/lflang/cli/Lff.java | 12 ++++++------ .../{FormattingUtils.java => FormattingUtil.java} | 4 ++-- .../main/java/org/lflang/ast/MalleableString.java | 6 +++--- .../ast/{ParsingUtils.java => ParsingUtil.java} | 2 +- .../diagram/synthesis/LinguaFrancaSynthesis.java | 6 +++--- .../lflang/federated/generator/FedImportEmitter.java | 4 ++-- .../lflang/federated/generator/FedMainEmitter.java | 4 ++-- .../federated/generator/FedReactorEmitter.java | 4 ++-- .../lflang/federated/generator/FedTargetEmitter.java | 4 ++-- .../java/org/lflang/formatting2/LFFormatter.java | 4 ++-- .../test/java/org/lflang/tests/LfParsingUtil.java | 4 ++-- .../lflang/tests/compiler/FormattingUnitTests.java | 4 ++-- .../org/lflang/tests/compiler/RoundTripTests.java | 10 +++++----- 13 files changed, 34 insertions(+), 34 deletions(-) rename core/src/main/java/org/lflang/ast/{FormattingUtils.java => FormattingUtil.java} (98%) rename core/src/main/java/org/lflang/ast/{ParsingUtils.java => ParsingUtil.java} (98%) diff --git a/cli/lff/src/main/java/org/lflang/cli/Lff.java b/cli/lff/src/main/java/org/lflang/cli/Lff.java index adfb23bada..7d33c2419d 100644 --- a/cli/lff/src/main/java/org/lflang/cli/Lff.java +++ b/cli/lff/src/main/java/org/lflang/cli/Lff.java @@ -9,9 +9,9 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import org.eclipse.emf.ecore.resource.Resource; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.ast.IsEqual; -import org.lflang.ast.ParsingUtils; +import org.lflang.ast.ParsingUtil; import org.lflang.util.FileUtil; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -47,8 +47,8 @@ public class Lff extends CliBase { @Option( names = {"-w", "--wrap"}, description = "Causes the formatter to line wrap the files to a" + " specified length.", - defaultValue = "" + FormattingUtils.DEFAULT_LINE_LENGTH, - fallbackValue = "" + FormattingUtils.DEFAULT_LINE_LENGTH) + defaultValue = "" + FormattingUtil.DEFAULT_LINE_LENGTH, + fallbackValue = "" + FormattingUtil.DEFAULT_LINE_LENGTH) private int lineLength; @Option( @@ -175,10 +175,10 @@ private void formatSingleFile(Path path, Path inputRoot, Path outputRoot) { } final String formattedFileContents = - FormattingUtils.render(resource.getContents().get(0), lineLength); + FormattingUtil.render(resource.getContents().get(0), lineLength); if (!new IsEqual(resource.getContents().get(0)) .doSwitch( - ParsingUtils.parseSourceAsIfInDirectory(path.getParent(), formattedFileContents))) { + ParsingUtil.parseSourceAsIfInDirectory(path.getParent(), formattedFileContents))) { reporter.printFatalErrorAndExit( "The formatter failed to produce output that is semantically equivalent to its input when" + " executed on the file " diff --git a/core/src/main/java/org/lflang/ast/FormattingUtils.java b/core/src/main/java/org/lflang/ast/FormattingUtil.java similarity index 98% rename from core/src/main/java/org/lflang/ast/FormattingUtils.java rename to core/src/main/java/org/lflang/ast/FormattingUtil.java index 500edc465d..7eb7069ef2 100644 --- a/core/src/main/java/org/lflang/ast/FormattingUtils.java +++ b/core/src/main/java/org/lflang/ast/FormattingUtil.java @@ -18,7 +18,7 @@ * @author Peter Donovan * @author Billy Bao */ -public class FormattingUtils { +public class FormattingUtil { /** * The minimum number of columns that should be allotted to a comment. This is relevant in case of * high indentation/small wrapLength. @@ -214,7 +214,7 @@ static boolean placeComment( String singleLineCommentPrefix, int startColumn) { if (comment.stream().allMatch(String::isBlank)) return true; - String wrapped = FormattingUtils.lineWrapComments(comment, width, singleLineCommentPrefix); + String wrapped = FormattingUtil.lineWrapComments(comment, width, singleLineCommentPrefix); if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { int sum = 0; for (int j = 0; j < components.size(); j++) { diff --git a/core/src/main/java/org/lflang/ast/MalleableString.java b/core/src/main/java/org/lflang/ast/MalleableString.java index 3daff23e07..d4dff9dae7 100644 --- a/core/src/main/java/org/lflang/ast/MalleableString.java +++ b/core/src/main/java/org/lflang/ast/MalleableString.java @@ -276,7 +276,7 @@ public RenderResult render( int numCommentsDisplacedHere = 0; if (commentsFromChildren.stream().anyMatch(s -> !s.isEmpty())) { for (int i = 0; i < commentsFromChildren.size(); i++) { - if (!FormattingUtils.placeComment( + if (!FormattingUtil.placeComment( commentsFromChildren.get(i), stringComponents, i, @@ -317,7 +317,7 @@ private int inlineCommentStartColumn( if (i > 0) minNonCommentWidth = Math.min(minNonCommentWidth, i); } for (int i : lineLengths) { - if (i < minNonCommentWidth + FormattingUtils.MAX_WHITESPACE_USED_FOR_ALIGNMENT) { + if (i < minNonCommentWidth + FormattingUtil.MAX_WHITESPACE_USED_FOR_ALIGNMENT) { maxNonIgnoredCommentWidth = Math.max(maxNonIgnoredCommentWidth, i); numIgnored--; } @@ -438,7 +438,7 @@ public RenderResult render( codeMapTag, sourceEObject != null ? sourceEObject : enclosingEObject); String renderedComments = - FormattingUtils.lineWrapComments( + FormattingUtil.lineWrapComments( result.unplacedComments.toList(), width - indentation, singleLineCommentPrefix); return new RenderResult( this.comments.stream(), diff --git a/core/src/main/java/org/lflang/ast/ParsingUtils.java b/core/src/main/java/org/lflang/ast/ParsingUtil.java similarity index 98% rename from core/src/main/java/org/lflang/ast/ParsingUtils.java rename to core/src/main/java/org/lflang/ast/ParsingUtil.java index caa0bb0174..6277db6234 100644 --- a/core/src/main/java/org/lflang/ast/ParsingUtils.java +++ b/core/src/main/java/org/lflang/ast/ParsingUtil.java @@ -11,7 +11,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.lf.Model; -public class ParsingUtils { +public class ParsingUtil { public static Model parse(Path file) { // Source: // https://wiki.eclipse.org/Xtext/FAQ#How_do_I_load_my_model_in_a_standalone_Java_application_.3F diff --git a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java index 060e73507d..b26fea12a2 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/LinguaFrancaSynthesis.java @@ -95,7 +95,7 @@ import org.lflang.AttributeUtils; import org.lflang.InferredType; import org.lflang.ast.ASTUtils; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.diagram.synthesis.action.CollapseAllReactorsAction; import org.lflang.diagram.synthesis.action.ExpandAllReactorsAction; import org.lflang.diagram.synthesis.action.FilterCycleAction; @@ -1473,7 +1473,7 @@ private String createParameterLabel(ParameterInstance param) { if (param.getOverride() != null) { b.append(" = "); var init = param.getActualValue(); - b.append(FormattingUtils.render(init)); + b.append(FormattingUtil.render(init)); } return b.toString(); } @@ -1504,7 +1504,7 @@ private String createStateVariableLabel(StateVar variable) { b.append(":").append(t.toOriginalText()); } if (variable.getInit() != null) { - b.append(FormattingUtils.render(variable.getInit())); + b.append(FormattingUtil.render(variable.getInit())); } return b.toString(); } diff --git a/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java index baf13d6a0a..2e21534fc4 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java @@ -5,7 +5,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.eclipse.emf.ecore.util.EcoreUtil; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.generator.CodeBuilder; import org.lflang.lf.Import; import org.lflang.lf.Model; @@ -49,7 +49,7 @@ String generateImports(FederateInstance federate, FedFileConfig fileConfig) { .removeIf(importedReactor -> !federate.contains(importedReactor)); return new_import; }) - .map(FormattingUtils.renderer(federate.targetConfig.target)) + .map(FormattingUtil.renderer(federate.targetConfig.target)) .collect(Collectors.joining("\n"))); return importStatements.getCode(); diff --git a/core/src/main/java/org/lflang/federated/generator/FedMainEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedMainEmitter.java index 86ce4f02b9..31cb435e31 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedMainEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedMainEmitter.java @@ -5,7 +5,7 @@ import org.eclipse.emf.ecore.EObject; import org.lflang.ErrorReporter; import org.lflang.ast.ASTUtils; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.lf.Reactor; import org.lflang.lf.Variable; @@ -28,7 +28,7 @@ String generateMainReactor( ASTUtils.allModes(originalMainReactor).stream().findFirst().get(), "Modes at the top level are not supported under federated execution."); } - var renderer = FormattingUtils.renderer(federate.targetConfig.target); + var renderer = FormattingUtil.renderer(federate.targetConfig.target); return String.join( "\n", diff --git a/core/src/main/java/org/lflang/federated/generator/FedReactorEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedReactorEmitter.java index 69a6342486..f00d590f12 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedReactorEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedReactorEmitter.java @@ -1,7 +1,7 @@ package org.lflang.federated.generator; import java.util.stream.Collectors; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.lf.Model; public class FedReactorEmitter { @@ -16,7 +16,7 @@ String generateReactorDefinitions(FederateInstance federate) { return ((Model) federate.instantiation.eContainer().eContainer()) .getReactors().stream() .filter(federate::contains) - .map(FormattingUtils.renderer(federate.targetConfig.target)) + .map(FormattingUtil.renderer(federate.targetConfig.target)) .collect(Collectors.joining("\n")); } } diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java index 402138f283..b411ff0a44 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java @@ -3,7 +3,7 @@ import java.io.IOException; import org.lflang.ErrorReporter; import org.lflang.TargetProperty; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.federated.extensions.FedTargetExtensionFactory; import org.lflang.federated.launcher.RtiConfig; import org.lflang.generator.LFGeneratorContext; @@ -27,7 +27,7 @@ String generateTarget( .initializeTargetConfig( context, numOfFederates, federate, fileConfig, errorReporter, rtiConfig); - return FormattingUtils.renderer(federate.targetConfig.target) + return FormattingUtil.renderer(federate.targetConfig.target) .apply( TargetProperty.extractTargetDecl(federate.targetConfig.target, federate.targetConfig)); } diff --git a/core/src/main/java/org/lflang/formatting2/LFFormatter.java b/core/src/main/java/org/lflang/formatting2/LFFormatter.java index 7df4053eef..4d7c511b76 100644 --- a/core/src/main/java/org/lflang/formatting2/LFFormatter.java +++ b/core/src/main/java/org/lflang/formatting2/LFFormatter.java @@ -15,7 +15,7 @@ import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.validation.CheckMode; import org.eclipse.xtext.validation.IResourceValidator; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; public class LFFormatter implements IFormatter2 { @@ -41,6 +41,6 @@ public List format(FormatterRequest request) { request.getTextRegionAccess(), documentRegion.getOffset(), documentRegion.getLength(), - FormattingUtils.render(documentContents.get(0)))); + FormattingUtil.render(documentContents.get(0)))); } } diff --git a/core/src/test/java/org/lflang/tests/LfParsingUtil.java b/core/src/test/java/org/lflang/tests/LfParsingUtil.java index 6f00d61129..d677195275 100644 --- a/core/src/test/java/org/lflang/tests/LfParsingUtil.java +++ b/core/src/test/java/org/lflang/tests/LfParsingUtil.java @@ -1,7 +1,7 @@ package org.lflang.tests; import org.junit.jupiter.api.Assertions; -import org.lflang.ast.ParsingUtils; +import org.lflang.ast.ParsingUtil; import org.lflang.lf.Model; /** @@ -11,7 +11,7 @@ public class LfParsingUtil { /** Parse the given file, asserts that there are no parsing errors. */ public static Model parseValidModel(String fileName, String reformattedTestCase) { - Model resultingModel = ParsingUtils.parse(reformattedTestCase); + Model resultingModel = ParsingUtil.parse(reformattedTestCase); checkValid(fileName, resultingModel); return resultingModel; } diff --git a/core/src/test/java/org/lflang/tests/compiler/FormattingUnitTests.java b/core/src/test/java/org/lflang/tests/compiler/FormattingUnitTests.java index 96cca6b559..67114894ea 100644 --- a/core/src/test/java/org/lflang/tests/compiler/FormattingUnitTests.java +++ b/core/src/test/java/org/lflang/tests/compiler/FormattingUnitTests.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LfParsingUtil; @@ -98,7 +98,7 @@ private void assertIsFormatted(String input) { private void assertFormatsTo(String input, String expectedOutput) { Model inputModel = LfParsingUtil.parseValidModel("test input", input); - String formattedString = FormattingUtils.render(inputModel); + String formattedString = FormattingUtil.render(inputModel); Assertions.assertEquals( expectedOutput, formattedString, "Formatted output is different from what was expected"); } diff --git a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java index 9987ead64d..d55cc6fad3 100644 --- a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java +++ b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java @@ -12,9 +12,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; -import org.lflang.ast.FormattingUtils; +import org.lflang.ast.FormattingUtil; import org.lflang.ast.IsEqual; -import org.lflang.ast.ParsingUtils; +import org.lflang.ast.ParsingUtil; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; @@ -42,14 +42,14 @@ public void roundTripTest() { } private void run(Path file) throws Exception { - Model originalModel = ParsingUtils.parse(file); + Model originalModel = ParsingUtil.parse(file); System.out.println(file); assertThat(originalModel.eResource().getErrors(), equalTo(emptyList())); // TODO: Check that the output is a fixed point final int smallLineLength = 20; - final String squishedTestCase = FormattingUtils.render(originalModel, smallLineLength); + final String squishedTestCase = FormattingUtil.render(originalModel, smallLineLength); final Model resultingModel = - ParsingUtils.parseSourceAsIfInDirectory(file.getParent(), squishedTestCase); + ParsingUtil.parseSourceAsIfInDirectory(file.getParent(), squishedTestCase); LfParsingUtil.checkValid("file in " + file.getParent(), resultingModel); assertThat(resultingModel.eResource().getErrors(), equalTo(emptyList())); From 3b8cae82d50f28008de1f9f22f6d2421ab52175c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 13:48:22 -0700 Subject: [PATCH 083/142] Do not move multiline comments out. If a code block begins with a multiline comment, the multiline comment should still belong to the code block. --- .../main/java/org/lflang/ast/ASTUtils.java | 23 +++++++++++++++++-- core/src/main/java/org/lflang/ast/ToLf.java | 8 ++----- core/src/main/java/org/lflang/ast/ToText.java | 2 +- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 4489b1523b..86dfa40735 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -47,6 +47,7 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.TerminalRule; +import org.eclipse.xtext.impl.ParserRuleImpl; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; @@ -1638,9 +1639,27 @@ public static Stream getPrecedingCommentNodes( /** Return whether {@code node} is a comment. */ public static boolean isComment(INode node) { + return isMultilineComment(node) || isSingleLineComment(node); + } + + /** Return whether {@code node} is a multiline comment. */ + public static boolean isMultilineComment(INode node) { return node instanceof HiddenLeafNode hlNode - && hlNode.getGrammarElement() instanceof TerminalRule tRule - && tRule.getName().endsWith("_COMMENT"); + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().equals("ML_COMMENT"); + } + + /** Return whether {@code node} is a multiline comment. */ + public static boolean isSingleLineComment(INode node) { + return node instanceof HiddenLeafNode hlNode + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().equals("SL_COMMENT"); + } + + public static boolean isInCode(INode node) { + return node.getParent() != null + && node.getParent().getGrammarElement().eContainer() instanceof ParserRuleImpl pri + && pri.getName().equals("Body"); } /** Return true if the given node starts on the same line as the given other node. */ diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index bc5808e925..3468d5dab0 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -16,7 +16,6 @@ import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.impl.ParserRuleImpl; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; @@ -198,7 +197,7 @@ private static List getContainedComments(INode node) { boolean inSemanticallyInsignificantLeadingRubbish = true; for (INode child : node.getAsTreeIterable()) { if (!inSemanticallyInsignificantLeadingRubbish && ASTUtils.isComment(child)) { - ret.add(child); + if (!(ASTUtils.isMultilineComment(child) && ASTUtils.isInCode(child))) ret.add(child); } else if (!(child instanceof ICompositeNode) && !child.getText().isBlank()) { inSemanticallyInsignificantLeadingRubbish = false; } @@ -206,10 +205,7 @@ private static List getContainedComments(INode node) { && (child.getText().contains("\n") || child.getText().contains("\r")) && !inSemanticallyInsignificantLeadingRubbish) { break; - } else if (child.getParent() != null - && child.getParent().getGrammarElement().eContainer() instanceof ParserRuleImpl pri - && pri.getName().equals("Body") - && !child.getText().isBlank()) { + } else if (ASTUtils.isInCode(node) && !child.getText().isBlank()) { break; } } diff --git a/core/src/main/java/org/lflang/ast/ToText.java b/core/src/main/java/org/lflang/ast/ToText.java index 103303f51e..f7c37fd98a 100644 --- a/core/src/main/java/org/lflang/ast/ToText.java +++ b/core/src/main/java/org/lflang/ast/ToText.java @@ -50,7 +50,7 @@ public String caseCode(Code code) { boolean started = false; for (ILeafNode leaf : node.getLeafNodes()) { if (!leaf.getText().equals("{=") && !leaf.getText().equals("=}")) { - var nothing = leaf.getText().isBlank() || ASTUtils.isComment(leaf); + var nothing = leaf.getText().isBlank() || ASTUtils.isSingleLineComment(leaf); if (!nothing || started || leaf.getText().startsWith("\n")) builder.append(leaf.getText()); if ((leaf.getText().contains("\n") || (!nothing))) { From 520df63790ffb97cadad341ed4d5fbd70320c845 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 13:49:20 -0700 Subject: [PATCH 084/142] Add tests. --- .../test/java/org/lflang/cli/LffCliTest.java | 102 ++++++++++++++++-- 1 file changed, 95 insertions(+), 7 deletions(-) diff --git a/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java b/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java index 792681eda5..3334d7093c 100644 --- a/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java +++ b/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.lflang.LocalStrings; @@ -58,6 +59,90 @@ public class LffCliTest { reaction(startup) {= =} } """; + + private static final List> TEST_CASES = + List.of( + List.of( + """ + target C + reactor Test { // this is a test + logical action a # this is an a + output humbug: int + reaction (a) -> /* moo */ humbug {= // this is a humbug reaction + /* it reacts like this*/ react react + =} + } + """, + """ + target C + + // this is a test + reactor Test { + logical action a // this is an a + output humbug: int + + /** moo */ + // this is a humbug reaction + reaction(a) -> humbug {= /* it reacts like this*/ react react =} + } + """), + List.of( + """ + target C + // Documentation + @icon("Variables.png") + reactor Variables {} + """, + """ + target C + + // Documentation + @icon("Variables.png") + reactor Variables { + } + """), + List.of( + """ + target C + reactor Filter(period: int = 0, b: double[](0, 0)) {} + main reactor { + az_f = new Filter( + period = 100, + b = (0.229019233988375, 0.421510777305010) + ) + } + """, + """ + target C + + reactor Filter(period: int = 0, b: double[] = {0, 0}) { + } + + main reactor { + az_f = new Filter(period = 100, b = {0.229019233988375, 0.421510777305010}) + } + """), + List.of( + """ + target Rust + reactor Snake { // q + state grid: SnakeGrid ({= /* foo */ SnakeGrid::new(grid_side, &snake) =}); // note that this one borrows snake temporarily + state grid2: SnakeGrid ({= // baz + SnakeGrid::new(grid_side, &snake) =}); + } + """, + """ + target Rust + + // q + reactor Snake { + // note that this one borrows snake temporarily + state grid: SnakeGrid = {= /* foo */ SnakeGrid::new(grid_side, &snake) =} + // baz + state grid2: SnakeGrid = {= SnakeGrid::new(grid_side, &snake) =} + } + """)); + LffTestFixture lffTester = new LffTestFixture(); @Test @@ -86,13 +171,16 @@ public void testWrongCliArg() { @Test public void testFormatSingleFileInPlace(@TempDir Path tempDir) throws IOException { - dirBuilder(tempDir).file("src/File.lf", FILE_BEFORE_REFORMAT); - - ExecutionResult result = lffTester.run(tempDir, "src/File.lf"); - - result.checkOk(); - - dirChecker(tempDir).checkContentsOf("src/File.lf", equalTo(FILE_AFTER_REFORMAT)); + for (var pair : TEST_CASES) { + var before = pair.get(0); + var after = pair.get(1); + dirBuilder(tempDir).file("src/File.lf", before); + for (int i = 0; i < 2; i++) { + ExecutionResult result = lffTester.run(tempDir, "src/File.lf"); + result.checkOk(); + dirChecker(tempDir).checkContentsOf("src/File.lf", equalTo(after)); + } + } } @Test From 080cdc0aae078fc8f068f0f3cf2ff369adb774e0 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 13:57:27 -0700 Subject: [PATCH 085/142] Remove files accidentally committed. --- .../test/java/org/lflang/cli/LffCliTest.java | 4 +-- .../main/java/org/lflang/ast/ASTUtils.java | 12 ++++---- test/C/all.csv | 29 ------------------- test/C/federate__receiver.csv | 11 ------- test/C/federate__receiver_summary.csv | 16 ---------- test/C/federate__sender.csv | 20 ------------- test/C/federate__sender_summary.csv | 27 ----------------- test/C/rti.csv | 15 ---------- test/C/rti_summary.csv | 16 ---------- 9 files changed, 8 insertions(+), 142 deletions(-) delete mode 100644 test/C/all.csv delete mode 100644 test/C/federate__receiver.csv delete mode 100644 test/C/federate__receiver_summary.csv delete mode 100644 test/C/federate__sender.csv delete mode 100644 test/C/federate__sender_summary.csv delete mode 100644 test/C/rti.csv delete mode 100644 test/C/rti_summary.csv diff --git a/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java b/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java index 3334d7093c..43c045919b 100644 --- a/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java +++ b/cli/lff/src/test/java/org/lflang/cli/LffCliTest.java @@ -95,7 +95,7 @@ public class LffCliTest { """, """ target C - + // Documentation @icon("Variables.png") reactor Variables { @@ -133,7 +133,7 @@ reactor Filter(period: int = 0, b: double[] = {0, 0}) { """, """ target Rust - + // q reactor Snake { // note that this one borrows snake temporarily diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 86dfa40735..e5d0da81ac 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -1645,21 +1645,21 @@ public static boolean isComment(INode node) { /** Return whether {@code node} is a multiline comment. */ public static boolean isMultilineComment(INode node) { return node instanceof HiddenLeafNode hlNode - && hlNode.getGrammarElement() instanceof TerminalRule tRule - && tRule.getName().equals("ML_COMMENT"); + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().equals("ML_COMMENT"); } /** Return whether {@code node} is a multiline comment. */ public static boolean isSingleLineComment(INode node) { return node instanceof HiddenLeafNode hlNode - && hlNode.getGrammarElement() instanceof TerminalRule tRule - && tRule.getName().equals("SL_COMMENT"); + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().equals("SL_COMMENT"); } public static boolean isInCode(INode node) { return node.getParent() != null - && node.getParent().getGrammarElement().eContainer() instanceof ParserRuleImpl pri - && pri.getName().equals("Body"); + && node.getParent().getGrammarElement().eContainer() instanceof ParserRuleImpl pri + && pri.getName().equals("Body"); } /** Return true if the given node starts on the same line as the given other node. */ diff --git a/test/C/all.csv b/test/C/all.csv deleted file mode 100644 index 4705d450d4..0000000000 --- a/test/C/all.csv +++ /dev/null @@ -1,29 +0,0 @@ -,event,self_id,partner_id,logical_time,microstep,physical_time,inout,x1,y1,arrow,x2,y2 -0,FED_ID,1,-1,-1686279803405901114,0,-1041305535,out,300,75,arrow,100,96 -1,FED_ID,-1,1,-1686279803405901114,0,-1041279256,in,100,96,marked,-1,-1 -2,ACK,-1,1,-1686279803405901114,0,-1041277413,out,100,116,arrow,300,137 -3,ACK,1,-1,-1686279803405901114,0,-1041236205,in,300,137,marked,-1,-1 -4,TIMESTAMP,1,-1,-1041185840,0,-1041181933,out,300,158,arrow,100,245 -5,FED_ID,0,-1,-1686279803405901114,0,-1040825162,out,500,180,arrow,100,204 -6,FED_ID,-1,0,-1686279803405901114,0,-1000243598,in,100,204,marked,-1,-1 -7,ACK,-1,0,-1686279803405901114,0,-1000241414,out,100,224,arrow,500,266 -8,TIMESTAMP,-1,1,-1041185840,0,-1000221006,in,100,245,marked,-1,-1 -9,ACK,0,-1,-1686279803405901114,0,-1000187212,in,500,266,marked,-1,-1 -10,TIMESTAMP,0,-1,-1000000000,0,-999986915,out,500,288,arrow,100,309 -11,TIMESTAMP,-1,0,-1000000000,0,-999957680,in,100,309,marked,-1,-1 -12,TIMESTAMP,-1,0,0,0,-999953903,out,100,329,arrow,500,371 -13,TIMESTAMP,-1,1,0,0,-999941831,out,100,350,arrow,300,391 -14,TIMESTAMP,0,-1,0,0,-999913577,in,500,371,marked,-1,-1 -15,TIMESTAMP,1,-1,0,0,-999906524,in,300,391,marked,-1,-1 -16,NET,1,-1,0,0,87819,out,300,416,arrow,100,477 -17,NET,0,-1,0,0,88491,out,500,435,arrow,100,456 -18,NET,-1,0,0,0,136240,in,100,456,marked,-1,-1 -19,NET,-1,1,0,0,168822,in,100,477,marked,-1,-1 -20,PTAG,-1,1,0,0,182147,out,100,498,arrow,300,539 -21,PTAG,-1,0,0,0,201463,out,100,519,arrow,500,559 -22,PTAG,1,-1,0,0,208607,in,300,539,marked,-1,-1 -23,PTAG,0,-1,0,0,216271,in,500,559,marked,-1,-1 -24,T_MSG,0,-1,0,0,446263,out,500,581,arrow,100,605 -25,T_MSG,-1,0,0,0,43615435,in,100,605,marked,-1,-1 -26,T_MSG,-1,1,0,0,43618230,out,100,625,arrow,300,646 -27,T_MSG,1,-1,0,0,43665168,in,300,646,marked,-1,-1 diff --git a/test/C/federate__receiver.csv b/test/C/federate__receiver.csv deleted file mode 100644 index f6a261ca92..0000000000 --- a/test/C/federate__receiver.csv +++ /dev/null @@ -1,11 +0,0 @@ -Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay -Worker wait starts, NO REACTOR, 1, -1, 0, 0, 341276, NO TRIGGER, 0 -Worker wait starts, NO REACTOR, 2, -1, 0, 0, 376362, NO TRIGGER, 0 -Sending FED_ID, NO REACTOR, 1, -1, -1686279803405901114, 0, -1041305535, NO TRIGGER, 0 -Receiving ACK, NO REACTOR, 1, -1, -1686279803405901114, 0, -1041236205, NO TRIGGER, 0 -Sending TIMESTAMP, NO REACTOR, 1, -1, -1041185840, 0, -1041181933, NO TRIGGER, 0 -Receiving TIMESTAMP, NO REACTOR, 1, -1, 0, 0, -999906524, NO TRIGGER, 0 -Sending NET, NO REACTOR, 1, -1, 0, 0, 87819, NO TRIGGER, 0 -Receiving PTAG, NO REACTOR, 1, -1, 0, 0, 208607, NO TRIGGER, 0 -Worker wait starts, NO REACTOR, 0, -1, 0, 0, 326138, NO TRIGGER, 0 -Receiving TAGGED_MSG, NO REACTOR, 1, -1, 0, 0, 43665168, NO TRIGGER, 0 diff --git a/test/C/federate__receiver_summary.csv b/test/C/federate__receiver_summary.csv deleted file mode 100644 index da8d04534b..0000000000 --- a/test/C/federate__receiver_summary.csv +++ /dev/null @@ -1,16 +0,0 @@ -Start time:, 1686279803405901114 -End time:, 1686279803449566282 -Total time:, 43665168 - -Total Event Occurrences -Worker wait starts, 3 -Sending TIMESTAMP, 1 -Sending NET, 1 -Sending FED_ID, 1 -Receiving ACK, 1 -Receiving TIMESTAMP, 1 -Receiving PTAG, 1 -Receiving TAGGED_MSG, 1 - -Reaction Executions -Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time diff --git a/test/C/federate__sender.csv b/test/C/federate__sender.csv deleted file mode 100644 index ea34698814..0000000000 --- a/test/C/federate__sender.csv +++ /dev/null @@ -1,20 +0,0 @@ -Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay -Worker wait starts, NO REACTOR, 1, -1, 0, 0, 326829, NO TRIGGER, 0 -Worker wait starts, NO REACTOR, 2, -1, 0, 0, 377073, NO TRIGGER, 0 -Sending FED_ID, NO REACTOR, 0, -1, -1686279803405901114, 0, -1040825162, NO TRIGGER, 0 -Receiving ACK, NO REACTOR, 0, -1, -1686279803405901114, 0, -1000187212, NO TRIGGER, 0 -Sending TIMESTAMP, NO REACTOR, 0, -1, -1000000000, 0, -999986915, NO TRIGGER, 0 -Receiving TIMESTAMP, NO REACTOR, 0, -1, 0, 0, -999913577, NO TRIGGER, 0 -Schedule called, sender, 0, 0, 0, 0, -999848234, sender.t, 0 -Schedule called, sender, 0, 0, 0, 0, -999845519, sender.t, 1000 -Sending NET, NO REACTOR, 0, -1, 0, 0, 88491, NO TRIGGER, 0 -Receiving PTAG, NO REACTOR, 0, -1, 0, 0, 216271, NO TRIGGER, 0 -Reaction starts, sender, 0, 0, 0, 0, 274490, NO TRIGGER, 0 -Schedule called, sender, 0, 0, 0, 0, 411548, sender.act, 0 -Reaction ends, sender, 0, 0, 0, 0, 413973, NO TRIGGER, 0 -Worker wait starts, NO REACTOR, 0, -1, 0, 0, 429051, NO TRIGGER, 0 -Worker wait ends, NO REACTOR, 0, -1, 0, 0, 434481, NO TRIGGER, 0 -Reaction starts, ns_federate__receiver, 0, 0, 0, 0, 442847, NO TRIGGER, 0 -Sending TAGGED_MSG, NO REACTOR, 0, -1, 0, 0, 446263, NO TRIGGER, 0 -Reaction ends, ns_federate__receiver, 0, 0, 0, 0, 463346, NO TRIGGER, 0 -Worker wait starts, NO REACTOR, 0, -1, 0, 0, 469397, NO TRIGGER, 0 diff --git a/test/C/federate__sender_summary.csv b/test/C/federate__sender_summary.csv deleted file mode 100644 index c3c8a72e1b..0000000000 --- a/test/C/federate__sender_summary.csv +++ /dev/null @@ -1,27 +0,0 @@ -Start time:, 1686279803405901114 -End time:, 1686279803406370511 -Total time:, 469397 - -Total Event Occurrences -Reaction starts, 2 -Reaction ends, 2 -Schedule called, 3 -Worker wait starts, 4 -Worker wait ends, 1 -Sending TIMESTAMP, 1 -Sending NET, 1 -Sending FED_ID, 1 -Sending TAGGED_MSG, 1 -Receiving ACK, 1 -Receiving TIMESTAMP, 1 -Receiving PTAG, 1 - -Reaction Executions -Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time -sender, 0, 1, 139483, 29.715358, 139483, 139483, 139483 -ns_federate__receiver, 0, 1, 20499, 4.367092, 20499, 20499, 20499 - -Schedule calls -Trigger, Occurrences -sender.act, 1 -sender.t, 2 diff --git a/test/C/rti.csv b/test/C/rti.csv deleted file mode 100644 index 8bd2112691..0000000000 --- a/test/C/rti.csv +++ /dev/null @@ -1,15 +0,0 @@ -Event, Reactor, Source, Destination, Elapsed Logical Time, Microstep, Elapsed Physical Time, Trigger, Extra Delay -Receiving FED_ID, NO REACTOR, -1, 1, -1686279803405901114, 0, -1041279256, NO TRIGGER, 0 -Sending ACK, NO REACTOR, -1, 1, -1686279803405901114, 0, -1041277413, NO TRIGGER, 0 -Receiving TIMESTAMP, NO REACTOR, -1, 1, -1041185840, 0, -1000221006, NO TRIGGER, 0 -Sending TIMESTAMP, NO REACTOR, -1, 1, 0, 0, -999941831, NO TRIGGER, 0 -Receiving NET, NO REACTOR, -1, 1, 0, 0, 168822, NO TRIGGER, 0 -Sending PTAG, NO REACTOR, -1, 1, 0, 0, 182147, NO TRIGGER, 0 -Sending TAGGED_MSG, NO REACTOR, -1, 1, 0, 0, 43618230, NO TRIGGER, 0 -Receiving FED_ID, NO REACTOR, -1, 0, -1686279803405901114, 0, -1000243598, NO TRIGGER, 0 -Sending ACK, NO REACTOR, -1, 0, -1686279803405901114, 0, -1000241414, NO TRIGGER, 0 -Receiving TIMESTAMP, NO REACTOR, -1, 0, -1000000000, 0, -999957680, NO TRIGGER, 0 -Sending TIMESTAMP, NO REACTOR, -1, 0, 0, 0, -999953903, NO TRIGGER, 0 -Receiving NET, NO REACTOR, -1, 0, 0, 0, 136240, NO TRIGGER, 0 -Sending PTAG, NO REACTOR, -1, 0, 0, 0, 201463, NO TRIGGER, 0 -Receiving TAGGED_MSG, NO REACTOR, -1, 0, 0, 0, 43615435, NO TRIGGER, 0 diff --git a/test/C/rti_summary.csv b/test/C/rti_summary.csv deleted file mode 100644 index 31fcc3dc4a..0000000000 --- a/test/C/rti_summary.csv +++ /dev/null @@ -1,16 +0,0 @@ -Start time:, 1686279803405901114 -End time:, 1686279803449519344 -Total time:, 43618230 - -Total Event Occurrences -Sending ACK, 2 -Sending TIMESTAMP, 2 -Sending PTAG, 2 -Sending TAGGED_MSG, 1 -Receiving TIMESTAMP, 2 -Receiving NET, 2 -Receiving FED_ID, 2 -Receiving TAGGED_MSG, 1 - -Reaction Executions -Reactor, Reaction, Occurrences, Total Time, Pct Total Time, Avg Time, Max Time, Min Time From d1a8aca595c13bbb260ec3040f932b61ff2e37d3 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 14:22:21 -0700 Subject: [PATCH 086/142] Try to pass formatting test on Windows. I believe this is the CRLF/LF thing. --- core/src/main/java/org/lflang/ast/ToText.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ToText.java b/core/src/main/java/org/lflang/ast/ToText.java index f7c37fd98a..c677f0730b 100644 --- a/core/src/main/java/org/lflang/ast/ToText.java +++ b/core/src/main/java/org/lflang/ast/ToText.java @@ -51,8 +51,10 @@ public String caseCode(Code code) { for (ILeafNode leaf : node.getLeafNodes()) { if (!leaf.getText().equals("{=") && !leaf.getText().equals("=}")) { var nothing = leaf.getText().isBlank() || ASTUtils.isSingleLineComment(leaf); - if (!nothing || started || leaf.getText().startsWith("\n")) - builder.append(leaf.getText()); + if (!nothing + || started + || leaf.getText().startsWith("\n") + || leaf.getText().startsWith("\r")) builder.append(leaf.getText()); if ((leaf.getText().contains("\n") || (!nothing))) { started = true; } From 0d3e43983265ca4801431b8f7cc0eae3443f0000 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 14 Jun 2023 17:04:50 -0700 Subject: [PATCH 087/142] Remove accidental check-in. --- test/C/temp.txt | 124 ------------------------------------------------ 1 file changed, 124 deletions(-) delete mode 100644 test/C/temp.txt diff --git a/test/C/temp.txt b/test/C/temp.txt deleted file mode 100644 index 6e6a4106e0..0000000000 --- a/test/C/temp.txt +++ /dev/null @@ -1,124 +0,0 @@ -Federate DistributedStop in Federation ID 'f4c5b423c156433c8b908f3c6595eb9aafd814168075d202' -#### Launching the federate federate__sender. -#### Launching the federate federate__receiver. -#### Bringing the RTI back to foreground so it can receive Control-C. -RTI -i ${FEDERATION_ID} -n 2 -c init exchanges-per-interval 10 -Federation ID for executable /home/peter/vscode-lingua-franca/lingua-franca/test/C/fed-gen/DistributedStop/bin/federate__sender: f4c5b423c156433c8b908f3c6595eb9aafd814168075d202 -DEBUG: _lf_new_token: Allocated memory for token: 0x55d77b60dab0 -DEBUG: _lf_new_token: Allocated memory for token: 0x55d77b60dec0 -DEBUG: Scheduler: Initializing with 3 workers -DEBUG: Scheduler: Max reaction level: 2 -DEBUG: Scheduler: Initialized vector of reactions for level 0 with size 1 -DEBUG: Scheduler: Initialized vector of reactions for level 1 with size 2 -DEBUG: Scheduler: Initialized vector of reactions for level 2 with size 1 -Federate 0: LOG: Connecting to the RTI. -Federate 0: LOG: Connected to an RTI. Sending federation ID for authentication. -Federate 0: DEBUG: Waiting for response to federation ID from the RTI. -Federate 0: LOG: Received acknowledgment from the RTI. -Federate 0: Connected to RTI at localhost:15045. -Federate 0: DEBUG: Physical time: 1686279449775465785. Elapsed: -7537092587079310023. Offset: 0 -Federate 0: DEBUG: Start time: 1686279449775465785ns ----- Start execution at time Thu Jun 8 19:57:29 2023 ----- plus 775465785 nanoseconds. -Federate 0: ---- Using 3 workers. -Federate 0: DEBUG: Scheduler: Initializing with 3 workers -Federate 0: DEBUG: Synchronizing with other federates. -Federate 0: DEBUG: Physical time: 1686279449775522231. Elapsed: 56446. Offset: 0 -Federate 0: DEBUG: Sending time 1686279449775522231 to the RTI. -Federate 0: DEBUG: Read 9 bytes. -Federate 0: Starting timestamp is: 1686279450818001739. -Federate 0: DEBUG: Physical time: 1686279449818147343. Elapsed: 42681558. Offset: 0 -Federate 0: LOG: Current physical time is: 1686279449818147343. -Federate 0: DEBUG: Scheduler: Enqueing reaction federate__sender.sender reaction 0, which has level 0. -Federate 0: DEBUG: Scheduler: Trying to lock the mutex for level 0. -Federate 0: DEBUG: Scheduler: Locked the mutex for level 0. -Federate 0: DEBUG: Scheduler: Accessing triggered reactions at the level 0 with index 0. -Federate 0: DEBUG: Scheduler: Index for level 0 is at 0. -Federate 0: LOG: Waiting for start time 1686279450818001739 plus STA 0. -Federate 0: DEBUG: -------- Waiting until physical time matches logical time 1686279450818001739 -Federate 0: DEBUG: Physical time: 1686279449818230780. Elapsed: -999770959. Offset: 0 -Federate 0: DEBUG: -------- Clock offset is 0 ns. -Federate 0: DEBUG: -------- Waiting 999770959 ns for physical time to match logical time 0. -Federate 0: DEBUG: Physical time: 1686279450818067383. Elapsed: 65644. Offset: 0 -Federate 0: DEBUG: Done waiting for start time 1686279450818001739. -Federate 0: DEBUG: Physical time: 1686279450818079496. Elapsed: 77757. Offset: 0 -Federate 0: DEBUG: Physical time is ahead of current time by 77757. This should be small. -Federate 0: DEBUG: Checking NET to see whether it should be bounded by physical time. Min delay from physical action: -9223372036854775808. -Federate 0: DEBUG: Sending tag (0, 0) to the RTI. -Federate 0: LOG: Sent next event tag (NET) (0, 0) to RTI. -Federate 0: DEBUG: Not waiting for reply to NET (0, 0) because I have no upstream federates. -Federate 0: DEBUG: Executing output control reactions. -Federate 0: LOG: Starting 3 worker threads. -Federate 0: DEBUG: Waiting for worker threads to exit. -Federate 0: DEBUG: Number of threads: 3. -Federate 0: LOG: Worker thread 0 started. -Federate 0: DEBUG: Scheduler: Worker 0 popping reaction with level 0, index for level: 0. -Federate 0: DEBUG: Worker 0: Got from scheduler reaction federate__sender.sender reaction 0: level: 0, is control reaction: 0, chain ID: 1, and deadline -9223372036854775808. -Federate 0: LOG: Worker 0: Invoking reaction federate__sender.sender reaction 0 at elapsed tag (0, 0). -Federate 0: DEBUG: _lf_replace_template_token: template: 0x55d77b60d5e0 newtoken: 0x55d77b60dab0. -Federate 0: DEBUG: _lf_replace_template_token: Incremented ref_count of 0x55d77b60dab0 to 2. -Federate 0: Sending 42 at (0, 0). -Federate 0: DEBUG: _lf_schedule: scheduling trigger 0x55d77b60d910 with delay 0 and token (nil). -Federate 0: DEBUG: _lf_schedule: current_tag.time = 168627Federation ID for executable /home/peter/vscode-lingua-franca/lingua-franca/test/C/fed-gen/DistributedStop/bin/federate__receiver: f4c5b423c156433c8b908f3c6595eb9aafd814168075d202 -DEBUG: _lf_new_token: Allocated memory for token: 0x55c15e3ebc00 -DEBUG: Scheduler: Initializing with 3 workers -DEBUG: Scheduler: Max reaction level: 2 -DEBUG: Scheduler: Initialized vector of reactions for level 0 with size 1 -DEBUG: Scheduler: Initialized vector of reactions for level 1 with size 1 -DEBUG: Scheduler: Initialized vector of reactions for level 2 with size 1 -Federate 1: LOG: Connecting to the RTI. -Federate 1: LOG: Connected to an RTI. Sending federation ID for authentication. -Federate 1: DEBUG: Waiting for response to federation ID from the RTI. -Federate 1: LOG: Received acknowledgment from the RTI. -Federate 1: Connected to RTI at localhost:15045. -Federate 1: DEBUG: Physical time: 1686279449817891932. Elapsed: -7537092587036883876. Offset: 0 -Federate 1: DEBUG: Start time: 1686279449817891932ns ----- Start execution at time Thu Jun 8 19:57:29 2023 ----- plus 817891932 nanoseconds. -Federate 1: ---- Using 3 workers. -Federate 1: DEBUG: Scheduler: Initializing with 3 workers -Federate 1: DEBUG: Synchronizing with other federates. -Federate 1: DEBUG: Physical time: 1686279449818001739. Elapsed: 109807. Offset: 0 -Federate 1: DEBUG: Sending time 1686279449818001739 to the RTI. -Federate 1: DEBUG: Read 9 bytes. -Federate 1: Starting timestamp is: 1686279450818001739. -Federate 1: DEBUG: Physical time: 1686279449818123568. Elapsed: 231636. Offset: 0 -Federate 1: LOG: Current physical time is: 1686279449818123568. -Federate 1: LOG: Waiting for start time 1686279450818001739 plus STA 0. -Federate 1: DEBUG: -------- Waiting until physical time matches logical time 1686279450818001739 -Federate 1: DEBUG: Physical time: 1686279449818218526. Elapsed: -999783213. Offset: 0 -Federate 1: DEBUG: -------- Clock offset is 0 ns. -Federate 1: DEBUG: -------- Waiting 999783213 ns for physical time to match logical time 0. -Federate 1: DEBUG: Physical time: 1686279450818074676. Elapsed: 72937. Offset: 0 -Federate 1: DEBUG: Done waiting for start time 1686279450818001739. -Federate 1: DEBUG: Physical time: 1686279450818083933. Elapsed: 82194. Offset: 0 -Federate 1: DEBUG: Physical time is ahead of current time by 82194. This should be small. -Federate 1: DEBUG: Checking NET to see whether it should be bounded by physical time. Min delay from physical action: -9223372036854775808. -Federate 1: DEBUG: Sending tag (0, 0) to the RTI. -Federate 1: LOG: Sent next event tag (NET) (0, 0) to RTI. -Federate 1: DEBUG: Waiting for a TAG from the RTI. -Federate 1: LOG: At tag (0, 0), received Provisional Tag Advance Grant (PTAG): (0, 0). -Federate 1: LOG: Starting 3 worker threads. -Federate 1: DEBUG: Waiting for worker threads to exit. -Federate 1: DEBUG: Number of threads: 3. -Federate 1: LOG: Worker thread 0 started. -Federate 1: DEBUG: Worker 0 is out of ready reactions. -Federate 1: DEBUG: Scheduler: Worker 0 is trying to acquire the scheduling semaphore. -Federate 1: LOG: Worker thread 1 started. -Federate 1: DEBUG: Worker 1 is out of ready reactions. -Federate 1: DEBUG: Scheduler: Worker 1 is trying to acquire the scheduling semaphore. -Federate 1: LOG: Worker thread 2 started. -Federate 1: DEBUG: Worker 2 is out of ready reactions. -Federate 1: DEBUG: Scheduler: Worker 2 is the last idle thread. -Federate 1: DEBUG: Receiving message to port 0 of length 4. -Federate 1: DEBUG: Physical time: 1686279450861618465. Elapsed: 43616726. Offset: 0 -Federate 1: LOG: Received message with tag: (0, 0), Current tag: (0, 0). -Federate 1: DEBUG: _lf_new_token: Allocated memory for token: 0x7f1664000ce0 -Federate 1: DEBUG: Updating the last known status tag of port 0 to (0, 0). -Federate 1: LOG: Inserting reactions directly at tag (0, 0). Intended tag: (0, 0). -Federate 1: DEBUG: _lf_replace_template_token: template: 0x55c15e3eba68 newtoken: 0x7f1664000ce0. -Federate 1: DEBUG: _lf_done_using: token = 0x55c15e3ebc00, ref_count = 1. -Federate 1: DEBUG: _lf_free_token: Putting token on the recycling bin: 0x55c15e3ebc00 -FedeKilling federate 66286. -Killing federate 66288. -#### Killing RTI 66280. From f998d89b12fc205402673a89f3f3cf3e96b4a221 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 23 Jun 2023 16:19:35 -0700 Subject: [PATCH 088/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 62c9fe71ba..4eb1b1d530 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 62c9fe71ba2a4b8828e502e2f1cad04c79049d69 +Subproject commit 4eb1b1d530ec74e51fd5f4ee159ca5c8765ecbc4 From 8c584b46c49f2464562a7c66e254e377ce4bcc1e Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 22 Jun 2023 12:50:53 -0700 Subject: [PATCH 089/142] Correctly implement hashcode for types. --- .../org/lflang/generator/c/CGenerator.java | 43 +++++++++++-------- .../generator/c/TypeParameterizedReactor.java | 24 ++++++++++- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index dd5e6feb97..06ea0d066a 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -805,7 +805,18 @@ private void generateReactorDefinitions() throws IOException { // do not generate code for reactors that are not instantiated } - private record TypeParameterizedReactorWithDecl(TypeParameterizedReactor tpr, ReactorDecl decl) {} + private record TypeParameterizedReactorWithDecl(TypeParameterizedReactor tpr, ReactorDecl decl) { + @Override + public boolean equals(Object obj) { + // This is equivalence modulo decl + return obj == this || obj instanceof TypeParameterizedReactorWithDecl tprd && tprd.tpr.equals(this.tpr); + } + + @Override + public int hashCode() { + return tpr.hashCode(); + } + } /** Generate user-visible header files for all reactors instantiated. */ private void generateHeaders() throws IOException { @@ -826,23 +837,21 @@ private void generateHeaders() throws IOException { it -> new TypeParameterizedReactorWithDecl( new TypeParameterizedReactor(it, rr), it.getReactorClass())) - .collect(Collectors.toSet()) + .distinct() .forEach( - it -> { - ASTUtils.allPorts(it.tpr.reactor()) - .forEach( - p -> - builder.pr( - CPortGenerator.generateAuxiliaryStruct( - it.tpr, - p, - getTarget(), - messageReporter, - types, - new CodeBuilder(), - true, - it.decl()))); - }); + it -> ASTUtils.allPorts(it.tpr.reactor()) + .forEach( + p -> + builder.pr( + CPortGenerator.generateAuxiliaryStruct( + it.tpr, + p, + getTarget(), + messageReporter, + types, + new CodeBuilder(), + true, + it.decl())))); } }, this::generateTopLevelPreambles); diff --git a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java index f514141241..1303e4f8d5 100644 --- a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java +++ b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java @@ -156,17 +156,37 @@ public String uniqueName() { @Override public int hashCode() { - return reactor.hashCode() * 31 + typeArgs.hashCode(); + return reactor.hashCode() * 31 + typeArgs.entrySet().stream().mapToInt(it -> it.getKey().hashCode() ^ typeHash(it.getValue())).sum(); } @Override public boolean equals(Object obj) { return obj instanceof TypeParameterizedReactor other && reactor.equals(other.reactor) - && typeArgs.equals(other.typeArgs); + && typeArgs.entrySet().stream().allMatch(it -> typeEquals(other.typeArgs.get(it.getKey()), it.getValue())); } public Reactor reactor() { return reactor; } + + // We operate on the ECore model rather than an internal IR, so hashcode and equals are provided here instead of as methods. + private static int typeHash(Type t) { + var sum = t.getStars() == null ? 0 : t.getStars().stream().toList().hashCode(); + sum = 31 * sum + (t.getCode() == null ? 0 : Objects.hashCode(t.getCode().getBody())); + sum = 31 * sum + Objects.hashCode(t.getId()); + sum = 31 * sum + Objects.hashCode(t.getArraySpec()); + sum = 2 * sum + (t.isTime() ? 1 : 0); + sum = 31 * sum + (t.getTypeArgs() == null ? 0 : t.getTypeArgs().stream().toList().hashCode()); + return sum; + } + + private static boolean typeEquals(Type t, Type tt) { + return t.getStars() == null ? tt.getStars() == null : t.getStars().stream().toList().equals(tt.getStars().stream().toList()) + && t.getCode() == null ? tt.getCode() == null : Objects.equals(t.getCode().getBody(), tt.getCode().getBody()) + && Objects.equals(t.getId(), tt.getId()) + && Objects.equals(t.getArraySpec(), tt.getArraySpec()) + && t.isTime() == tt.isTime() + && t.getTypeArgs() == null ? tt.getTypeArgs() == null : t.getTypeArgs().stream().toList().equals(tt.getTypeArgs().stream().toList()); + } } From e1c68432c5181403c9f4fc4f9c1f9ae09a81a9b2 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 22 Jun 2023 13:10:23 -0700 Subject: [PATCH 090/142] Fix another name collision. --- .../main/java/org/lflang/generator/c/CPortGenerator.java | 7 ++++--- .../lflang/generator/c/CReactorHeaderFileGenerator.java | 2 +- .../org/lflang/generator/c/TypeParameterizedReactor.java | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java index 6aafeaef5a..eafec3dce0 100644 --- a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java @@ -75,14 +75,15 @@ public static String generateAuxiliaryStruct( code.unindent(); var name = decl != null - ? localPortName(decl, port.getName()) + ? localPortName(tpr, decl, port.getName()) : variableStructType(port, tpr, userFacing); code.pr("} " + name + ";"); return code.toString(); } - public static String localPortName(ReactorDecl decl, String portName) { - return decl.getName().toLowerCase() + "_" + portName + "_t"; + public static String localPortName( + TypeParameterizedReactor tpr, ReactorDecl decl, String portName) { + return decl.getName().toLowerCase() + tpr.argsString() + "_" + portName + "_t"; } /** diff --git a/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java index 02e5d41f02..f6f393528b 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java @@ -208,7 +208,7 @@ String getType(boolean userFacing) { var typeName = container == null ? CGenerator.variableStructType(tv, r, userFacing) - : CPortGenerator.localPortName(container.getReactorClass(), getName()); + : CPortGenerator.localPortName(new TypeParameterizedReactor(container, r), container.getReactorClass(), getName()); var isMultiport = ASTUtils.isMultiport( ASTUtils.allPorts(r.reactor()).stream() diff --git a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java index 1303e4f8d5..2d4a468777 100644 --- a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java +++ b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java @@ -106,6 +106,11 @@ public String getName() { + typeArgs.values().stream().map(ASTUtils::toOriginalText).collect(Collectors.joining("_")); } + /** Return a string representation of the type args of this. */ + public String argsString() { + return typeArgs.values().stream().map(ASTUtils::toOriginalText).collect(Collectors.joining("_")); + } + /** #define type names as concrete types. */ public void doDefines(CodeBuilder b) { typeArgs.forEach( From 170a90682c3cdfd4326e0b41a3f1b779e2145ff0 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 22 Jun 2023 16:21:51 -0700 Subject: [PATCH 091/142] Format. --- .../org/lflang/generator/c/CGenerator.java | 30 +++++++++-------- .../c/CReactorHeaderFileGenerator.java | 5 ++- .../generator/c/TypeParameterizedReactor.java | 33 +++++++++++++------ 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 06ea0d066a..1099b4e7ca 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -809,7 +809,8 @@ private record TypeParameterizedReactorWithDecl(TypeParameterizedReactor tpr, Re @Override public boolean equals(Object obj) { // This is equivalence modulo decl - return obj == this || obj instanceof TypeParameterizedReactorWithDecl tprd && tprd.tpr.equals(this.tpr); + return obj == this + || obj instanceof TypeParameterizedReactorWithDecl tprd && tprd.tpr.equals(this.tpr); } @Override @@ -839,19 +840,20 @@ private void generateHeaders() throws IOException { new TypeParameterizedReactor(it, rr), it.getReactorClass())) .distinct() .forEach( - it -> ASTUtils.allPorts(it.tpr.reactor()) - .forEach( - p -> - builder.pr( - CPortGenerator.generateAuxiliaryStruct( - it.tpr, - p, - getTarget(), - messageReporter, - types, - new CodeBuilder(), - true, - it.decl())))); + it -> + ASTUtils.allPorts(it.tpr.reactor()) + .forEach( + p -> + builder.pr( + CPortGenerator.generateAuxiliaryStruct( + it.tpr, + p, + getTarget(), + messageReporter, + types, + new CodeBuilder(), + true, + it.decl())))); } }, this::generateTopLevelPreambles); diff --git a/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java index f6f393528b..5deaa5fb7b 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactorHeaderFileGenerator.java @@ -208,7 +208,10 @@ String getType(boolean userFacing) { var typeName = container == null ? CGenerator.variableStructType(tv, r, userFacing) - : CPortGenerator.localPortName(new TypeParameterizedReactor(container, r), container.getReactorClass(), getName()); + : CPortGenerator.localPortName( + new TypeParameterizedReactor(container, r), + container.getReactorClass(), + getName()); var isMultiport = ASTUtils.isMultiport( ASTUtils.allPorts(r.reactor()).stream() diff --git a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java index 2d4a468777..1c5ae863c0 100644 --- a/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java +++ b/core/src/main/java/org/lflang/generator/c/TypeParameterizedReactor.java @@ -108,7 +108,9 @@ public String getName() { /** Return a string representation of the type args of this. */ public String argsString() { - return typeArgs.values().stream().map(ASTUtils::toOriginalText).collect(Collectors.joining("_")); + return typeArgs.values().stream() + .map(ASTUtils::toOriginalText) + .collect(Collectors.joining("_")); } /** #define type names as concrete types. */ @@ -161,21 +163,26 @@ public String uniqueName() { @Override public int hashCode() { - return reactor.hashCode() * 31 + typeArgs.entrySet().stream().mapToInt(it -> it.getKey().hashCode() ^ typeHash(it.getValue())).sum(); + return reactor.hashCode() * 31 + + typeArgs.entrySet().stream() + .mapToInt(it -> it.getKey().hashCode() ^ typeHash(it.getValue())) + .sum(); } @Override public boolean equals(Object obj) { return obj instanceof TypeParameterizedReactor other && reactor.equals(other.reactor) - && typeArgs.entrySet().stream().allMatch(it -> typeEquals(other.typeArgs.get(it.getKey()), it.getValue())); + && typeArgs.entrySet().stream() + .allMatch(it -> typeEquals(other.typeArgs.get(it.getKey()), it.getValue())); } public Reactor reactor() { return reactor; } - // We operate on the ECore model rather than an internal IR, so hashcode and equals are provided here instead of as methods. + // We operate on the ECore model rather than an internal IR, so hashcode and equals are provided + // here instead of as methods. private static int typeHash(Type t) { var sum = t.getStars() == null ? 0 : t.getStars().stream().toList().hashCode(); sum = 31 * sum + (t.getCode() == null ? 0 : Objects.hashCode(t.getCode().getBody())); @@ -187,11 +194,17 @@ private static int typeHash(Type t) { } private static boolean typeEquals(Type t, Type tt) { - return t.getStars() == null ? tt.getStars() == null : t.getStars().stream().toList().equals(tt.getStars().stream().toList()) - && t.getCode() == null ? tt.getCode() == null : Objects.equals(t.getCode().getBody(), tt.getCode().getBody()) - && Objects.equals(t.getId(), tt.getId()) - && Objects.equals(t.getArraySpec(), tt.getArraySpec()) - && t.isTime() == tt.isTime() - && t.getTypeArgs() == null ? tt.getTypeArgs() == null : t.getTypeArgs().stream().toList().equals(tt.getTypeArgs().stream().toList()); + return t.getStars() == null + ? tt.getStars() == null + : t.getStars().stream().toList().equals(tt.getStars().stream().toList()) + && t.getCode() == null + ? tt.getCode() == null + : Objects.equals(t.getCode().getBody(), tt.getCode().getBody()) + && Objects.equals(t.getId(), tt.getId()) + && Objects.equals(t.getArraySpec(), tt.getArraySpec()) + && t.isTime() == tt.isTime() + && t.getTypeArgs() == null + ? tt.getTypeArgs() == null + : t.getTypeArgs().stream().toList().equals(tt.getTypeArgs().stream().toList()); } } From 718996f8bafb12f9c7945834e9d1d937add878b8 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 22 Jun 2023 23:17:08 -0700 Subject: [PATCH 092/142] Add test case. --- test/C/src/generics/MultipleInstantiations.lf | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/C/src/generics/MultipleInstantiations.lf diff --git a/test/C/src/generics/MultipleInstantiations.lf b/test/C/src/generics/MultipleInstantiations.lf new file mode 100644 index 0000000000..5f9e7abc97 --- /dev/null +++ b/test/C/src/generics/MultipleInstantiations.lf @@ -0,0 +1,21 @@ +target C + +reactor R(printf: string = "%s") { + input in: T + + reaction(in) {= + printf("%s", "Received "); + printf(self->printf, in->value); + printf("%s", ".\n"); + =} +} + +main reactor { + r1 = new R(printf="%d") + r2 = new R(printf="%d") + r3 = new R(printf="%s") + + reaction(startup) -> r1.in, r2.in, r3.in {= + lf_set(r1.in, 1); lf_set(r2.in, 2); lf_set(r3.in, "test"); + =} +} From 635221cc699c0cc7d17288b215adf96d82038aa9 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 21 Jul 2023 18:59:37 -0700 Subject: [PATCH 093/142] Fix missing import + update example + align reactor-c --- .../federated/generator/FederateInstance.java | 2 ++ core/src/main/resources/lib/c/reactor-c | 2 +- .../federated/transient/ConnectedTransient.lf | 25 ++++++++++++------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index e89f97314c..7f82f6c7a0 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -35,6 +35,8 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; + +import org.lflang.AttributeUtils; import org.lflang.MessageReporter; import org.lflang.TargetConfig; import org.lflang.TimeValue; diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 44aea060ff..b4c46621fc 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 44aea060ffc63054d4fbb4152d0cf495948ac6b0 +Subproject commit b4c46621fceea366bce95e35203918d4239a1386 diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index 786f10ddf4..12f7f6fc4e 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -1,5 +1,5 @@ target C { - timeout: 20 s, + timeout: 15 s, tracing: true } @@ -24,39 +24,46 @@ reactor Middle { reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); - lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN1 :: Sending %d at ", self->count, lf_time_logical_elapsed(), lf_tag().microstep); // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); - lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN2 :: Sending %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); // lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} } reactor Down { - timer t(2 s, 300 ms) - input in: int + timer t(100 ms, 500 ms) + input in1: int + input in2: int reaction(t) {= - lf_print("Timer :: at (%lld, %ld)", lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Timer :: at "PRINTF_TAG, lf_time_logical_elapsed(), lf_tag().microstep); + =} + + reaction(in1) {= + lf_print("Received %d at "PRINTF_TAG, in1->value, lf_time_logical_elapsed(), lf_tag().microstep); =} - reaction(in) {= - lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + reaction(in2) {= + lf_print("Received %d at "PRINTF_TAG, in2->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } federated reactor { up1 = new Up(period = 2 s) up2 = new Up(period = 1 s) + up3 = new Up(period = 4 s) @transient mid = new Middle() down = new Down() up1.out -> mid.in1 // Connections up2.out -> mid.in2 - mid.out -> down.in + mid.out -> down.in1 + up3.out -> down.in2 } From 08305ff945b4bd2d0b73920704969f43806d4f15 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 26 Jul 2023 17:04:59 -0700 Subject: [PATCH 094/142] Apply spotless and aligne reactor-c --- .../java/org/lflang/federated/generator/FederateInstance.java | 1 - core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 7f82f6c7a0..06757efc13 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -35,7 +35,6 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; - import org.lflang.AttributeUtils; import org.lflang.MessageReporter; import org.lflang.TargetConfig; diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index b4c46621fc..4c38eec5f4 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit b4c46621fceea366bce95e35203918d4239a1386 +Subproject commit 4c38eec5f4ff79af1e5e89332cbf72415ddcdc08 From 4771453df6dc7211d51447a5633e4bedfabf0294 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 1 Aug 2023 11:48:14 -0700 Subject: [PATCH 095/142] Do not truncate output. Needed for debugging --- core/src/main/resources/lib/c/reactor-c | 2 +- core/src/testFixtures/java/org/lflang/tests/LFTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 33d8ae4a3d..ef6ab52fb4 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 33d8ae4a3d8c758949199693e8016556fbf0bbec +Subproject commit ef6ab52fb4be5d7046228bf1bdd4aecf9372b9b8 diff --git a/core/src/testFixtures/java/org/lflang/tests/LFTest.java b/core/src/testFixtures/java/org/lflang/tests/LFTest.java index 9430f80bd5..1f9ed98537 100644 --- a/core/src/testFixtures/java/org/lflang/tests/LFTest.java +++ b/core/src/testFixtures/java/org/lflang/tests/LFTest.java @@ -259,8 +259,8 @@ private Thread recordStream(StringBuffer builder, InputStream inputStream) { while ((len = reader.read(buf)) > 0) { if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) { Runtime.getRuntime().gc(); - if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) - builder.delete(0, builder.length() / 2); + // if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) + // builder.delete(0, builder.length() / 2); } builder.append(buf, 0, len); } From d15a167c8422d12a37c6fbb845f0029641caeb7a Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 3 Aug 2023 15:57:29 -0700 Subject: [PATCH 096/142] Reduce tests timeou+ Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../federated/transient/ConnectedTransient.lf | 8 ++++---- .../transient/ConnectedTransient_2L.lf | 20 +++++++++---------- test/C/src/federated/transient/FastAndSlow.lf | 14 ++++++------- .../src/federated/transient/PingPong_Cycle.lf | 8 ++++---- test/C/src/federated/transient/Timers.lf | 10 ++++------ 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index ef6ab52fb4..919591121b 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit ef6ab52fb4be5d7046228bf1bdd4aecf9372b9b8 +Subproject commit 919591121bc0d4ce6ba06db0a0d24ef2f41a8466 diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index 12f7f6fc4e..3e3809df47 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -24,15 +24,15 @@ reactor Middle { reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); - lf_print("IN1 :: Sending %d at ", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - // lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN1 :: Sending %d at ", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); - lf_print("IN2 :: Sending %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - // lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN2 :: Sending %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} } diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index d5ceafe2f1..fad4ae1b5e 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -1,16 +1,16 @@ target C { - timeout: 20 s, + timeout: 1s, tracing: true } -reactor Up(period: time = 2 s) { +reactor Up(period: time = 500ms) { output out: int timer t(0, period) state count: int = 0 reaction(t) -> out {= lf_set(out, self->count); - lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); self->count++; =} } @@ -21,7 +21,7 @@ reactor PassThrough { reaction(in) -> out {= lf_set(out, in->value); - lf_print("PassThrough :: Passing %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("PassThrough :: Passing %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } @@ -34,13 +34,13 @@ reactor Middle { reaction(in1) -> out {= self->count += in1->value; lf_set(out, self->count); - lf_print("IN1 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN1 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); - lf_print("IN2 :: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN2 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} } @@ -48,18 +48,18 @@ reactor Down { input in: int reaction(in) {= - lf_print("Received %d at (%lld, %ld)", in->value, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Received %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } federated reactor { - up1 = new Up(period = 2 s) - up2 = new Up(period = 1 s) + up1 = new Up(period = 200 msec) + up2 = new Up(period = 100 msec) + down = new Down() @transient pt = new PassThrough() @transient mid = new Middle() - down = new Down() up1.out -> pt.in // Connections pt.out -> mid.in1 diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf index 08b6f9669c..155555a77f 100644 --- a/test/C/src/federated/transient/FastAndSlow.lf +++ b/test/C/src/federated/transient/FastAndSlow.lf @@ -2,25 +2,25 @@ // enclaved execution. The deadlines should never be violated for the test to pass.". Here, we // transform it into a federated one, where the `fast` federate is transient. target C { - timeout: 20 sec + timeout: 1 sec } reactor Slow { - timer t(0, 1 sec) + timer t(0, 500 msec) reaction(t) {= lf_print("Slow reaction starts"); - lf_sleep(700000000); + // lf_sleep(700000000); lf_print("Slow reaction ends"); - =} deadline(200 msec) {= lf_print_error_and_exit("Slow deadline was violated!"); =} + =} } reactor Fast { timer t(0 msec, 100 msec) - reaction(t) {= lf_print("Fast reaction executes"); =} deadline(200 msec) {= - lf_print_error_and_exit("Fast deadline was violated!"); - =} + reaction(t) {= + lf_print("Fast reaction executes"); + =} } federated reactor { diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf index c41824b3d7..141a16d668 100644 --- a/test/C/src/federated/transient/PingPong_Cycle.lf +++ b/test/C/src/federated/transient/PingPong_Cycle.lf @@ -1,10 +1,10 @@ target C { - timeout: 10 s, + timeout: 2 s, tracing: true } reactor Ping { - timer t(0, 1 s) + timer t(0, 500 msec) input in: int output out: int state counter: int = 0 @@ -14,7 +14,7 @@ reactor Ping { reaction(in) {= self->received = true; - lf_print("Ping Received %d at %lld.", in->value, lf_time_logical_elapsed()); + lf_print("Ping Received %d at "PRINTF_TIME".", in->value, lf_time_logical_elapsed()); =} reaction(shutdown) {= @@ -32,7 +32,7 @@ reactor Pong { reaction(in) -> out {= self->received = true; - lf_print("Pong Received %d at %lld.", in-> value, lf_time_logical_elapsed()); + lf_print("Pong Received %d at "PRINTF_TIME".", in-> value, lf_time_logical_elapsed()); lf_set(out, in->value); =} diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf index 961413ce8e..0ee1e10e0f 100644 --- a/test/C/src/federated/transient/Timers.lf +++ b/test/C/src/federated/transient/Timers.lf @@ -1,7 +1,5 @@ target C { - timeout: 10 s, - tracing: true, - threading: true + timeout: 2s } reactor Timer(period: time = 2 s) { @@ -17,8 +15,8 @@ reactor Timer(period: time = 2 s) { } federated reactor { - @transient - t0 = new Timer(period = 1 s) + t0 = new Timer() t1 = new Timer() - t2 = new Timer() + @transient + t2 = new Timer(period = 1 s) } From 07e0829fe579f7e4beafd838b2c2d8152514d58d Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 3 Aug 2023 16:12:26 -0700 Subject: [PATCH 097/142] Apply formatter --- test/C/src/federated/transient/ConnectedTransient_2L.lf | 4 ++-- test/C/src/federated/transient/FastAndSlow.lf | 4 +--- test/C/src/federated/transient/Timers.lf | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index fad4ae1b5e..1dfa9a0176 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -1,9 +1,9 @@ target C { - timeout: 1s, + timeout: 1 s, tracing: true } -reactor Up(period: time = 500ms) { +reactor Up(period: time = 500 ms) { output out: int timer t(0, period) state count: int = 0 diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf index 155555a77f..00c42db5fe 100644 --- a/test/C/src/federated/transient/FastAndSlow.lf +++ b/test/C/src/federated/transient/FastAndSlow.lf @@ -18,9 +18,7 @@ reactor Slow { reactor Fast { timer t(0 msec, 100 msec) - reaction(t) {= - lf_print("Fast reaction executes"); - =} + reaction(t) {= lf_print("Fast reaction executes"); =} } federated reactor { diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf index 0ee1e10e0f..43faaac4d7 100644 --- a/test/C/src/federated/transient/Timers.lf +++ b/test/C/src/federated/transient/Timers.lf @@ -1,5 +1,5 @@ target C { - timeout: 2s + timeout: 2 s } reactor Timer(period: time = 2 s) { From e0b4588fdff335eca3e608874f5627838f33ab99 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 11:32:43 -0700 Subject: [PATCH 098/142] Revert undeleting long outputs when testing. --- core/src/testFixtures/java/org/lflang/tests/LFTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/LFTest.java b/core/src/testFixtures/java/org/lflang/tests/LFTest.java index 1f9ed98537..9430f80bd5 100644 --- a/core/src/testFixtures/java/org/lflang/tests/LFTest.java +++ b/core/src/testFixtures/java/org/lflang/tests/LFTest.java @@ -259,8 +259,8 @@ private Thread recordStream(StringBuffer builder, InputStream inputStream) { while ((len = reader.read(buf)) > 0) { if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) { Runtime.getRuntime().gc(); - // if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) - // builder.delete(0, builder.length() / 2); + if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) + builder.delete(0, builder.length() / 2); } builder.append(buf, 0, len); } From 71c0aac6423e9d57f3b3d55a728b0c13c10c7f11 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 13:45:28 -0700 Subject: [PATCH 099/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 919591121b..27150bfe69 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 919591121bc0d4ce6ba06db0a0d24ef2f41a8466 +Subproject commit 27150bfe694a81c85b662031ea91cd2bb956ad79 From 88519bad765e5f5cc18f12eabf8ef87bfc1b8a1e Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 13:46:28 -0700 Subject: [PATCH 100/142] Tune the use cases --- .../src/federated/transient/BankTransients.lf | 43 +++++++++++++++++++ .../federated/transient/ConnectedTransient.lf | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/C/src/federated/transient/BankTransients.lf diff --git a/test/C/src/federated/transient/BankTransients.lf b/test/C/src/federated/transient/BankTransients.lf new file mode 100644 index 0000000000..54902025b6 --- /dev/null +++ b/test/C/src/federated/transient/BankTransients.lf @@ -0,0 +1,43 @@ +/** This program tests bank of transients */ +target C { + timeout: 2 s +} + +reactor Count { + output out: int + state count: int = 0 + timer t(0, 500 msec) + + reaction(t) -> out {= + lf_print("Sending count: %d", self->count); + lf_set(out, self->count); + self->count++; + =} +} + +reactor Pass { + input in: int + output out: int + state count: int = 0 + + reaction(in) -> out {= + self->count = in-> value; + lf_set(out, self->count); + =} +} + +reactor Print { + input in: int + + reaction(in) {= lf_print("Received %d.", in->value); =} +} + +federated reactor { + count = new[2] Count() + print = new[2] Print() + @transient + pass = new[2] Pass() + + count.out -> pass.in + pass.out -> print.in +} diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index 3e3809df47..c56a4b023d 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -1,5 +1,5 @@ target C { - timeout: 15 s, + timeout: 4 s, tracing: true } From bdf6c0ca5544a94bcd52aca971198215ea6605b2 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 13:53:16 -0700 Subject: [PATCH 101/142] Add a start on a real test for transients --- test/C/src/federated/transient/Transients.lf | 100 +++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 test/C/src/federated/transient/Transients.lf diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf new file mode 100644 index 0000000000..7041d0e5f6 --- /dev/null +++ b/test/C/src/federated/transient/Transients.lf @@ -0,0 +1,100 @@ +target C { + timeout: 2 s, + tracing: true +} + +preamble {= + #include +=} + +reactor TransientExec { + timer t(1400 msec, 2 sec) + + reaction(t) {= + lf_print("Launching the second execution of mid..."); + lf_print(">>>>>>>>>>>>>>>"); + system("echo ${LF_SOURCE_DIRECTORY}"); + system("$LF_HOME/test/C/fed-gen/Transients/bin/federate__mid"); + lf_print("Done launching"); + =} +} + +reactor Up { + output out: int + timer t(0, 500 msec) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} +} + +reactor Middle { + input in: int + output out: int + state count: int = 0 + + timer t(800 msec, 2 s) + + reaction(in) -> out {= + self->count += 100; + int to_send = self->count + in->value; + lf_set(out, to_send); + =} + + reaction(t) {= + // Middle will spontaneously stop at 800 msec + lf_stop(); + =} + + // Check that Middle have executed during two periods of Up + reaction(shutdown) {= + if (self->count != 200) { + lf_print_error_and_exit("Wrong passed values form Up and Mid! Received %d while expecting 204.", self->received); + } + =} +} + +reactor Down { + timer t(0, 500 ms) + + input in: int + + state count: int = 0 + state received: int = 0 + + reaction(t) {= + self->count += 1000; + lf_print("Count of Down is: %d at "PRINTF_TIME, self->count, lf_time_logical_elapsed()/1000000); + =} + + reaction(in) {= + self->received = in->value; + lf_print("Received of Down is: %d at "PRINTF_TIME, self->received, lf_time_logical_elapsed()/1000000); + =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count != 5000) { + lf_print_error_and_exit("Federate's timer failed to react."); + } + + // Check that Middle have joined during the last two periods of Up + if (self->received != 204) { + lf_print_error_and_exit("Wrong passed values form Up and Mid! Received %d while expecting 204.", self->received); + } + =} +} + +federated reactor { + up = new Up() + down = new Down() + midExec = new TransientExec() + @transient + mid = new Middle() + + up.out -> mid.in // Connections + mid.out -> down.in +} From b399e6ce2a4e95eeae71df05225442f4952fce65 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 4 Aug 2023 14:02:13 -0700 Subject: [PATCH 102/142] Add lf_get_federates_bin_directory(). --- core/src/main/java/org/lflang/generator/c/CCompiler.java | 4 ++++ core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 0933d95594..015793a1b5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -228,11 +228,13 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f String maybeQuote = ""; // Windows seems to require extra level of quoting. String srcPath = fileConfig.srcPath.toString(); // Windows requires escaping the backslashes. String rootPath = fileConfig.srcPkgPath.toString(); + String binPath = fileConfig.binPath.toString(); if (separator.equals("\\")) { separator = "\\\\\\\\"; maybeQuote = "\\\""; srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); rootPath = rootPath.replaceAll("\\\\", "\\\\\\\\"); + binPath = binPath.replaceAll("\\\\", "\\\\\\\\"); } arguments.addAll( List.of( @@ -251,6 +253,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f // Do not convert to Unix path arguments.add("-DLF_SOURCE_DIRECTORY=\"" + maybeQuote + srcPath + maybeQuote + "\""); arguments.add("-DLF_PACKAGE_DIRECTORY=\"" + maybeQuote + rootPath + maybeQuote + "\""); + } else { + arguments.add("-DLF_FEDERATES_BIN_DIRECTORY=\"" + maybeQuote + binPath + maybeQuote + "\""); } arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 27150bfe69..9a8f97cdc1 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 27150bfe694a81c85b662031ea91cd2bb956ad79 +Subproject commit 9a8f97cdc1a3b49b133afbb5ea3cab953d31f269 From 88f052d38cc8e6e714227fda385d3fe94a9b0fa7 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 18:01:42 -0700 Subject: [PATCH 103/142] Tune transient test to pass CI + Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- test/C/src/federated/transient/Transients.lf | 49 ++++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 9a8f97cdc1..584c85fd90 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9a8f97cdc1a3b49b133afbb5ea3cab953d31f269 +Subproject commit 584c85fd907b243bb6392e9bef0a0816f2ee3b59 diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 7041d0e5f6..6d95603f91 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -1,3 +1,8 @@ +/** + * This tests if a transient corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected that is it received correct + * TAG, regardless if the transient being absent or present. + */ target C { timeout: 2 s, tracing: true @@ -5,20 +10,34 @@ target C { preamble {= #include + #include =} +/** Persistent federate that is responsible for lauching the transient at logical time 1400ms */ reactor TransientExec { timer t(1400 msec, 2 sec) reaction(t) {= - lf_print("Launching the second execution of mid..."); - lf_print(">>>>>>>>>>>>>>>"); - system("echo ${LF_SOURCE_DIRECTORY}"); - system("$LF_HOME/test/C/fed-gen/Transients/bin/federate__mid"); - lf_print("Done launching"); + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + strcat(mid_launch_cmd, lf_get_federates_bin_directory()); + strcat(mid_launch_cmd, "/federate__mid -i "); + strcat(mid_launch_cmd, lf_get_federation_id()); + // Execute the command + int status = system(mid_launch_cmd); + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__mid."); + } else { + lf_print_error_and_exit("Unable to launch federate__mid."); + } =} } +/** + *Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at + * logical times 0, 500, 1000, 1500 and 2000. + */ reactor Up { output out: int timer t(0, 500 msec) @@ -31,6 +50,15 @@ reactor Up { =} } +/** + * Transient federate that forwards what it receives from Up, after augmenting it with + * its own count values. It will execute twice during the lifetime of the federation. + * In the first execution, it will spontaneously stop at logical time 800 ms. Then it will be + * launched again by TransientExec at logical time 140 0ms, to resign at the stop_tag of + * the fderation. + * In both executions, Middle will react twice to the incoming input from Up. Therefore + * at shutdown, count has to be 200. + */ reactor Middle { input in: int output out: int @@ -49,14 +77,19 @@ reactor Middle { lf_stop(); =} - // Check that Middle have executed during two periods of Up reaction(shutdown) {= + // The reaction should execute only twice. Therefore count should be 200 at + // shutdown if (self->count != 200) { - lf_print_error_and_exit("Wrong passed values form Up and Mid! Received %d while expecting 204.", self->received); + lf_print_error_and_exit("Mid reacted other than twice. Count is %d while it is expected to be 200.", self->count); } =} } +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting + * to its internal timer and also to inputs from the tarnsient, if any. + */ reactor Down { timer t(0, 500 ms) @@ -91,9 +124,9 @@ reactor Down { federated reactor { up = new Up() down = new Down() - midExec = new TransientExec() @transient mid = new Middle() + midExec = new TransientExec() up.out -> mid.in // Connections mid.out -> down.in From 82fae6716d5f7f58a6b0781322fe111562de6d40 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 18:14:27 -0700 Subject: [PATCH 104/142] Apply formatter --- test/C/src/federated/transient/Transients.lf | 28 +++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 6d95603f91..853bbabfc6 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -1,7 +1,7 @@ /** - * This tests if a transient corretly leaves then joins the federation. It also - * tests if the transient's downstream executes as expected that is it received correct - * TAG, regardless if the transient being absent or present. + * This tests if a transient corretly leaves then joins the federation. It also tests if the + * transient's downstream executes as expected that is it received correct TAG, regardless if the + * transient being absent or present. */ target C { timeout: 2 s, @@ -34,9 +34,9 @@ reactor TransientExec { =} } -/** - *Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at - * logical times 0, 500, 1000, 1500 and 2000. +/** + * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, + * 1000, 1500 and 2000. */ reactor Up { output out: int @@ -51,13 +51,11 @@ reactor Up { } /** - * Transient federate that forwards what it receives from Up, after augmenting it with - * its own count values. It will execute twice during the lifetime of the federation. - * In the first execution, it will spontaneously stop at logical time 800 ms. Then it will be - * launched again by TransientExec at logical time 140 0ms, to resign at the stop_tag of - * the fderation. - * In both executions, Middle will react twice to the incoming input from Up. Therefore - * at shutdown, count has to be 200. + * Transient federate that forwards what it receives from Up, after augmenting it with its own count + * values. It will execute twice during the lifetime of the federation. In the first execution, it + * will spontaneously stop at logical time 800 ms. Then it will be launched again by TransientExec + * at logical time 140 0ms, to resign at the stop_tag of the fderation. In both executions, Middle + * will react twice to the incoming input from Up. Therefore at shutdown, count has to be 200. */ reactor Middle { input in: int @@ -87,8 +85,8 @@ reactor Middle { } /** - * Persistent federate, which is downstream of the transient. It has to keep reacting - * to its internal timer and also to inputs from the tarnsient, if any. + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tarnsient, if any. */ reactor Down { timer t(0, 500 ms) From 9d2b0e0f296f969615d5b33c5e9b48040cb0da84 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 18:24:33 -0700 Subject: [PATCH 105/142] Adjust Transients.lf --- test/C/src/federated/transient/Transients.lf | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 853bbabfc6..9b3d926759 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -19,8 +19,7 @@ reactor TransientExec { reaction(t) {= // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - strcat(mid_launch_cmd, lf_get_federates_bin_directory()); + char mid_launch_cmd[512] = lf_get_federates_bin_directory(); strcat(mid_launch_cmd, "/federate__mid -i "); strcat(mid_launch_cmd, lf_get_federation_id()); // Execute the command @@ -54,8 +53,8 @@ reactor Up { * Transient federate that forwards what it receives from Up, after augmenting it with its own count * values. It will execute twice during the lifetime of the federation. In the first execution, it * will spontaneously stop at logical time 800 ms. Then it will be launched again by TransientExec - * at logical time 140 0ms, to resign at the stop_tag of the fderation. In both executions, Middle - * will react twice to the incoming input from Up. Therefore at shutdown, count has to be 200. + * at logical time 1400 ms, to resign at the stop_tag of the fderation. In both executions, Middle + * will react twice to the incoming input from Up. */ reactor Middle { input in: int @@ -74,14 +73,6 @@ reactor Middle { // Middle will spontaneously stop at 800 msec lf_stop(); =} - - reaction(shutdown) {= - // The reaction should execute only twice. Therefore count should be 200 at - // shutdown - if (self->count != 200) { - lf_print_error_and_exit("Mid reacted other than twice. Count is %d while it is expected to be 200.", self->count); - } - =} } /** From 620431c6931e7ca7f1f86102f0a2d69e361471e1 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 18:33:21 -0700 Subject: [PATCH 106/142] Adjust Transients.lf again --- test/C/src/federated/transient/Transients.lf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 9b3d926759..3e6bbed589 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -52,9 +52,9 @@ reactor Up { /** * Transient federate that forwards what it receives from Up, after augmenting it with its own count * values. It will execute twice during the lifetime of the federation. In the first execution, it - * will spontaneously stop at logical time 800 ms. Then it will be launched again by TransientExec - * at logical time 1400 ms, to resign at the stop_tag of the fderation. In both executions, Middle - * will react twice to the incoming input from Up. + * will spontaneously stop after the second reaction to in. Then it will be launched again by TransientExec + * at logical time 1400 ms, to resign at the stop_tag of the fderation, which is also after the 2nd + * reaction to in. In both executions, Middle reacts twice to the incoming input from Up. */ reactor Middle { input in: int @@ -67,17 +67,17 @@ reactor Middle { self->count += 100; int to_send = self->count + in->value; lf_set(out, to_send); + if (self->count == 200) { + // Middle will spontaneously stop after two reactions + lf_stop(); + } =} - reaction(t) {= - // Middle will spontaneously stop at 800 msec - lf_stop(); - =} } /** * Persistent federate, which is downstream of the transient. It has to keep reacting to its - * internal timer and also to inputs from the tarnsient, if any. + * internal timer and also to inputs from the tansient, if any. */ reactor Down { timer t(0, 500 ms) From b03d922e769659115cb70848155724115e2ae644 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Fri, 4 Aug 2023 18:42:46 -0700 Subject: [PATCH 107/142] Apply formatter --- test/C/src/federated/transient/Transients.lf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 3e6bbed589..c9daefbc03 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -52,9 +52,10 @@ reactor Up { /** * Transient federate that forwards what it receives from Up, after augmenting it with its own count * values. It will execute twice during the lifetime of the federation. In the first execution, it - * will spontaneously stop after the second reaction to in. Then it will be launched again by TransientExec - * at logical time 1400 ms, to resign at the stop_tag of the fderation, which is also after the 2nd - * reaction to in. In both executions, Middle reacts twice to the incoming input from Up. + * will spontaneously stop after the second reaction to in. Then it will be launched again by + * TransientExec at logical time 1400 ms, to resign at the stop_tag of the fderation, which is also + * after the 2nd reaction to in. In both executions, Middle reacts twice to the incoming input from + * Up. */ reactor Middle { input in: int @@ -72,7 +73,6 @@ reactor Middle { lf_stop(); } =} - } /** From 285ddbe2903da9e3686ee6b028f6194b5c5d067f Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 6 Aug 2023 22:54:48 -0700 Subject: [PATCH 108/142] Fix error in example --- test/C/src/federated/transient/Transients.lf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index c9daefbc03..f01536bcd9 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -19,7 +19,8 @@ reactor TransientExec { reaction(t) {= // Construct the command to launch the transient federate - char mid_launch_cmd[512] = lf_get_federates_bin_directory(); + char mid_launch_cmd[512]; + strcat(mid_launch_cmd, lf_get_federates_bin_directory()); strcat(mid_launch_cmd, "/federate__mid -i "); strcat(mid_launch_cmd, lf_get_federation_id()); // Execute the command From ab422e5bf50d9d83e91aadf12c28c24f2abfd497 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 6 Aug 2023 23:23:42 -0700 Subject: [PATCH 109/142] Another trial: Use sprintf instead of strcat + Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- test/C/src/federated/transient/Transients.lf | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 584c85fd90..644ed2c170 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 584c85fd907b243bb6392e9bef0a0816f2ee3b59 +Subproject commit 644ed2c17057419b05d2115c116b789030000ab9 diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index f01536bcd9..8d3d932eea 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -20,9 +20,10 @@ reactor TransientExec { reaction(t) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; - strcat(mid_launch_cmd, lf_get_federates_bin_directory()); - strcat(mid_launch_cmd, "/federate__mid -i "); - strcat(mid_launch_cmd, lf_get_federation_id()); + sprintf("%s/federate__mid -i %s", lf_get_federates_bin_directory(), f_get_federation_id()); + // strcat(mid_launch_cmd, lf_get_federates_bin_directory()); + // strcat(mid_launch_cmd, "/federate__mid -i "); + // strcat(mid_launch_cmd, lf_get_federation_id()); // Execute the command int status = system(mid_launch_cmd); // Exit if error From 0333cb9de7d6234c67e0b17e97e5f6bb2de5fe45 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 6 Aug 2023 23:39:35 -0700 Subject: [PATCH 110/142] Fix wrong call --- test/C/src/federated/transient/Transients.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 8d3d932eea..a76ed15991 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -20,7 +20,7 @@ reactor TransientExec { reaction(t) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; - sprintf("%s/federate__mid -i %s", lf_get_federates_bin_directory(), f_get_federation_id()); + sprintf("%s/federate__mid -i %s", lf_get_federates_bin_directory(), lf_get_federation_id()); // strcat(mid_launch_cmd, lf_get_federates_bin_directory()); // strcat(mid_launch_cmd, "/federate__mid -i "); // strcat(mid_launch_cmd, lf_get_federation_id()); From 08c2439d83571b9e2f2bbc06f3cb105d4892b814 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 08:07:11 -0700 Subject: [PATCH 111/142] Fix overllokgit status ! --- test/C/src/federated/transient/Transients.lf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index a76ed15991..44ee2ccd27 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -20,11 +20,12 @@ reactor TransientExec { reaction(t) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; - sprintf("%s/federate__mid -i %s", lf_get_federates_bin_directory(), lf_get_federation_id()); + sprintf(mid_launch_cmd, "%s/federate__mid -i %s", lf_get_federates_bin_directory(), lf_get_federation_id()); // strcat(mid_launch_cmd, lf_get_federates_bin_directory()); // strcat(mid_launch_cmd, "/federate__mid -i "); // strcat(mid_launch_cmd, lf_get_federation_id()); // Execute the command + // lf_print(">>>> Executing: %s", mid_launch_cmd); int status = system(mid_launch_cmd); // Exit if error if (status == 0) { From 4f4e66df50db79c2208a53c6e3f5936233668445 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 13:48:50 -0700 Subject: [PATCH 112/142] Refactoring of Transients.lf test --- test/C/src/federated/transient/Transients.lf | 79 +++++++++++++++----- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 44ee2ccd27..f012297de8 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -13,20 +13,21 @@ preamble {= #include =} -/** Persistent federate that is responsible for lauching the transient at logical time 1400ms */ +/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ reactor TransientExec { - timer t(1400 msec, 2 sec) + reaction(startup) {= + lf_sleep(1000000000); - reaction(t) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, "%s/federate__mid -i %s", lf_get_federates_bin_directory(), lf_get_federation_id()); - // strcat(mid_launch_cmd, lf_get_federates_bin_directory()); - // strcat(mid_launch_cmd, "/federate__mid -i "); - // strcat(mid_launch_cmd, lf_get_federation_id()); - // Execute the command - // lf_print(">>>> Executing: %s", mid_launch_cmd); + sprintf(mid_launch_cmd, + "%s/federate__mid -i %s", + lf_get_federates_bin_directory(), + lf_get_federation_id() + ); + int status = system(mid_launch_cmd); + // Exit if error if (status == 0) { lf_print("Successfully launched federate__mid."); @@ -56,24 +57,45 @@ reactor Up { * Transient federate that forwards what it receives from Up, after augmenting it with its own count * values. It will execute twice during the lifetime of the federation. In the first execution, it * will spontaneously stop after the second reaction to in. Then it will be launched again by - * TransientExec at logical time 1400 ms, to resign at the stop_tag of the fderation, which is also - * after the 2nd reaction to in. In both executions, Middle reacts twice to the incoming input from - * Up. + * TransientExec at logical time 1 s, to resign at the stop_tag of the fderation. Middle notifies + * Down that it joined and whether its effective start time is different from the start time of the + * federation. */ reactor Middle { input in: int output out: int + output out_joined: int + state count: int = 0 - timer t(800 msec, 2 s) + timer t(0, 250 msec) + + reaction(startup) -> out_joined {= + int first_join = (lf_get_effective_start_time() == lf_get_start_time()); + + if (first_join == 1) { + lf_print("Mid is joining at startup phase."); + } else { + lf_print("Mid is joining after the startup phase."); + } + + lf_set(out_joined, first_join); + =} + + reaction(t) {= + lf_print("Mid reacting to t at federation logical time "PRINTF_TIME" and local logical time "PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); + =} reaction(in) -> out {= self->count += 100; int to_send = self->count + in->value; lf_set(out, to_send); - if (self->count == 200) { - // Middle will spontaneously stop after two reactions - lf_stop(); + // If this is the first execution of Middle, then it will spontaneously stop after two reactions + if ( + (self->count == 200) && + (lf_get_effective_start_time() == lf_get_start_time()) + ) { + lf_stop(); } =} } @@ -86,9 +108,12 @@ reactor Down { timer t(0, 500 ms) input in: int + input in_joined: int state count: int = 0 state received: int = 0 + state num_joined: int = 0 + state distinct_join: int = 0 reaction(t) {= self->count += 1000; @@ -100,15 +125,25 @@ reactor Down { lf_print("Received of Down is: %d at "PRINTF_TIME, self->received, lf_time_logical_elapsed()/1000000); =} + reaction(in_joined) {= + self->num_joined++; + self->distinct_join += in_joined->value; + =} + reaction(shutdown) {= // Check that the TAG have been successfully issued to Down if (self->count != 5000) { - lf_print_error_and_exit("Federate's timer failed to react."); + lf_print_error_and_exit("Federate's timer failed to react."); + } + + // Check that Middle have joined 2 times + if (self->num_joined != 2 || self->distinct_join != 1) { + lf_print_error_and_exit("Transient federate Mid did not execute twice!"); } - // Check that Middle have joined during the last two periods of Up - if (self->received != 204) { - lf_print_error_and_exit("Wrong passed values form Up and Mid! Received %d while expecting 204.", self->received); + // Check that Middle have reacted correctly + if (self->received < 102) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 102, but have: %d.", self->received); } =} } @@ -116,10 +151,14 @@ reactor Down { federated reactor { up = new Up() down = new Down() + // Important note: since mid is instantiated before persistent federate midExec, + // it will join at the startup phase, making its effective start time equal to the federation + // start time. Defining mid at the end will break up the test described above. @transient mid = new Middle() midExec = new TransientExec() up.out -> mid.in // Connections + mid.out_joined -> down.in_joined mid.out -> down.in } From 2525ad7cf1b51704c55c55a55c3e943edddf2329 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 13:49:16 -0700 Subject: [PATCH 113/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 644ed2c170..12efc498e2 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 644ed2c17057419b05d2115c116b789030000ab9 +Subproject commit 12efc498e2a83ec11a131be7c1daf3803dd6c27b From 7383830a5aed1c736c506b14b4f1f25ea0b33ea4 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 14:02:58 -0700 Subject: [PATCH 114/142] Apply formatter --- test/C/src/federated/transient/Transients.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index f012297de8..faa072fe0e 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -72,7 +72,7 @@ reactor Middle { reaction(startup) -> out_joined {= int first_join = (lf_get_effective_start_time() == lf_get_start_time()); - + if (first_join == 1) { lf_print("Mid is joining at startup phase."); } else { From a82e7a413199d4ba2e572d0252e6443f30de9560 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 14:09:44 -0700 Subject: [PATCH 115/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 12efc498e2..1f339a66a4 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 12efc498e2a83ec11a131be7c1daf3803dd6c27b +Subproject commit 1f339a66a4d7bb571313591827307f91341143fc From 96e9d8eebc2e921894011c48d2422c9d4259de8e Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 15:38:09 -0700 Subject: [PATCH 116/142] Adjust Transients.lf test and align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- test/C/src/federated/transient/Transients.lf | 30 +++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 1f339a66a4..8dcc23a214 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 1f339a66a4d7bb571313591827307f91341143fc +Subproject commit 8dcc23a214ccbcb19d5cc89e1fff7e75f203a3f3 diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index faa072fe0e..6698363f84 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -56,15 +56,14 @@ reactor Up { /** * Transient federate that forwards what it receives from Up, after augmenting it with its own count * values. It will execute twice during the lifetime of the federation. In the first execution, it - * will spontaneously stop after the second reaction to in. Then it will be launched again by - * TransientExec at logical time 1 s, to resign at the stop_tag of the fderation. Middle notifies - * Down that it joined and whether its effective start time is different from the start time of the - * federation. + * will spontaneously stop after the second reaction to in. Then, it will be launched again by + * TransientExec at logical time 1 s, to resign at the stop_tag of the federation. Middle notifies + * Down that it joined and and sends its offset w.r.t the start time of the federation. */ reactor Middle { input in: int output out: int - output out_joined: int + output out_joined: instant_t state count: int = 0 @@ -74,16 +73,16 @@ reactor Middle { int first_join = (lf_get_effective_start_time() == lf_get_start_time()); if (first_join == 1) { - lf_print("Mid is joining at startup phase."); + lf_print("Mid is joining during the startup phase."); } else { - lf_print("Mid is joining after the startup phase."); + lf_print("Mid is joining after the startup phase and the offset is: "PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); } - lf_set(out_joined, first_join); + lf_set(out_joined, lf_get_effective_start_time() - lf_get_start_time()); =} reaction(t) {= - lf_print("Mid reacting to t at federation logical time "PRINTF_TIME" and local logical time "PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); + lf_print("Mid reacting to t at federation elapsed logical time "PRINTF_TIME" and local elapsed logical time "PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); =} reaction(in) -> out {= @@ -108,12 +107,13 @@ reactor Down { timer t(0, 500 ms) input in: int - input in_joined: int + input in_joined: instant_t state count: int = 0 state received: int = 0 state num_joined: int = 0 - state distinct_join: int = 0 + state join_offset_1: instant_t = 0 + state join_offset_2: instant_t = 0 reaction(t) {= self->count += 1000; @@ -127,7 +127,11 @@ reactor Down { reaction(in_joined) {= self->num_joined++; - self->distinct_join += in_joined->value; + if (self->num_joined == 1) { + self->join_offset_1 = in_joined->value; + } else { + self->join_offset_2 = in_joined->value; + } =} reaction(shutdown) {= @@ -137,7 +141,7 @@ reactor Down { } // Check that Middle have joined 2 times - if (self->num_joined != 2 || self->distinct_join != 1) { + if (self->num_joined != 2 || self->join_offset_2 <= self->join_offset_1) { lf_print_error_and_exit("Transient federate Mid did not execute twice!"); } From 6e902733a2f463d08858a84c11e8a244f2fb65be Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 16:19:32 -0700 Subject: [PATCH 117/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 8dcc23a214..53c6ad92b1 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 8dcc23a214ccbcb19d5cc89e1fff7e75f203a3f3 +Subproject commit 53c6ad92b1b1e77800b8ed3a4e87fb65491d0c2b From e1f92baeecd96f5261c402ed5812fb74362566e8 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 16:56:57 -0700 Subject: [PATCH 118/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 53c6ad92b1..be897db332 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 53c6ad92b1b1e77800b8ed3a4e87fb65491d0c2b +Subproject commit be897db33218a8617149760d184caa7301346d5a From 040e463b497b9886947efdba71e29b8ad2acd0ee Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 7 Aug 2023 23:15:30 -0700 Subject: [PATCH 119/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index be897db332..7249e0cd96 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit be897db33218a8617149760d184caa7301346d5a +Subproject commit 7249e0cd96371afca79493eb8026d2ee959b70f2 From 6585d29dbeb0daf893662b9f49b17ac132e614e5 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 9 Aug 2023 01:23:23 -0700 Subject: [PATCH 120/142] Add a test of timer synchrony in transient federates + Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 7249e0cd96..25beb95712 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 7249e0cd96371afca79493eb8026d2ee959b70f2 +Subproject commit 25beb9571285359b69b5fbd1d09bc36fb49a3d61 From 7e3279be586f84cdb0224cc2fb030972137de3de Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 9 Aug 2023 08:02:20 -0700 Subject: [PATCH 121/142] Add a test of timer synchrony in transient federates for real --- .../src/federated/transient/TransientTimer.lf | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 test/C/src/federated/transient/TransientTimer.lf diff --git a/test/C/src/federated/transient/TransientTimer.lf b/test/C/src/federated/transient/TransientTimer.lf new file mode 100644 index 0000000000..005fc32a91 --- /dev/null +++ b/test/C/src/federated/transient/TransientTimer.lf @@ -0,0 +1,101 @@ +/** + * This tests if a timer in a transient federate triggers with regard to the start_time of the + * federation (instead of the effective_start_time of the transient) + */ +target C { + timeout: 2 s, + tracing: true +} + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ +reactor TransientExec { + reaction(startup) {= + lf_sleep(1000000000); + + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__mid -i %s", + lf_get_federates_bin_directory(), + lf_get_federation_id() + ); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__mid."); + } else { + lf_print_error_and_exit("Unable to launch federate__mid."); + } + =} +} + +/** + * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, + * 1000, 1500 and 2000. + */ +reactor Up { + output out: int + timer t(0, 500 msec) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} +} + +/** + * Transient federate with a timer. It will execute twice during the lifetime of the federation. In + * the first execution, it will spontaneously stop after the second reaction to in. Then, it will be + * launched again by TransientExec at logical time 1 s, to resign at the stop_tag of the federation. + * At each reaction to the timer, we check that the tag is computed based on the start_time. + */ +reactor Middle { + input in: int + state count: int = 0 + timer t(0, 300 msec) + + reaction(startup) {= + int first_join = (lf_get_effective_start_time() == lf_get_start_time()); + + if (first_join == 1) { + lf_print("Mid is joining during the startup phase."); + } else { + lf_print("Mid is joining after the startup phase and the offset is: "PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); + } + =} + + reaction(t) {= + if (lf_time_logical_elapsed() % 300000000 != 0) { + lf_print_error_and_exit("Timer executing at a wrong tag."); + } + =} + + reaction(in) {= + self->count += 100; + // If this is the first execution of Middle, then it will spontaneously stop after two reactions + if ( + (self->count == 200) && + (lf_get_effective_start_time() == lf_get_start_time()) + ) { + lf_stop(); + } + =} +} + +federated reactor { + up = new Up() + @transient + mid = new Middle() + midExec = new TransientExec() + + up.out -> mid.in // Connections +} From c236bac841ee9e85169222d1ba0e378d772f666f Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 13 Aug 2023 21:07:21 -0700 Subject: [PATCH 122/142] transient is an annotation of an instantiation, not any object --- core/src/main/java/org/lflang/AttributeUtils.java | 2 +- test/C/src/federated/transient/ConnectedTransient_2L.lf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/AttributeUtils.java b/core/src/main/java/org/lflang/AttributeUtils.java index 14e19f1f6c..31495f7689 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -203,7 +203,7 @@ public static boolean isSparse(EObject node) { * * @param node An AST node. */ - public static boolean isTransient(EObject node) { + public static boolean isTransient(Instantiation node) { return findAttributeByName(node, "transient") != null; } diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index 1dfa9a0176..ac83221f92 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -47,6 +47,7 @@ reactor Middle { reactor Down { input in: int + @transient reaction(in) {= lf_print("Received %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} From d5269aff0b818bceb134408ceffaf43b87cfe2fc Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 13 Aug 2023 21:07:59 -0700 Subject: [PATCH 123/142] Remove forgoten annotation is test --- test/C/src/federated/transient/ConnectedTransient_2L.lf | 1 - 1 file changed, 1 deletion(-) diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf index ac83221f92..1dfa9a0176 100644 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ b/test/C/src/federated/transient/ConnectedTransient_2L.lf @@ -47,7 +47,6 @@ reactor Middle { reactor Down { input in: int - @transient reaction(in) {= lf_print("Received %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); =} From 95a61bbbaea428de89c82cf235c32b13195fbfa7 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Sun, 13 Aug 2023 22:58:51 -0700 Subject: [PATCH 124/142] Add commented attempt to validate transient annotation --- .../java/org/lflang/validation/LFValidator.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 7dcf00d107..068fa86f91 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -525,6 +525,22 @@ public void checkInstantiation(Instantiation instantiation) { error("Variable-width banks are not supported.", Literals.INSTANTIATION__WIDTH_SPEC); } } + + // // If the Instantiation has annotation '@transient', then make sure that the + // // container is a federated reactor, and that the coordination is centralized + // FederateInstance + // if (instantiation.isTransient()) { + // Reactor container = (Reactor) instantiation.eContainer(); + // if (!container.isFederated()) { + // error("Only federates can be transients: " + instantiation.getReactorClass().getName(), + // Literals.INSTANTIATION__REACTOR_CLASS); + // } + // if (this.target != Target.C) { + // error("Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); + // } + // // FIXME: Currently, transients are only supported in centralized coordination + // // Either add the check, or add the support in decentralized coordination. + // } } /** Check target parameters, which are key-value pairs. */ From ee129cb9c75e10d029cacff2ed77863b78539359 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 15 Aug 2023 11:42:15 -0700 Subject: [PATCH 125/142] Add commented template for validating transient annotation --- core/src/main/java/org/lflang/validation/LFValidator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 068fa86f91..446fdffe4a 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -526,9 +526,9 @@ public void checkInstantiation(Instantiation instantiation) { } } - // // If the Instantiation has annotation '@transient', then make sure that the + // // If the Instantiation has annotation '@transient', then make sure that the // // container is a federated reactor, and that the coordination is centralized - // FederateInstance + // FederateInstance // if (instantiation.isTransient()) { // Reactor container = (Reactor) instantiation.eContainer(); // if (!container.isFederated()) { @@ -536,7 +536,8 @@ public void checkInstantiation(Instantiation instantiation) { // Literals.INSTANTIATION__REACTOR_CLASS); // } // if (this.target != Target.C) { - // error("Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); + // error("Transient federates are only supported in the C target.", + // Literals.TARGET_DECL__NAME); // } // // FIXME: Currently, transients are only supported in centralized coordination // // Either add the check, or add the support in decentralized coordination. From 209f7838277ead8be0417a50c9cf1b16c707b183 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 15 Aug 2023 11:44:56 -0700 Subject: [PATCH 126/142] Cleanup residual cod e and comments + Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../postprocessor/ReactorPortAdjustment.java | 175 ------------------ util/tracing/visualization/fedsd.py | 3 +- util/tracing/visualization/fedsd_helper.py | 6 +- 4 files changed, 4 insertions(+), 182 deletions(-) delete mode 100644 org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index abcb6becc9..c0f9d723b3 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit abcb6becc974df661018d8e88b0b2b6e713393cc +Subproject commit c0f9d723b35906578e65e340b1464ad443fafa4e diff --git a/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java b/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java deleted file mode 100644 index 315eb0ebf4..0000000000 --- a/org.lflang/src/org/lflang/diagram/synthesis/postprocessor/ReactorPortAdjustment.java +++ /dev/null @@ -1,175 +0,0 @@ -/************* - * Copyright (c) 2023, Kiel University. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************/ -package org.lflang.diagram.synthesis.postprocessor; - -import com.google.inject.Binder; -import com.google.inject.Guice; -import com.google.inject.Scopes; -import com.google.inject.TypeLiteral; -import de.cau.cs.kieler.klighd.IStyleModifier; -import de.cau.cs.kieler.klighd.IViewer; -import de.cau.cs.kieler.klighd.internal.ILayoutRecorder; -import de.cau.cs.kieler.klighd.kgraph.KGraphElement; -import de.cau.cs.kieler.klighd.kgraph.KGraphFactory; -import de.cau.cs.kieler.klighd.kgraph.KNode; -import de.cau.cs.kieler.klighd.krendering.KRendering; -import de.cau.cs.kieler.klighd.krendering.KRenderingFactory; -import de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared; -import de.cau.cs.kieler.klighd.syntheses.AbstractDiagramSynthesis; -import java.util.List; -import javax.inject.Inject; -import org.eclipse.elk.core.options.CoreOptions; -import org.eclipse.elk.graph.properties.Property; -import org.eclipse.xtext.xbase.lib.Extension; -import org.lflang.diagram.synthesis.LinguaFrancaSynthesis; -import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions; - -/** - * Adjusts the port figures of reactors when fixed side are off to keep the input output indication - * correct. - * - * @author Alexander Schulz-Rosengarten - */ -public class ReactorPortAdjustment implements IStyleModifier { - - public static final String ID = - "org.lflang.diagram.synthesis.postprocessor.ReactorPortAdjustment"; - - /** INTERNAL property to mark node as flipped. */ - public static final Property FLIPPED = - new Property<>("org.lflang.diagram.synthesis.postprocessor.reactor.ports.flipped", false); - - @Inject @Extension private LinguaFrancaShapeExtensions _linguaFrancaShapeExtensions; - @Extension private KGraphFactory _kGraphFactory = KGraphFactory.eINSTANCE; - private static KRenderingFactory _kRenderingFactory = KRenderingFactory.eINSTANCE; - - /** Register this modifier on a reaction rendering. */ - public static void apply(KNode node, List renderings) { - var rendering = renderings.get(0); // Get first in bank - // Add modifier that fixes port positions such that edges are properly attached to the shape - var invisible = _kRenderingFactory.createKRotation(); - // make it ineffective (just for purpose of holding modifier) - invisible.setRotation(0); - // Add modifier to receive callback after layout - invisible.setModifierId(ID); - rendering.getStyles().add(invisible); - } - - public ReactorPortAdjustment() { - // Inject extension - if (_linguaFrancaShapeExtensions == null) { - var injector = - Guice.createInjector( - new com.google.inject.Module() { - // This Module is created to satisfy ViewSynthesisShared scope of used - // synthesis-extensions - public void configure(Binder binder) { - binder.bindScope(ViewSynthesisShared.class, Scopes.SINGLETON); - binder - .bind(new TypeLiteral>() {}) - .toInstance(new LinguaFrancaSynthesis()); - } - }); - _linguaFrancaShapeExtensions = injector.getInstance(LinguaFrancaShapeExtensions.class); - } - } - - @Override - public boolean modify(IStyleModifier.StyleModificationContext context) { - try { - KGraphElement node = context.getGraphElement(); - if (node instanceof KNode) { - KNode knode = (KNode) node; - - // Find root node - KNode parent = knode; - while (parent.eContainer() != null) { - parent = (KNode) parent.eContainer(); - } - - // Get viewer (this is a bit brittle because it fetches the viewer from some internal - // property) - Object viewer = - parent.getAllProperties().entrySet().stream() - .filter( - entry -> - entry.getKey().getId().equals("de.cau.cs.kieler.klighd.viewer") - || entry.getKey().getId().equals("klighd.layout.viewer")) - .findAny() - .map(entry -> entry.getValue()) - .orElse(null); - - ILayoutRecorder recorder = null; - if (viewer instanceof IViewer) { - recorder = ((IViewer) viewer).getViewContext().getLayoutRecorder(); - } - - if (recorder != null) { - recorder.startRecording(); - } - for (var port : knode.getPorts()) { - var isInput = port.getProperty(LinguaFrancaSynthesis.REACTOR_INPUT).booleanValue(); - if (!isInput && !port.getProperty(LinguaFrancaSynthesis.REACTOR_OUTPUT)) { - continue; // skip - } - - var xPos = port.getXpos(); - var isLeft = xPos < 0; - var flip = isInput != isLeft; - var isFlipped = port.getProperty(FLIPPED).booleanValue(); - var needsUpdate = flip != isFlipped; - - if (needsUpdate) { - // Remove figure - port.getData().removeIf(it -> it instanceof KRendering); - - // Get port type - var isMultiport = port.getProperty(LinguaFrancaSynthesis.REACTOR_MULTIPORT); - var isBank = port.getProperty(LinguaFrancaSynthesis.REACTOR_HAS_BANK_PORT_OFFSET); - - // Add new figure - _linguaFrancaShapeExtensions.addTrianglePort(port, isMultiport, flip); - port.setProperty(FLIPPED, flip); - - // Compute new offset - var oldOffset = port.getProperty(CoreOptions.PORT_BORDER_OFFSET); - var newOffset = - LinguaFrancaSynthesis.getReactorPortOffset(!isLeft, isMultiport, isBank); - - // Apply offset directly - port.setPos((float) (port.getXpos() + (oldOffset - newOffset)), port.getYpos()); - } - } - if (recorder != null) { - recorder.stopRecording(0); - } - } - } catch (Exception e) { - e.printStackTrace(); - // do not disturb rendering process - } - return false; - } -} diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index f00801fa33..44844cadae 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -26,8 +26,7 @@ .TAG { stroke: #08a578; fill: #08a578} \ .TIMESTAMP { stroke: grey; fill: grey } \ .FED_ID {stroke: #80DD99; fill: #80DD99 } \ - .CuTAG_RQ {stroke: #d0b7eb; fill: #d0b7eb} \ - .CuTAG_RQ_RES {stroke: #d0b7eb; fill: #d0b7eb} \ + .STOP {stroke: #d0b7eb; fill: #d0b7eb} \ .ADV {stroke-linecap="round" ; stroke: "red" ; fill: "red"} \ text { \ font-size: smaller; \ diff --git a/util/tracing/visualization/fedsd_helper.py b/util/tracing/visualization/fedsd_helper.py index 1bf97ac8ff..8c88f62a84 100644 --- a/util/tracing/visualization/fedsd_helper.py +++ b/util/tracing/visualization/fedsd_helper.py @@ -45,10 +45,8 @@ "Receiving ADR_QR": "ADR_QR", "Receiving UNIDENTIFIED": "UNIDENTIFIED", "Scheduler advancing time ends": "AdvLT", - "Sending CuTAG_QR": "CuTAG_QR", - "Sending CuTAG_QR_RES": "CuTAG_QR_RES", - "Receiving CuTAG_QR": "CuTAG_QR", - "Receiving CuTAG_QR_RES": "CuTAG_QR_RES" + "Sending STOP": "STOP", + "Receiving STOP": "STOP" } prune_event_name.setdefault(" ", "UNIDENTIFIED") From 3dac69452cb9ffdae2011bb62e4b99f732bac535 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 15 Aug 2023 13:04:38 -0700 Subject: [PATCH 127/142] Silence warnings in transient tests + adjust timing is TransientTimer test + Align reator-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../src/federated/transient/ConnectedTransient.lf | 14 +++++++------- test/C/src/federated/transient/PingPong_Cycle.lf | 4 ++-- test/C/src/federated/transient/TransientTimer.lf | 15 ++++++++------- test/C/src/federated/transient/Transients.lf | 10 +++++----- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index c0f9d723b3..b8c5869756 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit c0f9d723b35906578e65e340b1464ad443fafa4e +Subproject commit b8c586975659d94c39f6b72a5c69417dbc793161 diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf index c56a4b023d..ad052a72b8 100644 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ b/test/C/src/federated/transient/ConnectedTransient.lf @@ -10,7 +10,7 @@ reactor Up(period: time = 2 s) { reaction(t) -> out {= lf_set(out, self->count); - lf_print("Count is = %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Count is = %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); self->count++; =} } @@ -25,14 +25,14 @@ reactor Middle { self->count += in1->value; lf_set(out, self->count); // lf_print("IN1 :: Sending %d at ", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - lf_print("IN1 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN1 (New version):: Sending %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) -> out {= self->count += in2->value; lf_set(out, self->count); - // lf_print("IN2 :: Sending %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - lf_print("IN2 (New version):: Sending %d at (%lld, %ld)", self->count, lf_time_logical_elapsed(), lf_tag().microstep); + // lf_print("IN2 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("IN2 (New version):: Sending %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); =} } @@ -42,15 +42,15 @@ reactor Down { input in2: int reaction(t) {= - lf_print("Timer :: at "PRINTF_TAG, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Timer :: at " PRINTF_TAG, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in1) {= - lf_print("Received %d at "PRINTF_TAG, in1->value, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Received %d at " PRINTF_TAG, in1->value, lf_time_logical_elapsed(), lf_tag().microstep); =} reaction(in2) {= - lf_print("Received %d at "PRINTF_TAG, in2->value, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Received %d at " PRINTF_TAG, in2->value, lf_time_logical_elapsed(), lf_tag().microstep); =} } diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf index 141a16d668..06e00e9dd8 100644 --- a/test/C/src/federated/transient/PingPong_Cycle.lf +++ b/test/C/src/federated/transient/PingPong_Cycle.lf @@ -14,7 +14,7 @@ reactor Ping { reaction(in) {= self->received = true; - lf_print("Ping Received %d at "PRINTF_TIME".", in->value, lf_time_logical_elapsed()); + lf_print("Ping Received %d at " PRINTF_TIME ".", in->value, lf_time_logical_elapsed()); =} reaction(shutdown) {= @@ -32,7 +32,7 @@ reactor Pong { reaction(in) -> out {= self->received = true; - lf_print("Pong Received %d at "PRINTF_TIME".", in-> value, lf_time_logical_elapsed()); + lf_print("Pong Received %d at " PRINTF_TIME ".", in-> value, lf_time_logical_elapsed()); lf_set(out, in->value); =} diff --git a/test/C/src/federated/transient/TransientTimer.lf b/test/C/src/federated/transient/TransientTimer.lf index 005fc32a91..ba4a8b8ee0 100644 --- a/test/C/src/federated/transient/TransientTimer.lf +++ b/test/C/src/federated/transient/TransientTimer.lf @@ -3,7 +3,7 @@ * federation (instead of the effective_start_time of the transient) */ target C { - timeout: 2 s, + timeout: 3 s, tracing: true } @@ -15,7 +15,7 @@ preamble {= /** Persistent federate that is responsible for lauching the transient at logical time 1 s */ reactor TransientExec { reaction(startup) {= - lf_sleep(1000000000); + lf_sleep(1200000000); // Construct the command to launch the transient federate char mid_launch_cmd[512]; @@ -47,7 +47,7 @@ reactor Up { reaction(t) -> out {= lf_set(out, self->count); - lf_print("Count is = %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); self->count++; =} } @@ -61,15 +61,16 @@ reactor Up { reactor Middle { input in: int state count: int = 0 + state first_join: bool timer t(0, 300 msec) reaction(startup) {= - int first_join = (lf_get_effective_start_time() == lf_get_start_time()); + self->first_join = (lf_get_effective_start_time() == lf_get_start_time()); - if (first_join == 1) { + if (first_join) { lf_print("Mid is joining during the startup phase."); } else { - lf_print("Mid is joining after the startup phase and the offset is: "PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); + lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); } =} @@ -84,7 +85,7 @@ reactor Middle { // If this is the first execution of Middle, then it will spontaneously stop after two reactions if ( (self->count == 200) && - (lf_get_effective_start_time() == lf_get_start_time()) + (self->first_join) ) { lf_stop(); } diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 6698363f84..e824b2f990 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -48,7 +48,7 @@ reactor Up { reaction(t) -> out {= lf_set(out, self->count); - lf_print("Count is = %d at "PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); self->count++; =} } @@ -75,14 +75,14 @@ reactor Middle { if (first_join == 1) { lf_print("Mid is joining during the startup phase."); } else { - lf_print("Mid is joining after the startup phase and the offset is: "PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); + lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); } lf_set(out_joined, lf_get_effective_start_time() - lf_get_start_time()); =} reaction(t) {= - lf_print("Mid reacting to t at federation elapsed logical time "PRINTF_TIME" and local elapsed logical time "PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); + lf_print("Mid reacting to t at federation elapsed logical time " PRINTF_TIME " and local elapsed logical time " PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); =} reaction(in) -> out {= @@ -117,12 +117,12 @@ reactor Down { reaction(t) {= self->count += 1000; - lf_print("Count of Down is: %d at "PRINTF_TIME, self->count, lf_time_logical_elapsed()/1000000); + lf_print("Count of Down is: %d at " PRINTF_TIME, self->count, lf_time_logical_elapsed()/1000000); =} reaction(in) {= self->received = in->value; - lf_print("Received of Down is: %d at "PRINTF_TIME, self->received, lf_time_logical_elapsed()/1000000); + lf_print("Received of Down is: %d at " PRINTF_TIME, self->received, lf_time_logical_elapsed()/1000000); =} reaction(in_joined) {= From e170ce7ac38b7983f6d1707250e0d5b7655695a1 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 15 Aug 2023 14:16:13 -0700 Subject: [PATCH 128/142] Fix error in TransientTimer test. --- test/C/src/federated/transient/TransientTimer.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/TransientTimer.lf b/test/C/src/federated/transient/TransientTimer.lf index ba4a8b8ee0..a98e6456d4 100644 --- a/test/C/src/federated/transient/TransientTimer.lf +++ b/test/C/src/federated/transient/TransientTimer.lf @@ -67,7 +67,7 @@ reactor Middle { reaction(startup) {= self->first_join = (lf_get_effective_start_time() == lf_get_start_time()); - if (first_join) { + if (self->first_join) { lf_print("Mid is joining during the startup phase."); } else { lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); From b16bfe7d8201db95dccaa73dc4e22c65fbc9c97f Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 17 Aug 2023 12:45:10 -0700 Subject: [PATCH 129/142] Update transient tests to use a logical action, instead of lf_sleep() --- .../src/federated/transient/TransientTimer.lf | 12 +++++---- test/C/src/federated/transient/Transients.lf | 25 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/test/C/src/federated/transient/TransientTimer.lf b/test/C/src/federated/transient/TransientTimer.lf index a98e6456d4..c10bcdf7c5 100644 --- a/test/C/src/federated/transient/TransientTimer.lf +++ b/test/C/src/federated/transient/TransientTimer.lf @@ -3,8 +3,7 @@ * federation (instead of the effective_start_time of the transient) */ target C { - timeout: 3 s, - tracing: true + timeout: 3 s } preamble {= @@ -14,9 +13,11 @@ preamble {= /** Persistent federate that is responsible for lauching the transient at logical time 1 s */ reactor TransientExec { - reaction(startup) {= - lf_sleep(1200000000); + logical action a + + reaction(startup) -> a {= lf_schedule(a, MSEC(1200)); =} + reaction(a) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; sprintf(mid_launch_cmd, @@ -70,7 +71,8 @@ reactor Middle { if (self->first_join) { lf_print("Mid is joining during the startup phase."); } else { - lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); + lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", + lf_get_effective_start_time() - lf_get_start_time()); } =} diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index e824b2f990..85d85246dc 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -1,11 +1,10 @@ /** - * This tests if a transient corretly leaves then joins the federation. It also tests if the - * transient's downstream executes as expected that is it received correct TAG, regardless if the - * transient being absent or present. + * This lf program tests if a transient federate corretly leaves then joins the federation. It + * also tests if the transient's downstream executes as expected, that is it received correct + * TAGs, regardless of the transient being absent or present. */ target C { - timeout: 2 s, - tracing: true + timeout: 2 s } preamble {= @@ -15,9 +14,13 @@ preamble {= /** Persistent federate that is responsible for lauching the transient at logical time 1 s */ reactor TransientExec { - reaction(startup) {= - lf_sleep(1000000000); + logical action a + reaction(startup) -> a {= + lf_schedule(a, SEC(1)); + =} + + reaction(a) {= // Construct the command to launch the transient federate char mid_launch_cmd[512]; sprintf(mid_launch_cmd, @@ -75,14 +78,18 @@ reactor Middle { if (first_join == 1) { lf_print("Mid is joining during the startup phase."); } else { - lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", lf_get_effective_start_time() - lf_get_start_time()); + lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", + lf_get_effective_start_time() - lf_get_start_time()); } lf_set(out_joined, lf_get_effective_start_time() - lf_get_start_time()); =} reaction(t) {= - lf_print("Mid reacting to t at federation elapsed logical time " PRINTF_TIME " and local elapsed logical time " PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); + lf_print("Mid reacting to t at federation elapsed logical time " PRINTF_TIME " and local \ + elapsed logical time " PRINTF_TIME, + lf_time_logical_elapsed(), + lf_time_logical() - lf_get_effective_start_time()); =} reaction(in) -> out {= From 638c8449baedfe42a76a97c443dc60cbfa62ecff Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 17 Aug 2023 13:02:14 -0700 Subject: [PATCH 130/142] Apply formatter --- test/C/src/federated/transient/Transients.lf | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf index 85d85246dc..d6f04114e1 100644 --- a/test/C/src/federated/transient/Transients.lf +++ b/test/C/src/federated/transient/Transients.lf @@ -1,7 +1,7 @@ /** - * This lf program tests if a transient federate corretly leaves then joins the federation. It - * also tests if the transient's downstream executes as expected, that is it received correct - * TAGs, regardless of the transient being absent or present. + * This lf program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. */ target C { timeout: 2 s @@ -16,9 +16,7 @@ preamble {= reactor TransientExec { logical action a - reaction(startup) -> a {= - lf_schedule(a, SEC(1)); - =} + reaction(startup) -> a {= lf_schedule(a, SEC(1)); =} reaction(a) {= // Construct the command to launch the transient federate @@ -87,7 +85,7 @@ reactor Middle { reaction(t) {= lf_print("Mid reacting to t at federation elapsed logical time " PRINTF_TIME " and local \ - elapsed logical time " PRINTF_TIME, + elapsed logical time " PRINTF_TIME, lf_time_logical_elapsed(), lf_time_logical() - lf_get_effective_start_time()); =} From a1cbcb8c0237fc5cc2af95a50c170b1bbcf0e524 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 17 Aug 2023 17:15:37 -0700 Subject: [PATCH 131/142] Add msg type stop to fedsd utility --- util/tracing/visualization/fedsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index 44844cadae..e5fa830cca 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -54,7 +54,7 @@ # Events matching at the sender and receiver ends depend on whether they are tagged # (the elapsed logical time and microstep have to be the same) or not. # Set of tagged events (messages) -non_tagged_messages = {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG'} +non_tagged_messages = {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG', 'STOP'} def load_and_process_csv_file(csv_file) : ''' From 040ef72d110e89c25f9ad3927c83f90e9667cac1 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 17 Aug 2023 17:16:02 -0700 Subject: [PATCH 132/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index b8c5869756..1c579bb398 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit b8c586975659d94c39f6b72a5c69417dbc793161 +Subproject commit 1c579bb3983295c03f53d7ae979179392971a425 From 46341e168e23c53d439832f2e41bc3bcab980f65 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Wed, 23 Aug 2023 15:03:09 -0700 Subject: [PATCH 133/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 1909f95886..3ddc540f40 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 1909f958861478f8f99e088b805887332deac2e5 +Subproject commit 3ddc540f40fdbdeae3ffd9292c8a566d4f2bae4e From e567159e25a7be6b5be7e34df1d36e560a9c14f8 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 14 Sep 2023 08:40:21 -0700 Subject: [PATCH 134/142] Stab into more meaningful tests for transients --- .../src/federated/transient/BankTransients.lf | 43 ----- test/C/src/federated/transient/FastAndSlow.lf | 28 ---- .../src/federated/transient/PingPong_Cycle.lf | 54 ------- test/C/src/federated/transient/Timers.lf | 22 --- .../TransientDownstream1WithTimer.lf | 150 ++++++++++++++++++ .../TransientDownstream2UpWithTimer.lf | 117 ++++++++++++++ .../federated/transient/TransientHotSwap.lf | 131 +++++++++++++++ .../transient/TransientJoin3Times.lf | 105 ++++++++++++ .../transient/TransientTimerAlignement.lf | 104 ++++++++++++ .../transient/TransientWithPersistentState.lf | 0 10 files changed, 607 insertions(+), 147 deletions(-) delete mode 100644 test/C/src/federated/transient/BankTransients.lf delete mode 100644 test/C/src/federated/transient/FastAndSlow.lf delete mode 100644 test/C/src/federated/transient/PingPong_Cycle.lf delete mode 100644 test/C/src/federated/transient/Timers.lf create mode 100644 test/C/src/federated/transient/TransientDownstream1WithTimer.lf create mode 100644 test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf create mode 100644 test/C/src/federated/transient/TransientHotSwap.lf create mode 100644 test/C/src/federated/transient/TransientJoin3Times.lf create mode 100644 test/C/src/federated/transient/TransientTimerAlignement.lf create mode 100644 test/C/src/federated/transient/TransientWithPersistentState.lf diff --git a/test/C/src/federated/transient/BankTransients.lf b/test/C/src/federated/transient/BankTransients.lf deleted file mode 100644 index 54902025b6..0000000000 --- a/test/C/src/federated/transient/BankTransients.lf +++ /dev/null @@ -1,43 +0,0 @@ -/** This program tests bank of transients */ -target C { - timeout: 2 s -} - -reactor Count { - output out: int - state count: int = 0 - timer t(0, 500 msec) - - reaction(t) -> out {= - lf_print("Sending count: %d", self->count); - lf_set(out, self->count); - self->count++; - =} -} - -reactor Pass { - input in: int - output out: int - state count: int = 0 - - reaction(in) -> out {= - self->count = in-> value; - lf_set(out, self->count); - =} -} - -reactor Print { - input in: int - - reaction(in) {= lf_print("Received %d.", in->value); =} -} - -federated reactor { - count = new[2] Count() - print = new[2] Print() - @transient - pass = new[2] Pass() - - count.out -> pass.in - pass.out -> print.in -} diff --git a/test/C/src/federated/transient/FastAndSlow.lf b/test/C/src/federated/transient/FastAndSlow.lf deleted file mode 100644 index 00c42db5fe..0000000000 --- a/test/C/src/federated/transient/FastAndSlow.lf +++ /dev/null @@ -1,28 +0,0 @@ -// This example is derived from the C++ enclave test case, which says "This is a basic test for -// enclaved execution. The deadlines should never be violated for the test to pass.". Here, we -// transform it into a federated one, where the `fast` federate is transient. -target C { - timeout: 1 sec -} - -reactor Slow { - timer t(0, 500 msec) - - reaction(t) {= - lf_print("Slow reaction starts"); - // lf_sleep(700000000); - lf_print("Slow reaction ends"); - =} -} - -reactor Fast { - timer t(0 msec, 100 msec) - - reaction(t) {= lf_print("Fast reaction executes"); =} -} - -federated reactor { - slow = new Slow() - @transient - fast = new Fast() -} diff --git a/test/C/src/federated/transient/PingPong_Cycle.lf b/test/C/src/federated/transient/PingPong_Cycle.lf deleted file mode 100644 index 06e00e9dd8..0000000000 --- a/test/C/src/federated/transient/PingPong_Cycle.lf +++ /dev/null @@ -1,54 +0,0 @@ -target C { - timeout: 2 s, - tracing: true -} - -reactor Ping { - timer t(0, 500 msec) - input in: int - output out: int - state counter: int = 0 - state received: bool = false - - reaction(t) -> out {= lf_set(out, self->counter++); =} - - reaction(in) {= - self->received = true; - lf_print("Ping Received %d at " PRINTF_TIME ".", in->value, lf_time_logical_elapsed()); - =} - - reaction(shutdown) {= - if(!self->received) { - lf_print("Nothing received."); - exit(1); - } - =} -} - -reactor Pong { - input in: int - output out: int - state received: bool = false - - reaction(in) -> out {= - self->received = true; - lf_print("Pong Received %d at " PRINTF_TIME ".", in-> value, lf_time_logical_elapsed()); - lf_set(out, in->value); - =} - - reaction(shutdown) {= - if(!self->received) { - lf_print("Nothing received."); - exit(1); - } - =} -} - -federated reactor { - ping = new Ping() - @transient - pong = new Pong() - - ping.out -> pong.in - pong.out -> ping.in after 100 ms -} diff --git a/test/C/src/federated/transient/Timers.lf b/test/C/src/federated/transient/Timers.lf deleted file mode 100644 index 43faaac4d7..0000000000 --- a/test/C/src/federated/transient/Timers.lf +++ /dev/null @@ -1,22 +0,0 @@ -target C { - timeout: 2 s -} - -reactor Timer(period: time = 2 s) { - output out: int - timer t(0, period) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d", self->count); - self->count++; - =} -} - -federated reactor { - t0 = new Timer() - t1 = new Timer() - @transient - t2 = new Timer(period = 1 s) -} diff --git a/test/C/src/federated/transient/TransientDownstream1WithTimer.lf b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf new file mode 100644 index 0000000000..aa1aab6810 --- /dev/null +++ b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf @@ -0,0 +1,150 @@ +/** + * This lf program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. In this test: + * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, + * - the downstream of the transient federate has only a transient as upstream. + */ +target C { + timeout: 2 s +} + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, upstream of the transient. It reacts to its timer by sending increments in + * out output port. + */ +reactor Up(period: time = 500 ms) { + output out: int + timer t(0, period) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + self->count++; + =} +} + +/** + * Transient federate that forwards whatever it receives from Up to down. It reacts twice to in + * input ports, then stops. It will execute twice during the lifetime of the federation. The second + * launch is done by TransientExec at logical time 1 s. Each time Middle joins, it notifies Down. + */ +reactor Middle { + input in: int + output out: int + output join: int + state count: int = 0 + + // Middle notifies its downstream that he joined, but make sure first that the effective start + // tag is correct + reaction(startup) -> join {= + if(lf_get_effective_start_time() < lf_get_start_time()) { + lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); + } + + lf_set(join, 0); + =} + + // Pass the input value to the output port and stop spontaneously after two reactions to in + reaction(in) -> out {= + self->count++; + lf_set(out, in->value); + + if (self->count == 2) { + lf_stop(); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + + reaction(t) {= self->count_timer++; =} + + reaction(in) {= self->count_in_mid_reactions++; =} + + reaction(join) {= self->count_join++; =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + + // Check that Middle have joined 2 times + if (self->count_join != 2) { + lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); + } + + // Check that Middle have reacted correctly + if (self->count_in_mid_reactions < 4) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", + self->count_in_mid_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up = new Up() + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up.out -> mid.in + mid.join -> down.join + mid.out -> down.in +} diff --git a/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf b/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf new file mode 100644 index 0000000000..e733152f96 --- /dev/null +++ b/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf @@ -0,0 +1,117 @@ +/** + * This lf program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. In this test: + * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, + * - the downstream of the transient federate has both, persistent and transient upstreams. + */ +target C { + timeout: 2 s +} + +import Up from "TransientDownstream1WithTimer.lf" +import Middle from "TransientDownstream1WithTimer.lf" + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in_mid: int + input in_up: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_mid_reactions: int = 0 + state count_in_up_reactions: int = 0 + + reaction(t) {= self->count_timer++; =} + + reaction(in_mid) {= self->count_in_mid_reactions++; =} + + reaction(in_up) {= self->count_in_up_reactions++; =} + + reaction(join) {= self->count_join++; =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + if (self->count_in_up_reactions != 7) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_in_up_reactions, + 7); + } + + // Check that Middle have joined 2 times + if (self->count_join != 2) { + lf_print_error_and_exit("Transient federate did not join twice, but %d times!", self->count_join); + } + + // Check that Middle have reacted correctly + if (self->count_in_mid_reactions < 4) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 4, but had: %d.", + self->count_in_mid_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1 s, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up1 = new Up() + up2 = new Up(period = 300 msec) + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up1.out -> mid.in + mid.join -> down.join + mid.out -> down.in_mid + up2.out -> down.in_up +} diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf new file mode 100644 index 0000000000..f3a2bd6646 --- /dev/null +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -0,0 +1,131 @@ +/** + * This lf program tests the hot swap mechnism of a transient federate. In this test: + * - the transient federate is stopped by the RTI whenever a hot swap request is initiated. + * - the downstream of the transient federate has both, persistent and transient upstreams. + */ +target C { + timeout: 3 sec +} + +import Up from "TransientDownstream1WithTimer.lf" + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Transient federate that forwards whatever it receives from Up to down. It reacts twice to in + * input ports, then stops. It will execute twice during the lifetime of the federation. The second + * launch is done by TransientExec at logical time 1 s. Each time Middle joins, it notifies Down. + */ +reactor Middle { + input in: int + output out: int + output join: int + state count: int = 0 + + // Middle notifies its downstream that he joined, but make sure first that the effective start + // tag is correct + reaction(startup) -> join {= + if(lf_get_effective_start_time() < lf_get_start_time()) { + lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); + } + + lf_set(join, 0); + =} + + // Pass the input value to the output and stop spontaneously stops after two reactions to in + reaction(in) -> out {= + self->count++; + lf_print("Middle is counting: %d", self->count); + lf_set(out, self->count); + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + + reaction(t) {= self->count_timer++; =} + + reaction(in) {= + // Check that Middle is reacting correctly + if (in->value >= 4) { + lf_print_error_and_exit("Transient federate Mid execeeded the number of possible reactions. Received %d, while the value should not exceed 3.", + in->value); + } + =} + + reaction(join) {= self->count_join++; =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count_timer != 6) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 6); + } + + // Check that Middle have joined 2 times + if (self->count_join != 3) { + lf_print_error_and_exit("Transient federate did not join 3 times, but %d times!", self->count_join); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 1100 msec, period = 1 sec, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up = new Up(period = 400 msec) + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up.out -> mid.in + mid.join -> down.join + mid.out -> down.in +} diff --git a/test/C/src/federated/transient/TransientJoin3Times.lf b/test/C/src/federated/transient/TransientJoin3Times.lf new file mode 100644 index 0000000000..b24d0abe56 --- /dev/null +++ b/test/C/src/federated/transient/TransientJoin3Times.lf @@ -0,0 +1,105 @@ +/** + * This lf program tests if a transient federate corretly leaves then joins the federation. It also + * tests if the transient's downstream executes as expected, that is it received correct TAGs, + * regardless of the transient being absent or present. In this test, the downstream of the the + * transient federate has only a transient as upstream federate. + */ +target C { + timeout: 2 s +} + +import Up from "TransientDownstream1WithTimer.lf" +import Middle from "TransientDownstream1WithTimer.lf" + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient federate */ +reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { + timer t(offset, period) + + reaction(t) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__%s -i %s", + lf_get_federates_bin_directory(), + self->fed_instance_name, + lf_get_federation_id() + ); + + lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", + mid_launch_cmd, + lf_time_physical()); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__%s.", self->fed_instance_name); + } else { + lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); + } + =} +} + +/** + * Persistent federate, which is downstream of the transient. It has to keep reacting to its + * internal timer and also to inputs from the tansient, if any. + */ +reactor Down { + timer t(0, 500 ms) + + input in: int + input join: int + + state count_timer: int = 0 + state count_join: int = 0 + state count_in_reactions: int = 0 + + reaction(t) {= self->count_timer++; =} + + reaction(in) {= self->count_in_reactions++; =} + + reaction(join) {= self->count_join++; =} + + reaction(shutdown) {= + // Check that the TAG have been successfully issued to Down + if (self->count_timer != 5) { + lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", + self->count_timer, + 5); + } + + // Check that Middle have joined 2 times + if (self->count_join != 3) { + lf_print_error_and_exit("Transient federate did not join 3 times, but %d times!", self->count_join); + } + + // Check that Middle have reacted correctly + if (self->count_in_reactions < 6) { + lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 6, but had: %d.", + self->count_in_reactions); + } + =} +} + +federated reactor { + // Persistent federate that is responsible for lauching the transient once, after 1s + midExec = new TransientExec(offset = 700 msec, period = 700ms, fed_instance_name="mid") + + // Persistent downstream and upstream federates of the transient + up = new Up(period = 200 msec) + down = new Down() + + // Transient federate + @transient + mid = new Middle() + + // Connections + up.out -> mid.in + mid.join -> down.join + mid.out -> down.in +} diff --git a/test/C/src/federated/transient/TransientTimerAlignement.lf b/test/C/src/federated/transient/TransientTimerAlignement.lf new file mode 100644 index 0000000000..c10bcdf7c5 --- /dev/null +++ b/test/C/src/federated/transient/TransientTimerAlignement.lf @@ -0,0 +1,104 @@ +/** + * This tests if a timer in a transient federate triggers with regard to the start_time of the + * federation (instead of the effective_start_time of the transient) + */ +target C { + timeout: 3 s +} + +preamble {= + #include + #include +=} + +/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ +reactor TransientExec { + logical action a + + reaction(startup) -> a {= lf_schedule(a, MSEC(1200)); =} + + reaction(a) {= + // Construct the command to launch the transient federate + char mid_launch_cmd[512]; + sprintf(mid_launch_cmd, + "%s/federate__mid -i %s", + lf_get_federates_bin_directory(), + lf_get_federation_id() + ); + + int status = system(mid_launch_cmd); + + // Exit if error + if (status == 0) { + lf_print("Successfully launched federate__mid."); + } else { + lf_print_error_and_exit("Unable to launch federate__mid."); + } + =} +} + +/** + * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, + * 1000, 1500 and 2000. + */ +reactor Up { + output out: int + timer t(0, 500 msec) + state count: int = 0 + + reaction(t) -> out {= + lf_set(out, self->count); + lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); + self->count++; + =} +} + +/** + * Transient federate with a timer. It will execute twice during the lifetime of the federation. In + * the first execution, it will spontaneously stop after the second reaction to in. Then, it will be + * launched again by TransientExec at logical time 1 s, to resign at the stop_tag of the federation. + * At each reaction to the timer, we check that the tag is computed based on the start_time. + */ +reactor Middle { + input in: int + state count: int = 0 + state first_join: bool + timer t(0, 300 msec) + + reaction(startup) {= + self->first_join = (lf_get_effective_start_time() == lf_get_start_time()); + + if (self->first_join) { + lf_print("Mid is joining during the startup phase."); + } else { + lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", + lf_get_effective_start_time() - lf_get_start_time()); + } + =} + + reaction(t) {= + if (lf_time_logical_elapsed() % 300000000 != 0) { + lf_print_error_and_exit("Timer executing at a wrong tag."); + } + =} + + reaction(in) {= + self->count += 100; + // If this is the first execution of Middle, then it will spontaneously stop after two reactions + if ( + (self->count == 200) && + (self->first_join) + ) { + lf_stop(); + } + =} +} + +federated reactor { + up = new Up() + @transient + mid = new Middle() + midExec = new TransientExec() + + up.out -> mid.in // Connections +} diff --git a/test/C/src/federated/transient/TransientWithPersistentState.lf b/test/C/src/federated/transient/TransientWithPersistentState.lf new file mode 100644 index 0000000000..e69de29bb2 From 73025893f25766c00c602963be3f876c72dc7f7d Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Thu, 14 Sep 2023 08:41:11 -0700 Subject: [PATCH 135/142] Add transient annotation validation --- .../org/lflang/validation/LFValidator.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 446fdffe4a..2936d9bbd1 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -526,22 +526,22 @@ public void checkInstantiation(Instantiation instantiation) { } } - // // If the Instantiation has annotation '@transient', then make sure that the - // // container is a federated reactor, and that the coordination is centralized + // If the Instantiation has annotation '@transient', then make sure that the + // container is a federated reactor, and that the coordination is centralized // FederateInstance - // if (instantiation.isTransient()) { - // Reactor container = (Reactor) instantiation.eContainer(); - // if (!container.isFederated()) { - // error("Only federates can be transients: " + instantiation.getReactorClass().getName(), - // Literals.INSTANTIATION__REACTOR_CLASS); - // } - // if (this.target != Target.C) { - // error("Transient federates are only supported in the C target.", - // Literals.TARGET_DECL__NAME); - // } - // // FIXME: Currently, transients are only supported in centralized coordination - // // Either add the check, or add the support in decentralized coordination. - // } + if (AttributeUtils.isTransient(instantiation)) { + Reactor container = (Reactor) instantiation.eContainer(); + if (!container.isFederated()) { + error("Only federates can be transients: " + instantiation.getReactorClass().getName(), + Literals.INSTANTIATION__REACTOR_CLASS); + } + if (this.target != Target.C) { + error("Transient federates are only supported in the C target.", + Literals.TARGET_DECL__NAME); + } + // FIXME: Currently, transients are only supported in centralized coordination + // Either add the check, or add the support in decentralized coordination. + } } /** Check target parameters, which are key-value pairs. */ From f196c40081e0f07355421eecc103c8b6432c5259 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Mon, 2 Oct 2023 14:19:34 -0700 Subject: [PATCH 136/142] Cleaning transient tests + align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- .../federated/transient/ConnectedTransient.lf | 69 ------- .../transient/ConnectedTransient_2L.lf | 68 ------- .../TransientDownstream1WithTimer.lf | 4 +- .../federated/transient/TransientHotSwap.lf | 131 ------------- .../src/federated/transient/TransientTimer.lf | 104 ----------- .../transient/TransientTimerAlignement.lf | 104 ----------- .../transient/TransientWithPersistentState.lf | 0 test/C/src/federated/transient/Transients.lf | 173 ------------------ 9 files changed, 3 insertions(+), 652 deletions(-) delete mode 100644 test/C/src/federated/transient/ConnectedTransient.lf delete mode 100644 test/C/src/federated/transient/ConnectedTransient_2L.lf delete mode 100644 test/C/src/federated/transient/TransientHotSwap.lf delete mode 100644 test/C/src/federated/transient/TransientTimer.lf delete mode 100644 test/C/src/federated/transient/TransientTimerAlignement.lf delete mode 100644 test/C/src/federated/transient/TransientWithPersistentState.lf delete mode 100644 test/C/src/federated/transient/Transients.lf diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 0b45142241..e69e786ac2 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 0b45142241784b1084ec67f5cd0425c92fc35448 +Subproject commit e69e786ac2c0e40420007c68d070b78edbff47be diff --git a/test/C/src/federated/transient/ConnectedTransient.lf b/test/C/src/federated/transient/ConnectedTransient.lf deleted file mode 100644 index ad052a72b8..0000000000 --- a/test/C/src/federated/transient/ConnectedTransient.lf +++ /dev/null @@ -1,69 +0,0 @@ -target C { - timeout: 4 s, - tracing: true -} - -reactor Up(period: time = 2 s) { - output out: int - timer t(0, period) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} -} - -reactor Middle { - input in1: int - input in2: int - output out: int - state count: int = 0 - - reaction(in1) -> out {= - self->count += in1->value; - lf_set(out, self->count); - // lf_print("IN1 :: Sending %d at ", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - lf_print("IN1 (New version):: Sending %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} - - reaction(in2) -> out {= - self->count += in2->value; - lf_set(out, self->count); - // lf_print("IN2 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - lf_print("IN2 (New version):: Sending %d at (" PRINTF_TAG ")", self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} -} - -reactor Down { - timer t(100 ms, 500 ms) - input in1: int - input in2: int - - reaction(t) {= - lf_print("Timer :: at " PRINTF_TAG, lf_time_logical_elapsed(), lf_tag().microstep); - =} - - reaction(in1) {= - lf_print("Received %d at " PRINTF_TAG, in1->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} - - reaction(in2) {= - lf_print("Received %d at " PRINTF_TAG, in2->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} -} - -federated reactor { - up1 = new Up(period = 2 s) - up2 = new Up(period = 1 s) - up3 = new Up(period = 4 s) - @transient - mid = new Middle() - down = new Down() - - up1.out -> mid.in1 // Connections - up2.out -> mid.in2 - mid.out -> down.in1 - up3.out -> down.in2 -} diff --git a/test/C/src/federated/transient/ConnectedTransient_2L.lf b/test/C/src/federated/transient/ConnectedTransient_2L.lf deleted file mode 100644 index 1dfa9a0176..0000000000 --- a/test/C/src/federated/transient/ConnectedTransient_2L.lf +++ /dev/null @@ -1,68 +0,0 @@ -target C { - timeout: 1 s, - tracing: true -} - -reactor Up(period: time = 500 ms) { - output out: int - timer t(0, period) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} -} - -reactor PassThrough { - input in: int - output out: int - - reaction(in) -> out {= - lf_set(out, in->value); - lf_print("PassThrough :: Passing %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} -} - -reactor Middle { - input in1: int - input in2: int - output out: int - state count: int = 0 - - reaction(in1) -> out {= - self->count += in1->value; - lf_set(out, self->count); - lf_print("IN1 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} - - reaction(in2) -> out {= - self->count += in2->value; - lf_set(out, self->count); - lf_print("IN2 :: Sending %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - =} -} - -reactor Down { - input in: int - - reaction(in) {= - lf_print("Received %d at " PRINTF_TAG, in->value, lf_time_logical_elapsed(), lf_tag().microstep); - =} -} - -federated reactor { - up1 = new Up(period = 200 msec) - up2 = new Up(period = 100 msec) - down = new Down() - @transient - pt = new PassThrough() - @transient - mid = new Middle() - - up1.out -> pt.in // Connections - pt.out -> mid.in1 - up2.out -> mid.in2 - mid.out -> down.in -} diff --git a/test/C/src/federated/transient/TransientDownstream1WithTimer.lf b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf index aa1aab6810..79a0922ba3 100644 --- a/test/C/src/federated/transient/TransientDownstream1WithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf @@ -3,7 +3,7 @@ * tests if the transient's downstream executes as expected, that is it received correct TAGs, * regardless of the transient being absent or present. In this test: * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, - * - the downstream of the transient federate has only a transient as upstream. + * - the downstream of the transient federate has only one transient as upstream. */ target C { timeout: 2 s @@ -44,7 +44,7 @@ reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: cha } /** - * Persistent federate, upstream of the transient. It reacts to its timer by sending increments in + * Persistent federate, upstream of the transient. It reacts to its timer by sending increments to * out output port. */ reactor Up(period: time = 500 ms) { diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf deleted file mode 100644 index f3a2bd6646..0000000000 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ /dev/null @@ -1,131 +0,0 @@ -/** - * This lf program tests the hot swap mechnism of a transient federate. In this test: - * - the transient federate is stopped by the RTI whenever a hot swap request is initiated. - * - the downstream of the transient federate has both, persistent and transient upstreams. - */ -target C { - timeout: 3 sec -} - -import Up from "TransientDownstream1WithTimer.lf" - -preamble {= - #include - #include -=} - -/** Persistent federate that is responsible for lauching the transient federate */ -reactor TransientExec(offset: time = 0, period: time = 0, fed_instance_name: char* = "instance") { - timer t(offset, period) - - reaction(t) {= - // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, - "%s/federate__%s -i %s", - lf_get_federates_bin_directory(), - self->fed_instance_name, - lf_get_federation_id() - ); - - lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", - mid_launch_cmd, - lf_time_physical()); - - int status = system(mid_launch_cmd); - - // Exit if error - if (status == 0) { - lf_print("Successfully launched federate__%s.", self->fed_instance_name); - } else { - lf_print_error_and_exit("Unable to launch federate__%s. Abort!", self->fed_instance_name); - } - =} -} - -/** - * Transient federate that forwards whatever it receives from Up to down. It reacts twice to in - * input ports, then stops. It will execute twice during the lifetime of the federation. The second - * launch is done by TransientExec at logical time 1 s. Each time Middle joins, it notifies Down. - */ -reactor Middle { - input in: int - output out: int - output join: int - state count: int = 0 - - // Middle notifies its downstream that he joined, but make sure first that the effective start - // tag is correct - reaction(startup) -> join {= - if(lf_get_effective_start_time() < lf_get_start_time()) { - lf_print_error_and_exit("Fatal error: the transient's effective start time is less than the federation start time"); - } - - lf_set(join, 0); - =} - - // Pass the input value to the output and stop spontaneously stops after two reactions to in - reaction(in) -> out {= - self->count++; - lf_print("Middle is counting: %d", self->count); - lf_set(out, self->count); - =} -} - -/** - * Persistent federate, which is downstream of the transient. It has to keep reacting to its - * internal timer and also to inputs from the tansient, if any. - */ -reactor Down { - timer t(0, 500 ms) - - input in: int - input join: int - - state count_timer: int = 0 - state count_join: int = 0 - - reaction(t) {= self->count_timer++; =} - - reaction(in) {= - // Check that Middle is reacting correctly - if (in->value >= 4) { - lf_print_error_and_exit("Transient federate Mid execeeded the number of possible reactions. Received %d, while the value should not exceed 3.", - in->value); - } - =} - - reaction(join) {= self->count_join++; =} - - reaction(shutdown) {= - // Check that the TAG have been successfully issued to Down - if (self->count_timer != 6) { - lf_print_error_and_exit("Federate's timer reacted %d times, while it had to react %d times.", - self->count_timer, - 6); - } - - // Check that Middle have joined 2 times - if (self->count_join != 3) { - lf_print_error_and_exit("Transient federate did not join 3 times, but %d times!", self->count_join); - } - =} -} - -federated reactor { - // Persistent federate that is responsible for lauching the transient once, after 1s - midExec = new TransientExec(offset = 1100 msec, period = 1 sec, fed_instance_name="mid") - - // Persistent downstream and upstream federates of the transient - up = new Up(period = 400 msec) - down = new Down() - - // Transient federate - @transient - mid = new Middle() - - // Connections - up.out -> mid.in - mid.join -> down.join - mid.out -> down.in -} diff --git a/test/C/src/federated/transient/TransientTimer.lf b/test/C/src/federated/transient/TransientTimer.lf deleted file mode 100644 index c10bcdf7c5..0000000000 --- a/test/C/src/federated/transient/TransientTimer.lf +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This tests if a timer in a transient federate triggers with regard to the start_time of the - * federation (instead of the effective_start_time of the transient) - */ -target C { - timeout: 3 s -} - -preamble {= - #include - #include -=} - -/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ -reactor TransientExec { - logical action a - - reaction(startup) -> a {= lf_schedule(a, MSEC(1200)); =} - - reaction(a) {= - // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, - "%s/federate__mid -i %s", - lf_get_federates_bin_directory(), - lf_get_federation_id() - ); - - int status = system(mid_launch_cmd); - - // Exit if error - if (status == 0) { - lf_print("Successfully launched federate__mid."); - } else { - lf_print_error_and_exit("Unable to launch federate__mid."); - } - =} -} - -/** - * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, - * 1000, 1500 and 2000. - */ -reactor Up { - output out: int - timer t(0, 500 msec) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} -} - -/** - * Transient federate with a timer. It will execute twice during the lifetime of the federation. In - * the first execution, it will spontaneously stop after the second reaction to in. Then, it will be - * launched again by TransientExec at logical time 1 s, to resign at the stop_tag of the federation. - * At each reaction to the timer, we check that the tag is computed based on the start_time. - */ -reactor Middle { - input in: int - state count: int = 0 - state first_join: bool - timer t(0, 300 msec) - - reaction(startup) {= - self->first_join = (lf_get_effective_start_time() == lf_get_start_time()); - - if (self->first_join) { - lf_print("Mid is joining during the startup phase."); - } else { - lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", - lf_get_effective_start_time() - lf_get_start_time()); - } - =} - - reaction(t) {= - if (lf_time_logical_elapsed() % 300000000 != 0) { - lf_print_error_and_exit("Timer executing at a wrong tag."); - } - =} - - reaction(in) {= - self->count += 100; - // If this is the first execution of Middle, then it will spontaneously stop after two reactions - if ( - (self->count == 200) && - (self->first_join) - ) { - lf_stop(); - } - =} -} - -federated reactor { - up = new Up() - @transient - mid = new Middle() - midExec = new TransientExec() - - up.out -> mid.in // Connections -} diff --git a/test/C/src/federated/transient/TransientTimerAlignement.lf b/test/C/src/federated/transient/TransientTimerAlignement.lf deleted file mode 100644 index c10bcdf7c5..0000000000 --- a/test/C/src/federated/transient/TransientTimerAlignement.lf +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This tests if a timer in a transient federate triggers with regard to the start_time of the - * federation (instead of the effective_start_time of the transient) - */ -target C { - timeout: 3 s -} - -preamble {= - #include - #include -=} - -/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ -reactor TransientExec { - logical action a - - reaction(startup) -> a {= lf_schedule(a, MSEC(1200)); =} - - reaction(a) {= - // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, - "%s/federate__mid -i %s", - lf_get_federates_bin_directory(), - lf_get_federation_id() - ); - - int status = system(mid_launch_cmd); - - // Exit if error - if (status == 0) { - lf_print("Successfully launched federate__mid."); - } else { - lf_print_error_and_exit("Unable to launch federate__mid."); - } - =} -} - -/** - * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, - * 1000, 1500 and 2000. - */ -reactor Up { - output out: int - timer t(0, 500 msec) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} -} - -/** - * Transient federate with a timer. It will execute twice during the lifetime of the federation. In - * the first execution, it will spontaneously stop after the second reaction to in. Then, it will be - * launched again by TransientExec at logical time 1 s, to resign at the stop_tag of the federation. - * At each reaction to the timer, we check that the tag is computed based on the start_time. - */ -reactor Middle { - input in: int - state count: int = 0 - state first_join: bool - timer t(0, 300 msec) - - reaction(startup) {= - self->first_join = (lf_get_effective_start_time() == lf_get_start_time()); - - if (self->first_join) { - lf_print("Mid is joining during the startup phase."); - } else { - lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", - lf_get_effective_start_time() - lf_get_start_time()); - } - =} - - reaction(t) {= - if (lf_time_logical_elapsed() % 300000000 != 0) { - lf_print_error_and_exit("Timer executing at a wrong tag."); - } - =} - - reaction(in) {= - self->count += 100; - // If this is the first execution of Middle, then it will spontaneously stop after two reactions - if ( - (self->count == 200) && - (self->first_join) - ) { - lf_stop(); - } - =} -} - -federated reactor { - up = new Up() - @transient - mid = new Middle() - midExec = new TransientExec() - - up.out -> mid.in // Connections -} diff --git a/test/C/src/federated/transient/TransientWithPersistentState.lf b/test/C/src/federated/transient/TransientWithPersistentState.lf deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/C/src/federated/transient/Transients.lf b/test/C/src/federated/transient/Transients.lf deleted file mode 100644 index d6f04114e1..0000000000 --- a/test/C/src/federated/transient/Transients.lf +++ /dev/null @@ -1,173 +0,0 @@ -/** - * This lf program tests if a transient federate corretly leaves then joins the federation. It also - * tests if the transient's downstream executes as expected, that is it received correct TAGs, - * regardless of the transient being absent or present. - */ -target C { - timeout: 2 s -} - -preamble {= - #include - #include -=} - -/** Persistent federate that is responsible for lauching the transient at logical time 1 s */ -reactor TransientExec { - logical action a - - reaction(startup) -> a {= lf_schedule(a, SEC(1)); =} - - reaction(a) {= - // Construct the command to launch the transient federate - char mid_launch_cmd[512]; - sprintf(mid_launch_cmd, - "%s/federate__mid -i %s", - lf_get_federates_bin_directory(), - lf_get_federation_id() - ); - - int status = system(mid_launch_cmd); - - // Exit if error - if (status == 0) { - lf_print("Successfully launched federate__mid."); - } else { - lf_print_error_and_exit("Unable to launch federate__mid."); - } - =} -} - -/** - * Persistent federate, upstream of the transient. It outputs 0, 1, 2, 3, 4 at logical times 0, 500, - * 1000, 1500 and 2000. - */ -reactor Up { - output out: int - timer t(0, 500 msec) - state count: int = 0 - - reaction(t) -> out {= - lf_set(out, self->count); - lf_print("Count is = %d at " PRINTF_TAG, self->count, lf_time_logical_elapsed(), lf_tag().microstep); - self->count++; - =} -} - -/** - * Transient federate that forwards what it receives from Up, after augmenting it with its own count - * values. It will execute twice during the lifetime of the federation. In the first execution, it - * will spontaneously stop after the second reaction to in. Then, it will be launched again by - * TransientExec at logical time 1 s, to resign at the stop_tag of the federation. Middle notifies - * Down that it joined and and sends its offset w.r.t the start time of the federation. - */ -reactor Middle { - input in: int - output out: int - output out_joined: instant_t - - state count: int = 0 - - timer t(0, 250 msec) - - reaction(startup) -> out_joined {= - int first_join = (lf_get_effective_start_time() == lf_get_start_time()); - - if (first_join == 1) { - lf_print("Mid is joining during the startup phase."); - } else { - lf_print("Mid is joining after the startup phase and the offset is: " PRINTF_TIME" ns.", - lf_get_effective_start_time() - lf_get_start_time()); - } - - lf_set(out_joined, lf_get_effective_start_time() - lf_get_start_time()); - =} - - reaction(t) {= - lf_print("Mid reacting to t at federation elapsed logical time " PRINTF_TIME " and local \ - elapsed logical time " PRINTF_TIME, - lf_time_logical_elapsed(), - lf_time_logical() - lf_get_effective_start_time()); - =} - - reaction(in) -> out {= - self->count += 100; - int to_send = self->count + in->value; - lf_set(out, to_send); - // If this is the first execution of Middle, then it will spontaneously stop after two reactions - if ( - (self->count == 200) && - (lf_get_effective_start_time() == lf_get_start_time()) - ) { - lf_stop(); - } - =} -} - -/** - * Persistent federate, which is downstream of the transient. It has to keep reacting to its - * internal timer and also to inputs from the tansient, if any. - */ -reactor Down { - timer t(0, 500 ms) - - input in: int - input in_joined: instant_t - - state count: int = 0 - state received: int = 0 - state num_joined: int = 0 - state join_offset_1: instant_t = 0 - state join_offset_2: instant_t = 0 - - reaction(t) {= - self->count += 1000; - lf_print("Count of Down is: %d at " PRINTF_TIME, self->count, lf_time_logical_elapsed()/1000000); - =} - - reaction(in) {= - self->received = in->value; - lf_print("Received of Down is: %d at " PRINTF_TIME, self->received, lf_time_logical_elapsed()/1000000); - =} - - reaction(in_joined) {= - self->num_joined++; - if (self->num_joined == 1) { - self->join_offset_1 = in_joined->value; - } else { - self->join_offset_2 = in_joined->value; - } - =} - - reaction(shutdown) {= - // Check that the TAG have been successfully issued to Down - if (self->count != 5000) { - lf_print_error_and_exit("Federate's timer failed to react."); - } - - // Check that Middle have joined 2 times - if (self->num_joined != 2 || self->join_offset_2 <= self->join_offset_1) { - lf_print_error_and_exit("Transient federate Mid did not execute twice!"); - } - - // Check that Middle have reacted correctly - if (self->received < 102) { - lf_print_error_and_exit("Transient federate Mid did not execute and pass values from up corretly! Expected >= 102, but have: %d.", self->received); - } - =} -} - -federated reactor { - up = new Up() - down = new Down() - // Important note: since mid is instantiated before persistent federate midExec, - // it will join at the startup phase, making its effective start time equal to the federation - // start time. Defining mid at the end will break up the test described above. - @transient - mid = new Middle() - midExec = new TransientExec() - - up.out -> mid.in // Connections - mid.out_joined -> down.in_joined - mid.out -> down.in -} From a25f48be18f151a647805b0a1856a6f351772fd7 Mon Sep 17 00:00:00 2001 From: ChadliaJerad Date: Tue, 3 Oct 2023 00:27:18 -0700 Subject: [PATCH 137/142] Apply formatter --- .../org/lflang/validation/LFValidator.java | 9 +++++---- core/src/main/resources/lib/c/reactor-c | 2 +- .../TransientDownstream1WithTimer.lf | 16 ++++++++++----- .../TransientDownstream2UpWithTimer.lf | 20 +++++++++++++------ .../transient/TransientJoin3Times.lf | 14 +++++++++---- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index f4ddf84247..015bff0481 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -542,12 +542,13 @@ public void checkInstantiation(Instantiation instantiation) { if (AttributeUtils.isTransient(instantiation)) { Reactor container = (Reactor) instantiation.eContainer(); if (!container.isFederated()) { - error("Only federates can be transients: " + instantiation.getReactorClass().getName(), - Literals.INSTANTIATION__REACTOR_CLASS); + error( + "Only federates can be transients: " + instantiation.getReactorClass().getName(), + Literals.INSTANTIATION__REACTOR_CLASS); } if (this.target != Target.C) { - error("Transient federates are only supported in the C target.", - Literals.TARGET_DECL__NAME); + error( + "Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); } // FIXME: Currently, transients are only supported in centralized coordination // Either add the check, or add the support in decentralized coordination. diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index e69e786ac2..aa81a551f3 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit e69e786ac2c0e40420007c68d070b78edbff47be +Subproject commit aa81a551f34440e880c4133c4cf0da8d00bc79a6 diff --git a/test/C/src/federated/transient/TransientDownstream1WithTimer.lf b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf index 79a0922ba3..d56bfc3267 100644 --- a/test/C/src/federated/transient/TransientDownstream1WithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstream1WithTimer.lf @@ -2,8 +2,8 @@ * This lf program tests if a transient federate corretly leaves then joins the federation. It also * tests if the transient's downstream executes as expected, that is it received correct TAGs, * regardless of the transient being absent or present. In this test: - * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, - * - the downstream of the transient federate has only one transient as upstream. + * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, + * - the downstream of the transient federate has only one transient as upstream. */ target C { timeout: 2 s @@ -104,11 +104,17 @@ reactor Down { state count_join: int = 0 state count_in_mid_reactions: int = 0 - reaction(t) {= self->count_timer++; =} + reaction(t) {= + self->count_timer++; + =} - reaction(in) {= self->count_in_mid_reactions++; =} + reaction(in) {= + self->count_in_mid_reactions++; + =} - reaction(join) {= self->count_join++; =} + reaction(join) {= + self->count_join++; + =} reaction(shutdown) {= // Check that the TAG have been successfully issued to Down diff --git a/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf b/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf index e733152f96..95a8a258d8 100644 --- a/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstream2UpWithTimer.lf @@ -2,8 +2,8 @@ * This lf program tests if a transient federate corretly leaves then joins the federation. It also * tests if the transient's downstream executes as expected, that is it received correct TAGs, * regardless of the transient being absent or present. In this test: - * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, - * - the downstream of the transient federate has both, persistent and transient upstreams. + * - the transient federate spontaneously leaves the federation after 2 reactions to input port in, + * - the downstream of the transient federate has both, persistent and transient upstreams. */ target C { timeout: 2 s @@ -62,13 +62,21 @@ reactor Down { state count_in_mid_reactions: int = 0 state count_in_up_reactions: int = 0 - reaction(t) {= self->count_timer++; =} + reaction(t) {= + self->count_timer++; + =} - reaction(in_mid) {= self->count_in_mid_reactions++; =} + reaction(in_mid) {= + self->count_in_mid_reactions++; + =} - reaction(in_up) {= self->count_in_up_reactions++; =} + reaction(in_up) {= + self->count_in_up_reactions++; + =} - reaction(join) {= self->count_join++; =} + reaction(join) {= + self->count_join++; + =} reaction(shutdown) {= // Check that the TAG have been successfully issued to Down diff --git a/test/C/src/federated/transient/TransientJoin3Times.lf b/test/C/src/federated/transient/TransientJoin3Times.lf index b24d0abe56..c897f8498b 100644 --- a/test/C/src/federated/transient/TransientJoin3Times.lf +++ b/test/C/src/federated/transient/TransientJoin3Times.lf @@ -59,11 +59,17 @@ reactor Down { state count_join: int = 0 state count_in_reactions: int = 0 - reaction(t) {= self->count_timer++; =} + reaction(t) {= + self->count_timer++; + =} - reaction(in) {= self->count_in_reactions++; =} + reaction(in) {= + self->count_in_reactions++; + =} - reaction(join) {= self->count_join++; =} + reaction(join) {= + self->count_join++; + =} reaction(shutdown) {= // Check that the TAG have been successfully issued to Down @@ -88,7 +94,7 @@ reactor Down { federated reactor { // Persistent federate that is responsible for lauching the transient once, after 1s - midExec = new TransientExec(offset = 700 msec, period = 700ms, fed_instance_name="mid") + midExec = new TransientExec(offset = 700 msec, period = 700 ms, fed_instance_name="mid") // Persistent downstream and upstream federates of the transient up = new Up(period = 200 msec) From 6ab91f3b36995f1ad255d7c1a64abfd067b6b458 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 10 Oct 2023 18:23:04 +0100 Subject: [PATCH 138/142] Check if the error is due to this declaration --- core/src/main/java/org/lflang/validation/LFValidator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 015bff0481..1646d763b8 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -546,10 +546,10 @@ public void checkInstantiation(Instantiation instantiation) { "Only federates can be transients: " + instantiation.getReactorClass().getName(), Literals.INSTANTIATION__REACTOR_CLASS); } - if (this.target != Target.C) { - error( - "Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); - } + // if (this.target != Target.C) { + // error( + // "Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); + // } // FIXME: Currently, transients are only supported in centralized coordination // Either add the check, or add the support in decentralized coordination. } From 50966b025262e9e931ef76b22edf449ce049b54c Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 10 Oct 2023 22:30:16 +0100 Subject: [PATCH 139/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 9d2266252b..21d5e709a8 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9d2266252b6856587301337ddbe69c2a4d21a747 +Subproject commit 21d5e709a86db9b54dc9e4263432e1163662c037 From 000541091ef4f6ca7076b9f1fd4fecc697785d48 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 10 Oct 2023 22:38:46 +0100 Subject: [PATCH 140/142] Apply formatter --- core/src/main/java/org/lflang/validation/LFValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 1646d763b8..2bef0bbb4d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -548,7 +548,8 @@ public void checkInstantiation(Instantiation instantiation) { } // if (this.target != Target.C) { // error( - // "Transient federates are only supported in the C target.", Literals.TARGET_DECL__NAME); + // "Transient federates are only supported in the C target.", + // Literals.TARGET_DECL__NAME); // } // FIXME: Currently, transients are only supported in centralized coordination // Either add the check, or add the support in decentralized coordination. From 44341ef8a0e3c9855990dcfa7df652a627315d64 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 13 Nov 2023 11:10:32 +0100 Subject: [PATCH 141/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index b58e4a5293..d790105a1d 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit b58e4a5293fd3ffe372161b93afdfc821c9fe4f1 +Subproject commit d790105a1d5b595e441e1cc3c72b1d845550b55e From 1cae831454153d5092bc17c7e02d5a403b52a945 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 13 Nov 2023 18:21:47 +0100 Subject: [PATCH 142/142] Align reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index d790105a1d..55158ea984 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit d790105a1d5b595e441e1cc3c72b1d845550b55e +Subproject commit 55158ea984c2b5a69e800242da1557336f97e868