Skip to content

Commit 3c38945

Browse files
authored
Change maxwait exception handler keyword to tardy (#309)
* Make the (0) optional in maxwait(0) * Steps towards cleaning up AttributeUtils and supporting maxwait attribute * Silence ridicously pedantic linter * Spotless * Disable ridiculous linter error * Another pass on cleaning up AttributeUtils * Format * Revert silly lint changes * Leverate Time improvements * Support maxwait attribute on instantiations and connections * Spotless * Fix grammar error * Format * Changed handler keyword to * Formatting * Added a test with two iflate handlers * Better validation for maxwait * Changed iflate to tardy * Spotless
1 parent ea0bd09 commit 3c38945

File tree

14 files changed

+113
-72
lines changed

14 files changed

+113
-72
lines changed

lfc/core/src/main/java/org/lflang/LinguaFranca.xtext

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ Reaction:
178178
('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')
179179
( => sources+=VarRef (',' sources+=VarRef)*)?
180180
('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)?
181-
(code=Code)? (maxWait=MaxWait)? (deadline=Deadline)? (delimited?=';')?
181+
(code=Code)? (tardy=Tardy)? (deadline=Deadline)? (delimited?=';')?
182182
;
183183

184184
TriggerRef:
@@ -196,8 +196,8 @@ Watchdog:
196196
('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)?
197197
code=Code;
198198

199-
MaxWait:
200-
('STP' | 'STAA' | 'maxwait') ('(' value=Expression ')')? (code=Code)?;
199+
Tardy:
200+
present?='tardy' (code=Code)?;
201201

202202
Preamble:
203203
(visibility=Visibility)? 'preamble' code=Code;
@@ -227,7 +227,7 @@ Serializer:
227227

228228
/////////// Attributes
229229
Attribute:
230-
'@' attrName=(ID | 'maxwait') ('(' (attrParms+=AttrParm (',' attrParms+=AttrParm)* ','?)? ')')?
230+
'@' attrName=ID ('(' (attrParms+=AttrParm (',' attrParms+=AttrParm)* ','?)? ')')?
231231
;
232232

233233
AttrParm:
@@ -503,7 +503,7 @@ Token:
503503
'startup' | 'shutdown' | 'after' | 'deadline' | 'mutation' | 'preamble' |
504504
'new' | 'federated' | 'at' | 'as' | 'from' | 'widthof' | 'const' | 'method' |
505505
'interleaved' | 'mode' | 'initial' | 'reset' | 'history' | 'watchdog' |
506-
'extends' | 'forever' | 'never' | 'maxwait' |
506+
'extends' | 'forever' | 'never' | 'tardy' |
507507

508508
// Other terminals
509509
NEGINT | TRUE | FALSE |

lfc/core/src/main/java/org/lflang/ast/IsEqual.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.lflang.lf.KeyValuePair;
3535
import org.lflang.lf.KeyValuePairs;
3636
import org.lflang.lf.Literal;
37-
import org.lflang.lf.MaxWait;
3837
import org.lflang.lf.Method;
3938
import org.lflang.lf.MethodArgument;
4039
import org.lflang.lf.Mode;
@@ -51,6 +50,7 @@
5150
import org.lflang.lf.ReactorDecl;
5251
import org.lflang.lf.Serializer;
5352
import org.lflang.lf.StateVar;
53+
import org.lflang.lf.Tardy;
5454
import org.lflang.lf.TargetDecl;
5555
import org.lflang.lf.Time;
5656
import org.lflang.lf.Timer;
@@ -286,7 +286,7 @@ public Boolean caseReaction(Reaction object) {
286286
.equalAsObjects(Reaction::isMutation)
287287
.equalAsObjects(Reaction::getName)
288288
.equivalent(Reaction::getCode)
289-
.equivalent(Reaction::getMaxWait)
289+
.equivalent(Reaction::getTardy)
290290
.equivalent(Reaction::getDeadline)
291291
.conclusion;
292292
}
@@ -312,11 +312,8 @@ public Boolean caseDeadline(Deadline object) {
312312
}
313313

314314
@Override
315-
public Boolean caseMaxWait(MaxWait object) {
316-
return new ComparisonMachine<>(object, MaxWait.class)
317-
.equivalent(MaxWait::getValue)
318-
.equivalent(MaxWait::getCode)
319-
.conclusion;
315+
public Boolean caseTardy(Tardy object) {
316+
return new ComparisonMachine<>(object, Tardy.class).equivalent(Tardy::getCode).conclusion;
320317
}
321318

322319
@Override

lfc/core/src/main/java/org/lflang/ast/ToLf.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import org.lflang.lf.KeyValuePair;
4949
import org.lflang.lf.KeyValuePairs;
5050
import org.lflang.lf.Literal;
51-
import org.lflang.lf.MaxWait;
5251
import org.lflang.lf.Method;
5352
import org.lflang.lf.MethodArgument;
5453
import org.lflang.lf.Mode;
@@ -65,6 +64,7 @@
6564
import org.lflang.lf.ReactorDecl;
6665
import org.lflang.lf.Serializer;
6766
import org.lflang.lf.StateVar;
67+
import org.lflang.lf.Tardy;
6868
import org.lflang.lf.TargetDecl;
6969
import org.lflang.lf.Time;
7070
import org.lflang.lf.Timer;
@@ -315,7 +315,12 @@ public MalleableString caseAttrParm(AttrParm object) {
315315
// (name=ID '=')? value=AttrParmValue;
316316
var builder = new Builder();
317317
if (object.getName() != null) builder.append(object.getName()).append(" = ");
318-
return builder.append(object.getValue()).get();
318+
var value = object.getValue();
319+
if (value == null) {
320+
// The value is a Time.
321+
return caseTime(object.getTime());
322+
}
323+
return builder.append(value).get();
319324
}
320325

321326
@Override
@@ -652,7 +657,7 @@ public MalleableString caseReaction(Reaction object) {
652657
// ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')
653658
// (sources+=VarRef (',' sources+=VarRef)*)?
654659
// ('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)?
655-
// ((('named' name=ID)? code=Code) | 'named' name=ID)(maxwait=MaxWait)?(deadline=Deadline)?
660+
// ((('named' name=ID)? code=Code) | 'named' name=ID)(tardy=Tardy)?(deadline=Deadline)?
656661
Builder msb = new Builder();
657662
addAttributes(msb, object::getAttributes);
658663
if (object.isMutation()) {
@@ -683,7 +688,7 @@ public MalleableString caseReaction(Reaction object) {
683688
.collect(new Joiner(", ")));
684689
}
685690
if (object.getCode() != null) msb.append(" ").append(doSwitch(object.getCode()));
686-
if (object.getMaxWait() != null) msb.append(" ").append(doSwitch(object.getMaxWait()));
691+
if (object.getTardy() != null) msb.append(" ").append(doSwitch(object.getTardy()));
687692
if (object.getDeadline() != null) msb.append(" ").append(doSwitch(object.getDeadline()));
688693
return msb.get();
689694
}
@@ -743,9 +748,13 @@ public MalleableString caseWatchdog(Watchdog object) {
743748
}
744749

745750
@Override
746-
public MalleableString caseMaxWait(MaxWait object) {
747-
// 'maxwait' '(' value=Expression ')' code=Code
748-
return handler(object, "STAA", MaxWait::getValue, MaxWait::getCode);
751+
public MalleableString caseTardy(Tardy object) {
752+
// 'tardy' (code=Code)?
753+
if (object.getCode() != null) {
754+
return new Builder().append("tardy ").append(doSwitch(object.getCode())).get();
755+
} else {
756+
return new Builder().append("tardy").get();
757+
}
749758
}
750759

751760
private <T extends EObject> MalleableString handler(
@@ -788,6 +797,7 @@ public MalleableString caseInstantiation(Instantiation object) {
788797

789798
@Override
790799
public MalleableString caseConnection(Connection object) {
800+
// (attributes+=Attribute)*
791801
// ((leftPorts += VarRef (',' leftPorts += VarRef)*)
792802
// | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?))
793803
// ('->' | physical?='~>')
@@ -796,6 +806,7 @@ public MalleableString caseConnection(Connection object) {
796806
// (serializer=Serializer)?
797807
// ';'?
798808
Builder msb = new Builder();
809+
addAttributes(msb, object::getAttributes);
799810
Builder left = new Builder();
800811
Builder right = new Builder();
801812
if (object.isIterated()) {

lfc/core/src/main/java/org/lflang/ast/ToSExpr.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import org.lflang.lf.KeyValuePair;
4646
import org.lflang.lf.KeyValuePairs;
4747
import org.lflang.lf.Literal;
48-
import org.lflang.lf.MaxWait;
4948
import org.lflang.lf.Method;
5049
import org.lflang.lf.MethodArgument;
5150
import org.lflang.lf.Mode;
@@ -61,6 +60,7 @@
6160
import org.lflang.lf.ReactorDecl;
6261
import org.lflang.lf.Serializer;
6362
import org.lflang.lf.StateVar;
63+
import org.lflang.lf.Tardy;
6464
import org.lflang.lf.TargetDecl;
6565
import org.lflang.lf.Time;
6666
import org.lflang.lf.Timer;
@@ -474,7 +474,7 @@ public SExpr caseReaction(Reaction object) {
474474
// ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')
475475
// ( => sources+=VarRef (',' sources+=VarRef)*)?
476476
// ('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)?
477-
// (code=Code)? (maxwait=MaxWait)? (deadline=Deadline)? (delimited?=';')?
477+
// (code=Code)? (tardy=Tardy)? (deadline=Deadline)? (delimited?=';')?
478478
// ;
479479
return sList(
480480
"reaction",
@@ -485,7 +485,7 @@ public SExpr caseReaction(Reaction object) {
485485
sList("sources", object.getSources()),
486486
sList("effects", object.getEffects()),
487487
object.getCode(),
488-
object.getMaxWait(),
488+
object.getTardy(),
489489
object.getDeadline(),
490490
sList("is-delimited", object.isDelimited()));
491491
}
@@ -530,10 +530,10 @@ public SExpr caseWatchdog(Watchdog object) {
530530
}
531531

532532
@Override
533-
public SExpr caseMaxWait(MaxWait object) {
534-
// maxwait:
535-
// 'maxwait' ()'(' value=Expression ')')? code=Code;
536-
return sList("maxwait", object.getValue(), object.getCode());
533+
public SExpr caseTardy(Tardy object) {
534+
// tardy:
535+
// 'tardy' (code=Code)?;
536+
return sList("tardy", object.getCode());
537537
}
538538

539539
@Override

lfc/core/src/main/java/org/lflang/validation/AttributeSpec.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,10 @@ public void check(LFValidator validator, AttrParm parm) {
189189
}
190190
}
191191
case TIME -> {
192-
if (!ASTUtils.isBigInteger(parm.getValue())
193-
&& !parm.getValue().equals("forever")
194-
&& !parm.getValue().equals("never")) {
192+
// TIME attributes use parm.getTime(), not parm.getValue(), unless the value is "0"
193+
if (parm.getTime() == null && !parm.getValue().equals("0")) {
195194
validator.error(
196-
"Incorrect type: \""
197-
+ parm.getName()
198-
+ "\""
199-
+ " should be an integer, 'forever', or 'never'.",
195+
"Incorrect time specification: \"" + parm.getName() + "\"",
200196
Literals.ATTRIBUTE__ATTR_NAME);
201197
}
202198
}

lfc/core/src/main/java/org/lflang/validation/LFValidator.java

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.lflang.lf.BuiltinTrigger;
6565
import org.lflang.lf.BuiltinTriggerRef;
6666
import org.lflang.lf.CodeExpr;
67+
import org.lflang.lf.Connection;
6768
import org.lflang.lf.Deadline;
6869
import org.lflang.lf.Expression;
6970
import org.lflang.lf.Host;
@@ -603,12 +604,6 @@ public void checkReaction(Reaction reaction) {
603604
if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
604605
warning("Reaction has no trigger.", Literals.REACTION__TRIGGERS);
605606
}
606-
if (reaction.getMaxWait() != null && reaction.getMaxWait().getValue() != null) {
607-
error(
608-
"Reaction maxwait should not specify a time value. Use @maxwait on the instantiation or"
609-
+ " connection.",
610-
Literals.REACTION__MAX_WAIT);
611-
}
612607
//
613608
// if (reaction.getCode() == null) {
614609
// if (!this.target.supportsReactionDeclarations()) {
@@ -1019,6 +1014,29 @@ public void checkAttributes(Attribute attr) {
10191014
}
10201015
// Check the validity of the attribute.
10211016
spec.check(this, attr);
1017+
// Above generic check is not sufficient for maxwait.
1018+
if (name.equals("maxwait")) {
1019+
checkMaxWaitAttribute(attr);
1020+
}
1021+
}
1022+
1023+
private void checkMaxWaitAttribute(Attribute attr) {
1024+
// Check that the attribute is at the top level.
1025+
var container = attr.eContainer();
1026+
if (!(container instanceof Instantiation) && !(container instanceof Connection)) {
1027+
warning(
1028+
"maxwait attribute can only be used in an instantiation or connection.",
1029+
attr,
1030+
Literals.ATTRIBUTE__ATTR_NAME);
1031+
}
1032+
var top = container.eContainer();
1033+
if (!(top instanceof Reactor) || !((Reactor) top).isFederated()) {
1034+
warning(
1035+
"maxwait attribute can only be used at the top level in a federated reactor.",
1036+
attr,
1037+
Literals.ATTRIBUTE__ATTR_NAME);
1038+
return;
1039+
}
10221040
}
10231041

10241042
@Check(CheckType.FAST)
@@ -1100,25 +1118,6 @@ public void checkInitialMode(Reactor reactor) {
11001118
}
11011119
}
11021120

1103-
@Check(CheckType.FAST)
1104-
public void checkInstantiationMaxWaitAttribute(Instantiation instantiation) {
1105-
final var attr = AttributeUtils.findAttributeByName(instantiation, "maxwait");
1106-
if (attr != null) {
1107-
final var attrs = attr.getAttrParms();
1108-
if (attrs.size() == 1) {
1109-
if (attrs.get(0).getTime() != null) {
1110-
return;
1111-
} else if (attrs.get(0).getValue().equals("0")) {
1112-
return;
1113-
}
1114-
}
1115-
warning(
1116-
"maxwait attribute is required to specify exactly one time value.",
1117-
attr,
1118-
Literals.ATTR_PARM__VALUE);
1119-
}
1120-
}
1121-
11221121
@Check(CheckType.FAST)
11231122
public void checkModeStateNamespace(Reactor reactor) {
11241123
if (!reactor.getModes().isEmpty()) {

lfc/core/src/main/kotlin/org/lflang/generator/uc/UcReactionGenerator.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class UcReactionGenerator(private val reactor: Reactor) {
3838

3939
private val Reaction.ctorStpArgs
4040
get() =
41-
if (maxWait != null && maxWait.code != null)
41+
if (tardy != null && tardy.code != null)
4242
"LF_REACTION_TYPE(${reactor.codeType}, ${codeName}_stp_violation_handler)"
4343
else "NULL"
4444

@@ -52,8 +52,8 @@ class UcReactionGenerator(private val reactor: Reactor) {
5252
get() = effects.filter { it.isContainedRef }
5353

5454
private val reactionsWithDeadline = reactor.allReactions.filter { it.deadline != null }
55-
private val reactionsWithMaxWaitViolationHandler =
56-
reactor.allReactions.filter { it.maxWait != null && it.maxWait.code != null }
55+
private val reactionsWithTardyViolationHandler =
56+
reactor.allReactions.filter { it.tardy != null && it.tardy.code != null }
5757

5858
private val Reaction.allContainedTriggers
5959
get() = triggers.filter { !it.isEffectOf(this) && it.isContainedRef }
@@ -186,7 +186,7 @@ class UcReactionGenerator(private val reactor: Reactor) {
186186

187187
private fun generateReactionCtor(reaction: Reaction) =
188188
"""|
189-
|${if (reaction.maxWait != null) "LF_DEFINE_REACTION_STP_VIOLATION_HANDLER(${reactor.codeType}, ${reaction.codeName});" else ""}
189+
|${if (reaction.tardy != null) "LF_DEFINE_REACTION_STP_VIOLATION_HANDLER(${reactor.codeType}, ${reaction.codeName});" else ""}
190190
|${if (reaction.deadline != null) "LF_DEFINE_REACTION_DEADLINE_VIOLATION_HANDLER(${reactor.codeType}, ${reaction.codeName});" else ""}
191191
|LF_DEFINE_REACTION_CTOR(${reactor.codeType}, ${reaction.codeName}, ${reaction.index}, ${reaction.ctorDeadlineArgs}, ${reaction.ctorStpArgs});
192192
"""
@@ -227,7 +227,7 @@ class UcReactionGenerator(private val reactor: Reactor) {
227227
}
228228

229229
fun generateReactionStpViolationHandlers() =
230-
reactionsWithMaxWaitViolationHandler.joinToString(
230+
reactionsWithTardyViolationHandler.joinToString(
231231
separator = "\n", prefix = "// Reaction STP violation handlers\n", postfix = "\n") {
232232
generateReactionStpViolationHandler(it)
233233
}
@@ -267,7 +267,7 @@ class UcReactionGenerator(private val reactor: Reactor) {
267267
|LF_DEFINE_REACTION_STP_VIOLATION_HANDLER(${reactor.codeType}, ${reaction.codeName}) {
268268
${"| "..generateReactionScope(reaction)}
269269
| // Start of user-witten reaction STAA violation handler body
270-
${"| "..reaction.maxWait.code.toText()}
270+
${"| "..reaction.tardy.code.toText()}
271271
|}
272272
"""
273273
.trimMargin()

test/lf/src/FederatedMaxWait.lf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ reactor Dst {
2020
validate(!self->check2);
2121
printf("Hello from Dst!\n");
2222
self->check2 = true;
23-
=} maxwait {=
23+
=} tardy {=
2424
// STP violation is expected because maxwait defaults to zero so this startup reaction
2525
// will already have executed by the time the message is received from Src.
2626
printf("STP violation\n");

test/lf/src/FederatedMaxWait2.lf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ reactor Dst {
2424
printf("Hello from Dst!\n");
2525
self->check2 = true;
2626
env->request_shutdown(env);
27-
=} maxwait {=
27+
=} tardy {=
2828
printf("STP violation\n");
2929
// STP violation should not happen because maxwait is forever.
3030
validate(false);

test/lf/src/FederatedMaxWait3.lf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ reactor Dst {
2525
reaction(in1) {=
2626
printf("Hello from Dst!\n");
2727
self->check1 = true;
28-
=} maxwait {=
28+
=} tardy {=
2929
printf("STP violation on in1\n");
3030
validate(false);
3131
=}
3232

3333
reaction(in2) {=
3434
printf("Normal reaction handled at in2\n");
3535
validate(false);
36-
=} maxwait {=
36+
=} tardy {=
3737
printf("Hello from STP1!\n");
3838
self->check2 = true;
3939
=}
4040

4141
reaction(in2) {=
4242
validate(false);
43-
=} maxwait {=
43+
=} tardy {=
4444
printf("Hello from STP2!\n");
4545
self->check3 = true;
4646
=}

0 commit comments

Comments
 (0)