Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce forever and never time literal #2421

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions core/src/main/java/org/lflang/LinguaFranca.xtext
Depetrol marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,16 @@ SignedInt:
INT | NEGINT
;

Forever:
'forever'
;

Never:
'never'
;

Literal:
STRING | CHAR_LIT | SignedFloat | SignedInt | Boolean
STRING | CHAR_LIT | SignedFloat | SignedInt | Boolean | Forever | Never
;

Boolean:
Expand Down Expand Up @@ -521,7 +529,7 @@ Token:
'startup' | 'shutdown' | 'after' | 'deadline' | 'mutation' | 'preamble' |
'new' | 'federated' | 'at' | 'as' | 'from' | 'widthof' | 'const' | 'method' |
'interleaved' | 'mode' | 'initial' | 'reset' | 'history' | 'watchdog' |
'extends' |
'extends' | 'forever' | 'never' |

// Other terminals
NEGINT | TRUE | FALSE |
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/org/lflang/TimeValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public final class TimeValue implements Comparable<TimeValue> {
/** The maximum value of this type. This is approximately equal to 292 years. */
public static final TimeValue MAX_VALUE = new TimeValue(Long.MAX_VALUE, TimeUnit.NANO);

/** The minimum value of this type. */
public static final TimeValue MIN_VALUE = new TimeValue(Long.MIN_VALUE, TimeUnit.NANO);

/** A time value equal to zero. */
public static final TimeValue ZERO = new TimeValue(0, null);

Expand Down
50 changes: 50 additions & 0 deletions core/src/main/java/org/lflang/ast/ASTUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,26 @@ public static boolean isZero(String literal) {
return false;
}

/**
* Report whether the given literal is forever or not.
*
* @param literal AST node to inspect.
* @return True if the given literal denotes the constant {@code forever}, false otherwise.
*/
public static boolean isForever(String literal) {
return literal != null && literal.equals("forever");
}

/**
* Report whether the given literal is never or not.
*
* @param literal AST node to inspect.
* @return True if the given literal denotes the constant {@code never}, false otherwise.
*/
public static boolean isNever(String literal) {
return literal != null && literal.equals("never");
}

/**
* Report whether the given expression is zero or not.
*
Expand All @@ -957,6 +977,32 @@ public static boolean isZero(Expression expr) {
return false;
}

/**
* Report whether the given expression is forever or not.
*
* @param expr AST node to inspect.
* @return True if the given value denotes the constant {@code forever}, false otherwise.
*/
public static boolean isForever(Expression expr) {
if (expr instanceof Literal) {
return isForever(((Literal) expr).getLiteral());
}
return false;
}

/**
* Report whether the given expression is never or not.
*
* @param expr AST node to inspect.
* @return True if the given value denotes the constant {@code never}, false otherwise.
*/
public static boolean isNever(Expression expr) {
if (expr instanceof Literal) {
return isNever(((Literal) expr).getLiteral());
}
return false;
}

/**
* Report whether the given string literal is an integer number or not.
*
Expand Down Expand Up @@ -1137,6 +1183,10 @@ public static TimeValue getLiteralTimeValue(Expression expr) {
return toTimeValue((Time) expr);
} else if (expr instanceof Literal && isZero(((Literal) expr).getLiteral())) {
return TimeValue.ZERO;
} else if (expr instanceof Literal && isForever(((Literal) expr).getLiteral())) {
return TimeValue.MAX_VALUE;
} else if (expr instanceof Literal && isNever(((Literal) expr).getLiteral())) {
return TimeValue.MIN_VALUE;
} else {
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/lflang/generator/TargetTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ default String getTargetInitializer(Initializer init, Type type) {
default String getTargetExpr(Expression expr, InferredType type) {
if (ASTUtils.isZero(expr) && type != null && type.isTime) {
return getTargetTimeExpr(TimeValue.ZERO);
} else if (ASTUtils.isForever(expr) && type != null) {
return getTargetTimeExpr(TimeValue.MAX_VALUE);
} else if (ASTUtils.isNever(expr) && type != null) {
return getTargetTimeExpr(TimeValue.MIN_VALUE);
} else if (expr instanceof ParameterReference) {
return getTargetParamRef((ParameterReference) expr, type);
} else if (expr instanceof Time) {
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/lflang/validation/LFValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,14 @@ private void checkExpressionIsTime(Expression value, EStructuralFeature feature)
return;
}

if (ASTUtils.isForever(((Literal) value).getLiteral())) {
return;
}

if (ASTUtils.isNever(((Literal) value).getLiteral())) {
return;
}

if (ASTUtils.isInteger(((Literal) value).getLiteral())) {
error("Missing time unit.", feature);
return;
Expand Down
8 changes: 1 addition & 7 deletions test/C/src/LastTimeDefer.lf
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@ main reactor {
logical action a(1 ms, 300 ms): int
state c: int = 0
state c2: int = 0 // For expected values.
state last: time = 0

reaction(startup) {=
// Unfortunately, a time state variable cannot be initialized with NEVER.
// So we do that here.
self->last = NEVER;
=}
state last: time = never

reaction(t) -> a {=
tag_t now = lf_tag();
Expand Down
8 changes: 1 addition & 7 deletions test/C/src/LastTimeDrop.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ main reactor {
timer t(0, 100 ms)
logical action a(1 ms, 300 ms, "drop"): int
state c: int = 0
state last: time = 0

reaction(startup) {=
// Unfortunately, a time state variable cannot be initialized with NEVER.
// So we do that here.
self->last = NEVER;
=}
state last: time = never

reaction(t) -> a {=
tag_t now = lf_tag();
Expand Down
8 changes: 1 addition & 7 deletions test/C/src/LastTimeReplace.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ main reactor {
timer t(0, 100 ms)
logical action a(1 ms, 300 ms, "replace"): int
state c: int = 0
state last: time = 0

reaction(startup) {=
// Unfortunately, a time state variable cannot be initialized with NEVER.
// So we do that here.
self->last = NEVER;
=}
state last: time = never

reaction(t) -> a {=
tag_t now = lf_tag();
Expand Down
6 changes: 3 additions & 3 deletions test/C/src/modal_models/BanksCount3ModesComplex.lf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ reactor MetaCounter {
output[2] always: int
output[2] mode1: int
output[2] mode2: int
output[2] never: int
output[2] neverp: int

outer_counters = new[2] CounterCycle()
(next)+ -> outer_counters.next
Expand Down Expand Up @@ -46,7 +46,7 @@ reactor MetaCounter {
mode3_counters = new[2] CounterCycle()

(next)+ -> mode3_counters.next
mode3_counters.count -> never
mode3_counters.count -> neverp
}
}

Expand All @@ -72,7 +72,7 @@ main reactor {
250000000,1,1,1,1,1,1,1,1,0,3,0,3,0,3,0,3,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
}, training = false)

counters.always, counters.mode1, counters.mode2, counters.never -> test.events
counters.always, counters.mode1, counters.mode2, counters.neverp -> test.events

// Trigger
reaction(stepper) -> counters.next {=
Expand Down
8 changes: 4 additions & 4 deletions test/C/src/modal_models/ModalNestedReactions.lf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ reactor CounterCycle {

output count: int
output only_in_two: bool
output never: int
output neverp: int

initial mode One {
reaction(next) -> count, reset(Two) {=
Expand All @@ -29,8 +29,8 @@ reactor CounterCycle {
}

mode Three {
reaction(next) -> never {=
lf_set(never, true);
reaction(next) -> neverp {=
lf_set(neverp, true);
=}
}
}
Expand Down Expand Up @@ -69,7 +69,7 @@ main reactor {
}
=}

reaction(counter.never) {=
reaction(counter.neverp) {=
printf("ERROR: Detected output from unreachable mode.\n");
exit(4);
=}
Expand Down
14 changes: 7 additions & 7 deletions test/Python/src/federated/Dataflow.lf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ preamble {=
import time
=}

reactor Client(STP_offset = {= FOREVER =}) {
reactor Client(STA=forever) {
input server_message
output client_message

Expand All @@ -24,13 +24,13 @@ reactor Client(STP_offset = {= FOREVER =}) {
request_stop()
# Need to unconditionally produce output or downstream could lock up waiting for it.
client_message.set(val)
=} STP(10 s) {=
print("Client STP Violated!")
=} STP(forever) {=
print("Client STAA Violated!")
exit(1)
=}
}

reactor Server(STP_offset = {= FOREVER =}) {
reactor Server(STA=forever) {
output server_message
input client_message1
input client_message2
Expand All @@ -51,13 +51,13 @@ reactor Server(STP_offset = {= FOREVER =}) {
request_stop()
# Need to unconditionally produce output or downstream could lock up waiting for it.
server_message.set(val)
=} STP(10 s) {=
print("Server STP Violated!")
=} STP(forever) {=
print("Server STAA Violated!")
exit(1)
=}
}

federated reactor(STP_offset = {= FOREVER =}) {
federated reactor(STA=forever) {
client1 = new Client()
client2 = new Client()
server = new Server()
Expand Down
6 changes: 3 additions & 3 deletions test/Python/src/modal_models/BanksCount3ModesComplex.lf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ reactor MetaCounter {
output[2] always
output[2] mode1
output[2] mode2
output[2] never
output[2] neverp

outer_counters = new[2] CounterCycle()
(next)+ -> outer_counters.next
Expand Down Expand Up @@ -46,7 +46,7 @@ reactor MetaCounter {
mode3_counters = new[2] CounterCycle()

(next)+ -> mode3_counters.next
mode3_counters.count -> never
mode3_counters.count -> neverp
}
}

Expand All @@ -69,7 +69,7 @@ main reactor {
250000000,1,1,1,1,1,1,1,1,0,3,0,3,0,3,0,3,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
], training = False)

counters.always, counters.mode1, counters.mode2, counters.never -> test.events
counters.always, counters.mode1, counters.mode2, counters.neverp -> test.events

# Trigger
reaction(stepper) -> counters.next {=
Expand Down
8 changes: 4 additions & 4 deletions test/Python/src/modal_models/ModalNestedReactions.lf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ reactor CounterCycle {

output count
output only_in_two
output never
output neverp

initial mode One {
reaction(next) -> count, reset(Two) {=
Expand All @@ -29,8 +29,8 @@ reactor CounterCycle {
}

mode Three {
reaction(next) -> never {=
never.set(True)
reaction(next) -> neverp {=
neverp.set(True)
=}
}
}
Expand Down Expand Up @@ -68,7 +68,7 @@ main reactor {
exit(3)
=}

reaction(counter.never) {=
reaction(counter.neverp) {=
sys.stderr.write("ERROR: Detected output from unreachable mode.\n")
exit(4)
=}
Expand Down
Loading