From 76f0cfb7f38479370f9918a1e20c60654aa5050f Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 8 Feb 2022 08:17:50 +0100 Subject: [PATCH 01/17] Renamed Requirement to Cause --- .../BehaviorInterpretationResult.java | 6 ++-- .../interpreter/BehaviorInterpreter.java | 30 +++++++++---------- .../nodes/StateChangedPublisher.java | 4 +-- .../ActivatableEvent.java | 2 +- .../AndInteractionNode.java | 2 +- .../ComparisonInteractionNode.java | 2 +- .../EventActivationListener.java | 2 +- .../FixedValueDescription.java | 2 +- .../ITriggerListener.java | 2 +- .../IValueDescription.java | 2 +- .../ImplicationNode.java | 14 ++++----- .../InteractionListener.java | 2 +- .../InteractionNode.java | 2 +- .../NotInteractionNode.java | 2 +- .../OrInteractionNode.java | 2 +- .../TriggerNotifier.java | 2 +- 16 files changed, 38 insertions(+), 40 deletions(-) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/ActivatableEvent.java (93%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/AndInteractionNode.java (96%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/ComparisonInteractionNode.java (97%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/EventActivationListener.java (95%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/FixedValueDescription.java (84%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/ITriggerListener.java (68%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/IValueDescription.java (67%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/ImplicationNode.java (60%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/InteractionListener.java (75%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/InteractionNode.java (79%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/NotInteractionNode.java (92%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/OrInteractionNode.java (96%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{requirements => cause}/TriggerNotifier.java (91%) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java index 8f4358b..99dd9fa 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java @@ -1,8 +1,8 @@ package cambio.tltea.interpreter; -import cambio.tltea.interpreter.nodes.requirements.EventActivationListener; -import cambio.tltea.interpreter.nodes.requirements.InteractionNode; -import cambio.tltea.interpreter.nodes.requirements.TriggerNotifier; +import cambio.tltea.interpreter.nodes.cause.EventActivationListener; +import cambio.tltea.interpreter.nodes.cause.InteractionNode; +import cambio.tltea.interpreter.nodes.cause.TriggerNotifier; import cambio.tltea.parser.core.ASTNode; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java index 7ca2935..1b63469 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java @@ -1,6 +1,6 @@ package cambio.tltea.interpreter; -import cambio.tltea.interpreter.nodes.requirements.*; +import cambio.tltea.interpreter.nodes.cause.*; import cambio.tltea.interpreter.utils.ASTManipulator; import cambio.tltea.parser.core.*; @@ -21,44 +21,44 @@ class BehaviorInterpreter { public BehaviorInterpretationResult interpret(ASTNode ast) { var workCopy = ast.clone(); result.setModifiedAST(workCopy); - var interpretedAST = interpretAsRequirement(workCopy); + var interpretedAST = interpretAsCause(workCopy); result.setInterpretedAST(interpretedAST); return result; } - private InteractionNode interpretAsRequirement(ASTNode root) { + private InteractionNode interpretAsCause(ASTNode root) { if (root instanceof ValueASTNode valueNode) { - return interpretAsRequirement(valueNode); + return interpretAsCause(valueNode); } else if (root instanceof UnaryOperationASTNode unNode) { - return interpretAsRequirement(unNode); + return interpretAsCause(unNode); } else if (root instanceof BinaryOperationASTNode biNode) { - return interpretAsRequirement(biNode); + return interpretAsCause(biNode); } return null; } - private InteractionNode interpretAsRequirement(UnaryOperationASTNode unNode) { + private InteractionNode interpretAsCause(UnaryOperationASTNode unNode) { switch (unNode.getOperator()) { case NOT -> { if (unNode.getChild() instanceof UnaryOperationASTNode child && child.getOperator() == OperatorToken.NOT) { - interpretAsRequirement(ASTManipulator.removeDoubleNot(unNode)); + interpretAsCause(ASTManipulator.removeDoubleNot(unNode)); }//TODO: replace !true / !false with false / true - var child = interpretAsRequirement(unNode.getChild()); + var child = interpretAsCause(unNode.getChild()); return new NotInteractionNode((InteractionNode) child); } default -> throw new UnsupportedOperationException("Operator not yet supported: " + unNode.getOperator()); } } - private InteractionNode interpretAsRequirement(BinaryOperationASTNode binaryNode) { + private InteractionNode interpretAsCause(BinaryOperationASTNode binaryNode) { switch (binaryNode.getOperator()) { case IFF: { - interpretAsRequirement(ASTManipulator.splitIFF(binaryNode)); + interpretAsCause(ASTManipulator.splitIFF(binaryNode)); } case IMPLIES: { - var left = (InteractionNode) interpretAsRequirement(binaryNode.getLeftChild()); + var left = (InteractionNode) interpretAsCause(binaryNode.getLeftChild()); var right = interpretAsBehavior(binaryNode.getRightChild()); return new ImplicationNode(left, right, result.getTriggerNotifier()); } @@ -76,7 +76,7 @@ private InteractionNode interpretAsRequirement(BinaryOperationASTNode b } } - private InteractionNode interpretAsRequirement(ValueASTNode valueNode) { + private InteractionNode interpretAsCause(ValueASTNode valueNode) { try { double d = Double.parseDouble(valueNode.getValue()); return new FixedValueDescription<>(d); @@ -103,13 +103,13 @@ private List> flattenRequirement(BinaryOperationASTNode if (root.getLeftChild() instanceof BinaryOperationASTNode leftChild && leftChild.getOperator() == root.getOperator()) { children.addAll(flattenRequirement(leftChild)); } else { - children.add((InteractionNode) interpretAsRequirement(root.getLeftChild())); + children.add((InteractionNode) interpretAsCause(root.getLeftChild())); } if (root.getRightChild() instanceof BinaryOperationASTNode rightChild && rightChild.getOperator() == root.getOperator()) { children.addAll(flattenRequirement(rightChild)); } else { - children.add((InteractionNode) interpretAsRequirement(root.getRightChild())); + children.add((InteractionNode) interpretAsCause(root.getRightChild())); } return children; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java index 83d4b28..a577ed6 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java @@ -1,11 +1,9 @@ package cambio.tltea.interpreter.nodes; -import cambio.tltea.interpreter.nodes.requirements.InteractionListener; +import cambio.tltea.interpreter.nodes.cause.InteractionListener; import java.util.Collection; import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; /** * @author Lion Wagner diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ActivatableEvent.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java similarity index 93% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ActivatableEvent.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java index 89b9340..e2345aa 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ActivatableEvent.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/AndInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java similarity index 96% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/AndInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java index b2225f6..2f2c465 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/AndInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangedPublisher; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ComparisonInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java similarity index 97% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ComparisonInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java index 2e40e28..2ffdbd1 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ComparisonInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.parser.core.OperatorToken; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/EventActivationListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java similarity index 95% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/EventActivationListener.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java index dd2361d..2eaac70 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/EventActivationListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangedPublisher; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/FixedValueDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java similarity index 84% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/FixedValueDescription.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java index 5022f1a..b76817e 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/FixedValueDescription.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; /** * @author Lion Wagner diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ITriggerListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java similarity index 68% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ITriggerListener.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java index 3c0ad57..ededff0 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ITriggerListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; @FunctionalInterface public interface ITriggerListener { diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/IValueDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java similarity index 67% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/IValueDescription.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java index d194969..bacee89 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/IValueDescription.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; public abstract class IValueDescription extends InteractionNode { public abstract T getValue(); diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ImplicationNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java similarity index 60% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ImplicationNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java index 07d0428..aa15d27 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/ImplicationNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; @@ -7,16 +7,16 @@ */ public class ImplicationNode extends InteractionNode implements InteractionListener { - private final InteractionNode requirement; + private final InteractionNode cause; private final String consequence; private final TriggerNotifier notifier; - public ImplicationNode(InteractionNode requirement, String consequence, TriggerNotifier notifier) { - this.requirement = requirement; + public ImplicationNode(InteractionNode cause, String consequence, TriggerNotifier notifier) { + this.cause = cause; this.consequence = consequence; this.notifier = notifier; - requirement.subscribe(this); + cause.subscribe(this); } @Override @@ -27,10 +27,10 @@ public void onEvent(StateChangeEvent event) { } /** - * @return whether the requirement is satisfied + * @return whether the cause expression is satisfied */ @Override public Boolean getValue() { - return requirement.getValue(); + return cause.getValue(); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java similarity index 75% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionListener.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java index f097fc0..45ca7df 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java similarity index 79% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java index 7c07bd4..d25582c 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/InteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangedPublisher; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/NotInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java similarity index 92% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/NotInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java index 545c8d2..6a6fe87 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/NotInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/OrInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java similarity index 96% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/OrInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java index 9f3c5c5..e79f729 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/OrInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangedPublisher; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/TriggerNotifier.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java similarity index 91% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/TriggerNotifier.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java index 8366f83..5c681ad 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/requirements/TriggerNotifier.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.requirements; +package cambio.tltea.interpreter.nodes.cause; import java.util.Collection; import java.util.HashSet; From c956c7fb587f135edafff1166512c4bb7cd0116b Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 8 Feb 2022 08:48:38 +0100 Subject: [PATCH 02/17] Restructuring --- .../interpreter/BehaviorInterpretationResult.java | 2 +- .../cambio/tltea/interpreter/BehaviorInterpreter.java | 1 + .../nodes/{cause => }/ITriggerListener.java | 2 +- ...teractionListener.java => StateChangeListener.java} | 4 ++-- .../tltea/interpreter/nodes/StateChangedPublisher.java | 10 ++++------ .../interpreter/nodes/{cause => }/TriggerNotifier.java | 4 ++-- .../interpreter/nodes/cause/ActivatableEvent.java | 3 ++- .../interpreter/nodes/cause/AndInteractionNode.java | 3 ++- .../tltea/interpreter/nodes/cause/ImplicationNode.java | 4 +++- .../interpreter/nodes/cause/NotInteractionNode.java | 3 ++- .../interpreter/nodes/cause/OrInteractionNode.java | 3 ++- 11 files changed, 22 insertions(+), 17 deletions(-) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{cause => }/ITriggerListener.java (71%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{cause/InteractionListener.java => StateChangeListener.java} (59%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{cause => }/TriggerNotifier.java (84%) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java index 99dd9fa..32555fc 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java @@ -2,7 +2,7 @@ import cambio.tltea.interpreter.nodes.cause.EventActivationListener; import cambio.tltea.interpreter.nodes.cause.InteractionNode; -import cambio.tltea.interpreter.nodes.cause.TriggerNotifier; +import cambio.tltea.interpreter.nodes.TriggerNotifier; import cambio.tltea.parser.core.ASTNode; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java index 1b63469..4a64eb0 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java @@ -1,5 +1,6 @@ package cambio.tltea.interpreter; +import cambio.tltea.interpreter.nodes.TriggerNotifier; import cambio.tltea.interpreter.nodes.cause.*; import cambio.tltea.interpreter.utils.ASTManipulator; import cambio.tltea.parser.core.*; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ITriggerListener.java similarity index 71% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/ITriggerListener.java index ededff0..be42659 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ITriggerListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ITriggerListener.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.cause; +package cambio.tltea.interpreter.nodes; @FunctionalInterface public interface ITriggerListener { diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java similarity index 59% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java index 45ca7df..ad2a6b8 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java @@ -1,8 +1,8 @@ -package cambio.tltea.interpreter.nodes.cause; +package cambio.tltea.interpreter.nodes; import cambio.tltea.interpreter.nodes.StateChangeEvent; @FunctionalInterface -public interface InteractionListener{ +public interface StateChangeListener{ void onEvent(StateChangeEvent event); } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java index a577ed6..5961b88 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java @@ -1,7 +1,5 @@ package cambio.tltea.interpreter.nodes; -import cambio.tltea.interpreter.nodes.cause.InteractionListener; - import java.util.Collection; import java.util.HashSet; @@ -9,18 +7,18 @@ * @author Lion Wagner */ public abstract class StateChangedPublisher { - protected final Collection> subscribers = new HashSet<>(); + protected final Collection> subscribers = new HashSet<>(); - public final void subscribe(InteractionListener listener) { + public final void subscribe(StateChangeListener listener) { subscribers.add(listener); } - public final void unsubscribe(InteractionListener listener) { + public final void unsubscribe(StateChangeListener listener) { subscribers.remove(listener); } protected final void notifySubscribers(StateChangeEvent event) { - for (InteractionListener listener : subscribers) { + for (StateChangeListener listener : subscribers) { listener.onEvent(event); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java similarity index 84% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java index 5c681ad..977b7d6 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/TriggerNotifier.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java @@ -1,4 +1,4 @@ -package cambio.tltea.interpreter.nodes.cause; +package cambio.tltea.interpreter.nodes; import java.util.Collection; import java.util.HashSet; @@ -18,7 +18,7 @@ public final void unsubscribe(ITriggerListener listener) { subscribers.remove(listener); } - void trigger(String eventName, Object... args) { + public void trigger(String eventName, Object... args) { for (ITriggerListener listener : subscribers) { listener.onTrigger(eventName, args); } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java index e2345aa..aff0150 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java @@ -2,12 +2,13 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; import org.jetbrains.annotations.NotNull; /** * @author Lion Wagner */ -public final class ActivatableEvent extends IValueDescription implements InteractionListener { +public final class ActivatableEvent extends IValueDescription implements StateChangeListener { private final EventActivationListener listener; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java index 2f2c465..1dec285 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java @@ -1,6 +1,7 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; import cambio.tltea.interpreter.nodes.StateChangedPublisher; import java.util.LinkedList; @@ -9,7 +10,7 @@ /** * @author Lion Wagner */ -public class AndInteractionNode extends InteractionNode implements InteractionListener { +public class AndInteractionNode extends InteractionNode implements StateChangeListener { private boolean state = false; private final LinkedList> children = new LinkedList<>(); diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java index aa15d27..b3b1ba6 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java @@ -1,11 +1,13 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.interpreter.nodes.TriggerNotifier; /** * @author Lion Wagner */ -public class ImplicationNode extends InteractionNode implements InteractionListener { +public class ImplicationNode extends InteractionNode implements StateChangeListener { private final InteractionNode cause; private final String consequence; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java index 6a6fe87..edfe618 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java @@ -1,11 +1,12 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; /** * @author Lion Wagner */ -public final class NotInteractionNode extends InteractionNode implements InteractionListener { +public final class NotInteractionNode extends InteractionNode implements StateChangeListener { private final InteractionNode child; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java index e79f729..5fcce51 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java @@ -1,6 +1,7 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; import cambio.tltea.interpreter.nodes.StateChangedPublisher; import java.util.LinkedList; @@ -9,7 +10,7 @@ /** * @author Lion Wagner */ -public class OrInteractionNode extends InteractionNode implements InteractionListener { +public class OrInteractionNode extends InteractionNode implements StateChangeListener { private boolean state = false; From 7b602dbb141f57271b854ec22c7e1f34f538a4e3 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 8 Feb 2022 09:07:10 +0100 Subject: [PATCH 03/17] consequence node structure --- .../nodes/consequence/ConsequenceNode.java | 15 +++++++++++++++ .../consequence/EventActivationDescription.java | 9 +++++++++ 2 files changed, 24 insertions(+) create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java new file mode 100644 index 0000000..e4c5c0f --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java @@ -0,0 +1,15 @@ +package cambio.tltea.interpreter.nodes.consequence; + +import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangedPublisher; + +import java.util.LinkedList; + +/** + * @author Lion Wagner + */ +public abstract class ConsequenceNode { + + public abstract LinkedList activate(); + +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java new file mode 100644 index 0000000..b3f5657 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java @@ -0,0 +1,9 @@ +package cambio.tltea.interpreter.nodes.consequence; + +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; + +/** + * @author Lion Wagner + */ +public record EventActivationDescription(String eventName, TemporalOperatorInfo temporalOperatorInfo) { +} From 83fb5509fcc8c7cb1b9414d81857ec0ab51a577c Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 15 Feb 2022 13:55:19 +0100 Subject: [PATCH 04/17] Cleanup for TemporalProposition and -Interval --- .../parser/core/temporal/DoubleInterval.java | 26 --- .../parser/core/temporal/IntInterval.java | 12 -- .../tltea/parser/core/temporal/Interval.java | 86 -------- .../core/temporal/TemporalInterval.java | 109 ++++++++++ .../temporal/TemporalPropositionParser.java | 47 +++-- .../core/temporal/TemporalIntervalTest.java | 192 ++++++++++++++++++ .../TemporalPropositionParserTest.java | 38 +++- 7 files changed, 361 insertions(+), 149 deletions(-) delete mode 100644 parser/src/main/java/cambio/tltea/parser/core/temporal/DoubleInterval.java delete mode 100644 parser/src/main/java/cambio/tltea/parser/core/temporal/IntInterval.java delete mode 100644 parser/src/main/java/cambio/tltea/parser/core/temporal/Interval.java create mode 100644 parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java create mode 100644 parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalIntervalTest.java diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/DoubleInterval.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/DoubleInterval.java deleted file mode 100644 index 2ab12dd..0000000 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/DoubleInterval.java +++ /dev/null @@ -1,26 +0,0 @@ -package cambio.tltea.parser.core.temporal; - -public final class DoubleInterval extends Interval { - - public DoubleInterval(double start, double end) { - super(start, end, true, !Double.isInfinite(end)); - } - - public DoubleInterval(double start, double end, boolean startInclusive) { - super(start, end, startInclusive, !Double.isInfinite(end)); - } - - public DoubleInterval(double start, double end, boolean startInclusive, boolean endInclusive) { - super(start, end, startInclusive, endInclusive && !Double.isInfinite(end)); - } - - @Override - public Double getDuration() { - return end - start; - } - - @Override - public String toString() { - return (startInclusive ? "[" : "(") + start + "," + end + (endInclusive ? "]" : ")"); - } -} diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/IntInterval.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/IntInterval.java deleted file mode 100644 index 819e3b3..0000000 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/IntInterval.java +++ /dev/null @@ -1,12 +0,0 @@ -package cambio.tltea.parser.core.temporal; - -public class IntInterval extends Interval { - public IntInterval(int start, int end) { - super(start, end); - } - - @Override - public Integer getDuration() { - return end - start; - } -} diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/Interval.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/Interval.java deleted file mode 100644 index 21b6d2a..0000000 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/Interval.java +++ /dev/null @@ -1,86 +0,0 @@ -package cambio.tltea.parser.core.temporal; - -import java.util.Objects; - -public abstract class Interval implements ITemporalValue { - - protected final T start; - protected final T end; - protected final boolean startInclusive; - protected final boolean endInclusive; - - public Interval(T start, T end) { - this(start, end, true); - } - - public Interval(T start, T end, boolean startInclusive) { - this(start, end, startInclusive, true); - } - - public Interval(T start, T end, boolean startInclusive, boolean endInclusive) { - this.start = start; - this.end = end; - this.startInclusive = startInclusive; - this.endInclusive = endInclusive; - } - - public T getStart() { - return start; - } - - public T getEnd() { - return end; - } - - public boolean isStartInclusive() { - return startInclusive; - } - - public boolean isEndInclusive() { - return endInclusive; - } - - - public boolean contains(T value) { - return (startInclusive && value.doubleValue() >= start.doubleValue()) || (!startInclusive && value.doubleValue() > start.doubleValue()) && - (endInclusive && value.doubleValue() <= end.doubleValue()) || (!endInclusive && value.doubleValue() < end.doubleValue()); - - } - - - public boolean contains(Interval interval) { - return (startInclusive && interval.getStart().doubleValue() >= start.doubleValue()) || (!startInclusive && interval.getStart().doubleValue() > start.doubleValue()) && - (endInclusive && interval.getEnd().doubleValue() <= end.doubleValue()) || (!endInclusive && interval.getEnd().doubleValue() < end.doubleValue()); - } - - - public boolean overlaps(Interval interval) { - return !(isBefore(interval) || isAfter(interval)); - } - - - public boolean isBefore(Interval interval) { - //TODO: inclusive intervals behavior - return end.doubleValue() < interval.getStart().doubleValue(); - } - - public boolean isAfter(Interval interval) { - //TODO: inclusive intervals behavior - return start.doubleValue() > interval.getEnd().doubleValue(); - } - - public abstract T getDuration(); - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Interval interval = (Interval) o; - return startInclusive == interval.startInclusive && endInclusive == interval.endInclusive && start.equals(interval.start) && end.equals(interval.end); - } - - @Override - public int hashCode() { - return Objects.hash(start, end, startInclusive, endInclusive); - } -} diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java new file mode 100644 index 0000000..b3875d4 --- /dev/null +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java @@ -0,0 +1,109 @@ +package cambio.tltea.parser.core.temporal; + +import java.util.Objects; + +public final class TemporalInterval implements ITemporalValue { + + private final double start; + private final double end; + private final boolean startInclusive; + private final boolean endInclusive; + + public TemporalInterval(double start, double end) { + this(start, end, true); + } + + public TemporalInterval(double start, double end, boolean startInclusive) { + this(start, end, startInclusive, true); + } + + public TemporalInterval(double start, double end, boolean startInclusive, boolean endInclusive) { + this.start = start; + this.end = end; + this.startInclusive = startInclusive; + this.endInclusive = endInclusive; + } + + public Double getStart() { + return start; + } + + public Double getEnd() { + return end; + } + + public boolean isStartInclusive() { + return startInclusive; + } + + public boolean isEndInclusive() { + return endInclusive; + } + + + public boolean contains(double value) { + return ((startInclusive && value >= start) || + (!startInclusive && value > start)) + && + ((endInclusive && value <= end) || + (!endInclusive && value < end)); + + } + + + public boolean contains(TemporalInterval interval) { + return contains(interval.getStart()) && contains(interval.getEnd()); + } + + + public boolean overlaps(TemporalInterval interval) { + return !(isBefore(interval) || isAfter(interval)); + } + + + public boolean isBefore(TemporalInterval interval) { + if (end <= interval.getStart()) { + if (end == interval.getStart()) { + return !(endInclusive && interval.isStartInclusive()); + } + return true; + } + return false; + } + + public boolean isAfter(TemporalInterval interval) { + if (start >= interval.getEnd()) { + if (start == interval.getEnd()) { + return !(startInclusive && interval.isEndInclusive()); + } + return true; + } + return false; + } + + public Double getDuration() { + return end - start; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TemporalInterval interval = (TemporalInterval) o; + return startInclusive == interval.startInclusive && endInclusive == interval.endInclusive && (start == interval.start) && (end == interval.end); + } + + @Override + public int hashCode() { + return Objects.hash(start, end, startInclusive, endInclusive); + } + + @Override + public String toString() { + return (startInclusive ? "[" : "(") + start + "," + end + (endInclusive ? "]" : ")"); + } +} diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalPropositionParser.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalPropositionParser.java index 6f3133f..2000ee5 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalPropositionParser.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalPropositionParser.java @@ -1,9 +1,15 @@ package cambio.tltea.parser.core.temporal; import java.util.List; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public final class TemporalPropositionParser { + + private static final List infList = List.of("inf", "infinity", "∞"); + public static ITemporalValue parse(String expression) { expression = stripBrackets(expression.trim()); // trim and remove brackets @@ -13,36 +19,41 @@ public static ITemporalValue parse(String expression) { } catch (NumberFormatException e) { } - // check if it is a directional time value + // check if it is a relative time value and parse it to an instance or interval try { if (expression.startsWith("=")) { return new TimeInstance(Double.parseDouble(expression.substring(1))); } else if (expression.startsWith(">=")) { - return new DoubleInterval(Double.parseDouble(expression.substring(2)), Double.POSITIVE_INFINITY); + return new TemporalInterval(Double.parseDouble(expression.substring(2)), Double.POSITIVE_INFINITY); } else if (expression.startsWith(">")) { - return new DoubleInterval(Double.parseDouble(expression.substring(1)), Double.POSITIVE_INFINITY, false); + return new TemporalInterval(Double.parseDouble(expression.substring(1)), Double.POSITIVE_INFINITY, false); } else if (expression.startsWith("<=")) { - return new DoubleInterval(0, Double.parseDouble(expression.substring(2))); + return new TemporalInterval(0, Double.parseDouble(expression.substring(2))); } else if (expression.startsWith("<")) { - return new DoubleInterval(0, Double.parseDouble(expression.substring(1)), true, false); + return new TemporalInterval(0, Double.parseDouble(expression.substring(1)), true, false); } - } catch (NumberFormatException e) { + } catch (NumberFormatException ignored) { } + + //create pattern for [,;:] + Pattern pattern = Pattern.compile("(\\d+\\.?\\d*)([,;:])(\\+?((\\d+\\.?\\d*)|(inf|infinity|∞)))"); + Matcher matcher = pattern.matcher(expression.toLowerCase().replaceAll("\s", "")); + + // check if it is an interval description - if (expression.contains(",")) { - String[] parts = expression.toLowerCase().replaceAll("\s", "").split(","); - try { - //remove + from the start of parts[1] - if (parts[1].startsWith("+")) { - parts[1] = parts[1].substring(1); - } - List infList = List.of("inf", "infinity", "∞"); - if (infList.contains(parts[1])) { - return new DoubleInterval(Double.parseDouble(parts[0]), Double.POSITIVE_INFINITY); - } else return new DoubleInterval(Double.parseDouble(parts[0]), Double.parseDouble(parts[1])); - } catch (NumberFormatException e) { + + if (matcher.matches()) { + MatchResult result = matcher.toMatchResult(); + //remove starting + from result.group(3) if it exists + String secondNumber = result.group(3).startsWith("+") ? result.group(3).substring(1) : result.group(3); + + if (infList.contains(secondNumber)) { + return new TemporalInterval(Double.parseDouble(result.group(1)), Double.POSITIVE_INFINITY); + } else { + return new TemporalInterval(Double.parseDouble(result.group(1)), Double.parseDouble(result.group(3))); } + } // otherwise, return a TemporalEventDescription wrapper diff --git a/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalIntervalTest.java b/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalIntervalTest.java new file mode 100644 index 0000000..6dd7fb7 --- /dev/null +++ b/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalIntervalTest.java @@ -0,0 +1,192 @@ +package cambio.tltea.parser.core.temporal; + +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +class TemporalIntervalTest { + + private final static Random RANDOM = new Random(); + + private final static int repetitions = 100; + + @RepeatedTest(repetitions) + void getStart_getEnd() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + assertEquals(start, interval.getStart()); + assertEquals(end, interval.getEnd()); + } + + @RepeatedTest(repetitions) + void isStartInclusive() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + assertTrue(interval.isStartInclusive()); + + var interval2 = new TemporalInterval(start, end, false); + assertFalse(interval2.isStartInclusive()); + assertFalse(interval2.contains(start)); + + var interval3 = new TemporalInterval(start, end, false, false); + assertFalse(interval3.isStartInclusive()); + assertFalse(interval3.contains(start)); + } + + @RepeatedTest(repetitions) + void isEndInclusive() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + assertTrue(interval.isEndInclusive()); + + var interval2 = new TemporalInterval(start, end, false, false); + assertFalse(interval2.isEndInclusive()); + assertFalse(interval2.contains(end)); + + var interval3 = new TemporalInterval(start, end, false, false); + assertFalse(interval3.isEndInclusive()); + assertFalse(interval3.contains(end)); + } + + @RepeatedTest(repetitions) + void contains() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + assertTrue(interval.contains(start)); + assertTrue(interval.contains(end)); + + for (int i = 0; i < 100; i++) { + var inInterval = start + RANDOM.nextDouble() * (end - start); + assertTrue(interval.contains(inInterval)); + } + } + + + @RepeatedTest(repetitions) + void containsInterval() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + assertTrue(interval.contains(start)); + assertTrue(interval.contains(end)); + + for (int i = 0; i < 100; i++) { + var inIntervalStart = start + RANDOM.nextDouble() * (end - start); + var inIntervalEnd = inIntervalStart + RANDOM.nextDouble() * (end - inIntervalStart); + var inInterval = new TemporalInterval(inIntervalStart, inIntervalEnd); + assertTrue(interval.contains(inInterval)); + } + + var exclusiveInterval = new TemporalInterval(start, end, false, false); + assertTrue(interval.contains(exclusiveInterval)); + var inclusiveInterval = new TemporalInterval(start, end, true, true); + assertTrue(interval.contains(inclusiveInterval)); + + + var exclusiveInterval2 = new TemporalInterval(start - (RANDOM.nextDouble() + 0.000000001), end, false, false); + assertFalse(interval.contains(exclusiveInterval2)); + var inclusiveInterval2 = new TemporalInterval(start, end + (RANDOM.nextDouble() + 0.000000001), true, true); + assertFalse(interval.contains(inclusiveInterval2)); + + } + + @RepeatedTest(repetitions) + void overlaps() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + + for (int i = 0; i < 50; i++) { + var inIntervalStart = start + RANDOM.nextDouble() * (end - start); + var inIntervalEnd = inIntervalStart + RANDOM.nextDouble() * (Double.MAX_VALUE - inIntervalStart); + var inInterval = new TemporalInterval(inIntervalStart, inIntervalEnd); + assertTrue(interval.overlaps(inInterval)); + } + for (int i = 0; i < 50; i++) { + var inIntervalEnd = start + RANDOM.nextDouble() * (end - start); + var inIntervalStart = RANDOM.nextDouble() * inIntervalEnd; + var inInterval = new TemporalInterval(inIntervalStart, inIntervalEnd); + assertTrue(interval.overlaps(inInterval)); + } + + var exclusiveInterval = new TemporalInterval(-1, start, false, false); + assertFalse(interval.overlaps(exclusiveInterval)); + var exclusiveInterval2 = new TemporalInterval(end, end + RANDOM.nextDouble() * end, false, false); + assertFalse(interval.overlaps(exclusiveInterval2)); + + } + + @RepeatedTest(repetitions) + void isBefore() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var inclusiveInterval = new TemporalInterval(start, end, true, true); + var exclusiveInterval = new TemporalInterval(start, end, false, false); + + var beforeInterval = new TemporalInterval(-1, start - (RANDOM.nextDouble() + 0.000000001)); + var beforeInterval2 = new TemporalInterval(-1, start, true, true); + + var overlappingStart = end * RANDOM.nextDouble(); + var overlappingEnd = exclusiveInterval.contains(overlappingStart) + ? overlappingStart + (Double.MAX_VALUE - overlappingStart) * RANDOM.nextDouble() + : start + (end - start) * RANDOM.nextDouble(); + var overlappingInterval = new TemporalInterval(overlappingStart, overlappingEnd); + + assertTrue(beforeInterval.isBefore(inclusiveInterval)); + assertTrue(inclusiveInterval.isAfter(beforeInterval)); + + assertTrue(beforeInterval2.isBefore(exclusiveInterval)); + assertTrue(exclusiveInterval.isAfter(beforeInterval2)); + + assertFalse(overlappingInterval.isBefore(inclusiveInterval)); + assertFalse(inclusiveInterval.isAfter(overlappingInterval)); + assertFalse(overlappingInterval.isBefore(exclusiveInterval)); + assertFalse(exclusiveInterval.isAfter(overlappingInterval)); + } + + + @RepeatedTest(repetitions) + void getDuration() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end, RANDOM.nextBoolean(), RANDOM.nextBoolean()); + assertEquals(end - start, interval.getDuration()); + } + + @RepeatedTest(repetitions) + void testEquals() { + double start = (Integer.MAX_VALUE / 2.0) * RANDOM.nextDouble(); + double end = start + start * RANDOM.nextDouble(); + var interval = new TemporalInterval(start, end); + var interval2 = new TemporalInterval(start, end); + var interval3 = new TemporalInterval(start, end, true, false); + var interval4 = new TemporalInterval(start, end, false, true); + var interval5 = new TemporalInterval(start, end, false, false); + + //noinspection SimplifiableAssertion,ConstantConditions + assertFalse(interval.equals(null)); + assertEquals(interval, interval); + assertEquals(interval, interval2); + assertNotEquals(interval, interval3); + assertNotEquals(interval, interval4); + assertNotEquals(interval, interval5); + + var interval6 = new TemporalInterval(start + RANDOM.nextDouble(), end); + var interval7 = new TemporalInterval(start, end + RANDOM.nextDouble()); + var interval8 = new TemporalInterval(start + RANDOM.nextDouble(), end + RANDOM.nextDouble()); + + assertNotEquals(interval, interval6); + assertNotEquals(interval, interval7); + assertNotEquals(interval, interval8); + + + + } +} \ No newline at end of file diff --git a/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalPropositionParserTest.java b/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalPropositionParserTest.java index 48441ec..b8159e2 100644 --- a/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalPropositionParserTest.java +++ b/parser/src/test/java/cambio/tltea/parser/core/temporal/TemporalPropositionParserTest.java @@ -1,20 +1,42 @@ package cambio.tltea.parser.core.temporal; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.Test; -import java.lang.reflect.Array; -import java.util.ArrayList; import java.util.List; +import java.util.Random; import static org.junit.jupiter.api.Assertions.*; class TemporalPropositionParserTest { + @Test + void fuzzer() { + Random gen = new Random(); + for (int i = 0; i < 100; i++) { + String input = RandomStringUtils.random(gen.nextInt(10000)); + ITemporalValue result = TemporalPropositionParser.parse(input); + assertTrue(result instanceof TemporalEventDescription); + } + } + + + @Test + void empty_String() { + String input = ""; + ITemporalValue result = TemporalPropositionParser.parse(input); + assertTrue(result instanceof TemporalEventDescription); + TemporalEventDescription temporalEventDescription = (TemporalEventDescription) result; + assertEquals("", temporalEventDescription.getValue()); + } + private static String stripBrackets(String s) { if (s.startsWith("[") && s.endsWith("]")) { return s.substring(1, s.length() - 1); - } else return s; + } else { + return s; + } } private void TemporalEventTest(String input, String expectedOut) { @@ -34,8 +56,8 @@ private void TimeInstantTest(String input, double i) { private void IntervalTest(String input, double expectedStart, double expectedEnd, boolean expectedStartInclusive, boolean expectedEndInclusive) { ITemporalValue result = TemporalPropositionParser.parse(input); - assertTrue(result instanceof DoubleInterval); - DoubleInterval interval = (DoubleInterval) result; + assertTrue(result instanceof TemporalInterval); + TemporalInterval interval = (TemporalInterval) result; assertEquals(expectedStart, interval.getStart()); assertEquals(expectedEnd, interval.getEnd()); assertEquals(expectedStartInclusive, interval.isStartInclusive()); @@ -47,8 +69,9 @@ void TemporalEventDescriptionTest() { List inputs = List.of(" [42a]","[[42a]]","[>42a]","[1337,42a]","[endOf Time]"); for (String input : inputs) { String expected = stripBrackets(input.trim()); - System.out.println("Testing: " + input + " -> " + expected); + System.out.print("Testing: \"" + input + "\" -> \"" + expected+"\"..."); TemporalEventTest(input, expected); + System.out.println("success"); } } @@ -136,9 +159,10 @@ void IntervalInfTest() { List l = List.of("inf", "+inf", "INF", "Inf", "infinity", "+infinity", "∞", "+∞"); for (String end : l) { - System.out.printf("Testing parsing of %s to infinity%n", end); + System.out.printf("Testing parsing of %s to infinity...", end); String input = "[42," + end + "]"; IntervalTest(input, 42, Double.POSITIVE_INFINITY, true, false); + System.out.println("success"); } } From f76d848d00e669d948eb1cad0450a09cb4b5986a Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 15 Feb 2022 13:56:34 +0100 Subject: [PATCH 05/17] Further Usage of OperatorToken istead of Operator.image --- .../cambio/tltea/parser/core/BinaryOperationASTNode.java | 9 ++++----- .../java/cambio/tltea/parser/core/IOperatorInfo.java | 2 +- .../cambio/tltea/parser/core/LiteralOperatorInfo.java | 6 +++++- .../core/temporal/TemporalBinaryOperationASTNode.java | 2 +- .../tltea/parser/core/temporal/TemporalOperatorInfo.java | 7 ++++++- .../core/temporal/TemporalUnaryOperationASTNode.java | 7 ++++++- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java index deeadfb..1c33242 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java @@ -32,7 +32,7 @@ public BinaryOperationASTNode(String operatorImage, ASTNode left, ASTNode right) } public BinaryOperationASTNode(LiteralOperatorInfo operator, ASTNode left, ASTNode right) { - this(operator.operatorImage(), left, right); + this(operator.operator(), left, right); } @@ -45,12 +45,11 @@ public BinaryOperationASTNode(LiteralOperatorInfo operator, ASTNode left, ASTNod */ public final BinaryOperationASTNode seepIn(IOperatorInfo operatorInfo, ASTNode leftNode) { - if (operatorPriority > BinaryOperatorPrecedenceMap.INSTANCE.getPrecedence( - OperatorTokenImageMap.INSTANCE.getToken(operatorInfo.operatorImage())) + if (operatorPriority > BinaryOperatorPrecedenceMap.INSTANCE.getPrecedence(operatorInfo.operator()) || this.isBracketed()) { BinaryOperationASTNode newParent = null; if (operatorInfo instanceof LiteralOperatorInfo info) { - newParent = new BinaryOperationASTNode(info.operatorImage(), leftNode, this); + newParent = new BinaryOperationASTNode(info.operator(), leftNode, this); } else if (operatorInfo instanceof TemporalOperatorInfo info) { newParent = new TemporalBinaryOperationASTNode(info, leftNode, this); } @@ -65,7 +64,7 @@ public final BinaryOperationASTNode seepIn(IOperatorInfo operatorInfo, ASTNode l } else { BinaryOperationASTNode newChild = null; if (operatorInfo instanceof LiteralOperatorInfo info) { - newChild = new BinaryOperationASTNode(info.operatorImage(), leftNode, left); + newChild = new BinaryOperationASTNode(info.operator(), leftNode, left); } if (operatorInfo instanceof TemporalOperatorInfo info) { newChild = new TemporalBinaryOperationASTNode(info, leftNode, left); diff --git a/parser/src/main/java/cambio/tltea/parser/core/IOperatorInfo.java b/parser/src/main/java/cambio/tltea/parser/core/IOperatorInfo.java index 5c8d65d..71c4d3b 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/IOperatorInfo.java +++ b/parser/src/main/java/cambio/tltea/parser/core/IOperatorInfo.java @@ -2,5 +2,5 @@ public interface IOperatorInfo { - String operatorImage(); + OperatorToken operator(); } diff --git a/parser/src/main/java/cambio/tltea/parser/core/LiteralOperatorInfo.java b/parser/src/main/java/cambio/tltea/parser/core/LiteralOperatorInfo.java index 6f18069..f0a6e1d 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/LiteralOperatorInfo.java +++ b/parser/src/main/java/cambio/tltea/parser/core/LiteralOperatorInfo.java @@ -1,4 +1,8 @@ package cambio.tltea.parser.core; -public record LiteralOperatorInfo(String operatorImage) implements IOperatorInfo { +public record LiteralOperatorInfo(OperatorToken operator) implements IOperatorInfo { + + public LiteralOperatorInfo(String operatorImage) { + this(OperatorTokenImageMap.INSTANCE.getToken(operatorImage)); + } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java index f9b2d4d..6ac551e 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java @@ -16,7 +16,7 @@ public TemporalBinaryOperationASTNode(String operator, ASTNode left, ASTNode rig } public TemporalBinaryOperationASTNode(TemporalOperatorInfo operatorInfo, ASTNode left, ASTNode right) { - super(operatorInfo.operatorImage(), left, right); + super(operatorInfo.operator(), left, right); this.setTemporalExpressionValue(operatorInfo.temporalValueExpression()); } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java index 3b4fa20..6ccde15 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java @@ -1,6 +1,11 @@ package cambio.tltea.parser.core.temporal; import cambio.tltea.parser.core.IOperatorInfo; +import cambio.tltea.parser.core.OperatorToken; +import cambio.tltea.parser.core.OperatorTokenImageMap; -public record TemporalOperatorInfo(String operatorImage, String temporalValueExpression) implements IOperatorInfo { +public record TemporalOperatorInfo(OperatorToken operator, String temporalValueExpression) implements IOperatorInfo { + public TemporalOperatorInfo(String operatorImage, String temporalValueExpression) { + this(OperatorTokenImageMap.INSTANCE.getToken(operatorImage), temporalValueExpression); + } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java index 7705fe6..7553274 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java @@ -1,6 +1,7 @@ package cambio.tltea.parser.core.temporal; import cambio.tltea.parser.core.ASTNode; +import cambio.tltea.parser.core.OperatorToken; import cambio.tltea.parser.core.UnaryOperationASTNode; /** @@ -15,8 +16,12 @@ public TemporalUnaryOperationASTNode(String operator, ASTNode child) { this.setTemporalExpressionValue("[0, ∞]"); } + public TemporalUnaryOperationASTNode(OperatorToken operator, ASTNode child) { + this(operator.image(), child); + } + public TemporalUnaryOperationASTNode(TemporalOperatorInfo operatorInfo, ASTNode child) { - this(operatorInfo.operatorImage(), child); + this(operatorInfo.operator(), child); this.setTemporalExpressionValue(operatorInfo.temporalValueExpression()); } From 12ead38d1ab46ef3209f0e16082c602d3be7f6b3 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 26 Apr 2022 10:55:00 +0200 Subject: [PATCH 06/17] Large WIP update --- TLTeaInterprtationClasses.drawio | 1 + diagrams.drawio | 2 +- .../BehaviorInterpretationResult.java | 10 +- .../interpreter/BehaviorInterpreter.java | 110 +++++++++--- .../interpreter/nodes/CauseDescription.kt | 19 ++ .../interpreter/nodes/CauseInterpreter.kt | 131 ++++++++++++++ .../nodes/ConsequenceDescription.kt | 14 ++ .../nodes/ConsequenceInterpreter.kt | 170 ++++++++++++++++++ .../interpreter/nodes/ImplicationNode.kt | 33 ++++ .../interpreter/nodes/StateChangeEvent.java | 5 +- .../nodes/StateChangeListener.java | 2 +- .../interpreter/nodes/TriggerNotifier.java | 9 + ...InteractionNode.java => AndCauseNode.java} | 16 +- .../interpreter/nodes/cause/CauseNode.java | 16 ++ .../nodes/cause/ComparisonCauseNode.java | 85 +++++++++ .../cause/ComparisonInteractionNode.java | 49 ----- .../nodes/cause/ConstantValueProvider.java | 22 +++ .../nodes/cause/EventActivationListener.java | 24 +-- ...bleEvent.java => EventActivationNode.java} | 9 +- .../nodes/cause/FixedValueDescription.java | 19 -- .../nodes/cause/IValueDescription.java | 5 - .../nodes/cause/ImplicationNode.java | 38 ---- .../nodes/cause/InteractionNode.java | 10 -- ...InteractionNode.java => NotCauseNode.java} | 13 +- ...rInteractionNode.java => OrCauseNode.java} | 15 +- .../nodes/cause/ValueProvider.java | 11 ++ .../consequence/ActivationConsequenceNode.kt | 10 ++ .../consequence/ActivationDescription.kt | 41 +++++ .../nodes/consequence/AndConsequenceNode.kt | 17 ++ .../ChildrenOwningConsequenceNode.kt | 10 ++ .../consequence/ConsequenceDescriptionTree.kt | 3 + .../nodes/consequence/ConsequenceNode.java | 15 -- .../nodes/consequence/ConsequenceNode.kt | 16 ++ .../EventActivationDescription.java | 9 - .../consequence/EventConsequenceNodes.kt | 29 +++ .../consequence/GreaterThanConsequence.kt | 14 ++ .../nodes/consequence/OrConsequenceNode.kt | 14 ++ .../nodes/consequence/ValueConsequenceNode.kt | 22 +++ .../interpreter/utils/ASTManipulator.java | 154 +++++++++++++--- .../interpreter/BehaviorInterpreterTest.java | 26 +++ .../nodes/ConsequenceInterpreterTest.kt | 20 +++ .../cambio/tltea/parser/core/ASTNode.java | 22 +++ .../tltea/parser/core/ASTNodePrinter.kt | 121 +++++++++++++ .../parser/core/BinaryOperationASTNode.java | 12 ++ .../tltea/parser/core/OperatorASTNode.java | 6 +- .../tltea/parser/core/OperatorToken.java | 80 ++++++--- .../parser/core/UnaryOperationASTNode.java | 15 +- .../tltea/parser/core/ValueASTNode.java | 10 ++ .../ITemporalExpressionValueHolder.java | 6 +- .../ITemporalOperationInfoHolder.java | 5 + .../parser/core/temporal/ITemporalValue.java | 8 +- .../TemporalBinaryOperationASTNode.java | 15 +- .../temporal/TemporalEventDescription.java | 28 +-- .../core/temporal/TemporalInterval.java | 13 +- .../core/temporal/TemporalOperatorInfo.java | 59 +++++- .../TemporalUnaryOperationASTNode.java | 15 +- .../tltea/parser/core/ASTNodePrinterTest.kt | 21 +++ pom.xml | 77 ++++++++ 58 files changed, 1454 insertions(+), 297 deletions(-) create mode 100644 TLTeaInterprtationClasses.drawio create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/{AndInteractionNode.java => AndCauseNode.java} (71%) create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/{ActivatableEvent.java => EventActivationNode.java} (68%) delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/{NotInteractionNode.java => NotCauseNode.java} (54%) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/{OrInteractionNode.java => OrCauseNode.java} (71%) create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt create mode 100644 parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt create mode 100644 parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalOperationInfoHolder.java create mode 100644 parser/src/test/java/cambio/tltea/parser/core/ASTNodePrinterTest.kt diff --git a/TLTeaInterprtationClasses.drawio b/TLTeaInterprtationClasses.drawio new file mode 100644 index 0000000..78ad6d0 --- /dev/null +++ b/TLTeaInterprtationClasses.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/diagrams.drawio b/diagrams.drawio index 7991aea..8d4269e 100644 --- a/diagrams.drawio +++ b/diagrams.drawio @@ -1 +1 @@ -7Vpbc9o6EP41PML4Jl8ek5D0tE17mMJM2qczKlZArW1RIQfIrz8SlsGyTHBcgt2keSDe1f3bTyvt2j37Kl6/o3Ax/0RCFPUsI1z37GHPsixgu/yf0GwyjRv4mWJGcZipzL1ijB+RVBpSm+IQLZWKjJCI4YWqnJIkQVOm6CClZKVWuyeROuoCzpCmGE9hpGvvcMjmUmu6wb7gH4Rnczm0b3lZQQzzynIlyzkMyaqgsq979hUlhGVP8foKRQK8HJes3c2B0t3EKEpYnQb/ffzw6+b6B3x0vxijf610uAnjvuzlAUapXPDklss3hMZpBOXE2SZHg5I0CZHo0OjZl6s5Zmi8gFNRuuL257o5iyMumfxRn2A+GqIMrQsqOeF3iMSI0Q2vIkttid0mh13Kq4IpcnznBSu4Ugel9We7nvcA8QeJ0TPwsqrx4uSPY0i7hpdttI2XU4FXf4J0Zok1Yr7tLiI8S7iKEYEOlFKE7vlML5ccO5zMJqJs6O8Vt9viobXXfJFrM7e6OVyIYabpdyTEzMmYwiQhptxrYCIGWZJUgHR5TxI2ljNzTm4ijdNehY38ChvtDHdyIwHNSBfjSetcdrwSUHbbZHZ1MpOfKOlPKEKdg8tuHS5fg+t9whBdUMR/364DcIMSr6ucNDirAwg0S33CYxy/XRsFlmojy2/dSZv6Ve36QazQMsaMplOW0vadkGcA1Qm1fmEz9RubhhJKwgsRKgj2RXC5xFMVGLTG7Gvh+ZvAcwCkNFxLeLfCJhcSPvuvReFbUdg2csFOFM0EoaQ8QhTHWzeZtTloGr4d6BQ9tf6sHoN0htjxixoKlXBIN3TBkFU+KtdRFEGGH9Qgqsq4coQRwVsq5yxzD1yS8i6ydctWxaCn1NEujtz0qvdnBozW0ZZru2X/Bv3st00/63XQDzSln1M6RxxwXvrp8Vdj+hlF+hXJB4DGPi6UOXSAkQOgcNJQKPl73HNqcg+8Tu4Bo9RR+Yx9ae7pYeVf7h0IKTvCPad87bVL7qo296wj5/dLc08P1Tt77IIXOHZBTfr5r5N+jt8y/fTUx7Pp19z4fk3j5xFlR6zvlw4+LSasa/1ygsUC57105Sw+t/NpzhizbpQYdIsxx27XdRkTaB35A9M6M2v0/I5Mwhndy/MEQM3zdODF3AnzPH1jYJiesvM8gcZTB3/FrbP5fgxqbkerWx48cF2FFY7hNtyP5RT5mbM29ik8eH4VFGyybTXwsI5FHqdOw/yZDj7w3IHhBfs/lV5mQ3qZBlD55Rgvxq97r//xLvp1+/gBvTe/08/p4uey4quL0XjUv8OPkIYa0d7MSxd+cVLNctaXLpWGOuGh8pwURsN0ReND6CmSHg8jOuUy/sTUbSX8euZ2iPvjhfi87q+DyG1ite4hWkpydsJD1E1ydstD9MuvBJtGjc4RT9PYQXBx/1loVn3/ca19/T8= \ No newline at end of file +7Vpbc9o6EP41PMLY8v0xCUlP27SHKcykfTqjYgXU2hYVcoD8+iNhGSzLBMcl2E2aB+Jd3b/9tNKu3bOu4vU7ChfzTyREUQ8Y4bpnDXsAAMs2+D+h2WSawHczxYziMFOZe8UYPyKplO1mKQ7RUqnICIkYXqjKKUkSNGWKDlJKVmq1exKpoy7gDGmK8RRGuvYOh2wutaYb7Av+QXg2l0P7wMsKYphXlitZzmFIVgWVdd2zrighLHuK11coEuDluGTtbg6U7iZGUcLqNPjv44dfN9c/4KP7xRj9C9LhJoz7spcHGKVywZNbLt8QGqcRlBNnmxwNStIkRKJDo2ddruaYofECTkXpituf6+Ysjrhk8kd9gvloiDK0LqjkhN8hEiNGN7yKLLUkdpscdimvCqbI8Z0XrOBKHZTWn+163gPEHyRGz8ALVOPFyR/HkHYNL8toGy+7Aq/+BOnMEmvEfNtdRHiWcBUjAh0opQjd85leLjl2OJlNRNnQ3ytut8VDsNd8kWszt7o5XIhhpul3JMTMyZjCJCGm3GtgIgZZklSAdHlPEjaWM7NPbiKN016FjfwKG+0Md3IjOZqRLsaT1rlseyWgrLbJ7OpkJj9R0p9QhDoHl9U6XL4G1/uEIbqgiP++XQfgBiVeVzlp56wOINAs9QmPcfx2bRQA1UbAb91Jm/pV7fpBrBAYY0bTKUtp+07IMxzVCbV+YTP1G5uGEkrCCxEqCPZFcLnEUxUYtMbsa+H5m8Bz4EhpuJbwboVNLiR89l+LwreisG3kOjtRNBOEkvIIURxv3WTW5qBp+HagU/TU+rN6DNIZYscvaihUwiHd0AVDVvmoXEdRBBl+UIOoKuPKEUYEb6mcs8w9cEnKu8jWLVsVg55SR7s4ctOr3p8ZMFpHW67tlv0b9LPeNv3A66Cf05R+dukcsZ3z0k+PvxrTzyjSr0g+x9HYx4Uyhw4wcuAonDQUSv4e9+ya3HNeJ/cco9RR+Yx9ae7pYeVf7h0IKTvCPbt87bVK7qo298CR8/uluaeH6p09dp0XOHadmvTzXyf9bL9l+umpj2fTr7nx/ZrGzyPKjljfLx18WkxY1/rlBAtwznvpyll8bufTnDFm3Sgx6BZjjt2u6zIm0DryByY4M2v0/I5Mwhndy/MEjprn6cCLuRPmefrGwDA9Zed5Ao2nDv6KW2fz/RjU3I6gWx48cF2FFbbhNtyP5RT5mbM21ik8eH4VFGyyLDXwAMcij1OnYf5MBx947sDwgv2fSi+zIb1Mw1H5ZRsvxq97r//xLvp1+/gBvTe/08/p4uey4quL0XjUv8OPkIYa0d7MSxd+cVLNctaXLpWGOuGh8pwURsN0ReND6CmSHg8jOuUy/sTUbSX8euZ2iPvjhfi87q+DyG0CWvcQLSU5O+Eh6iY5u+Uh+uVXgk2jRvuIp2nsILi4/yw0q77/uNa6/h8= \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java index 32555fc..766b49a 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java @@ -1,7 +1,7 @@ package cambio.tltea.interpreter; import cambio.tltea.interpreter.nodes.cause.EventActivationListener; -import cambio.tltea.interpreter.nodes.cause.InteractionNode; +import cambio.tltea.interpreter.nodes.cause.CauseNode; import cambio.tltea.interpreter.nodes.TriggerNotifier; import cambio.tltea.parser.core.ASTNode; import org.jetbrains.annotations.Contract; @@ -17,13 +17,13 @@ */ public final class BehaviorInterpretationResult { private ASTNode modifiedAST; - private InteractionNode interpretedAST; + private CauseNode interpretedAST; private List listeners; private TriggerNotifier triggerNotifier; /** */ - public BehaviorInterpretationResult(ASTNode modifiedAST, InteractionNode interpretedAST, + public BehaviorInterpretationResult(ASTNode modifiedAST, CauseNode interpretedAST, List listeners, TriggerNotifier triggerNotifier) { this.modifiedAST = modifiedAST; @@ -65,11 +65,11 @@ void setModifiedAST(ASTNode modifiedAST) { this.modifiedAST = modifiedAST; } - public InteractionNode getInterpretedAST() { + public CauseNode getInterpretedAST() { return interpretedAST; } - void setInterpretedAST(InteractionNode interpretedAST) { + void setInterpretedAST(CauseNode interpretedAST) { this.interpretedAST = interpretedAST; } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java index 4a64eb0..b9495df 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java @@ -1,15 +1,39 @@ package cambio.tltea.interpreter; +import cambio.tltea.interpreter.nodes.ImplicationNode; import cambio.tltea.interpreter.nodes.TriggerNotifier; import cambio.tltea.interpreter.nodes.cause.*; +import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode; +import cambio.tltea.interpreter.nodes.consequence.EventActivationDescription; import cambio.tltea.interpreter.utils.ASTManipulator; import cambio.tltea.parser.core.*; +import cambio.tltea.parser.core.temporal.ITemporalExpressionValueHolder; +import cambio.tltea.parser.core.temporal.ITemporalValue; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** + * Expects a future MTL formula. + *

+ * Operators G[...] - Globally/Always F[...] - Finally/Eventually N[...] - Next + *

+ * Binary R[...] - Release U[...] - Until + *

+ * Not Allowed: + *

+ * S[...] - Since H[...] - History (always in the past) P[...] - Past (Once in the Past) Back to + *

+ *

+ *

+ * Simplifications: + *

+ * F[...] α = TRUE U[...] β R[...] α = NOT β U[...] NOT α N[TimeInstance] α = FALSE U[...] α + *

+ *

+ * NOT G NOT α = F α NOT F NOT α = G α + * * @author Lion Wagner */ class BehaviorInterpreter { @@ -22,13 +46,16 @@ class BehaviorInterpreter { public BehaviorInterpretationResult interpret(ASTNode ast) { var workCopy = ast.clone(); result.setModifiedAST(workCopy); + + workCopy = ASTManipulator.insertImplicitGloballyRoot(workCopy); + var interpretedAST = interpretAsCause(workCopy); result.setInterpretedAST(interpretedAST); return result; } - private InteractionNode interpretAsCause(ASTNode root) { + private CauseNode interpretAsCause(ASTNode root) { if (root instanceof ValueASTNode valueNode) { return interpretAsCause(valueNode); } else if (root instanceof UnaryOperationASTNode unNode) { @@ -39,7 +66,7 @@ private InteractionNode interpretAsCause(ASTNode root) { return null; } - private InteractionNode interpretAsCause(UnaryOperationASTNode unNode) { + private CauseNode interpretAsCause(UnaryOperationASTNode unNode) { switch (unNode.getOperator()) { case NOT -> { if (unNode.getChild() instanceof UnaryOperationASTNode child @@ -47,29 +74,30 @@ private InteractionNode interpretAsCause(UnaryOperationASTNode unNode) interpretAsCause(ASTManipulator.removeDoubleNot(unNode)); }//TODO: replace !true / !false with false / true var child = interpretAsCause(unNode.getChild()); - return new NotInteractionNode((InteractionNode) child); + return new NotCauseNode((CauseNode) child); } - default -> throw new UnsupportedOperationException("Operator not yet supported: " + unNode.getOperator()); + default -> throw new UnsupportedOperationException( + "Operator not supported for cause description (left side of implication): " + unNode.getOperator()); } } - private InteractionNode interpretAsCause(BinaryOperationASTNode binaryNode) { + private CauseNode interpretAsCause(BinaryOperationASTNode binaryNode) { switch (binaryNode.getOperator()) { case IFF: { interpretAsCause(ASTManipulator.splitIFF(binaryNode)); } case IMPLIES: { - var left = (InteractionNode) interpretAsCause(binaryNode.getLeftChild()); + var left = (CauseNode) interpretAsCause(binaryNode.getLeftChild()); var right = interpretAsBehavior(binaryNode.getRightChild()); return new ImplicationNode(left, right, result.getTriggerNotifier()); } case AND: { - var children = flattenRequirement(binaryNode); - return new AndInteractionNode(children.toArray(new InteractionNode[0])); + var children = flattenCause(binaryNode); + return new AndCauseNode(children.toArray(new CauseNode[0])); } case OR: { - var children = flattenRequirement(binaryNode); - return new OrInteractionNode(children.toArray(new InteractionNode[0])); + var children = flattenCause(binaryNode); + return new OrCauseNode(children.toArray(new CauseNode[0])); } default: { throw new UnsupportedOperationException("Operator not yet supported: " + binaryNode.getOperator()); @@ -77,42 +105,43 @@ private InteractionNode interpretAsCause(BinaryOperationASTNode binaryN } } - private InteractionNode interpretAsCause(ValueASTNode valueNode) { + private CauseNode interpretAsCause(ValueASTNode valueNode) { try { double d = Double.parseDouble(valueNode.getValue()); - return new FixedValueDescription<>(d); + return new ConstantValueProvider<>(d); } catch (NumberFormatException e) { - } if (valueNode.getValue().startsWith("(") && valueNode.getValue().endsWith(")")) { - ActivatableEvent activatableEvent = new ActivatableEvent(valueNode.getValue()); - result.addListener(activatableEvent.getEventListener()); - return activatableEvent; + EventActivationNode eventActivationNode = new EventActivationNode(valueNode.getValue()); + result.addListener(eventActivationNode.getEventListener()); + return eventActivationNode; } else if (valueNode.getValue().startsWith("[") && valueNode.getValue().endsWith("]")) { //TODO: return value watcher } - return new FixedValueDescription<>(valueNode.getValue()); + return new ConstantValueProvider<>(valueNode.getValue()); } @SuppressWarnings("unchecked") //should be safe casting - private List> flattenRequirement(BinaryOperationASTNode root) { - List> children = new ArrayList<>(); + private List> flattenCause(BinaryOperationASTNode root) { + List> children = new ArrayList<>(); if (root.getLeftChild() instanceof BinaryOperationASTNode leftChild && leftChild.getOperator() == root.getOperator()) { - children.addAll(flattenRequirement(leftChild)); + children.addAll(flattenCause(leftChild)); } else { - children.add((InteractionNode) interpretAsCause(root.getLeftChild())); + children.add((CauseNode) interpretAsCause(root.getLeftChild())); } if (root.getRightChild() instanceof BinaryOperationASTNode rightChild && rightChild.getOperator() == root.getOperator()) { - children.addAll(flattenRequirement(rightChild)); + children.addAll(flattenCause(rightChild)); } else { - children.add((InteractionNode) interpretAsCause(root.getRightChild())); + children.add((CauseNode) interpretAsCause(root.getRightChild())); } + //TODO: map EventActivationListeners to ComparisonNodes (==TRUE) + return children; } @@ -124,4 +153,39 @@ private String interpretAsBehavior(ASTNode node) { throw new IllegalArgumentException("Expected Value Node"); } } + + private ConsequenceNode interpretAsConsequence(ASTNode node) { + return interpretAsConsequence(node, null); + } + + private ConsequenceNode interpretAsConsequence(ASTNode node, ITemporalValue tmpvalue) { + if (node instanceof BinaryOperationASTNode binode) { + return interpretAsConsequence(binode, tmpvalue); + } else if (node instanceof UnaryOperationASTNode unode) { + return interpretAsConsequence(unode, tmpvalue); + } else if (node instanceof ValueASTNode vnode) { + return interpretAsConsequence(vnode, tmpvalue); + } + return null; + } + + private ConsequenceNode interpretAsConsequence(ValueASTNode node, ITemporalValue tmpvalue) { + return new EventActivationDescription(node.getValue(), tmpvalue); + } + + private ConsequenceNode interpretAsConsequence(UnaryOperationASTNode node, ITemporalValue tmpvalue) { + if (node instanceof ITemporalExpressionValueHolder valueHolder) { + tmpvalue = valueHolder.getTemporalValue(); + } else { + throw new IllegalArgumentException("Unsupported Operation"); + } + return interpretAsConsequence(node.getChild(), tmpvalue); + } + + private ConsequenceNode interpretAsConsequence(BinaryOperationASTNode node, ITemporalValue tmpvalue) { + + return null; + } + } + diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt new file mode 100644 index 0000000..b7cfcd4 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt @@ -0,0 +1,19 @@ +@file:JvmName("CauseDescription") + +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.cause.CauseNode +import cambio.tltea.interpreter.nodes.cause.EventActivationListener + +class CauseDescription( + val causeASTRoot: CauseNode, + private val listeners: List +) { + + val causeChangeListener: StateChangedPublisher = causeASTRoot + + fun getListeners(): List { + return listeners.toList() + } + +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt new file mode 100644 index 0000000..2bbc7d9 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt @@ -0,0 +1,131 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.cause.* +import cambio.tltea.interpreter.utils.ASTManipulator +import cambio.tltea.parser.core.* + +class CauseInterpreter { + + private val listeners = mutableListOf() + + fun interpretLTL(root: ASTNode): CauseDescription { + val interpretedRoot: CauseNode = interpretAsCause(root) + return CauseDescription(interpretedRoot, listeners) + } + + + private fun interpretAsCause(root: ASTNode): CauseNode { + return when (root) { + is ValueASTNode -> { + interpretAsCauseEvent(root) + } + is UnaryOperationASTNode -> { + interpretAsCause(root) + } + is BinaryOperationASTNode -> { + interpretAsCause(root) + } + else -> { + throw IllegalArgumentException("Unsupported ASTNode type: ${root.javaClass.name}"); + } + } + } + + private fun interpretAsCause( + unNode: UnaryOperationASTNode + ): CauseNode { + + when (unNode.operator) { + OperatorToken.NOT -> { + if (unNode.child is ValueASTNode) { + @Suppress("UNCHECKED_CAST") + return NotCauseNode(interpretAsCauseEvent(unNode.child as ValueASTNode)) + } else return (interpretAsCause(ASTManipulator.applyNot(unNode))) + } + else -> { + throw UnsupportedOperationException("Operator not supported for cause description (left side of implication): " + unNode.getOperator()); + } + } + } + + private fun interpretAsCauseEvent(valueNode: ValueASTNode): CauseNode { + if (valueNode.value.startsWith("(") && valueNode.value.endsWith(")")) { + val eventActivationNode = EventActivationNode(valueNode.value) + listeners.add(eventActivationNode.eventListener) + + //wrap event activation in a ==True comparison + return ComparisonCauseNode(OperatorToken.EQ, null, eventActivationNode, ConstantValueProvider(true)) + } else if (valueNode.value.contains("$")) { + TODO("A value watcher cannot be created yet.") + } + throw UnsupportedOperationException( + "Value %s cannot be interpreted as event Activation. Try wrapping it in parenthesis like '(%s)'.".format( + valueNode.value, + valueNode.value + ) + ) + } + + private fun interpretAsValue(valueNode: ValueASTNode): ValueProvider<*> { + try { + val d = valueNode.value.toDouble() + return ConstantValueProvider(d) + } catch (e: NumberFormatException) { + } + return ConstantValueProvider(valueNode.value) + } + + + private fun interpretAsCause(binaryNode: BinaryOperationASTNode): CauseNode { + return when (binaryNode.operator) { + OperatorToken.AND -> { + val children = flattenCause(binaryNode) + AndCauseNode(*children.toTypedArray()) + } + OperatorToken.OR -> { + val children = flattenCause(binaryNode) + OrCauseNode(*children.toTypedArray()) + } + else -> { + if (OperatorToken.ComparisonOperatorTokens.contains(binaryNode.operator) + && binaryNode.leftChild is ValueASTNode + && binaryNode.rightChild is ValueASTNode + ) { + return ComparisonCauseNode( + binaryNode.operator, + null, + interpretAsValue(binaryNode.leftChild as ValueASTNode), + interpretAsValue(binaryNode.rightChild as ValueASTNode) + ) + } + + throw UnsupportedOperationException( + "Operator not yet supported as cause description: " + + binaryNode.operator + + "\n(left side of implication)" + ) + } + } + } + + private fun flattenCause(root: BinaryOperationASTNode): List { + val children = mutableListOf() + + val leftChild = root.leftChild + if (leftChild is BinaryOperationASTNode && leftChild.operator == root.operator) { + children.addAll(flattenCause(leftChild)) + } else { + children.add(interpretAsCause(leftChild)) + } + + val rightChild = root.rightChild + if (rightChild is BinaryOperationASTNode && rightChild.operator == root.operator) { + children.addAll(flattenCause(rightChild)) + } else { + children.add(interpretAsCause(rightChild)) + } + + return children + } + +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt new file mode 100644 index 0000000..6f911c5 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt @@ -0,0 +1,14 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode + +class ConsequenceDescription { + + fun activateConsequence() { + consequenceAST?.activateConsequence() + } + + var consequenceAST: ConsequenceNode? = null + + +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt new file mode 100644 index 0000000..edc1135 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt @@ -0,0 +1,170 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode +import cambio.tltea.interpreter.nodes.consequence.EventActivationConsequenceNode +import cambio.tltea.interpreter.nodes.consequence.EventPreventionConsequenceNode +import cambio.tltea.interpreter.utils.ASTManipulator +import cambio.tltea.parser.core.* +import cambio.tltea.parser.core.temporal.* + + +//until => left is true till right is true +class ConsequenceInterpreter private constructor(private val triggerNotifier: TriggerNotifier) { + + constructor() : this(TriggerNotifier()) + + + fun interpretAsMTL(mtlRoot: ASTNode): ConsequenceDescription { + + val consequenceDescription = ConsequenceDescription() + //gather initial temporal info + val temporalContext = if (mtlRoot is ITemporalOperationInfoHolder) mtlRoot.toTemporalOperatorInfo() + else TemporalOperatorInfo(OperatorToken.GLOBALLY, TemporalInterval(0.0, Double.POSITIVE_INFINITY)) + + val consequnceAST = interpret(mtlRoot, temporalContext, consequenceDescription) + consequenceDescription.consequenceAST = consequnceAST + return consequenceDescription + } + + /** + * General matcher function + */ + private fun interpret( + node: ASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + return when (node) { + is TemporalBinaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) + is TemporalUnaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) + is BinaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) + is UnaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) + is ValueASTNode -> interpret(node, temporalContext, consequenceDescription) + else -> { + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + } + } + + } + + + private fun interpret( + node: TemporalBinaryOperationASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + val temporalContext = node.toTemporalOperatorInfo() + if (node.leftChild is ITemporalOperationInfoHolder || node.rightChild is ITemporalOperationInfoHolder) { + throw IllegalArgumentException("Cannot interpret two consecutive temporal operators") + } + if (node.operator != OperatorToken.UNTIL) { + throw IllegalArgumentException("Cannot interpret temporal operator ${node.operator}") + } + // UNTIL + + + } + + private fun interpret( + node: TemporalUnaryOperationASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + if (node.child is ITemporalOperationInfoHolder) { + throw IllegalArgumentException("Cannot interpret two consecutive temporal operators") + } + //Prophecy, Globally, Finally, Next + + } + + + private fun interpret( + node: BinaryOperationASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + if (node is TemporalBinaryOperationASTNode) { + return interpret(node, temporalContext, consequenceDescription) + } else if (OperatorToken.ComparisonOperatorTokens.contains(node.operator)) { + //create consequnce comparison node + } else when (node.operator) { + OperatorToken.IMPLIES -> { + //create implication node + return interpretImplication(node, temporalContext, consequenceDescription) + } + OperatorToken.AND -> { + //create consequence and node + } + OperatorToken.OR -> { + //create consequence or node + } + OperatorToken.IFF -> { + //split <-> into <- and -> + return interpret(ASTManipulator.splitIFF(node), temporalContext, consequenceDescription) + } + else -> { + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + } + } + + } + + private fun interpret( + node: UnaryOperationASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + if (node.operator == OperatorToken.NOT) { + val child = node.child + if (child is ValueASTNode) { + var value = child.value; + if (child.value.startsWith("(") && child.value.endsWith(")")) { + value = child.value.substring(1, child.value.length - 1) + } + return EventPreventionConsequenceNode(triggerNotifier, temporalContext, value) + } else if (child is UnaryOperationASTNode && child.operator == OperatorToken.NOT) { + interpret(ASTManipulator.removeDoubleNot(node), temporalContext, consequenceDescription) + } else { + interpret(ASTManipulator.applyNot(node), temporalContext, consequenceDescription) + } + + } else { + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + } + } + + private fun interpret( + node: ValueASTNode, + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription + ): ConsequenceNode { + if (node.value.startsWith("(") && node.value.endsWith(")")) { + val value = node.value.substring(1, node.value.length - 1) + return EventActivationConsequenceNode(triggerNotifier, temporalContext, value) + } else { + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + } + } + + private fun interpretImplication( + root: BinaryOperationASTNode, + temporalContext: TemporalOperatorInfo + ): ConsequenceNode { + if (root.operator != OperatorToken.IMPLIES) { + throw IllegalArgumentException("Expected operator ${OperatorToken.IMPLIES}, but found ${root.operator}") + } + + val left = root.leftChild + val right = root.rightChild + + val cause = CauseInterpreter().interpretLTL(left) + val consequence = ConsequenceInterpreter(triggerNotifier).interpretAsMTL(right) + + return ImplicationNode( + cause, + consequence, + temporalContext, + triggerNotifier + ) + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt new file mode 100644 index 0000000..85e2421 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt @@ -0,0 +1,33 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +/** + * @author Lion Wagner + */ +class ImplicationNode( + private val causeDescription: CauseDescription, + private val consequence: ConsequenceDescription, + temporalContext: TemporalOperatorInfo, + triggerNotifier: TriggerNotifier +) : ConsequenceNode(triggerNotifier, temporalContext), StateChangeListener { + + override fun activateConsequence() { + triggerNotifier.activateListeners(causeDescription.getListeners()) + } + + override fun onEvent(event: StateChangeEvent) { + //activate consequence if the new value carried by the event is "true" + if (event.newValue) { + consequence.activateConsequence() + } + } + + /** + * @return whether the cause expression is satisfied + */ + val currentValue: Boolean + get() = causeDescription.causeASTRoot.currentValue + +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeEvent.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeEvent.java index afeb45d..a3b4620 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeEvent.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeEvent.java @@ -1,10 +1,13 @@ package cambio.tltea.interpreter.nodes; +import cambio.tltea.parser.core.temporal.ITemporalValue; + /** * @author Lion Wagner */ public record StateChangeEvent(StateChangedPublisher publisher, - T newValue, T oldValue) { + T newValue, T oldValue, ITemporalValue when) { + public T getNewValue() { return newValue; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java index ad2a6b8..1b86521 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangeListener.java @@ -1,6 +1,6 @@ package cambio.tltea.interpreter.nodes; -import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.parser.core.temporal.ITemporalValue; @FunctionalInterface public interface StateChangeListener{ diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java index 977b7d6..9ad6082 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java @@ -1,7 +1,12 @@ package cambio.tltea.interpreter.nodes; +import cambio.tltea.interpreter.nodes.cause.EventActivationListener; +import cambio.tltea.interpreter.nodes.cause.EventActivationNode; +import org.jetbrains.annotations.NotNull; + import java.util.Collection; import java.util.HashSet; +import java.util.List; /** * @author Lion Wagner @@ -23,4 +28,8 @@ public void trigger(String eventName, Object... args) { listener.onTrigger(eventName, args); } } + + public void activateListeners(@NotNull List listeners) { + + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java similarity index 71% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java index 1dec285..d4bc80c 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java @@ -2,7 +2,7 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.StateChangedPublisher; +import cambio.tltea.interpreter.nodes.TriggerNotifier; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; @@ -10,19 +10,19 @@ /** * @author Lion Wagner */ -public class AndInteractionNode extends InteractionNode implements StateChangeListener { +public class AndCauseNode extends CauseNode implements StateChangeListener { private boolean state = false; - private final LinkedList> children = new LinkedList<>(); + private final LinkedList children = new LinkedList<>(); private final AtomicInteger trueCount = new AtomicInteger(0); - public AndInteractionNode(InteractionNode... children) { - for (InteractionNode child : children) { + public AndCauseNode( CauseNode... children) { + for (CauseNode child : children) { this.children.add(child); child.subscribe(this); - if (child.getValue()) { + if (child.getCurrentValue()) { trueCount.incrementAndGet(); } } @@ -41,13 +41,13 @@ public void onEvent(StateChangeEvent event) { state = trueCount.get() == this.children.size(); if (oldSate != state) { - notifySubscribers(new StateChangeEvent<>(this, true, false)); + notifySubscribers(new StateChangeEvent<>(this, true, false, event.when())); } } } @Override - public Boolean getValue() { + public Boolean getCurrentValue() { return state; } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java new file mode 100644 index 0000000..a272d75 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java @@ -0,0 +1,16 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.interpreter.nodes.StateChangedPublisher; +import cambio.tltea.interpreter.nodes.TriggerNotifier; + +/** + * @author Lion Wagner + */ +public abstract class CauseNode extends StateChangedPublisher { + + public abstract Boolean getCurrentValue(); + + public CauseNode() { + } +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java new file mode 100644 index 0000000..a5e6c03 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java @@ -0,0 +1,85 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.interpreter.nodes.StateChangeEvent; +import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.interpreter.nodes.TriggerNotifier; +import cambio.tltea.parser.core.OperatorToken; +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; + +/** + * @author Lion Wagner + */ +public class ComparisonCauseNode extends CauseNode implements StateChangeListener { + private final OperatorToken operator; + private final ValueProvider left; + private final ValueProvider right; + + public ComparisonCauseNode(OperatorToken operator, + TemporalOperatorInfo temporalContext, + ValueProvider left, + ValueProvider right) { + if (!OperatorToken.ComparisonOperatorTokens.contains(operator)) { + throw new IllegalArgumentException("Operator not supported as comparison: " + operator); + } + this.operator = operator; + this.left = left; + this.right = right; + } + + + //TODO: optimization we always take the same path through this method therefore we may be able to optimize + @Override + public Boolean getCurrentValue() { + var val1 = left.getCurrentValue(); + var val2 = right.getCurrentValue(); + + if (val1 == null || val2 == null) { + return false; + } + if (val1 instanceof String && val2 instanceof String) { + return switch (operator) { + case EQ -> val1.equals(val2); + case NEQ -> !val1.equals(val2); + default -> throw new IllegalArgumentException("Operator not supported for string comparison:" + operator); + }; + } else if (val1 instanceof Number n1 && val2 instanceof Number n2) { + return switch (operator) { + case EQ -> val1.equals(val2); + case NEQ -> !val1.equals(val2); + case GT -> n1.doubleValue() > n2.doubleValue(); + case GEQ -> n1.doubleValue() >= n2.doubleValue(); + case LT -> n1.doubleValue() < n2.doubleValue(); + case LEQ -> n1.doubleValue() <= n2.doubleValue(); + default -> throw new IllegalArgumentException("Operator not supported as comparison: " + operator); + }; + } else if (val1 instanceof Comparable || val2 instanceof Comparable) { + try { + int compareValue = 0; + if (val1 instanceof Comparable c1) { + compareValue = c1.compareTo(val2); + } else //noinspection ConstantConditions + if (val2 instanceof Comparable c2) { + compareValue = -c2.compareTo(val1);//need to be reversed because we are comparing the other way around + } + return switch (operator) { + case EQ -> compareValue == 0; + case NEQ -> compareValue != 0; + case GT -> compareValue > 0; + case GEQ -> compareValue >= 0; + case LT -> compareValue < 0; + case LEQ -> compareValue <= 0; + default -> throw new IllegalArgumentException("Operator not supported as comparison: " + operator); + }; + } catch (ClassCastException ignored) { + } + } + + throw new IllegalArgumentException("Value type could not be compared: " + val1.getClass() + " and " + val2.getClass()); + } + + + @Override + public void onEvent(StateChangeEvent event) { + + } +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java deleted file mode 100644 index 2ffdbd1..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonInteractionNode.java +++ /dev/null @@ -1,49 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - -import cambio.tltea.parser.core.OperatorToken; - -/** - * @author Lion Wagner - */ -public class ComparisonInteractionNode extends InteractionNode { - private final OperatorToken operator; - private final IValueDescription left; - private final IValueDescription right; - - public ComparisonInteractionNode(OperatorToken operator, - IValueDescription left, - IValueDescription right) { - this.operator = operator; - this.left = left; - this.right = right; - } - - - @Override - public Boolean getValue() { - var val1 = left.getValue(); - var val2 = right.getValue(); - - if (val1 == null || val2 == null) { - return false; - } - if (val1 instanceof String && val2 instanceof String) { - return switch (operator) { - case EQ -> val1.equals(val2); - case NEQ -> !val1.equals(val2); - default -> throw new IllegalArgumentException("Operator not supported for string comparison:" + operator); - }; - } else if (val1 instanceof Number n1 && val2 instanceof Number n2) { - return switch (operator) { - case EQ -> val1.equals(val2); - case NEQ -> !val1.equals(val2); - case GT -> n1.doubleValue() > n2.doubleValue(); - case GEQ -> n1.doubleValue() >= n2.doubleValue(); - case LT -> n1.doubleValue() < n2.doubleValue(); - case LEQ -> n1.doubleValue() <= n2.doubleValue(); - default -> throw new IllegalArgumentException("Operator not supported as comparison: " + operator); - }; - } - else throw new IllegalArgumentException("Value type could not be compared: " + val1.getClass() + " and " + val2.getClass()); - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java new file mode 100644 index 0000000..5838dd9 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java @@ -0,0 +1,22 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.interpreter.nodes.TriggerNotifier; + +/** + * @author Lion Wagner + */ +public class ConstantValueProvider extends ValueProvider { + + protected final T value; + + public ConstantValueProvider(T value) { + super(); + this.value = value; + } + + @Override + public T getCurrentValue() { + return value; + } + +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java index 2eaac70..3f04b37 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java @@ -2,6 +2,7 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangedPublisher; +import cambio.tltea.parser.core.temporal.ITemporalValue; /** * @author Lion Wagner @@ -25,24 +26,27 @@ public boolean isActivated() { } - public void setActivated() { - activate(); + public void setActivated(ITemporalValue time) { + activate(time); } - public void activate() { - notifyAndChangeState(true); + public void activate(ITemporalValue time) { + notifyAndChangeState(true, time); } - public void reset() { - deactivate(); + public void reset(ITemporalValue time) { + deactivate(time); } - public void deactivate() { - notifyAndChangeState(false); + public void deactivate(ITemporalValue time) { + notifyAndChangeState(false, time); } - private void notifyAndChangeState(boolean activated) { - subscribers.forEach(listener -> listener.onEvent(new StateChangeEvent<>(this, activated, this.activated))); + private void notifyAndChangeState(boolean activated, ITemporalValue time) { + subscribers.forEach(listener -> listener.onEvent(new StateChangeEvent<>(this, + activated, + this.activated, + time))); this.activated = activated; } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java similarity index 68% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java index aff0150..e21740a 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ActivatableEvent.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java @@ -3,16 +3,17 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.interpreter.nodes.TriggerNotifier; import org.jetbrains.annotations.NotNull; /** * @author Lion Wagner */ -public final class ActivatableEvent extends IValueDescription implements StateChangeListener { +public final class EventActivationNode extends ValueProvider implements StateChangeListener { private final EventActivationListener listener; - public ActivatableEvent(String eventName) { + public EventActivationNode(String eventName) { listener = new EventActivationListener(eventName); listener.subscribe(this); } @@ -22,12 +23,12 @@ public EventActivationListener getEventListener() { } @Override - public @NotNull Boolean getValue() { + public @NotNull Boolean getCurrentValue() { return listener.isActivated(); } @Override public void onEvent(StateChangeEvent event) { - notifySubscribers(new StateChangeEvent<>(this, event.getNewValue(), event.getOldValue())); + notifySubscribers(new StateChangeEvent<>(this, event.getNewValue(), event.getOldValue(), event.when())); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java deleted file mode 100644 index b76817e..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/FixedValueDescription.java +++ /dev/null @@ -1,19 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - -/** - * @author Lion Wagner - */ -public class FixedValueDescription extends IValueDescription { - - protected final T value; - - public FixedValueDescription(T value) { - this.value = value; - } - - @Override - public T getValue() { - return value; - } - -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java deleted file mode 100644 index bacee89..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/IValueDescription.java +++ /dev/null @@ -1,5 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - -public abstract class IValueDescription extends InteractionNode { - public abstract T getValue(); -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java deleted file mode 100644 index b3b1ba6..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ImplicationNode.java +++ /dev/null @@ -1,38 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - -import cambio.tltea.interpreter.nodes.StateChangeEvent; -import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.TriggerNotifier; - -/** - * @author Lion Wagner - */ -public class ImplicationNode extends InteractionNode implements StateChangeListener { - - private final InteractionNode cause; - private final String consequence; - private final TriggerNotifier notifier; - - public ImplicationNode(InteractionNode cause, String consequence, TriggerNotifier notifier) { - this.cause = cause; - this.consequence = consequence; - this.notifier = notifier; - - cause.subscribe(this); - } - - @Override - public void onEvent(StateChangeEvent event) { - if (event.getNewValue()) { - notifier.trigger(consequence); - } - } - - /** - * @return whether the cause expression is satisfied - */ - @Override - public Boolean getValue() { - return cause.getValue(); - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java deleted file mode 100644 index d25582c..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/InteractionNode.java +++ /dev/null @@ -1,10 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - -import cambio.tltea.interpreter.nodes.StateChangedPublisher; - -/** - * @author Lion Wagner - */ -public abstract class InteractionNode extends StateChangedPublisher { - public abstract T getValue(); -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java similarity index 54% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java index edfe618..bb43b3c 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java @@ -2,26 +2,27 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.interpreter.nodes.TriggerNotifier; /** * @author Lion Wagner */ -public final class NotInteractionNode extends InteractionNode implements StateChangeListener { +public final class NotCauseNode extends CauseNode implements StateChangeListener { - private final InteractionNode child; + private final CauseNode child; - public NotInteractionNode(InteractionNode child) { + public NotCauseNode(CauseNode child) { this.child = child; child.subscribe(this); } @Override - public Boolean getValue() { - return !child.getValue(); + public Boolean getCurrentValue() { + return !child.getCurrentValue(); } @Override public void onEvent(StateChangeEvent event) { - this.notifySubscribers(new StateChangeEvent<>(this, !event.getNewValue(), !event.getOldValue())); + this.notifySubscribers(new StateChangeEvent<>(this, !event.getNewValue(), !event.getOldValue(), event.when())); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java similarity index 71% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java index 5fcce51..a370b95 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrInteractionNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java @@ -3,6 +3,9 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; import cambio.tltea.interpreter.nodes.StateChangedPublisher; +import cambio.tltea.interpreter.nodes.TriggerNotifier; +import cambio.tltea.parser.core.temporal.ITemporalValue; +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; @@ -10,20 +13,20 @@ /** * @author Lion Wagner */ -public class OrInteractionNode extends InteractionNode implements StateChangeListener { +public class OrCauseNode extends CauseNode implements StateChangeListener { private boolean state = false; - private final LinkedList> children = new LinkedList<>(); + private final LinkedList children = new LinkedList<>(); private final AtomicInteger trueCount = new AtomicInteger(0); - public OrInteractionNode(InteractionNode... children) { + public OrCauseNode(CauseNode... children) { for (var child : children) { this.children.add(child); child.subscribe(this); - if (child.getValue()) { + if (child.getCurrentValue()) { trueCount.incrementAndGet(); } } @@ -42,13 +45,13 @@ public void onEvent(StateChangeEvent event) { state = trueCount.get() > 0; if (oldSate != state) { - notifySubscribers(new StateChangeEvent<>(this, true, false)); + notifySubscribers(new StateChangeEvent<>(this, true, false, event.when())); } } } @Override - public Boolean getValue() { + public Boolean getCurrentValue() { return state; } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java new file mode 100644 index 0000000..1ced1eb --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java @@ -0,0 +1,11 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.interpreter.nodes.StateChangedPublisher; +import cambio.tltea.interpreter.nodes.TriggerNotifier; + +public abstract class ValueProvider extends StateChangedPublisher { + public abstract T getCurrentValue(); + + public ValueProvider() { + } +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt new file mode 100644 index 0000000..0ab886c --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt @@ -0,0 +1,10 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier + +class ActivationConsequenceNode(triggerNotifier: TriggerNotifier) : ConsequenceNode(triggerNotifier) { + override fun activateConsequence() { + TODO("Not yet implemented") + } + +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt new file mode 100644 index 0000000..2b0d3e7 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt @@ -0,0 +1,41 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.parser.core.OperatorToken +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + + +abstract class ActivationDescription( + open val temporalContext: TemporalOperatorInfo, + open val activationNode: ConsequenceNode +) + +data class OrActivationDescription( + override val temporalContext: TemporalOperatorInfo, + override val activationNode: OrConsequenceNode, + val children: List +) : ActivationDescription(temporalContext, activationNode) + + +class ComparisonActivationDescription( + override val temporalContext: TemporalOperatorInfo, + override val activationNode: ComparisonConsequenceNode, + val operator: OperatorToken, + val left: ValueConsequenceNode<*>, + val right: ValueConsequenceNode<*> +) : ActivationDescription(temporalContext, activationNode) { + +} + +class EventActivationDescription( + override val temporalContext: TemporalOperatorInfo, + override val activationNode: ConsequenceNode, + val eventName: String +) : ActivationDescription(temporalContext, activationNode) { +} + +class EventPreventionActivationDescription( + override val temporalContext: TemporalOperatorInfo, + override val activationNode: ConsequenceNode, + val eventName: String +) : ActivationDescription(temporalContext, activationNode) { +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt new file mode 100644 index 0000000..a1ea1fa --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt @@ -0,0 +1,17 @@ +@file:JvmName("AndConsequence") + +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +class AndConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + children: List +) : + ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { + override fun activateConsequence() { + children.forEach { it.activateConsequence() } + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt new file mode 100644 index 0000000..5feb7d0 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt @@ -0,0 +1,10 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +abstract class ChildrenOwningConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + protected val children: List +) : ConsequenceNode(triggerNotifier, temporalContext) \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt new file mode 100644 index 0000000..8ee51cb --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt @@ -0,0 +1,3 @@ +package cambio.tltea.interpreter.nodes.consequence + +class ConsequenceDescriptionTree diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java deleted file mode 100644 index e4c5c0f..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.java +++ /dev/null @@ -1,15 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence; - -import cambio.tltea.interpreter.nodes.StateChangeEvent; -import cambio.tltea.interpreter.nodes.StateChangedPublisher; - -import java.util.LinkedList; - -/** - * @author Lion Wagner - */ -public abstract class ConsequenceNode { - - public abstract LinkedList activate(); - -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt new file mode 100644 index 0000000..cfe07e5 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt @@ -0,0 +1,16 @@ +@file:JvmName("ConsequenceNode") + +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +/** + * @author Lion Wagner + */ +abstract class ConsequenceNode( + protected val triggerNotifier: TriggerNotifier, + protected val temporalContext: TemporalOperatorInfo +) { + abstract fun activateConsequence() +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java deleted file mode 100644 index b3f5657..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationDescription.java +++ /dev/null @@ -1,9 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence; - -import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; - -/** - * @author Lion Wagner - */ -public record EventActivationDescription(String eventName, TemporalOperatorInfo temporalOperatorInfo) { -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt new file mode 100644 index 0000000..9c48f6a --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt @@ -0,0 +1,29 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +abstract class EventConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo +) : ConsequenceNode(triggerNotifier, temporalContext) + +class EventActivationConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + private val eventName: String, +) : EventConsequenceNode(triggerNotifier, temporalContext) { + override fun activateConsequence() { + TODO("Not yet implemented") + } +} + +class EventPreventionConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + private val eventName: String, +) : ConsequenceNode(triggerNotifier, temporalContext) { + override fun activateConsequence() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt new file mode 100644 index 0000000..130c367 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt @@ -0,0 +1,14 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier + +/** + * @author Lion Wagner + */ +class ComparisonConsequenceNode(triggerNotifier: TriggerNotifier) : ConsequenceNode(triggerNotifier) { + override fun execute() { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt new file mode 100644 index 0000000..4a70383 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt @@ -0,0 +1,14 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +class OrConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + children: List +) : ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { + override fun activateConsequence() { + } + +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt new file mode 100644 index 0000000..fd69c9e --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt @@ -0,0 +1,22 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +abstract class ValueConsequenceNode(triggerNotifier: TriggerNotifier, val value: T, + temporalContext: TemporalOperatorInfo +) : + ConsequenceNode(triggerNotifier, temporalContext) { + override fun activateConsequence() { + throw UnsupportedOperationException("Value consequence nodes cannot be activated") + } +} + +class NumberConsequenceNode(triggerNotifier: TriggerNotifier, value: Double) : + ValueConsequenceNode(triggerNotifier, value) + +class StringConsequenceNode(triggerNotifier: TriggerNotifier, value: String) : + ValueConsequenceNode(triggerNotifier, value) + +class BooleanConsequenceNode(triggerNotifier: TriggerNotifier, value: Boolean) : + ValueConsequenceNode(triggerNotifier, value) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java index 6a56190..0910c50 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java @@ -1,6 +1,8 @@ package cambio.tltea.interpreter.utils; import cambio.tltea.parser.core.*; +import cambio.tltea.parser.core.temporal.TemporalUnaryOperationASTNode; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; /** @@ -49,45 +51,145 @@ public final class ASTManipulator { /** - * Removes double negation from an AST. - * Accepts both parent and child negation nodes as input. - * E.g. morphs (a) && !!(b) into (a) && (b), if given the first or second NOT node as input. - * + * Removes double negation from an AST. Accepts both parent and child negation nodes as input. E.g. morphs (a) && + * !!(b) into (a) && (b), if given the first or second NOT node as input. + *

* It is recommended to always use the parent as input to ensure a correct interpretation. * - * @param unNode Negation node that should be removed. + * @param doubleNotParent Negation node that should be removed. * @return The node that was double negated. */ - public static @NotNull ASTNode removeDoubleNot(@NotNull UnaryOperationASTNode unNode) { - if (unNode.getOperator() != OperatorToken.NOT) { + public static @NotNull OperatorASTNode removeDoubleNot(@NotNull UnaryOperationASTNode doubleNotParent) { + if (doubleNotParent.getOperator() != OperatorToken.NOT) { throw new IllegalArgumentException("Expected a NOT node."); } - ASTNode targetChild = null; - ASTNode targetParent = null; - if (unNode.getParent() instanceof UnaryOperationASTNode unParent && - unParent.getOperator() == OperatorToken.NOT) { - targetChild = unNode.getChild(); - targetParent = unParent.getParent(); - } else if (unNode.getChild() instanceof UnaryOperationASTNode unChild && - unChild.getOperator() == OperatorToken.NOT) { - targetChild = unChild.getChild(); - targetParent = unNode.getParent(); + if (doubleNotParent.getChild() instanceof UnaryOperationASTNode doubleNotChild && doubleNotChild.getOperator() == OperatorToken.NOT) { + redirectParent(doubleNotParent.getParent(), + doubleNotParent, + ((UnaryOperationASTNode) doubleNotParent.getChild()).getChild()); + return doubleNotParent.getParent(); + } + return doubleNotParent; + } + + public static TemporalUnaryOperationASTNode insertImplicitGloballyRoot(ASTNode root) { + if (root instanceof TemporalUnaryOperationASTNode temporalNode) { + return temporalNode; + } + + var newNode = new TemporalUnaryOperationASTNode(OperatorToken.GLOBALLY, root); + insertBefore(root, newNode); + return newNode; + } + + public static TemporalUnaryOperationASTNode insertImplicitFinallyRoot(ASTNode root) { + if (root instanceof TemporalUnaryOperationASTNode temporalNode) { + return temporalNode; + } + + var newNode = new TemporalUnaryOperationASTNode(OperatorToken.FINALLY, root); + insertBefore(root, newNode); + return newNode; + } + + + public static ASTNode applyNot(@NotNull UnaryOperationASTNode notNode) { + if (notNode.getOperator() != OperatorToken.NOT) { + throw new IllegalArgumentException("Expected a NOT node."); } - if (targetChild == null) { - throw new IllegalStateException("Expected a double NOT node. Or remaining child was empty."); + if (notNode.getChild() instanceof BinaryOperationASTNode binaryNode) { + if (OperatorToken.ComparisonOperatorTokens.contains(binaryNode.getOperator())) { + return applyNotToComparison(binaryNode); + } + + return switch (binaryNode.getOperator()) { + case AND -> applyNotToAnd(binaryNode); + case OR -> applyNotToOr(binaryNode); + default -> throw new IllegalArgumentException("Operator not supported."); + }; } + else if(notNode.getChild() instanceof UnaryOperationASTNode unaryChild && + unaryChild.getOperator() == OperatorToken.NOT) { + return removeDoubleNot(unaryChild); + } + throw new IllegalArgumentException("Cannot apply NOT (yet?) to " + notNode.getChild() + .getClass() + .getSimpleName() + " node."); + } - if (targetParent instanceof BinaryOperationASTNode binParent) { - if (binParent.getLeftChild() == unNode) { - binParent.setLeftChild(targetChild); + @Contract("_ -> new") + private static @NotNull OperatorASTNode applyNotToOr(@NotNull BinaryOperationASTNode binaryNode) { + return new BinaryOperationASTNode(OperatorToken.AND, + new UnaryOperationASTNode(OperatorToken.NOT, binaryNode.getLeftChild()), + new UnaryOperationASTNode(OperatorToken.NOT, binaryNode.getRightChild())); + } + + @Contract("_ -> new") + private static @NotNull OperatorASTNode applyNotToAnd(@NotNull BinaryOperationASTNode binaryNode) { + return new BinaryOperationASTNode(OperatorToken.OR, + new UnaryOperationASTNode(OperatorToken.NOT, binaryNode.getLeftChild()), + new UnaryOperationASTNode(OperatorToken.NOT, binaryNode.getRightChild())); + } + + + /** + * Inserts the insertedNode before the currentNode. + * + * @param currentNode + * @param insertedNode + */ + private static void insertBefore(ASTNode currentNode, UnaryOperationASTNode insertedNode) { + redirectParent(currentNode.getParent(), currentNode, insertedNode); + } + + /** + * Replaces the given oldChild with the newChild. Does handle {@link UnaryOperationASTNode}s and {@link + * BinaryOperationASTNode}s. + * + * This does not replace the relation that the oldChild potentially has to its children! + * + * @param parent The parent of the oldChild. + * @param oldChild The child that should be replaced. + * @param newChild The new child that should replace the oldChild. + */ + public static void redirectParent(@NotNull OperatorASTNode parent, + @NotNull ASTNode oldChild, + @NotNull ASTNode newChild) { + if (parent instanceof UnaryOperationASTNode unParent) { + if (unParent.getChild() == oldChild) { + unParent.setChild(newChild); + } else { + throw new IllegalStateException("Expected oldChild to be a child of parent."); + } + } else if (parent instanceof BinaryOperationASTNode binParent) { + if (binParent.getLeftChild() == oldChild) { + binParent.setLeftChild(newChild); + } else if (binParent.getRightChild() == oldChild) { + binParent.setRightChild(newChild); } else { - binParent.setRightChild(targetChild); + throw new IllegalStateException("Expected oldChild to be a child of parent."); } - } else if (targetParent instanceof UnaryOperationASTNode unParent) { - unParent.setChild(targetChild); + } else { + throw new IllegalStateException("Unexpected parent type: " + parent.getClass().getSimpleName()); } + } - return targetChild; + private static BinaryOperationASTNode applyNotToComparison(@NotNull BinaryOperationASTNode comparisonNode) { + OperatorToken reversedOperator = switch (comparisonNode.getOperator()) { + case EQ -> OperatorToken.NEQ; + case NEQ -> OperatorToken.EQ; + case LT -> OperatorToken.GEQ; + case LEQ -> OperatorToken.GT; + case GT -> OperatorToken.LEQ; + case GEQ -> OperatorToken.LT; + default -> throw new IllegalStateException("Unexpected operator."); + }; + UnaryOperationASTNode notParent = (UnaryOperationASTNode) comparisonNode.getParent(); + BinaryOperationASTNode replacer = new BinaryOperationASTNode(reversedOperator, + comparisonNode.getLeftChild(), + comparisonNode.getRightChild()); + redirectParent(notParent.getParent(), notParent, replacer); + return replacer; } } diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java new file mode 100644 index 0000000..3b32cf1 --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java @@ -0,0 +1,26 @@ +package cambio.tltea.interpreter; + +import cambio.tltea.interpreter.nodes.cause.EventActivationListener; +import cambio.tltea.parser.core.ASTNode; +import cambio.tltea.parser.core.temporal.TimeInstance; +import cambio.tltea.parser.mtl.generated.MTLParser; +import cambio.tltea.parser.mtl.generated.ParseException; +import org.junit.jupiter.api.Test; + +class BehaviorInterpreterTest { + @Test + void debugTest() throws ParseException { + String input = "((P)&(C)&(D))->(Q)"; + ASTNode ast = new MTLParser(input).parse(); + BehaviorInterpreter behaviorInterpreter = new BehaviorInterpreter(); + var result = behaviorInterpreter.interpret(ast); + + result.getTriggerNotifier().subscribe((eventName, args) -> { + System.out.println(eventName); + }); + + result.getListeners().forEach(eventActivationListener -> eventActivationListener.activate(new TimeInstance(0))); + + System.out.println(result); + } +} \ No newline at end of file diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt new file mode 100644 index 0000000..93d117c --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt @@ -0,0 +1,20 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.parser.mtl.generated.MTLParser +import org.junit.jupiter.api.Test + +import org.junit.jupiter.api.Assertions.* + +internal class ConsequenceInterpreterTest { + + @Test + fun interpretSimpleImplication() { + val formula = "(a) -> (b)" + val ast = MTLParser.parse(formula) + val interpretationResult = ConsequenceInterpreter().interpretAsMTL(ast) + + println(interpretationResult.consequenceAST) + + + } +} \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/ASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/ASTNode.java index 7c854f1..51a84a1 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/ASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/ASTNode.java @@ -1,5 +1,7 @@ package cambio.tltea.parser.core; +import java.io.PrintStream; + /** * @author Lion Wagner */ @@ -20,8 +22,26 @@ protected final void setParent(OperatorASTNode parent) { this.parent = parent; } + public final int depth() { + if (parent == null) { + return 0; + } + return 1 + parent.depth(); + } + public abstract int getSize(); + public abstract int getTreeWidth(); + + public final void printTree() { + printTree(System.out); + } + + public final void printTree(PrintStream out) { + ASTNodePrinter.INSTANCE.print(this, out); + } + + /** * Get children count. */ @@ -46,6 +66,8 @@ public String toString() { '}'; } + public abstract String toFormulaString(); + public boolean isBracketed() { return isBracketed; } diff --git a/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt b/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt new file mode 100644 index 0000000..7f5816d --- /dev/null +++ b/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt @@ -0,0 +1,121 @@ +package cambio.tltea.parser.core + +import java.io.PrintStream +import kotlin.math.min + +internal object ASTNodePrinter { + + private const val DEFAULT_CONSOLE_COLUMN_COUNT = 80 + + fun print(root: ASTNode) { + print(root, System.out) + } + + fun print(root: ASTNode, out: PrintStream) { + val treeWidth = root.treeWidth * 3 // *3 to reserve width of <-> + if (treeWidth > DEFAULT_CONSOLE_COLUMN_COUNT) { + out.printf( + "[TL-Tea] Warning: Tree might be to large (~%d columns) to be printed properly on a default console (80 columns)%n", + treeWidth + ) + } + val dataMap1 = mutableMapOf>() + dataMap1[root] = Pair(treeWidth, true) + + val dataMap = createNodeInfo(root, treeWidth, dataMap1) + val sb = StringBuilder() + print(sb, root, dataMap) + out.println(sb.toString()) + } + + private fun createNodeInfo( + root: ASTNode, + totalWidth: Int, + dataMap: MutableMap> + ): Map> { + when (root) { + is UnaryOperationASTNode -> { + dataMap[root.child] = Pair(totalWidth, true) + createNodeInfo(root.child, totalWidth, dataMap) + } + is BinaryOperationASTNode -> { + dataMap[root.leftChild] = Pair(totalWidth/2, false) + dataMap[root.rightChild] = Pair(totalWidth/2, true) + createNodeInfo(root.leftChild, totalWidth / 2, dataMap) + createNodeInfo(root.rightChild, totalWidth / 2, dataMap) + } + } + return dataMap + } + + private fun print(sb: StringBuilder, node: ASTNode, widthData: Map>) { + var currentDepth = 0 + val stack = ArrayDeque() + val lastDepthNodes = mutableListOf() + stack.addFirst(node) + + while (stack.isNotEmpty()) { + val current = stack.removeFirst() + if (current.depth() > currentDepth) { + sb.append("\n") + currentDepth = current.depth() + + for (node in lastDepthNodes) { + when (node) { + is UnaryOperationASTNode -> { + printWithPadding(sb, widthData[node]!!.first, "|") + } + is BinaryOperationASTNode -> { + val quaterLength = widthData[node]!!.first / 4 + printWithPadding(sb, quaterLength + 1, "") + printWithPadding(sb, quaterLength, "/") + sb.append(" ") + printWithPadding(sb, quaterLength, "\\", false) + printWithPadding(sb, quaterLength + 1, "")// + } + } + } + sb.append("\n") + lastDepthNodes.clear() + } + lastDepthNodes.add(current) + printWithPadding(sb, widthData[current]!!.first, current.toFormulaString(), widthData[current]!!.second) + + when (current) { + is UnaryOperationASTNode -> { + stack.addLast(current.child) + } + is BinaryOperationASTNode -> { + stack.addLast(current.leftChild) + stack.addLast(current.rightChild) + } + } + } + } + + + private fun printWithPadding(sb: StringBuilder, totalLength: Int, s: String, preferRightPadding: Boolean = true) { + var leftPadding = (totalLength - s.length) / 2 + var rightPadding = leftPadding + if ((totalLength % 2 == 0) xor (s.length % 2 == 0)) { + if (preferRightPadding) { + rightPadding++ + } else { + leftPadding++ + } + } + if (rightPadding > 0 || leftPadding > 0) { + for (i in 0 until rightPadding) { + sb.append(" ") + } + sb.append(s) + for (i in 0 until leftPadding) { + sb.append(" ") + } + } else { + sb.append(s.substring(0, min(totalLength, s.length))) + } + } + + +} \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java index 1c33242..8e3a7a2 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/BinaryOperationASTNode.java @@ -84,6 +84,11 @@ public String toString() { '}'; } + @Override + public String toFormulaString() { + return operator.getShorthandImage(); + } + @Override public ASTNode clone() { return new BinaryOperationASTNode(operator, left.clone(), right.clone()); @@ -94,6 +99,11 @@ public int getSize() { return 1 + left.getSize() + right.getSize(); } + @Override + public int getTreeWidth() { + return left.getTreeWidth() + right.getTreeWidth(); + } + @Override public int getChildrenCount() { return 2; @@ -114,10 +124,12 @@ public ASTNode getRightChild() { public void setLeftChild(ASTNode left) { this.left = left; + left.setParent(this); } public void setRightChild(ASTNode right) { this.right = right; + right.setParent(this); } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java index 14e52cf..4bcbb47 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java @@ -7,8 +7,12 @@ public abstract class OperatorASTNode extends ASTNode { protected final OperatorToken operator; public OperatorASTNode(String operatorImage) { + this(OperatorTokenImageMap.INSTANCE.getToken(operatorImage)); + } + + public OperatorASTNode(OperatorToken operator) { super(); - this.operator = OperatorTokenImageMap.INSTANCE.getToken(operatorImage); + this.operator = operator; } public OperatorToken getOperator() { diff --git a/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java b/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java index 5aa2883..dbd0cbb 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java +++ b/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java @@ -1,31 +1,59 @@ package cambio.tltea.parser.core; +import java.util.EnumSet; +import java.util.Set; + public enum OperatorToken { - TRUE(""), - FALSE(""), - NOT(""), - AND(""), - OR(""), - IMPLIES(""), - IFF(""), - EQ(""), - NEQ(""), - LT(""), - LEQ(""), - GT(""), - GEQ(""), - NEXT(""), - GLOBALLY(""), - FINALLY(""), - UNTIL(""), - RELEASE(""), - WEAKUNTIL(""), - UNKNOWN(""); + TRUE("","T"), + FALSE("","F"), + NOT("", "¬"), + AND("", "∧"), + OR("", "∨"), + IMPLIES("", "->"), + IFF("", "<->"), + EQ("", "=="), + NEQ("", "!="), + LT("", "<"), + LEQ("", "<="), + GT("", ">"), + GEQ("", ">="), + NEXT("", "X"), + BEFORE("","B"), + GLOBALLY("","G"), + FINALLY("","F"), + UNTIL("", "U"), + RELEASE("", "R"), + WEAKUNTIL("", "W"), + SINCE("", "S"), + PAST("", "P"), + PROPHECY("", "▷"), + HISTORY("", "H"), + UNKNOWN("", ""); + + public static final Set TemporalOperatorTokens = EnumSet.of(OperatorToken.GLOBALLY, + OperatorToken.FINALLY, + OperatorToken.UNTIL, + OperatorToken.SINCE, + OperatorToken.RELEASE, + OperatorToken.WEAKUNTIL, + OperatorToken.BEFORE, + OperatorToken.NEXT, + OperatorToken.PAST, + OperatorToken.HISTORY, + OperatorToken.PROPHECY); + public static final Set ComparisonOperatorTokens = EnumSet.of(OperatorToken.EQ, + OperatorToken.NEQ, + OperatorToken.LT, + OperatorToken.LEQ, + OperatorToken.GT, + OperatorToken.GEQ); private String image; + private String shorthandImage; - OperatorToken(String image) { + OperatorToken(String image, String shorthandString) { this.image = image; + this.shorthandImage = shorthandString; } public static OperatorToken fromString(String text) { @@ -42,6 +70,7 @@ public static OperatorToken fromString(String text) { private OperatorToken setImage(String image) { this.image = image; + this.shorthandImage = image; return this; } @@ -53,6 +82,14 @@ public String image() { return image; } + public String getShorthandImage() { + return shorthandImage; + } + + public String shorthandImage() { + return shorthandImage; + } + public static OperatorToken UNKNOWN(String image) { return OperatorToken.UNKNOWN.setImage(image); } @@ -61,4 +98,5 @@ public static OperatorToken UNKNOWN(String image) { public String toString() { return String.format("%s[%s]", this.name(), this.image); } + } diff --git a/parser/src/main/java/cambio/tltea/parser/core/UnaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/UnaryOperationASTNode.java index 3be5f7e..9d9039c 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/UnaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/UnaryOperationASTNode.java @@ -10,7 +10,9 @@ public class UnaryOperationASTNode extends OperatorASTNode { private ASTNode child; public UnaryOperationASTNode(@NotNull OperatorToken operator, ASTNode child) { - this(operator.image(), child); + super(operator); + this.child = child; + child.setParent(this); } public UnaryOperationASTNode(String operator, ASTNode child) { @@ -24,12 +26,18 @@ public int getSize() { return getChildrenCount() + child.getSize(); } + @Override + public int getTreeWidth() { + return child.getTreeWidth(); + } + public ASTNode getChild() { return child; } public void setChild(ASTNode child) { this.child = child; + child.setParent(this); } @Override @@ -42,6 +50,11 @@ public boolean isLeaf() { return false; } + @Override + public String toFormulaString() { + return operator.getShorthandImage(); + } + @Override public ASTNode clone() { return new UnaryOperationASTNode(this.operator, child.clone()); diff --git a/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java index 96f0e2d..fb2aad4 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java @@ -20,6 +20,11 @@ public int getSize() { return 1; } + @Override + public int getTreeWidth() { + return 1; + } + @Override public int getChildrenCount() { return 0; @@ -37,6 +42,11 @@ public String toString() { '}'; } + @Override + public String toFormulaString() { + return value; + } + @Override public ASTNode clone() { return new ValueASTNode(value); diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalExpressionValueHolder.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalExpressionValueHolder.java index 3cacafd..db63e6e 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalExpressionValueHolder.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalExpressionValueHolder.java @@ -2,7 +2,11 @@ public interface ITemporalExpressionValueHolder { - public void setTemporalExpressionValue(String temporalValueExpression); + default void setTemporalExpressionValue(String temporalValueExpression){ + setTemporalExpressionValue(TemporalPropositionParser.parse(temporalValueExpression)); + } + + void setTemporalExpressionValue(ITemporalValue temporalValueExpression); ITemporalValue getTemporalValue(); diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalOperationInfoHolder.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalOperationInfoHolder.java new file mode 100644 index 0000000..f9a2e19 --- /dev/null +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalOperationInfoHolder.java @@ -0,0 +1,5 @@ +package cambio.tltea.parser.core.temporal; + +public interface ITemporalOperationInfoHolder { + TemporalOperatorInfo toTemporalOperatorInfo(); +} diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalValue.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalValue.java index ea3fcb7..b0031bb 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalValue.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/ITemporalValue.java @@ -2,7 +2,13 @@ /** * Interface to mark temporal value classes. + *

+ * For available implementations see + * + * @see TemporalInterval + * @see TemporalEventDescription + * @see TimeInstance */ -public interface ITemporalValue { +public sealed interface ITemporalValue permits TemporalInterval, TemporalEventDescription, TimeInstance { } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java index 6ac551e..3d81514 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java @@ -6,7 +6,7 @@ /** * @author Lion Wagner */ -public final class TemporalBinaryOperationASTNode extends BinaryOperationASTNode implements ITemporalExpressionValueHolder { +public final class TemporalBinaryOperationASTNode extends BinaryOperationASTNode implements ITemporalExpressionValueHolder, ITemporalOperationInfoHolder { private ITemporalValue temporalValueExpression; @@ -20,10 +20,14 @@ public TemporalBinaryOperationASTNode(TemporalOperatorInfo operatorInfo, ASTNode this.setTemporalExpressionValue(operatorInfo.temporalValueExpression()); } + @Override + public TemporalOperatorInfo toTemporalOperatorInfo(){ + return new TemporalOperatorInfo(this.getOperator(), this.getTemporalValue()); + } @Override - public void setTemporalExpressionValue(String temporalValueExpression) { - this.temporalValueExpression = TemporalPropositionParser.parse(temporalValueExpression); + public void setTemporalExpressionValue(ITemporalValue temporalValueExpression) { + this.temporalValueExpression = temporalValueExpression; } @Override @@ -31,4 +35,9 @@ public ITemporalValue getTemporalValue() { return temporalValueExpression; } + @Override + public String toFormulaString() { + return super.toFormulaString() + this.getTemporalValue().toString(); + } + } \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java index c63e985..d0256d2 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java @@ -1,35 +1,9 @@ package cambio.tltea.parser.core.temporal; -import java.util.Objects; - -public class TemporalEventDescription implements ITemporalValue { - - private final String value; - - public TemporalEventDescription(String value) { - this.value = value; - } - +public record TemporalEventDescription(String value) implements ITemporalValue { public String getValue() { return value; } - @Override - public String toString() { - return "TemporalEvent: "+ value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TemporalEventDescription that = (TemporalEventDescription) o; - return Objects.equals(value, that.value); - } - - @Override - public int hashCode() { - return Objects.hash(value); - } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java index b3875d4..2b00c74 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalInterval.java @@ -20,8 +20,17 @@ public TemporalInterval(double start, double end, boolean startInclusive) { public TemporalInterval(double start, double end, boolean startInclusive, boolean endInclusive) { this.start = start; this.end = end; - this.startInclusive = startInclusive; - this.endInclusive = endInclusive; + this.startInclusive = startInclusive && start != Double.NEGATIVE_INFINITY; + this.endInclusive = endInclusive && end != Double.POSITIVE_INFINITY; + + if (start > end) { + throw new IllegalArgumentException("Start value must be less than end value"); + } + else if (start == end) { + if (!startInclusive || !endInclusive) { + throw new IllegalArgumentException("Start and end values must be equal if they are not inclusive"); + } + } } public Double getStart() { diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java index 6ccde15..8a9ba9e 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java @@ -3,9 +3,66 @@ import cambio.tltea.parser.core.IOperatorInfo; import cambio.tltea.parser.core.OperatorToken; import cambio.tltea.parser.core.OperatorTokenImageMap; +import org.jetbrains.annotations.Contract; + +import java.util.*; + +public final class TemporalOperatorInfo implements IOperatorInfo { + private final OperatorToken operator; + private final ITemporalValue temporalValueExpression; + + + public TemporalOperatorInfo(OperatorToken operator, ITemporalValue temporalValueExpression) { + if (OperatorToken.TemporalOperatorTokens.contains(operator)) { + throw new IllegalArgumentException("Operator " + operator + " is not allowed"); + } + this.operator = operator; + this.temporalValueExpression = temporalValueExpression; + } -public record TemporalOperatorInfo(OperatorToken operator, String temporalValueExpression) implements IOperatorInfo { public TemporalOperatorInfo(String operatorImage, String temporalValueExpression) { this(OperatorTokenImageMap.INSTANCE.getToken(operatorImage), temporalValueExpression); } + + public TemporalOperatorInfo(String operator, ITemporalValue temporalValueExpression) { + this(OperatorTokenImageMap.INSTANCE.getToken(operator), temporalValueExpression); + } + + public TemporalOperatorInfo(OperatorToken operator, String temporalValueExpression) { + this(operator, TemporalPropositionParser.parse(temporalValueExpression)); + } +@Contract + public OperatorToken operator() { + return operator; + } + + public ITemporalValue temporalValueExpression() { + return temporalValueExpression; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + var that = (TemporalOperatorInfo) obj; + return Objects.equals(this.operator, that.operator) && + Objects.equals(this.temporalValueExpression, that.temporalValueExpression); + } + + @Override + public int hashCode() { + return Objects.hash(operator, temporalValueExpression); + } + + @Override + public String toString() { + return "TemporalOperatorInfo[" + + "operator=" + operator + ", " + + "temporalValueExpression=" + temporalValueExpression + ']'; + } + } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java index 7553274..94ab23c 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java @@ -7,7 +7,7 @@ /** * @author Lion Wagner */ -public final class TemporalUnaryOperationASTNode extends UnaryOperationASTNode implements ITemporalExpressionValueHolder { +public final class TemporalUnaryOperationASTNode extends UnaryOperationASTNode implements ITemporalExpressionValueHolder, ITemporalOperationInfoHolder { ITemporalValue temporalValueExpression; @@ -25,14 +25,23 @@ public TemporalUnaryOperationASTNode(TemporalOperatorInfo operatorInfo, ASTNode this.setTemporalExpressionValue(operatorInfo.temporalValueExpression()); } + @Override + public TemporalOperatorInfo toTemporalOperatorInfo() { + return new TemporalOperatorInfo(this.getOperator(), this.getTemporalValue()); + } @Override - public void setTemporalExpressionValue(String temporalValueExpression) { - this.temporalValueExpression = TemporalPropositionParser.parse(temporalValueExpression); + public void setTemporalExpressionValue(ITemporalValue temporalValueExpression) { + this.temporalValueExpression = temporalValueExpression; } @Override public ITemporalValue getTemporalValue() { return temporalValueExpression; } + + @Override + public String toFormulaString() { + return super.toFormulaString() + this.getTemporalValue().toString(); + } } diff --git a/parser/src/test/java/cambio/tltea/parser/core/ASTNodePrinterTest.kt b/parser/src/test/java/cambio/tltea/parser/core/ASTNodePrinterTest.kt new file mode 100644 index 0000000..5ec58ed --- /dev/null +++ b/parser/src/test/java/cambio/tltea/parser/core/ASTNodePrinterTest.kt @@ -0,0 +1,21 @@ +package cambio.tltea.parser.core + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +internal class ASTNodePrinterTest +{ + @Test + fun testPrint() + { + //create ASTTree for "(!B) & (A | C)" + val leaf1 = ValueASTNode("B") + val leaf2 = ValueASTNode("A") + val leaf3 = ValueASTNode("C") + val node1 = UnaryOperationASTNode(OperatorToken.NOT, leaf1) + val node2 = BinaryOperationASTNode(OperatorToken.OR, leaf2, leaf3) + val root = BinaryOperationASTNode(OperatorToken.AND,node1, node2) + ASTNodePrinter.print(root) + } +} + diff --git a/pom.xml b/pom.xml index 2078b23..b04d664 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,8 @@ 17 17 17 + 1.6.20-M1 + true @@ -32,6 +34,32 @@ org.apache.maven.plugins maven-compiler-plugin 3.2 + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + org.apache.maven.plugins @@ -40,6 +68,44 @@ + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + test-compile + test-compile + + test-compile + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + + 1.8 + + + @@ -62,6 +128,17 @@ 3.12.0 test + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + From 768f1b1c4bd4d657c96390fd2e0cc76c6503105d Mon Sep 17 00:00:00 2001 From: LWagner Date: Mon, 2 May 2022 19:49:29 +0200 Subject: [PATCH 07/17] ConsequenceNodes --- TLTeaInterprtationClasses.drawio | 2 +- .../interpreter/nodes/CauseDescription.kt | 9 +-- .../interpreter/nodes/ImplicationNode.kt | 6 +- .../interpreter/nodes/TriggerNotifier.java | 35 ----------- .../interpreter/nodes/TriggerNotifier.kt | 63 +++++++++++++++++++ .../consequence/ActivationConsequenceNode.kt | 11 ++-- .../consequence/ActivationDescription.kt | 4 +- .../consequence/ConsequenceDescriptionTree.kt | 3 - .../EventActivationConsequenceNode.kt | 14 +++++ .../nodes/consequence/EventActivationData.kt | 28 +++++++++ .../consequence/EventConsequenceNodes.kt | 29 --------- .../EventPreventionConsequenceNode.kt | 14 +++++ .../consequence/GreaterThanConsequence.kt | 14 ----- .../nodes/consequence/OrConsequenceNode.kt | 2 +- .../nodes/consequence/ValueConsequenceNode.kt | 22 ------- .../consequence/ValueEventConsequenceNode.kt | 20 ++++++ .../interpreter/BehaviorInterpreterTest.java | 3 +- .../nodes/ConsequenceInterpreterTest.kt | 3 +- 18 files changed, 160 insertions(+), 122 deletions(-) delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt diff --git a/TLTeaInterprtationClasses.drawio b/TLTeaInterprtationClasses.drawio index 78ad6d0..c690ee0 100644 --- a/TLTeaInterprtationClasses.drawio +++ b/TLTeaInterprtationClasses.drawio @@ -1 +1 @@ -7V1rc6u4Gf41nmk/xIO4CPgYO2d328nJSTdpO7vfFKPY6sHIBZzL/vpKgLhI2JZ9wNhbkpnEvGBh9DzvVRdPrPn64+cYbVZfaYDDiWkEHxPrbmKaNnAA+8cln7nENF0vlyxjEuQyUAmeyB+4EBqFdEsCnDQuTCkNU7JpChc0ivAibchQHNP35mWvNGzedYOWWBE8LVCoSv9NgnRVSAH0qxO/YLJcFbf2TDc/sUbi4uJJkhUK6HtNZH2ZWPOY0jR/tf6Y45D3nuiX/H0/7ThbfrAYR6nOG+b+L+bjP57Q1+cH+vrbf35P/v7P4EY8xhsKt8UTP8Y4IAuU4uJjp5+iL2K6jQLMmzMm1ux9RVL8tEELfvadwc9kq3QdsiPAXgYoWWXX8oNXEoZzGtKYHQf4FW1D9pFnKCTLiEnivPtmbzhO2Z3D20KeUt6m+pzFo/PL8UdNVDz3z5iucRp/skvEWbfAoGCh6xfH7xWk0ChkqxqallMIUUGjZdl21dPsRdHZR3S84Het4+dom+AHpkJKxyfvZB2iCPOepFH6VJwBtT5csN7B8c5OXKxIGNyjT7rlT5akaPFdHM1WNCZ/sGaRgI6djtNCFU3YuOKJv7MgQIwTds2jAAZIoq/oo3HhPUrSQrCgYYg2CXkpH2ON4iWJZjRN6bq4qAPcLauJu22puAPYgjvsDXZTgV1BOyQZ0kka0++l0ZG1KKLZRQL+EL+2adCaBEGYNcb0lETLZ06GuxtQSe6zN95ZleTXohu4KKYpSlEOE8ckRC84fKQJSQmta+6GkijN+sqZTZy7TBKncxqxh0Akww8z+N8xp0ALsvtV5DDewrtAPXi9vtC1WtCdcS+G03uSpDjCcfKXvyqIs8dLS8QlhI8HPdf4Jr62ii8XUfbe1zDzSitGFRy1YN7Edsa6c25MHY6yOWfHoDoeDnjL1gNeEKR75G3VnLNOwP/d4mgxGvUujbpvNI264w5u1OFo1LV129bG+1KMurPDqKNFSt5YnFxT9NG2d4//8LbdUwjwzHRkieMHmpJXwiz0Ebb9x4x2C2Ou1Y5DKTiHsAVouwVox+wJaGG2a0Df0yVXvyw1Gz14R8gDR/LgnqYHF6age+TV8G304Ie05Go8uKnGZ0xhmONeoWiJH7cvIUlWx1nxUb/36LctRejQ0HTh/em36sJH/T6kLVej35YaoT98e+YhrGncPtzxW0YB+/vt14kJs8rzC1N2uMw7BaI1V9XoJeH/yiJsopqDFdrgjAMpx/ZA/fuFaewyq5h/26Y5t4q6ePz9G4c85b1nTA2nI6cqlbhBCyhOGyh96Zyl6tycrtkzkiSh0VgS6dDgmlJA5eqWRHozuLY6vDEa3EOKcjUG11YTpX/xl48xfSMBj6RyM/tcWdlR03sJrbyWkcwza/qYOmlreqk316PpauqU9QGK0krZR93uRLcdz2noNjCcwZV7zJv0lfvq8iZHDdIyNy6GqkfN7moeit/02sAY3G2LIvqo2Yc1u9ST69FsNSj78sF0OlCrGkx4y+dJsqOXkHKlmjFRoXUA5oc/EX7/rOdrJY7mfMCdepLQbbzAez6tSICYui+xTukZB41JmyoMbf0e4xCl5A03PltbzxfNPXIq1SJveQ6hiMRFE/ljFu+q8FMbglJ11JUayrtBaSgjQvmMP8ANtVp2wdwQkB/khqh/DcENC4KpCasfu8kU+0SmmJ43da3qB0i8gefljZoKXDBvBB0O2xQ48qZf3rjXxBtb194MyRvbsqc1fK1m3mifyhsoFZeU2e87mMIwQ5+1y4ogbPfH9yRX6jRWLrAXeYvd0lBNZUsaGuUokChbGjelqChgGg/b9UtW2myIL4/Bjq7lE1QfhMGeM7UtX/w2DZ9/cmhl2lMHGuVvk83yBLGj2dy5ZVQX3/w5KSlKI91RsgD8xpgC22rAXE7C74O1hj31fNu1oGfz8px06yqtPz4ncKasPRNawHHZHYTPFArh6VG3aldcSF9fE9yLW4dq8Wgf9QKC1jQKnlckajAONOho2gN7dZGKDhINSqO4UHa/umxywIGGOvLj8vIq33D79+NQVN9qRvONEeI2n41NaDSWL7ueXiDxCRi66+h6K1/CtpVWEtxj+VLSmKspX8I9JSqtwGhGaYhRdPmRkcDmooN1qfLpg1PrElJ+6Xo/6pe6Dmpc1bmcEtQYZwlqxGc7HNQ4w3EHyLn+qSGy7IQcuaGOghppEN7xzxDTuOZue3d5NkvQ6aKHaywLTGsJldvM1BTLo81C25vWEkBTICcibVMKeHqurbpqGHQbBePK455WHku2DHqmXpzUWxjsjpPvtMPgUleuJgx2r2rETfTv4ZFaezi3IG8eUC5CPbrGYvAhGOB7lmc4ELq+VGz2L63Y7KrDcDU/cYeTRUw2mR6O7mKya8eqLpyIxED9PYl6cyLqMMToRA5p0dU4EWCoir/PfXRRqM9UWDRYsOLIDj48wUN7hodo8gJKJ0BebafrbuR2gESXwd0LaNnQrrlNSl6WZ8rMN0lRl2EevaNKjX0dba5SWqa2pZ2HwqSOzIXubidy3NKZvfCuqQTm684c9XRjzmpg2ZLHlXcD0/HAX7ll6NETeJwdsUXHNTJoNu9j2XuKZOcclBYJ+VUMSgvjcNEJkyeVXRXDo8tNX+aMvB3b4C7MU4spf1tvQr4XLhkXrHe795PEKtveM2nnLJU0r22XtzEJ2q8oV5ME+Sq62cbbh0PLg2pcIpkp08699XjXo21Kk6Ikd0TU2oW+SQvQbKAWHdq2WpMDke4AadkchO+8MtahzlWHkidvWYPP6fHHOpS2Cfavbs8QYLTF5vWpPOxcmNUI9g5viF0vB1wypJ1M1vq6beslp5sQHcoLCk8O0eUJqCIq6zh9lOenihWRvc6xAIbGlMGLyQ21uegPOGHZl3GUV7JqVze9Aw0NnhsCQ00OWyNIjsM99wT9hZGaLqIivOwjym/LKW4zqX8hTVusYEwteZmF1QmDTKlRyd70VygChpoRAAXMP2s6YMn61pIOmOdMB4CxZynUbhs91FQHEQBcdOXOlnI+z/enfu1HCvS0lypJzSr7IHRVY5buIxan9hsktHw/zybfH5gJy69wUceveLpqVEtQ9pF2EaIkIYuB4wZwQtzQYwzryGjL1WHtIRBbakierN7zjEzQ8h1AFYOylUoqeyri7DV3/TJH26ZdFnN8w5gaBnBMxzYtl1m5ptE7dQ0dABBOWUIEXdeHjESguSKzWgJ1Nl6pkwFjvOQWKR6MM9qrV07JUnrkjDQUdfq6XXlahiFvvdCRM7xRVuA1t0w4+AbrHFssAKBONfq/KrP7khdzWjZw7KjMzg6rrw7NAay+gdX68j8= \ No newline at end of file +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 \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt index b7cfcd4..8b052ed 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt @@ -7,13 +7,14 @@ import cambio.tltea.interpreter.nodes.cause.EventActivationListener class CauseDescription( val causeASTRoot: CauseNode, - private val listeners: List + private val listeners: List, + private val triggerNotifier: TriggerNotifier ) { - val causeChangeListener: StateChangedPublisher = causeASTRoot + val causeChangePublisher: StateChangedPublisher = causeASTRoot - fun getListeners(): List { - return listeners.toList() + fun activateListeners() { + triggerNotifier.activateListeners(listeners) } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt index 85e2421..24cc7c7 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt @@ -14,7 +14,11 @@ class ImplicationNode( ) : ConsequenceNode(triggerNotifier, temporalContext), StateChangeListener { override fun activateConsequence() { - triggerNotifier.activateListeners(causeDescription.getListeners()) + //activate listeners to input of cause + causeDescription.activateListeners() + + //activate self listening to changes + causeDescription.causeChangePublisher.subscribe(this) } override fun onEvent(event: StateChangeEvent) { diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java deleted file mode 100644 index 9ad6082..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.java +++ /dev/null @@ -1,35 +0,0 @@ -package cambio.tltea.interpreter.nodes; - -import cambio.tltea.interpreter.nodes.cause.EventActivationListener; -import cambio.tltea.interpreter.nodes.cause.EventActivationNode; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.HashSet; -import java.util.List; - -/** - * @author Lion Wagner - */ -public class TriggerNotifier { - - protected final Collection subscribers = new HashSet<>(); - - public final void subscribe(ITriggerListener listener) { - subscribers.add(listener); - } - - public final void unsubscribe(ITriggerListener listener) { - subscribers.remove(listener); - } - - public void trigger(String eventName, Object... args) { - for (ITriggerListener listener : subscribers) { - listener.onTrigger(eventName, args); - } - } - - public void activateListeners(@NotNull List listeners) { - - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt new file mode 100644 index 0000000..7738b9a --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt @@ -0,0 +1,63 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.cause.EventActivationListener +import cambio.tltea.interpreter.nodes.consequence.ActivationData +import java.util.function.Consumer + +/** + * @author Lion Wagner + */ +class TriggerNotifier { + + private val anySubscribers: MutableCollection>> = HashSet() + + private val filteredSubscribers: HashMap>, MutableSet>>> = + HashMap() + + fun subscribeEventListener(listener: Consumer>) { + anySubscribers.add(listener) + } + + fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) { + if (!filteredSubscribers.containsKey(filter)) { + filteredSubscribers[filter] = HashSet() + } + filteredSubscribers[filter]!!.add(listener) + } + + fun unsubscribe(listener: Consumer>) { + anySubscribers.remove(listener) + filteredSubscribers.values.forEach { it.remove(listener) } + } + + internal fun trigger(activationData: ActivationData<*>) { + anySubscribers.forEach { it.accept(activationData) } + filteredSubscribers[activationData.javaClass]?.forEach { it.accept(activationData) } + } + + private val eventActivationListeners: MutableCollection> = HashSet() + private val listenerActivationQueue: MutableList = ArrayList() + + + /** + * Subscribes a listener that will be notified when a new event listener is activated. + */ + fun subscribeListenerActivationListener(listener: Consumer) { + eventActivationListeners.add(listener) + activateListeners(listenerActivationQueue) + listenerActivationQueue.clear() + } + + fun unsubscribeListenerActivationListener(listener: Consumer) { + eventActivationListeners.remove(listener) + } + + internal fun activateListeners(listeners: Collection) { + if (eventActivationListeners.isEmpty()) { + listenerActivationQueue.addAll(listeners) + } + listeners.forEach { eventListener -> + eventActivationListeners.forEach { it.accept(eventListener) } + } + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt index 0ab886c..dc023dd 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt @@ -1,10 +1,9 @@ package cambio.tltea.interpreter.nodes.consequence import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo -class ActivationConsequenceNode(triggerNotifier: TriggerNotifier) : ConsequenceNode(triggerNotifier) { - override fun activateConsequence() { - TODO("Not yet implemented") - } - -} +abstract class ActivationConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo +) : ConsequenceNode(triggerNotifier, temporalContext) \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt index 2b0d3e7..46fbdc0 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt @@ -20,8 +20,8 @@ class ComparisonActivationDescription( override val temporalContext: TemporalOperatorInfo, override val activationNode: ComparisonConsequenceNode, val operator: OperatorToken, - val left: ValueConsequenceNode<*>, - val right: ValueConsequenceNode<*> + val left: ValueEventConsequenceNode<*>, + val right: ValueEventConsequenceNode<*> ) : ActivationDescription(temporalContext, activationNode) { } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt deleted file mode 100644 index 8ee51cb..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceDescriptionTree.kt +++ /dev/null @@ -1,3 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence - -class ConsequenceDescriptionTree diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt new file mode 100644 index 0000000..1985b87 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt @@ -0,0 +1,14 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +class EventActivationConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + private val eventName: String, +) : ActivationConsequenceNode(triggerNotifier, temporalContext) { + override fun activateConsequence() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt new file mode 100644 index 0000000..a42e031 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt @@ -0,0 +1,28 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.parser.core.OperatorToken +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +abstract class ActivationData(val data: T, val temporalContext: TemporalOperatorInfo) + +class EventPreventionData(eventName: String, temporalContext: TemporalOperatorInfo) : + ActivationData(eventName, temporalContext) + +class EventActivationData(eventName: String, temporalContext: TemporalOperatorInfo) : + ActivationData(eventName, temporalContext) + +class ValueEventActivationData( + data: T, + temporalContext: TemporalOperatorInfo, + operator: OperatorToken +) : ActivationData( + data, + temporalContext +) { + + init { + if (!OperatorToken.ComparisonOperatorTokens.contains(operator)) { + throw IllegalArgumentException("Operator must be a comparison operator") + } + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt deleted file mode 100644 index 9c48f6a..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventConsequenceNodes.kt +++ /dev/null @@ -1,29 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence - -import cambio.tltea.interpreter.nodes.TriggerNotifier -import cambio.tltea.parser.core.temporal.TemporalOperatorInfo - -abstract class EventConsequenceNode( - triggerNotifier: TriggerNotifier, - temporalContext: TemporalOperatorInfo -) : ConsequenceNode(triggerNotifier, temporalContext) - -class EventActivationConsequenceNode( - triggerNotifier: TriggerNotifier, - temporalContext: TemporalOperatorInfo, - private val eventName: String, -) : EventConsequenceNode(triggerNotifier, temporalContext) { - override fun activateConsequence() { - TODO("Not yet implemented") - } -} - -class EventPreventionConsequenceNode( - triggerNotifier: TriggerNotifier, - temporalContext: TemporalOperatorInfo, - private val eventName: String, -) : ConsequenceNode(triggerNotifier, temporalContext) { - override fun activateConsequence() { - TODO("Not yet implemented") - } -} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt new file mode 100644 index 0000000..c8105bf --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt @@ -0,0 +1,14 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +class EventPreventionConsequenceNode( + triggerNotifier: TriggerNotifier, + temporalContext: TemporalOperatorInfo, + private val eventName: String, +) : ActivationConsequenceNode(triggerNotifier, temporalContext) { + override fun activateConsequence() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt deleted file mode 100644 index 130c367..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/GreaterThanConsequence.kt +++ /dev/null @@ -1,14 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence - -import cambio.tltea.interpreter.nodes.TriggerNotifier - -/** - * @author Lion Wagner - */ -class ComparisonConsequenceNode(triggerNotifier: TriggerNotifier) : ConsequenceNode(triggerNotifier) { - override fun execute() { - TODO("Not yet implemented") - } - - -} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt index 4a70383..d1d87ec 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt @@ -9,6 +9,6 @@ class OrConsequenceNode( children: List ) : ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { override fun activateConsequence() { + TODO("Not yet implemented") } - } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt deleted file mode 100644 index fd69c9e..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueConsequenceNode.kt +++ /dev/null @@ -1,22 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence - -import cambio.tltea.interpreter.nodes.TriggerNotifier -import cambio.tltea.parser.core.temporal.TemporalOperatorInfo - -abstract class ValueConsequenceNode(triggerNotifier: TriggerNotifier, val value: T, - temporalContext: TemporalOperatorInfo -) : - ConsequenceNode(triggerNotifier, temporalContext) { - override fun activateConsequence() { - throw UnsupportedOperationException("Value consequence nodes cannot be activated") - } -} - -class NumberConsequenceNode(triggerNotifier: TriggerNotifier, value: Double) : - ValueConsequenceNode(triggerNotifier, value) - -class StringConsequenceNode(triggerNotifier: TriggerNotifier, value: String) : - ValueConsequenceNode(triggerNotifier, value) - -class BooleanConsequenceNode(triggerNotifier: TriggerNotifier, value: Boolean) : - ValueConsequenceNode(triggerNotifier, value) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt new file mode 100644 index 0000000..32e7efa --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt @@ -0,0 +1,20 @@ +package cambio.tltea.interpreter.nodes.consequence + +import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo + +class ValueEventConsequenceNode( + triggerNotifier: TriggerNotifier, + val value: T, + temporalContext: TemporalOperatorInfo +) : ActivationConsequenceNode(triggerNotifier, temporalContext) { + + override fun activateConsequence() { + throw UnsupportedOperationException("Value consequence nodes cannot be activated") + + } + + fun getType(): Class { + return value::class.javaObjectType + } +} diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java index 3b32cf1..d931e1f 100644 --- a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java +++ b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java @@ -1,6 +1,5 @@ package cambio.tltea.interpreter; -import cambio.tltea.interpreter.nodes.cause.EventActivationListener; import cambio.tltea.parser.core.ASTNode; import cambio.tltea.parser.core.temporal.TimeInstance; import cambio.tltea.parser.mtl.generated.MTLParser; @@ -15,7 +14,7 @@ void debugTest() throws ParseException { BehaviorInterpreter behaviorInterpreter = new BehaviorInterpreter(); var result = behaviorInterpreter.interpret(ast); - result.getTriggerNotifier().subscribe((eventName, args) -> { + result.getTriggerNotifier().subscribeEventListener((eventName, args) -> { System.out.println(eventName); }); diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt index 93d117c..e736ed8 100644 --- a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt +++ b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreterTest.kt @@ -1,5 +1,6 @@ package cambio.tltea.interpreter.nodes +import cambio.tltea.interpreter.nodes.consequence.ValueEventActivationData import cambio.tltea.parser.mtl.generated.MTLParser import org.junit.jupiter.api.Test @@ -14,7 +15,5 @@ internal class ConsequenceInterpreterTest { val interpretationResult = ConsequenceInterpreter().interpretAsMTL(ast) println(interpretationResult.consequenceAST) - - } } \ No newline at end of file From 402fc78b11224c32a4434626c615a561d262cd90 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 3 May 2022 17:34:35 +0200 Subject: [PATCH 08/17] Forward! --- TLTeaInterprtationClasses.drawio | 2 +- .../BehaviorInterpretationResult.java | 88 -------- .../BehaviorInterpretationResult.kt | 33 +++ .../interpreter/BehaviorInterpreter.java | 191 ----------------- .../cambio/tltea/interpreter/Interpreter.java | 12 -- .../cambio/tltea/interpreter/Interpreter.kt | 15 ++ .../interpreter/nodes/CauseDescription.kt | 9 +- .../interpreter/nodes/CauseInterpreter.kt | 6 +- .../nodes/ConsequenceDescription.kt | 9 +- .../nodes/ConsequenceInterpreter.kt | 195 +++++++++++++----- .../nodes/ISubscribableTriggerNotifier.kt | 10 + .../interpreter/nodes/ImplicationNode.kt | 8 + .../interpreter/nodes/TriggerNotifier.kt | 35 +--- .../nodes/cause/ComparisonCauseNode.java | 20 +- .../nodes/cause/ConstantValueProvider.java | 13 +- .../nodes/cause/EventActivationListener.java | 16 +- .../nodes/cause/EventActivationNode.java | 34 --- .../nodes/cause/ValueListener.java | 13 ++ .../nodes/cause/ValueProvider.java | 25 ++- .../consequence/ActivationDescription.kt | 41 ---- .../nodes/consequence/AndConsequenceNode.kt | 6 +- .../ChildrenOwningConsequenceNode.kt | 2 +- .../nodes/consequence/ConsequenceNode.kt | 1 + .../EventActivationConsequenceNode.kt | 4 + .../EventPreventionConsequenceNode.kt | 4 + .../nodes/consequence/OrConsequenceNode.kt | 4 + .../consequence/ValueEventConsequenceNode.kt | 10 +- .../interpreter/utils/ASTManipulator.java | 44 ++-- .../nodes/cause/ComparisonCauseNodeTest.java | 60 ++++++ .../tltea/parser/core/OperatorToken.java | 32 ++- .../tltea/parser/core/ValueASTNode.java | 15 ++ 31 files changed, 440 insertions(+), 517 deletions(-) delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.kt create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java create mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java delete mode 100644 interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java diff --git a/TLTeaInterprtationClasses.drawio b/TLTeaInterprtationClasses.drawio index c690ee0..8c1ad9c 100644 --- a/TLTeaInterprtationClasses.drawio +++ b/TLTeaInterprtationClasses.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java deleted file mode 100644 index 766b49a..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.java +++ /dev/null @@ -1,88 +0,0 @@ -package cambio.tltea.interpreter; - -import cambio.tltea.interpreter.nodes.cause.EventActivationListener; -import cambio.tltea.interpreter.nodes.cause.CauseNode; -import cambio.tltea.interpreter.nodes.TriggerNotifier; -import cambio.tltea.parser.core.ASTNode; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.UnmodifiableView; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * @author Lion Wagner - */ -public final class BehaviorInterpretationResult { - private ASTNode modifiedAST; - private CauseNode interpretedAST; - private List listeners; - private TriggerNotifier triggerNotifier; - - /** - */ - public BehaviorInterpretationResult(ASTNode modifiedAST, CauseNode interpretedAST, - List listeners, - TriggerNotifier triggerNotifier) { - this.modifiedAST = modifiedAST; - this.interpretedAST = interpretedAST; - this.listeners = listeners; - this.triggerNotifier = triggerNotifier; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (BehaviorInterpretationResult) obj; - return Objects.equals(this.modifiedAST, that.modifiedAST) && - Objects.equals(this.interpretedAST, that.interpretedAST) && - Objects.equals(this.listeners, that.listeners) && - Objects.equals(this.triggerNotifier, that.triggerNotifier); - } - - @Override - public int hashCode() { - return Objects.hash(modifiedAST, interpretedAST, listeners, triggerNotifier); - } - - @Override - public String toString() { - return "BehaviorInterpretationResult[" + - "modifiedAST=" + modifiedAST + ", " + - "interpretedAST=" + interpretedAST + ", " + - "listener=" + listeners + ", " + - "triggerNotifier=" + triggerNotifier + ']'; - } - - public ASTNode getModifiedAST() { - return modifiedAST; - } - - void setModifiedAST(ASTNode modifiedAST) { - this.modifiedAST = modifiedAST; - } - - public CauseNode getInterpretedAST() { - return interpretedAST; - } - - void setInterpretedAST(CauseNode interpretedAST) { - this.interpretedAST = interpretedAST; - } - - @Contract(pure = true) - public @NotNull @UnmodifiableView List getListeners() { - return Collections.unmodifiableList(listeners); - } - - public TriggerNotifier getTriggerNotifier() { - return triggerNotifier; - } - - void addListener(EventActivationListener listener) { - this.listeners.add(listener); - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt new file mode 100644 index 0000000..47457f2 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt @@ -0,0 +1,33 @@ +package cambio.tltea.interpreter + +import cambio.tltea.interpreter.nodes.ConsequenceDescription +import cambio.tltea.interpreter.nodes.ISubscribableTriggerNotifier +import cambio.tltea.interpreter.nodes.consequence.ActivationData +import cambio.tltea.parser.core.ASTNode +import java.util.function.Consumer + +/** + * @author Lion Wagner + */ +class BehaviorInterpretationResult internal constructor(val modifiedAST: ASTNode, val consequenceDescription: ConsequenceDescription) : + ISubscribableTriggerNotifier { + + + // ----- delegating the subscriptions to the trigger manager----- + override fun subscribeEventListener(listener: Consumer>) { + consequenceDescription.triggerNotifier.subscribeEventListener(listener) + } + + override fun subscribeEventListenerWithFilter( + listener: Consumer>, + filter: Class> + ) { + consequenceDescription.triggerNotifier.subscribeEventListenerWithFilter(listener, filter) + } + + override fun unsubscribe(listener: Consumer>) { + consequenceDescription.triggerNotifier.unsubscribe(listener) + } + //--------------------------------------------------------------- + +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java deleted file mode 100644 index b9495df..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpreter.java +++ /dev/null @@ -1,191 +0,0 @@ -package cambio.tltea.interpreter; - -import cambio.tltea.interpreter.nodes.ImplicationNode; -import cambio.tltea.interpreter.nodes.TriggerNotifier; -import cambio.tltea.interpreter.nodes.cause.*; -import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode; -import cambio.tltea.interpreter.nodes.consequence.EventActivationDescription; -import cambio.tltea.interpreter.utils.ASTManipulator; -import cambio.tltea.parser.core.*; -import cambio.tltea.parser.core.temporal.ITemporalExpressionValueHolder; -import cambio.tltea.parser.core.temporal.ITemporalValue; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * Expects a future MTL formula. - *

- * Operators G[...] - Globally/Always F[...] - Finally/Eventually N[...] - Next - *

- * Binary R[...] - Release U[...] - Until - *

- * Not Allowed: - *

- * S[...] - Since H[...] - History (always in the past) P[...] - Past (Once in the Past) Back to - *

- *

- *

- * Simplifications: - *

- * F[...] α = TRUE U[...] β R[...] α = NOT β U[...] NOT α N[TimeInstance] α = FALSE U[...] α - *

- *

- * NOT G NOT α = F α NOT F NOT α = G α - * - * @author Lion Wagner - */ -class BehaviorInterpreter { - - public final BehaviorInterpretationResult result = new BehaviorInterpretationResult(null, - null, - new LinkedList<>(), - new TriggerNotifier()); - - public BehaviorInterpretationResult interpret(ASTNode ast) { - var workCopy = ast.clone(); - result.setModifiedAST(workCopy); - - workCopy = ASTManipulator.insertImplicitGloballyRoot(workCopy); - - var interpretedAST = interpretAsCause(workCopy); - result.setInterpretedAST(interpretedAST); - return result; - } - - - private CauseNode interpretAsCause(ASTNode root) { - if (root instanceof ValueASTNode valueNode) { - return interpretAsCause(valueNode); - } else if (root instanceof UnaryOperationASTNode unNode) { - return interpretAsCause(unNode); - } else if (root instanceof BinaryOperationASTNode biNode) { - return interpretAsCause(biNode); - } - return null; - } - - private CauseNode interpretAsCause(UnaryOperationASTNode unNode) { - switch (unNode.getOperator()) { - case NOT -> { - if (unNode.getChild() instanceof UnaryOperationASTNode child - && child.getOperator() == OperatorToken.NOT) { - interpretAsCause(ASTManipulator.removeDoubleNot(unNode)); - }//TODO: replace !true / !false with false / true - var child = interpretAsCause(unNode.getChild()); - return new NotCauseNode((CauseNode) child); - } - default -> throw new UnsupportedOperationException( - "Operator not supported for cause description (left side of implication): " + unNode.getOperator()); - } - } - - private CauseNode interpretAsCause(BinaryOperationASTNode binaryNode) { - switch (binaryNode.getOperator()) { - case IFF: { - interpretAsCause(ASTManipulator.splitIFF(binaryNode)); - } - case IMPLIES: { - var left = (CauseNode) interpretAsCause(binaryNode.getLeftChild()); - var right = interpretAsBehavior(binaryNode.getRightChild()); - return new ImplicationNode(left, right, result.getTriggerNotifier()); - } - case AND: { - var children = flattenCause(binaryNode); - return new AndCauseNode(children.toArray(new CauseNode[0])); - } - case OR: { - var children = flattenCause(binaryNode); - return new OrCauseNode(children.toArray(new CauseNode[0])); - } - default: { - throw new UnsupportedOperationException("Operator not yet supported: " + binaryNode.getOperator()); - } - } - } - - private CauseNode interpretAsCause(ValueASTNode valueNode) { - try { - double d = Double.parseDouble(valueNode.getValue()); - return new ConstantValueProvider<>(d); - } catch (NumberFormatException e) { - } - - if (valueNode.getValue().startsWith("(") && valueNode.getValue().endsWith(")")) { - EventActivationNode eventActivationNode = new EventActivationNode(valueNode.getValue()); - result.addListener(eventActivationNode.getEventListener()); - return eventActivationNode; - } else if (valueNode.getValue().startsWith("[") && valueNode.getValue().endsWith("]")) { - //TODO: return value watcher - } - return new ConstantValueProvider<>(valueNode.getValue()); - - } - - - @SuppressWarnings("unchecked") //should be safe casting - private List> flattenCause(BinaryOperationASTNode root) { - List> children = new ArrayList<>(); - - if (root.getLeftChild() instanceof BinaryOperationASTNode leftChild && leftChild.getOperator() == root.getOperator()) { - children.addAll(flattenCause(leftChild)); - } else { - children.add((CauseNode) interpretAsCause(root.getLeftChild())); - } - - if (root.getRightChild() instanceof BinaryOperationASTNode rightChild && rightChild.getOperator() == root.getOperator()) { - children.addAll(flattenCause(rightChild)); - } else { - children.add((CauseNode) interpretAsCause(root.getRightChild())); - } - - //TODO: map EventActivationListeners to ComparisonNodes (==TRUE) - - return children; - } - - - private String interpretAsBehavior(ASTNode node) { - if (node instanceof ValueASTNode) { - return ((ValueASTNode) node).getValue(); - } else { - throw new IllegalArgumentException("Expected Value Node"); - } - } - - private ConsequenceNode interpretAsConsequence(ASTNode node) { - return interpretAsConsequence(node, null); - } - - private ConsequenceNode interpretAsConsequence(ASTNode node, ITemporalValue tmpvalue) { - if (node instanceof BinaryOperationASTNode binode) { - return interpretAsConsequence(binode, tmpvalue); - } else if (node instanceof UnaryOperationASTNode unode) { - return interpretAsConsequence(unode, tmpvalue); - } else if (node instanceof ValueASTNode vnode) { - return interpretAsConsequence(vnode, tmpvalue); - } - return null; - } - - private ConsequenceNode interpretAsConsequence(ValueASTNode node, ITemporalValue tmpvalue) { - return new EventActivationDescription(node.getValue(), tmpvalue); - } - - private ConsequenceNode interpretAsConsequence(UnaryOperationASTNode node, ITemporalValue tmpvalue) { - if (node instanceof ITemporalExpressionValueHolder valueHolder) { - tmpvalue = valueHolder.getTemporalValue(); - } else { - throw new IllegalArgumentException("Unsupported Operation"); - } - return interpretAsConsequence(node.getChild(), tmpvalue); - } - - private ConsequenceNode interpretAsConsequence(BinaryOperationASTNode node, ITemporalValue tmpvalue) { - - return null; - } - -} - diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.java b/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.java deleted file mode 100644 index 7424f93..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.java +++ /dev/null @@ -1,12 +0,0 @@ -package cambio.tltea.interpreter; - -import cambio.tltea.parser.core.ASTNode; - -/** - * @author Lion Wagner - */ -public final class Interpreter { - public static BehaviorInterpretationResult interpretAsBehavior(ASTNode root) { - return new BehaviorInterpreter().interpret(root); - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.kt new file mode 100644 index 0000000..2ce2762 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/Interpreter.kt @@ -0,0 +1,15 @@ +package cambio.tltea.interpreter + +import cambio.tltea.interpreter.nodes.ConsequenceInterpreter +import cambio.tltea.parser.core.ASTNode + +/** + * @author Lion Wagner + */ +object Interpreter { + fun interpretAsBehavior(root: ASTNode): BehaviorInterpretationResult { + val clone = root.clone() + val consequenceDescription = ConsequenceInterpreter().interpretAsMTL(clone) + return BehaviorInterpretationResult(clone, consequenceDescription) + } +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt index 8b052ed..f190cf9 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt @@ -7,14 +7,17 @@ import cambio.tltea.interpreter.nodes.cause.EventActivationListener class CauseDescription( val causeASTRoot: CauseNode, - private val listeners: List, - private val triggerNotifier: TriggerNotifier + private val listeners: List ) { val causeChangePublisher: StateChangedPublisher = causeASTRoot fun activateListeners() { - triggerNotifier.activateListeners(listeners) + listeners.forEach { it.startListening() } + } + + fun deactivateListeners() { + listeners.forEach { it.stopListening() } } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt index 2bbc7d9..4b82bba 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt @@ -50,11 +50,11 @@ class CauseInterpreter { private fun interpretAsCauseEvent(valueNode: ValueASTNode): CauseNode { if (valueNode.value.startsWith("(") && valueNode.value.endsWith(")")) { - val eventActivationNode = EventActivationNode(valueNode.value) - listeners.add(eventActivationNode.eventListener) + val eventActivationListener = EventActivationListener(valueNode.value) + listeners.add(eventActivationListener) //wrap event activation in a ==True comparison - return ComparisonCauseNode(OperatorToken.EQ, null, eventActivationNode, ConstantValueProvider(true)) + return ComparisonCauseNode(OperatorToken.EQ, null, eventActivationListener, ConstantValueProvider(true)) } else if (valueNode.value.contains("$")) { TODO("A value watcher cannot be created yet.") } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt index 6f911c5..8588a18 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt @@ -2,13 +2,16 @@ package cambio.tltea.interpreter.nodes import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode -class ConsequenceDescription { +class ConsequenceDescription(val triggerNotifier: TriggerNotifier) { - fun activateConsequence() { + internal fun activateConsequence() { consequenceAST?.activateConsequence() } - var consequenceAST: ConsequenceNode? = null + internal fun deactivateConsequence() { + consequenceAST?.deactivateConsequence() + } + var consequenceAST: ConsequenceNode? = null } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt index edc1135..7fef4a8 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt @@ -1,45 +1,92 @@ package cambio.tltea.interpreter.nodes -import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode -import cambio.tltea.interpreter.nodes.consequence.EventActivationConsequenceNode -import cambio.tltea.interpreter.nodes.consequence.EventPreventionConsequenceNode +import cambio.tltea.interpreter.nodes.consequence.* import cambio.tltea.interpreter.utils.ASTManipulator import cambio.tltea.parser.core.* import cambio.tltea.parser.core.temporal.* -//until => left is true till right is true -class ConsequenceInterpreter private constructor(private val triggerNotifier: TriggerNotifier) { - constructor() : this(TriggerNotifier()) +/** + * Expects a future MTL formula. + *

+ * Operators G[...] - Globally/Always F[...] - Finally/Eventually N[...] - Next + *

+ * Binary R[...] - Release U[...] - Until + *

+ * Not Allowed: + *

+ * S[...] - Since H[...] - History (always in the past) P[...] - Past (Once in the Past) Back to + *

+ *

+ *

+ * Simplifications: + *

+ * F[...] α = TRUE U[...] β R[...] α = NOT β U[...] NOT α N[TimeInstance] α = FALSE U[...] α + *

+ *

+ * NOT G NOT α = F α NOT F NOT α = G α + * + * @author Lion Wagner + */ +//until[x,y] => left is true till right is true +//Roughly, but not exactly G[x,y](!right -> left) +class ConsequenceInterpreter { - fun interpretAsMTL(mtlRoot: ASTNode): ConsequenceDescription { + /** + * @param mtlRoot the root of the parsed MTL formula + * @param triggerNotifier this parameter can be used to combine multiple {@link TriggerNotifier}s from previous interpretations + */ + @JvmOverloads + fun interpretAsMTL(mtlRoot: ASTNode, triggerNotifier: TriggerNotifier = TriggerNotifier()): ConsequenceDescription { - val consequenceDescription = ConsequenceDescription() + val consequenceDescription = ConsequenceDescription(triggerNotifier) //gather initial temporal info val temporalContext = if (mtlRoot is ITemporalOperationInfoHolder) mtlRoot.toTemporalOperatorInfo() else TemporalOperatorInfo(OperatorToken.GLOBALLY, TemporalInterval(0.0, Double.POSITIVE_INFINITY)) - val consequnceAST = interpret(mtlRoot, temporalContext, consequenceDescription) - consequenceDescription.consequenceAST = consequnceAST + val consequenceAST = interpret(mtlRoot, triggerNotifier, temporalContext, consequenceDescription) + consequenceDescription.consequenceAST = consequenceAST return consequenceDescription } + /** * General matcher function */ private fun interpret( node: ASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { return when (node) { - is TemporalBinaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) - is TemporalUnaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) - is BinaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) - is UnaryOperationASTNode -> interpret(node, temporalContext, consequenceDescription) - is ValueASTNode -> interpret(node, temporalContext, consequenceDescription) + is TemporalBinaryOperationASTNode -> interpretTemporalBinaryOperation( + node, + triggerNotifier, + temporalContext, + consequenceDescription + ) + is TemporalUnaryOperationASTNode -> interpretTemporalUnaryOperation( + node, + triggerNotifier, + temporalContext, + consequenceDescription + ) + is BinaryOperationASTNode -> interpretBinaryOperation( + node, + triggerNotifier, + temporalContext, + consequenceDescription + ) + is UnaryOperationASTNode -> interpretUnaryOperation( + node, + triggerNotifier, + temporalContext, + consequenceDescription + ) + is ValueASTNode -> interpretValueNode(node, triggerNotifier, temporalContext, consequenceDescription) else -> { throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") } @@ -48,8 +95,9 @@ class ConsequenceInterpreter private constructor(private val triggerNotifier: Tr } - private fun interpret( + private fun interpretTemporalBinaryOperation( node: TemporalBinaryOperationASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { @@ -62,70 +110,118 @@ class ConsequenceInterpreter private constructor(private val triggerNotifier: Tr } // UNTIL + TODO("Implement until node interpretation") } - private fun interpret( + private fun interpretTemporalUnaryOperation( node: TemporalUnaryOperationASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { if (node.child is ITemporalOperationInfoHolder) { throw IllegalArgumentException("Cannot interpret two consecutive temporal operators") } + //TODO: for now the temporal context is simply passed down. In the future multiple temporal contexts may need to interact. //Prophecy, Globally, Finally, Next - + val temporalContext = node.toTemporalOperatorInfo() + return interpret(node.child, triggerNotifier, temporalContext, consequenceDescription) } - private fun interpret( + private fun interpretBinaryOperation( node: BinaryOperationASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { + if (node is TemporalBinaryOperationASTNode) { - return interpret(node, temporalContext, consequenceDescription) + return interpretTemporalBinaryOperation(node, triggerNotifier, temporalContext, consequenceDescription) } else if (OperatorToken.ComparisonOperatorTokens.contains(node.operator)) { //create consequnce comparison node - } else when (node.operator) { - OperatorToken.IMPLIES -> { - //create implication node - return interpretImplication(node, temporalContext, consequenceDescription) - } - OperatorToken.AND -> { - //create consequence and node - } - OperatorToken.OR -> { - //create consequence or node - } - OperatorToken.IFF -> { - //split <-> into <- and -> - return interpret(ASTManipulator.splitIFF(node), temporalContext, consequenceDescription) + val leftChild = node.leftChild as ValueASTNode + val rightChild = node.rightChild as ValueASTNode + + var targetEventHolder: ValueASTNode = leftChild + var targetValueHolder: ValueASTNode = rightChild + + if (rightChild.containsEventName()) { + targetEventHolder = rightChild + targetValueHolder = leftChild + } else if (!leftChild.containsEventName()) { + throw IllegalArgumentException("Cannot interpret value event. Neither left nor right child is a target property or event.") } - else -> { - throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + + return ValueEventConsequenceNode( + triggerNotifier, + targetEventHolder.eventName, + targetValueHolder.value, + temporalContext + ) + + } else { + val interpretShorthand = + { child: ASTNode -> interpret(child, triggerNotifier, temporalContext, consequenceDescription) } + when (node.operator) { + OperatorToken.IMPLIES -> { + //create implication node + return interpretImplication(node, triggerNotifier, temporalContext) + } + OperatorToken.AND -> { + //create consequence "and" node + val children = ASTManipulator.flatten(node) + return AndConsequenceNode(triggerNotifier, temporalContext, children.map { interpretShorthand(it) }) + } + OperatorToken.OR -> { + //create consequence "or" node + val children = ASTManipulator.flatten(node) + return OrConsequenceNode(triggerNotifier, temporalContext, children.map { interpretShorthand(it) }) + } + OperatorToken.IFF -> { + //split <-> into <- and -> + //this only works in rare cases + return interpretBinaryOperation( + ASTManipulator.splitIFF(node), + triggerNotifier, + temporalContext, + consequenceDescription + ) + } + else -> { + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + } } } } - private fun interpret( + private fun interpretUnaryOperation( node: UnaryOperationASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { if (node.operator == OperatorToken.NOT) { val child = node.child if (child is ValueASTNode) { - var value = child.value; - if (child.value.startsWith("(") && child.value.endsWith(")")) { - value = child.value.substring(1, child.value.length - 1) - } + val value = if (child.containsEventName()) child.eventName else child.value return EventPreventionConsequenceNode(triggerNotifier, temporalContext, value) } else if (child is UnaryOperationASTNode && child.operator == OperatorToken.NOT) { - interpret(ASTManipulator.removeDoubleNot(node), temporalContext, consequenceDescription) + return interpret( + ASTManipulator.removeDoubleNot(node), + triggerNotifier, + temporalContext, + consequenceDescription + ) } else { - interpret(ASTManipulator.applyNot(node), temporalContext, consequenceDescription) + return interpret( + ASTManipulator.applyNot(node), + triggerNotifier, + temporalContext, + consequenceDescription + ) } } else { @@ -133,14 +229,14 @@ class ConsequenceInterpreter private constructor(private val triggerNotifier: Tr } } - private fun interpret( + private fun interpretValueNode( node: ValueASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription - ): ConsequenceNode { - if (node.value.startsWith("(") && node.value.endsWith(")")) { - val value = node.value.substring(1, node.value.length - 1) - return EventActivationConsequenceNode(triggerNotifier, temporalContext, value) + ): ActivationConsequenceNode { + if (node.containsEventName()) { + return EventActivationConsequenceNode(triggerNotifier, temporalContext, node.eventName) } else { throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") } @@ -148,6 +244,7 @@ class ConsequenceInterpreter private constructor(private val triggerNotifier: Tr private fun interpretImplication( root: BinaryOperationASTNode, + triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo ): ConsequenceNode { if (root.operator != OperatorToken.IMPLIES) { @@ -158,7 +255,7 @@ class ConsequenceInterpreter private constructor(private val triggerNotifier: Tr val right = root.rightChild val cause = CauseInterpreter().interpretLTL(left) - val consequence = ConsequenceInterpreter(triggerNotifier).interpretAsMTL(right) + val consequence = ConsequenceInterpreter().interpretAsMTL(right, triggerNotifier) return ImplicationNode( cause, diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt new file mode 100644 index 0000000..badda3a --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt @@ -0,0 +1,10 @@ +package cambio.tltea.interpreter.nodes + +import cambio.tltea.interpreter.nodes.consequence.ActivationData +import java.util.function.Consumer + +interface ISubscribableTriggerNotifier { + fun subscribeEventListener(listener: Consumer>) + fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) + fun unsubscribe(listener: Consumer>) +} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt index 24cc7c7..35850e9 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt @@ -21,11 +21,19 @@ class ImplicationNode( causeDescription.causeChangePublisher.subscribe(this) } + override fun deactivateConsequence() { + causeDescription.deactivateListeners() + causeDescription.causeChangePublisher.unsubscribe(this) + } + override fun onEvent(event: StateChangeEvent) { //activate consequence if the new value carried by the event is "true" if (event.newValue) { consequence.activateConsequence() } + else { + consequence.deactivateConsequence() + } } /** diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt index 7738b9a..7438792 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt @@ -1,31 +1,30 @@ package cambio.tltea.interpreter.nodes -import cambio.tltea.interpreter.nodes.cause.EventActivationListener import cambio.tltea.interpreter.nodes.consequence.ActivationData import java.util.function.Consumer /** * @author Lion Wagner */ -class TriggerNotifier { +class TriggerNotifier : ISubscribableTriggerNotifier { private val anySubscribers: MutableCollection>> = HashSet() private val filteredSubscribers: HashMap>, MutableSet>>> = HashMap() - fun subscribeEventListener(listener: Consumer>) { + override fun subscribeEventListener(listener: Consumer>) { anySubscribers.add(listener) } - fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) { + override fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) { if (!filteredSubscribers.containsKey(filter)) { filteredSubscribers[filter] = HashSet() } filteredSubscribers[filter]!!.add(listener) } - fun unsubscribe(listener: Consumer>) { + override fun unsubscribe(listener: Consumer>) { anySubscribers.remove(listener) filteredSubscribers.values.forEach { it.remove(listener) } } @@ -34,30 +33,4 @@ class TriggerNotifier { anySubscribers.forEach { it.accept(activationData) } filteredSubscribers[activationData.javaClass]?.forEach { it.accept(activationData) } } - - private val eventActivationListeners: MutableCollection> = HashSet() - private val listenerActivationQueue: MutableList = ArrayList() - - - /** - * Subscribes a listener that will be notified when a new event listener is activated. - */ - fun subscribeListenerActivationListener(listener: Consumer) { - eventActivationListeners.add(listener) - activateListeners(listenerActivationQueue) - listenerActivationQueue.clear() - } - - fun unsubscribeListenerActivationListener(listener: Consumer) { - eventActivationListeners.remove(listener) - } - - internal fun activateListeners(listeners: Collection) { - if (eventActivationListeners.isEmpty()) { - listenerActivationQueue.addAll(listeners) - } - listeners.forEach { eventListener -> - eventActivationListeners.forEach { it.accept(eventListener) } - } - } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java index a5e6c03..c50bd0a 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java @@ -2,9 +2,9 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.TriggerNotifier; import cambio.tltea.parser.core.OperatorToken; import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; +import kotlin.NotImplementedError; /** * @author Lion Wagner @@ -30,8 +30,8 @@ public ComparisonCauseNode(OperatorToken operator, //TODO: optimization we always take the same path through this method therefore we may be able to optimize @Override public Boolean getCurrentValue() { - var val1 = left.getCurrentValue(); - var val2 = right.getCurrentValue(); + var val1 = left.currentValue; + var val2 = right.currentValue; if (val1 == null || val2 == null) { return false; @@ -40,7 +40,7 @@ public Boolean getCurrentValue() { return switch (operator) { case EQ -> val1.equals(val2); case NEQ -> !val1.equals(val2); - default -> throw new IllegalArgumentException("Operator not supported for string comparison:" + operator); + default -> throw new IllegalStateException("Operator not supported for string comparison:" + operator); }; } else if (val1 instanceof Number n1 && val2 instanceof Number n2) { return switch (operator) { @@ -50,7 +50,7 @@ public Boolean getCurrentValue() { case GEQ -> n1.doubleValue() >= n2.doubleValue(); case LT -> n1.doubleValue() < n2.doubleValue(); case LEQ -> n1.doubleValue() <= n2.doubleValue(); - default -> throw new IllegalArgumentException("Operator not supported as comparison: " + operator); + default -> throw new IllegalStateException("Operator not supported as comparison: " + operator); }; } else if (val1 instanceof Comparable || val2 instanceof Comparable) { try { @@ -68,18 +68,22 @@ public Boolean getCurrentValue() { case GEQ -> compareValue >= 0; case LT -> compareValue < 0; case LEQ -> compareValue <= 0; - default -> throw new IllegalArgumentException("Operator not supported as comparison: " + operator); + default -> throw new IllegalStateException("Operator not supported as comparison: " + operator); }; } catch (ClassCastException ignored) { } } - throw new IllegalArgumentException("Value type could not be compared: " + val1.getClass() + " and " + val2.getClass()); + throw new IllegalStateException("Value type could not be compared: " + val1.getClass() + " and " + val2.getClass()); } + public OperatorToken getOperator() { + return operator; + } + @Override public void onEvent(StateChangeEvent event) { - + throw new NotImplementedError(); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java index 5838dd9..28ba017 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java @@ -1,22 +1,13 @@ package cambio.tltea.interpreter.nodes.cause; -import cambio.tltea.interpreter.nodes.TriggerNotifier; - /** * @author Lion Wagner */ -public class ConstantValueProvider extends ValueProvider { - - protected final T value; +public class ConstantValueProvider extends ValueProvider { public ConstantValueProvider(T value) { super(); - this.value = value; - } - - @Override - public T getCurrentValue() { - return value; + this.currentValue = value; } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java index 3f04b37..d27f13f 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java @@ -1,18 +1,14 @@ package cambio.tltea.interpreter.nodes.cause; -import cambio.tltea.interpreter.nodes.StateChangeEvent; -import cambio.tltea.interpreter.nodes.StateChangedPublisher; import cambio.tltea.parser.core.temporal.ITemporalValue; /** * @author Lion Wagner */ -public final class EventActivationListener extends StateChangedPublisher { +public final class EventActivationListener extends ValueProvider { private final String eventName; - private boolean activated = false; - public EventActivationListener(String eventName) { this.eventName = eventName; } @@ -22,7 +18,7 @@ public String getEventName() { } public boolean isActivated() { - return activated; + return currentValue; } @@ -41,12 +37,4 @@ public void reset(ITemporalValue time) { public void deactivate(ITemporalValue time) { notifyAndChangeState(false, time); } - - private void notifyAndChangeState(boolean activated, ITemporalValue time) { - subscribers.forEach(listener -> listener.onEvent(new StateChangeEvent<>(this, - activated, - this.activated, - time))); - this.activated = activated; - } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java deleted file mode 100644 index e21740a..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package cambio.tltea.interpreter.nodes.cause; - - -import cambio.tltea.interpreter.nodes.StateChangeEvent; -import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.TriggerNotifier; -import org.jetbrains.annotations.NotNull; - -/** - * @author Lion Wagner - */ -public final class EventActivationNode extends ValueProvider implements StateChangeListener { - - private final EventActivationListener listener; - - public EventActivationNode(String eventName) { - listener = new EventActivationListener(eventName); - listener.subscribe(this); - } - - public EventActivationListener getEventListener() { - return listener; - } - - @Override - public @NotNull Boolean getCurrentValue() { - return listener.isActivated(); - } - - @Override - public void onEvent(StateChangeEvent event) { - notifySubscribers(new StateChangeEvent<>(this, event.getNewValue(), event.getOldValue(), event.when())); - } -} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java new file mode 100644 index 0000000..d9bd777 --- /dev/null +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java @@ -0,0 +1,13 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.parser.core.temporal.ITemporalValue; + +/** + * @author Lion Wagner + */ +public class ValueListener extends ValueProvider { + + public void updateValue(T value, ITemporalValue time) { + super.notifyAndChangeState(value, time); + } +} diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java index 1ced1eb..8860968 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java @@ -1,11 +1,30 @@ package cambio.tltea.interpreter.nodes.cause; +import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangedPublisher; -import cambio.tltea.interpreter.nodes.TriggerNotifier; +import cambio.tltea.parser.core.temporal.ITemporalValue; public abstract class ValueProvider extends StateChangedPublisher { - public abstract T getCurrentValue(); + private boolean isListening; + protected T currentValue; - public ValueProvider() { + protected void notifyAndChangeState(T newValue, ITemporalValue time) { + if (!isListening) { + return; + } + subscribers.forEach(listener -> listener.onEvent(new StateChangeEvent<>(this, + newValue, + currentValue, + time))); + this.currentValue = newValue; + } + + + public void startListening() { + isListening = true; + } + + public void stopListening() { + isListening = false; } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt deleted file mode 100644 index 46fbdc0..0000000 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationDescription.kt +++ /dev/null @@ -1,41 +0,0 @@ -package cambio.tltea.interpreter.nodes.consequence - -import cambio.tltea.parser.core.OperatorToken -import cambio.tltea.parser.core.temporal.TemporalOperatorInfo - - -abstract class ActivationDescription( - open val temporalContext: TemporalOperatorInfo, - open val activationNode: ConsequenceNode -) - -data class OrActivationDescription( - override val temporalContext: TemporalOperatorInfo, - override val activationNode: OrConsequenceNode, - val children: List -) : ActivationDescription(temporalContext, activationNode) - - -class ComparisonActivationDescription( - override val temporalContext: TemporalOperatorInfo, - override val activationNode: ComparisonConsequenceNode, - val operator: OperatorToken, - val left: ValueEventConsequenceNode<*>, - val right: ValueEventConsequenceNode<*> -) : ActivationDescription(temporalContext, activationNode) { - -} - -class EventActivationDescription( - override val temporalContext: TemporalOperatorInfo, - override val activationNode: ConsequenceNode, - val eventName: String -) : ActivationDescription(temporalContext, activationNode) { -} - -class EventPreventionActivationDescription( - override val temporalContext: TemporalOperatorInfo, - override val activationNode: ConsequenceNode, - val eventName: String -) : ActivationDescription(temporalContext, activationNode) { -} \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt index a1ea1fa..eff30ed 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt @@ -8,10 +8,14 @@ import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class AndConsequenceNode( triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, - children: List + children: Collection ) : ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { override fun activateConsequence() { children.forEach { it.activateConsequence() } } + + override fun deactivateConsequence() { + children.forEach { it.deactivateConsequence() } + } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt index 5feb7d0..7ccfa7b 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt @@ -6,5 +6,5 @@ import cambio.tltea.parser.core.temporal.TemporalOperatorInfo abstract class ChildrenOwningConsequenceNode( triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, - protected val children: List + protected val children: Collection ) : ConsequenceNode(triggerNotifier, temporalContext) \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt index cfe07e5..dd08337 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt @@ -13,4 +13,5 @@ abstract class ConsequenceNode( protected val temporalContext: TemporalOperatorInfo ) { abstract fun activateConsequence() + abstract fun deactivateConsequence() } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt index 1985b87..71b8aa0 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt @@ -11,4 +11,8 @@ class EventActivationConsequenceNode( override fun activateConsequence() { TODO("Not yet implemented") } + + override fun deactivateConsequence() { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt index c8105bf..7a6d55d 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt @@ -11,4 +11,8 @@ class EventPreventionConsequenceNode( override fun activateConsequence() { TODO("Not yet implemented") } + + override fun deactivateConsequence() { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt index d1d87ec..619006f 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt @@ -11,4 +11,8 @@ class OrConsequenceNode( override fun activateConsequence() { TODO("Not yet implemented") } + + override fun deactivateConsequence() { + TODO("Not yet implemented") + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt index 32e7efa..ed7a91e 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt @@ -5,16 +5,20 @@ import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class ValueEventConsequenceNode( triggerNotifier: TriggerNotifier, - val value: T, + val targetProperty: String, + val targetValue: T, temporalContext: TemporalOperatorInfo ) : ActivationConsequenceNode(triggerNotifier, temporalContext) { override fun activateConsequence() { - throw UnsupportedOperationException("Value consequence nodes cannot be activated") + TODO("Not yet implemented") + } + override fun deactivateConsequence() { + TODO("Not yet implemented") } fun getType(): Class { - return value::class.javaObjectType + return targetValue::class.javaObjectType } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java index 0910c50..c68988c 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java @@ -5,6 +5,10 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + /** * @author Lion Wagner */ @@ -108,10 +112,9 @@ public static ASTNode applyNot(@NotNull UnaryOperationASTNode notNode) { case OR -> applyNotToOr(binaryNode); default -> throw new IllegalArgumentException("Operator not supported."); }; - } - else if(notNode.getChild() instanceof UnaryOperationASTNode unaryChild && - unaryChild.getOperator() == OperatorToken.NOT) { - return removeDoubleNot(unaryChild); + } else if (notNode.getChild() instanceof UnaryOperationASTNode unaryChild && + unaryChild.getOperator() == OperatorToken.NOT) { + return removeDoubleNot(unaryChild); } throw new IllegalArgumentException("Cannot apply NOT (yet?) to " + notNode.getChild() .getClass() @@ -176,15 +179,7 @@ public static void redirectParent(@NotNull OperatorASTNode parent, } private static BinaryOperationASTNode applyNotToComparison(@NotNull BinaryOperationASTNode comparisonNode) { - OperatorToken reversedOperator = switch (comparisonNode.getOperator()) { - case EQ -> OperatorToken.NEQ; - case NEQ -> OperatorToken.EQ; - case LT -> OperatorToken.GEQ; - case LEQ -> OperatorToken.GT; - case GT -> OperatorToken.LEQ; - case GEQ -> OperatorToken.LT; - default -> throw new IllegalStateException("Unexpected operator."); - }; + OperatorToken reversedOperator = comparisonNode.getOperator().invert(); UnaryOperationASTNode notParent = (UnaryOperationASTNode) comparisonNode.getParent(); BinaryOperationASTNode replacer = new BinaryOperationASTNode(reversedOperator, comparisonNode.getLeftChild(), @@ -192,4 +187,27 @@ private static BinaryOperationASTNode applyNotToComparison(@NotNull BinaryOperat redirectParent(notParent.getParent(), notParent, replacer); return replacer; } + + public static @NotNull Collection flatten(@NotNull BinaryOperationASTNode node) { + OperatorToken op = node.getOperator(); + if (op != OperatorToken.AND && op != OperatorToken.OR) { + throw new IllegalArgumentException("Expected AND or OR operator, but got " + op); + } + + Collection result = new HashSet<>(); + + ASTNode leftChild = node.getLeftChild(); + ASTNode rightChild = node.getRightChild(); + + result.add(leftChild); + result.add(rightChild); + if (leftChild instanceof BinaryOperationASTNode binLeft && binLeft.getOperator() == op) { + result.addAll(flatten(binLeft)); + } + if (rightChild instanceof BinaryOperationASTNode binRight && binRight.getOperator() == op) { + result.addAll(flatten(binRight)); + } + + return result; + } } diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java new file mode 100644 index 0000000..68aa128 --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java @@ -0,0 +1,60 @@ +package cambio.tltea.interpreter.nodes.cause; + +import cambio.tltea.parser.core.OperatorToken; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class ComparisonCauseNodeTest { + + @Test + void stringComparisonTest() { + ConstantValueProvider value = new ConstantValueProvider<>("a"); + ConstantValueProvider clone = new ConstantValueProvider<>("a"); + ConstantValueProvider other = new ConstantValueProvider<>("B"); + testEQNEQ(value, clone, other); + + ComparisonCauseNode failing = new ComparisonCauseNode(OperatorToken.LT, null, value, value); + Assertions.assertThrows(IllegalStateException.class, failing::getCurrentValue); + + } + + @Test + void integerComparisonTest() { + ConstantValueProvider value = new ConstantValueProvider<>(1); + ConstantValueProvider clone = new ConstantValueProvider<>(1); + ConstantValueProvider other = new ConstantValueProvider<>(2); + testEQNEQ(value, clone, other); + + testWithInversion(true, value, value, OperatorToken.EQ); + testWithInversion(true, value, clone, OperatorToken.EQ); + testWithInversion(false, value, value, OperatorToken.NEQ); + testWithInversion(false, value, clone, OperatorToken.NEQ); + testWithInversion(true, value, other, OperatorToken.LT); + testWithInversion(true, value, other, OperatorToken.LEQ); + testWithInversion(false, value, other, OperatorToken.GT); + testWithInversion(false, value, other, OperatorToken.GEQ); + } + + private void testEQNEQ(ConstantValueProvider value, + ConstantValueProvider equalValue, + ConstantValueProvider otherValue) { + ComparisonCauseNode identityNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, value); + ComparisonCauseNode equalNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, equalValue); + ComparisonCauseNode neqNode = new ComparisonCauseNode(OperatorToken.NEQ, null, value, otherValue); + + Assertions.assertTrue(identityNode.getCurrentValue()); + Assertions.assertTrue(equalNode.getCurrentValue()); + Assertions.assertFalse(neqNode.getCurrentValue()); + } + + private void testWithInversion(boolean expected, ValueProvider value1, ValueProvider value2, OperatorToken op) { + ComparisonCauseNode node = new ComparisonCauseNode(op, null, value1, value2); + ComparisonCauseNode invertedOpAndValues = new ComparisonCauseNode(op.invert(), null, value2, value1); + ComparisonCauseNode invertedOP = new ComparisonCauseNode(op.invert(), null, value1, value2); + + Assertions.assertEquals(expected, node.getCurrentValue()); + Assertions.assertEquals(expected, invertedOpAndValues.getCurrentValue()); + Assertions.assertEquals(!expected, invertedOP.getCurrentValue()); + + } +} \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java b/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java index dbd0cbb..d86ab26 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java +++ b/parser/src/main/java/cambio/tltea/parser/core/OperatorToken.java @@ -4,23 +4,23 @@ import java.util.Set; public enum OperatorToken { - TRUE("","T"), - FALSE("","F"), + TRUE("", "T"), + FALSE("", "F"), NOT("", "¬"), AND("", "∧"), OR("", "∨"), IMPLIES("", "->"), IFF("", "<->"), - EQ("", "=="), + EQ("", "=="), NEQ("", "!="), LT("", "<"), LEQ("", "<="), - GT("", ">"), + GT("", ">"), GEQ("", ">="), NEXT("", "X"), - BEFORE("","B"), - GLOBALLY("","G"), - FINALLY("","F"), + BEFORE("", "B"), + GLOBALLY("", "G"), + FINALLY("", "F"), UNTIL("", "U"), RELEASE("", "R"), WEAKUNTIL("", "W"), @@ -99,4 +99,22 @@ public String toString() { return String.format("%s[%s]", this.name(), this.image); } + /** + * If the operator is a comparison operator, returns the corresponding inverted comparison operator token. E.g. + * {@link OperatorToken#EQ} -> {@link OperatorToken#NEQ} and {@link OperatorToken#LT} -> {@link OperatorToken#GEQ}. + * + * @return the inverted comparison operator token + * @throws IllegalArgumentException if the operator is not invertible operator + */ + public OperatorToken invert() { + return switch (this) { + case EQ -> OperatorToken.NEQ; + case NEQ -> OperatorToken.EQ; + case LT -> OperatorToken.GEQ; + case LEQ -> OperatorToken.GT; + case GT -> OperatorToken.LEQ; + case GEQ -> OperatorToken.LT; + default -> throw new IllegalArgumentException("Cannot invert operator " + this); + }; + } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java index fb2aad4..7acc990 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/ValueASTNode.java @@ -1,5 +1,7 @@ package cambio.tltea.parser.core; +import org.jetbrains.annotations.NotNull; + /** * @author Lion Wagner */ @@ -51,4 +53,17 @@ public String toFormulaString() { public ASTNode clone() { return new ValueASTNode(value); } + + + public boolean containsEventName() { + return value.startsWith("(") && value.endsWith(")"); + } + + public @NotNull String getEventName() { + if (containsEventName()) { + return value.substring(1, value.length() - 1); + } else { + throw new IllegalStateException("Value does not contain event name"); + } + } } From 8031e8dcbe15adcc3c11de53d2ce8f716707b047 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 3 May 2022 19:49:48 +0200 Subject: [PATCH 09/17] Remaining fixes --- TLTeaInterprtationClasses.drawio | 2 +- .../BehaviorInterpretationResult.kt | 18 ++++- .../interpreter/nodes/CauseDescription.kt | 2 +- .../interpreter/nodes/CauseInterpreter.kt | 4 +- .../nodes/ConsequenceDescription.kt | 2 +- .../nodes/ConsequenceInterpreter.kt | 74 ++++++++++--------- .../interpreter/nodes/ImplicationNode.kt | 4 +- .../{TriggerNotifier.kt => TriggerManager.kt} | 11 ++- .../interpreter/nodes/cause/AndCauseNode.java | 1 - .../interpreter/nodes/cause/CauseNode.java | 2 - .../nodes/cause/ComparisonCauseNode.java | 23 ++++-- .../nodes/cause/EventActivationListener.java | 4 +- .../interpreter/nodes/cause/NotCauseNode.java | 1 - .../interpreter/nodes/cause/OrCauseNode.java | 4 - .../nodes/cause/ValueListener.java | 2 +- .../nodes/cause/ValueProvider.java | 4 +- .../consequence/ActivationConsequenceNode.kt | 6 +- .../nodes/consequence/AndConsequenceNode.kt | 6 +- .../ChildrenOwningConsequenceNode.kt | 6 +- .../nodes/consequence/ConsequenceNode.kt | 4 +- .../EventActivationConsequenceNode.kt | 10 +-- .../nodes/consequence/EventActivationData.kt | 6 +- .../EventPreventionConsequenceNode.kt | 6 +- .../nodes/consequence/OrConsequenceNode.kt | 6 +- .../consequence/ValueEventConsequenceNode.kt | 12 +-- .../interpreter/utils/ASTManipulator.java | 2 +- .../interpreter/BehaviorInterpreterTest.java | 25 ------- .../interpreter/BehaviorInterpreterTest.kt | 32 ++++++++ .../tltea/parser/core/ASTNodePrinter.kt | 2 +- .../core/temporal/TemporalOperatorInfo.java | 2 +- 30 files changed, 159 insertions(+), 124 deletions(-) rename interpreter/src/main/java/cambio/tltea/interpreter/nodes/{TriggerNotifier.kt => TriggerManager.kt} (75%) delete mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt diff --git a/TLTeaInterprtationClasses.drawio b/TLTeaInterprtationClasses.drawio index 8c1ad9c..4051e3f 100644 --- a/TLTeaInterprtationClasses.drawio +++ b/TLTeaInterprtationClasses.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt index 47457f2..ab27f3f 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt @@ -2,6 +2,7 @@ package cambio.tltea.interpreter import cambio.tltea.interpreter.nodes.ConsequenceDescription import cambio.tltea.interpreter.nodes.ISubscribableTriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.interpreter.nodes.consequence.ActivationData import cambio.tltea.parser.core.ASTNode import java.util.function.Consumer @@ -9,24 +10,33 @@ import java.util.function.Consumer /** * @author Lion Wagner */ -class BehaviorInterpretationResult internal constructor(val modifiedAST: ASTNode, val consequenceDescription: ConsequenceDescription) : +class BehaviorInterpretationResult internal constructor( + val modifiedAST: ASTNode, + val consequenceDescription: ConsequenceDescription, + val triggerManager: TriggerManager = consequenceDescription.triggerManager +) : ISubscribableTriggerNotifier { + + fun activateProcessing() { + consequenceDescription.activateConsequence() + } + // ----- delegating the subscriptions to the trigger manager----- override fun subscribeEventListener(listener: Consumer>) { - consequenceDescription.triggerNotifier.subscribeEventListener(listener) + consequenceDescription.triggerManager.subscribeEventListener(listener) } override fun subscribeEventListenerWithFilter( listener: Consumer>, filter: Class> ) { - consequenceDescription.triggerNotifier.subscribeEventListenerWithFilter(listener, filter) + consequenceDescription.triggerManager.subscribeEventListenerWithFilter(listener, filter) } override fun unsubscribe(listener: Consumer>) { - consequenceDescription.triggerNotifier.unsubscribe(listener) + consequenceDescription.triggerManager.unsubscribe(listener) } //--------------------------------------------------------------- diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt index f190cf9..fb0670f 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseDescription.kt @@ -7,7 +7,7 @@ import cambio.tltea.interpreter.nodes.cause.EventActivationListener class CauseDescription( val causeASTRoot: CauseNode, - private val listeners: List + val listeners: List ) { val causeChangePublisher: StateChangedPublisher = causeASTRoot diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt index 4b82bba..89d79af 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt @@ -49,8 +49,8 @@ class CauseInterpreter { } private fun interpretAsCauseEvent(valueNode: ValueASTNode): CauseNode { - if (valueNode.value.startsWith("(") && valueNode.value.endsWith(")")) { - val eventActivationListener = EventActivationListener(valueNode.value) + if (valueNode.containsEventName()) { + val eventActivationListener = EventActivationListener(valueNode.eventName) listeners.add(eventActivationListener) //wrap event activation in a ==True comparison diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt index 8588a18..535bea6 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceDescription.kt @@ -2,7 +2,7 @@ package cambio.tltea.interpreter.nodes import cambio.tltea.interpreter.nodes.consequence.ConsequenceNode -class ConsequenceDescription(val triggerNotifier: TriggerNotifier) { +class ConsequenceDescription(val triggerManager: TriggerManager) { internal fun activateConsequence() { consequenceAST?.activateConsequence() diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt index 7fef4a8..cb46617 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt @@ -6,7 +6,6 @@ import cambio.tltea.parser.core.* import cambio.tltea.parser.core.temporal.* - /** * Expects a future MTL formula. *

@@ -36,17 +35,17 @@ class ConsequenceInterpreter { /** * @param mtlRoot the root of the parsed MTL formula - * @param triggerNotifier this parameter can be used to combine multiple {@link TriggerNotifier}s from previous interpretations + * @param triggerManager this parameter can be used to combine multiple {@link TriggerNotifier}s from previous interpretations */ @JvmOverloads - fun interpretAsMTL(mtlRoot: ASTNode, triggerNotifier: TriggerNotifier = TriggerNotifier()): ConsequenceDescription { + fun interpretAsMTL(mtlRoot: ASTNode, triggerManager: TriggerManager = TriggerManager()): ConsequenceDescription { - val consequenceDescription = ConsequenceDescription(triggerNotifier) + val consequenceDescription = ConsequenceDescription(triggerManager) //gather initial temporal info val temporalContext = if (mtlRoot is ITemporalOperationInfoHolder) mtlRoot.toTemporalOperatorInfo() else TemporalOperatorInfo(OperatorToken.GLOBALLY, TemporalInterval(0.0, Double.POSITIVE_INFINITY)) - val consequenceAST = interpret(mtlRoot, triggerNotifier, temporalContext, consequenceDescription) + val consequenceAST = interpret(mtlRoot, temporalContext, consequenceDescription) consequenceDescription.consequenceAST = consequenceAST return consequenceDescription } @@ -57,36 +56,31 @@ class ConsequenceInterpreter { */ private fun interpret( node: ASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { return when (node) { is TemporalBinaryOperationASTNode -> interpretTemporalBinaryOperation( node, - triggerNotifier, temporalContext, consequenceDescription ) is TemporalUnaryOperationASTNode -> interpretTemporalUnaryOperation( node, - triggerNotifier, temporalContext, consequenceDescription ) is BinaryOperationASTNode -> interpretBinaryOperation( node, - triggerNotifier, temporalContext, consequenceDescription ) is UnaryOperationASTNode -> interpretUnaryOperation( node, - triggerNotifier, temporalContext, consequenceDescription ) - is ValueASTNode -> interpretValueNode(node, triggerNotifier, temporalContext, consequenceDescription) + is ValueASTNode -> interpretValueNode(node, temporalContext, consequenceDescription) else -> { throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") } @@ -97,7 +91,6 @@ class ConsequenceInterpreter { private fun interpretTemporalBinaryOperation( node: TemporalBinaryOperationASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { @@ -116,7 +109,6 @@ class ConsequenceInterpreter { private fun interpretTemporalUnaryOperation( node: TemporalUnaryOperationASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { @@ -126,21 +118,20 @@ class ConsequenceInterpreter { //TODO: for now the temporal context is simply passed down. In the future multiple temporal contexts may need to interact. //Prophecy, Globally, Finally, Next val temporalContext = node.toTemporalOperatorInfo() - return interpret(node.child, triggerNotifier, temporalContext, consequenceDescription) + return interpret(node.child, temporalContext, consequenceDescription) } private fun interpretBinaryOperation( node: BinaryOperationASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { if (node is TemporalBinaryOperationASTNode) { - return interpretTemporalBinaryOperation(node, triggerNotifier, temporalContext, consequenceDescription) + return interpretTemporalBinaryOperation(node, temporalContext, consequenceDescription) } else if (OperatorToken.ComparisonOperatorTokens.contains(node.operator)) { - //create consequnce comparison node + //create consequence comparison node val leftChild = node.leftChild as ValueASTNode val rightChild = node.rightChild as ValueASTNode @@ -154,37 +145,49 @@ class ConsequenceInterpreter { throw IllegalArgumentException("Cannot interpret value event. Neither left nor right child is a target property or event.") } + val targetValue = try { + targetValueHolder.value.toDouble() + } catch (e: NumberFormatException) { + targetValueHolder.value + } + return ValueEventConsequenceNode( - triggerNotifier, targetEventHolder.eventName, - targetValueHolder.value, + targetValue, + node.operator, + consequenceDescription.triggerManager, temporalContext ) } else { val interpretShorthand = - { child: ASTNode -> interpret(child, triggerNotifier, temporalContext, consequenceDescription) } + { child: ASTNode -> interpret(child, temporalContext, consequenceDescription) } when (node.operator) { OperatorToken.IMPLIES -> { //create implication node - return interpretImplication(node, triggerNotifier, temporalContext) + return interpretImplication(node, temporalContext, consequenceDescription) } OperatorToken.AND -> { //create consequence "and" node val children = ASTManipulator.flatten(node) - return AndConsequenceNode(triggerNotifier, temporalContext, children.map { interpretShorthand(it) }) + return AndConsequenceNode( + consequenceDescription.triggerManager, + temporalContext, + children.map { interpretShorthand(it) }) } OperatorToken.OR -> { //create consequence "or" node val children = ASTManipulator.flatten(node) - return OrConsequenceNode(triggerNotifier, temporalContext, children.map { interpretShorthand(it) }) + return OrConsequenceNode( + consequenceDescription.triggerManager, + temporalContext, + children.map { interpretShorthand(it) }) } OperatorToken.IFF -> { //split <-> into <- and -> //this only works in rare cases return interpretBinaryOperation( ASTManipulator.splitIFF(node), - triggerNotifier, temporalContext, consequenceDescription ) @@ -199,7 +202,6 @@ class ConsequenceInterpreter { private fun interpretUnaryOperation( node: UnaryOperationASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ConsequenceNode { @@ -207,18 +209,16 @@ class ConsequenceInterpreter { val child = node.child if (child is ValueASTNode) { val value = if (child.containsEventName()) child.eventName else child.value - return EventPreventionConsequenceNode(triggerNotifier, temporalContext, value) + return EventPreventionConsequenceNode(consequenceDescription.triggerManager, temporalContext, value) } else if (child is UnaryOperationASTNode && child.operator == OperatorToken.NOT) { return interpret( ASTManipulator.removeDoubleNot(node), - triggerNotifier, temporalContext, consequenceDescription ) } else { return interpret( ASTManipulator.applyNot(node), - triggerNotifier, temporalContext, consequenceDescription ) @@ -231,12 +231,15 @@ class ConsequenceInterpreter { private fun interpretValueNode( node: ValueASTNode, - triggerNotifier: TriggerNotifier, temporalContext: TemporalOperatorInfo, consequenceDescription: ConsequenceDescription ): ActivationConsequenceNode { if (node.containsEventName()) { - return EventActivationConsequenceNode(triggerNotifier, temporalContext, node.eventName) + return EventActivationConsequenceNode( + consequenceDescription.triggerManager, + temporalContext, + node.eventName + ) } else { throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") } @@ -244,8 +247,8 @@ class ConsequenceInterpreter { private fun interpretImplication( root: BinaryOperationASTNode, - triggerNotifier: TriggerNotifier, - temporalContext: TemporalOperatorInfo + temporalContext: TemporalOperatorInfo, + consequenceDescription: ConsequenceDescription ): ConsequenceNode { if (root.operator != OperatorToken.IMPLIES) { throw IllegalArgumentException("Expected operator ${OperatorToken.IMPLIES}, but found ${root.operator}") @@ -255,13 +258,16 @@ class ConsequenceInterpreter { val right = root.rightChild val cause = CauseInterpreter().interpretLTL(left) - val consequence = ConsequenceInterpreter().interpretAsMTL(right, triggerNotifier) + val consequence = ConsequenceInterpreter().interpretAsMTL(right, consequenceDescription.triggerManager) + + consequenceDescription.triggerManager.eventActivationListeners.addAll(cause.listeners) + return ImplicationNode( cause, consequence, temporalContext, - triggerNotifier + consequenceDescription.triggerManager, ) } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt index 35850e9..c08729b 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ImplicationNode.kt @@ -10,8 +10,8 @@ class ImplicationNode( private val causeDescription: CauseDescription, private val consequence: ConsequenceDescription, temporalContext: TemporalOperatorInfo, - triggerNotifier: TriggerNotifier -) : ConsequenceNode(triggerNotifier, temporalContext), StateChangeListener { + triggerManager: TriggerManager +) : ConsequenceNode(triggerManager, temporalContext), StateChangeListener { override fun activateConsequence() { //activate listeners to input of cause diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt similarity index 75% rename from interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt rename to interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt index 7438792..3d66bb2 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerNotifier.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt @@ -1,12 +1,15 @@ package cambio.tltea.interpreter.nodes +import cambio.tltea.interpreter.nodes.cause.EventActivationListener import cambio.tltea.interpreter.nodes.consequence.ActivationData import java.util.function.Consumer /** * @author Lion Wagner */ -class TriggerNotifier : ISubscribableTriggerNotifier { +class TriggerManager : ISubscribableTriggerNotifier { + + internal val eventActivationListeners: MutableCollection = HashSet() private val anySubscribers: MutableCollection>> = HashSet() @@ -17,7 +20,10 @@ class TriggerNotifier : ISubscribableTriggerNotifier { anySubscribers.add(listener) } - override fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) { + override fun subscribeEventListenerWithFilter( + listener: Consumer>, + filter: Class> + ) { if (!filteredSubscribers.containsKey(filter)) { filteredSubscribers[filter] = HashSet() } @@ -33,4 +39,5 @@ class TriggerNotifier : ISubscribableTriggerNotifier { anySubscribers.forEach { it.accept(activationData) } filteredSubscribers[activationData.javaClass]?.forEach { it.accept(activationData) } } + } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java index d4bc80c..a2472b7 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java @@ -2,7 +2,6 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.TriggerNotifier; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java index a272d75..9459c70 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java @@ -1,8 +1,6 @@ package cambio.tltea.interpreter.nodes.cause; -import cambio.tltea.interpreter.nodes.StateChangeListener; import cambio.tltea.interpreter.nodes.StateChangedPublisher; -import cambio.tltea.interpreter.nodes.TriggerNotifier; /** * @author Lion Wagner diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java index c50bd0a..5517546 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java @@ -1,19 +1,19 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.interpreter.nodes.StateChangeEvent; -import cambio.tltea.interpreter.nodes.StateChangeListener; import cambio.tltea.parser.core.OperatorToken; import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; -import kotlin.NotImplementedError; /** * @author Lion Wagner */ -public class ComparisonCauseNode extends CauseNode implements StateChangeListener { +public class ComparisonCauseNode extends CauseNode { private final OperatorToken operator; private final ValueProvider left; private final ValueProvider right; + private boolean lastValue = false; + public ComparisonCauseNode(OperatorToken operator, TemporalOperatorInfo temporalContext, ValueProvider left, @@ -24,12 +24,25 @@ public ComparisonCauseNode(OperatorToken operator, this.operator = operator; this.left = left; this.right = right; + + this.left.subscribe(event -> { + var lastValue = this.lastValue; + super.notifySubscribers(new StateChangeEvent<>(this, getCurrentValue(), lastValue, event.when())); + }); + this.right.subscribe(event -> { + var lastValue = this.lastValue; + super.notifySubscribers(new StateChangeEvent<>(this, getCurrentValue(), lastValue, event.when())); + }); } //TODO: optimization we always take the same path through this method therefore we may be able to optimize @Override public Boolean getCurrentValue() { + return lastValue = compareSides(); + } + + private boolean compareSides() { var val1 = left.currentValue; var val2 = right.currentValue; @@ -82,8 +95,4 @@ public OperatorToken getOperator() { return operator; } - @Override - public void onEvent(StateChangeEvent event) { - throw new NotImplementedError(); - } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java index d27f13f..c917d77 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java @@ -27,7 +27,7 @@ public void setActivated(ITemporalValue time) { } public void activate(ITemporalValue time) { - notifyAndChangeState(true, time); + changeStateAndNotify(true, time); } public void reset(ITemporalValue time) { @@ -35,6 +35,6 @@ public void reset(ITemporalValue time) { } public void deactivate(ITemporalValue time) { - notifyAndChangeState(false, time); + changeStateAndNotify(false, time); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java index bb43b3c..4a1871a 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java @@ -2,7 +2,6 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.TriggerNotifier; /** * @author Lion Wagner diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java index a370b95..9302155 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java @@ -2,10 +2,6 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; -import cambio.tltea.interpreter.nodes.StateChangedPublisher; -import cambio.tltea.interpreter.nodes.TriggerNotifier; -import cambio.tltea.parser.core.temporal.ITemporalValue; -import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java index d9bd777..90616d5 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java @@ -8,6 +8,6 @@ public class ValueListener extends ValueProvider { public void updateValue(T value, ITemporalValue time) { - super.notifyAndChangeState(value, time); + super.changeStateAndNotify(value, time); } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java index 8860968..ef00de5 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java @@ -8,15 +8,15 @@ public abstract class ValueProvider extends StateChangedPublisher { private boolean isListening; protected T currentValue; - protected void notifyAndChangeState(T newValue, ITemporalValue time) { + protected void changeStateAndNotify(T newValue, ITemporalValue time) { if (!isListening) { return; } + this.currentValue = newValue; subscribers.forEach(listener -> listener.onEvent(new StateChangeEvent<>(this, newValue, currentValue, time))); - this.currentValue = newValue; } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt index dc023dd..a2a72ba 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ActivationConsequenceNode.kt @@ -1,9 +1,9 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo abstract class ActivationConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo -) : ConsequenceNode(triggerNotifier, temporalContext) \ No newline at end of file +) : ConsequenceNode(triggerManager, temporalContext) \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt index eff30ed..220047c 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/AndConsequenceNode.kt @@ -2,15 +2,15 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class AndConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo, children: Collection ) : - ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { + ChildrenOwningConsequenceNode(triggerManager, temporalContext, children) { override fun activateConsequence() { children.forEach { it.activateConsequence() } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt index 7ccfa7b..0d5f6b2 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ChildrenOwningConsequenceNode.kt @@ -1,10 +1,10 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo abstract class ChildrenOwningConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo, protected val children: Collection -) : ConsequenceNode(triggerNotifier, temporalContext) \ No newline at end of file +) : ConsequenceNode(triggerManager, temporalContext) \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt index dd08337..6c5be70 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ConsequenceNode.kt @@ -2,14 +2,14 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo /** * @author Lion Wagner */ abstract class ConsequenceNode( - protected val triggerNotifier: TriggerNotifier, + protected val triggerManager: TriggerManager, protected val temporalContext: TemporalOperatorInfo ) { abstract fun activateConsequence() diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt index 71b8aa0..79aaacc 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationConsequenceNode.kt @@ -1,18 +1,18 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class EventActivationConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo, private val eventName: String, -) : ActivationConsequenceNode(triggerNotifier, temporalContext) { +) : ActivationConsequenceNode(triggerManager, temporalContext) { override fun activateConsequence() { - TODO("Not yet implemented") + triggerManager.trigger(EventActivationData(eventName, temporalContext)) } override fun deactivateConsequence() { - TODO("Not yet implemented") + triggerManager.trigger(EventPreventionData(eventName, temporalContext)) } } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt index a42e031..220e11b 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventActivationData.kt @@ -12,9 +12,11 @@ class EventActivationData(eventName: String, temporalContext: TemporalOperatorIn ActivationData(eventName, temporalContext) class ValueEventActivationData( + val targetProperty: String, data: T, - temporalContext: TemporalOperatorInfo, - operator: OperatorToken + val operator: OperatorToken, + val active: Boolean, + temporalContext: TemporalOperatorInfo ) : ActivationData( data, temporalContext diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt index 7a6d55d..f2863a1 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/EventPreventionConsequenceNode.kt @@ -1,13 +1,13 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class EventPreventionConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo, private val eventName: String, -) : ActivationConsequenceNode(triggerNotifier, temporalContext) { +) : ActivationConsequenceNode(triggerManager, temporalContext) { override fun activateConsequence() { TODO("Not yet implemented") } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt index 619006f..0194865 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/OrConsequenceNode.kt @@ -1,13 +1,13 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class OrConsequenceNode( - triggerNotifier: TriggerNotifier, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo, children: List -) : ChildrenOwningConsequenceNode(triggerNotifier, temporalContext, children) { +) : ChildrenOwningConsequenceNode(triggerManager, temporalContext, children) { override fun activateConsequence() { TODO("Not yet implemented") } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt index ed7a91e..8473c74 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/consequence/ValueEventConsequenceNode.kt @@ -1,21 +1,23 @@ package cambio.tltea.interpreter.nodes.consequence -import cambio.tltea.interpreter.nodes.TriggerNotifier +import cambio.tltea.interpreter.nodes.TriggerManager +import cambio.tltea.parser.core.OperatorToken import cambio.tltea.parser.core.temporal.TemporalOperatorInfo class ValueEventConsequenceNode( - triggerNotifier: TriggerNotifier, val targetProperty: String, val targetValue: T, + val operator: OperatorToken, + triggerManager: TriggerManager, temporalContext: TemporalOperatorInfo -) : ActivationConsequenceNode(triggerNotifier, temporalContext) { +) : ActivationConsequenceNode(triggerManager, temporalContext) { override fun activateConsequence() { - TODO("Not yet implemented") + triggerManager.trigger(ValueEventActivationData(targetProperty, targetValue, operator, true, temporalContext)) } override fun deactivateConsequence() { - TODO("Not yet implemented") + triggerManager.trigger(ValueEventActivationData(targetProperty, targetValue, operator, false, temporalContext)) } fun getType(): Class { diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java index c68988c..56cef81 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/utils/ASTManipulator.java @@ -114,7 +114,7 @@ public static ASTNode applyNot(@NotNull UnaryOperationASTNode notNode) { }; } else if (notNode.getChild() instanceof UnaryOperationASTNode unaryChild && unaryChild.getOperator() == OperatorToken.NOT) { - return removeDoubleNot(unaryChild); + return removeDoubleNot(notNode); } throw new IllegalArgumentException("Cannot apply NOT (yet?) to " + notNode.getChild() .getClass() diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java deleted file mode 100644 index d931e1f..0000000 --- a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package cambio.tltea.interpreter; - -import cambio.tltea.parser.core.ASTNode; -import cambio.tltea.parser.core.temporal.TimeInstance; -import cambio.tltea.parser.mtl.generated.MTLParser; -import cambio.tltea.parser.mtl.generated.ParseException; -import org.junit.jupiter.api.Test; - -class BehaviorInterpreterTest { - @Test - void debugTest() throws ParseException { - String input = "((P)&(C)&(D))->(Q)"; - ASTNode ast = new MTLParser(input).parse(); - BehaviorInterpreter behaviorInterpreter = new BehaviorInterpreter(); - var result = behaviorInterpreter.interpret(ast); - - result.getTriggerNotifier().subscribeEventListener((eventName, args) -> { - System.out.println(eventName); - }); - - result.getListeners().forEach(eventActivationListener -> eventActivationListener.activate(new TimeInstance(0))); - - System.out.println(result); - } -} \ No newline at end of file diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt new file mode 100644 index 0000000..9469470 --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt @@ -0,0 +1,32 @@ +package cambio.tltea.interpreter + +import cambio.tltea.interpreter.Interpreter.interpretAsBehavior +import cambio.tltea.parser.core.temporal.TimeInstance +import cambio.tltea.parser.mtl.generated.MTLParser +import cambio.tltea.parser.mtl.generated.ParseException +import org.junit.jupiter.api.Test + +internal class BehaviorInterpreterTest { + @Test + @Throws(ParseException::class) + fun debugTest() { + val input = "((P)&(!!(C))&(D))->((Q)==1234)" + val ast = MTLParser(input).parse() + val result = interpretAsBehavior(ast) + result.activateProcessing(); + + + result.triggerManager.subscribeEventListener { + println("hi $it") + } + + result.triggerManager.eventActivationListeners + .filter { !it.eventName.contains("F") } + .forEach { it.activate(TimeInstance(0.0)) } + result.triggerManager.eventActivationListeners + .filter { it.eventName.contains("F") } + .forEach { it.activate(TimeInstance(0.0)) } + + println(result) + } +} \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt b/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt index 7f5816d..d8d8cda 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt +++ b/parser/src/main/java/cambio/tltea/parser/core/ASTNodePrinter.kt @@ -3,7 +3,7 @@ package cambio.tltea.parser.core import java.io.PrintStream import kotlin.math.min -internal object ASTNodePrinter { +object ASTNodePrinter { private const val DEFAULT_CONSOLE_COLUMN_COUNT = 80 diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java index 8a9ba9e..a4064d8 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalOperatorInfo.java @@ -13,7 +13,7 @@ public final class TemporalOperatorInfo implements IOperatorInfo { public TemporalOperatorInfo(OperatorToken operator, ITemporalValue temporalValueExpression) { - if (OperatorToken.TemporalOperatorTokens.contains(operator)) { + if (!OperatorToken.TemporalOperatorTokens.contains(operator)) { throw new IllegalArgumentException("Operator " + operator + " is not allowed"); } this.operator = operator; From d3ac5cda9c14057bf9c588a25da71f2f3f04dbd1 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 3 May 2022 20:00:27 +0200 Subject: [PATCH 10/17] fixed tests --- .../tltea/interpreter/nodes/cause/CauseNode.java | 2 -- .../nodes/cause/ComparisonCauseNodeTest.java | 15 +++++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java index 9459c70..2a6e28d 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/CauseNode.java @@ -9,6 +9,4 @@ public abstract class CauseNode extends StateChangedPublisher { public abstract Boolean getCurrentValue(); - public CauseNode() { - } } diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java index 68aa128..839c9e3 100644 --- a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java +++ b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java @@ -39,22 +39,21 @@ private void testEQNEQ(ConstantValueProvider value, ConstantValueProvider equalValue, ConstantValueProvider otherValue) { ComparisonCauseNode identityNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, value); + ComparisonCauseNode invertedIdentityNode = new ComparisonCauseNode(OperatorToken.NEQ, null, value, value); ComparisonCauseNode equalNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, equalValue); ComparisonCauseNode neqNode = new ComparisonCauseNode(OperatorToken.NEQ, null, value, otherValue); Assertions.assertTrue(identityNode.getCurrentValue()); + Assertions.assertFalse(invertedIdentityNode.getCurrentValue()); Assertions.assertTrue(equalNode.getCurrentValue()); - Assertions.assertFalse(neqNode.getCurrentValue()); + Assertions.assertTrue(neqNode.getCurrentValue()); } - private void testWithInversion(boolean expected, ValueProvider value1, ValueProvider value2, OperatorToken op) { + private void testWithInversion(boolean expected, + ValueProvider value1, + ValueProvider value2, + OperatorToken op) { ComparisonCauseNode node = new ComparisonCauseNode(op, null, value1, value2); - ComparisonCauseNode invertedOpAndValues = new ComparisonCauseNode(op.invert(), null, value2, value1); - ComparisonCauseNode invertedOP = new ComparisonCauseNode(op.invert(), null, value1, value2); - Assertions.assertEquals(expected, node.getCurrentValue()); - Assertions.assertEquals(expected, invertedOpAndValues.getCurrentValue()); - Assertions.assertEquals(!expected, invertedOP.getCurrentValue()); - } } \ No newline at end of file From 7aefaf781c7cc9e70f394a066ad7b08a8712b8f8 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 10 May 2022 05:48:49 +0200 Subject: [PATCH 11/17] Implement Equals for TemporalEventDescription --- .../temporal/TemporalEventDescription.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java index d0256d2..acb138f 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalEventDescription.java @@ -1,9 +1,28 @@ package cambio.tltea.parser.core.temporal; +import java.util.Objects; + public record TemporalEventDescription(String value) implements ITemporalValue { public String getValue() { return value; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TemporalEventDescription)) { + return false; + } + + TemporalEventDescription that = (TemporalEventDescription) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } } From b1308ff1a9c5b8f4c6757b10a928bce3dd1ecfd7 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 10 May 2022 05:50:03 +0200 Subject: [PATCH 12/17] Added temporal behavior to cause interpretation --- .../interpreter/nodes/CauseInterpreter.kt | 44 +-- .../nodes/ConsequenceInterpreter.kt | 2 +- .../nodes/StateChangedPublisher.java | 2 +- .../interpreter/nodes/cause/AndCauseNode.java | 4 +- .../interpreter/nodes/cause/CauseNode.java | 33 +++ .../nodes/cause/ComparisonCauseNode.java | 20 +- .../nodes/cause/ConstantValueProvider.java | 3 + .../nodes/cause/EventActivationListener.java | 6 + .../interpreter/nodes/cause/NotCauseNode.java | 4 +- .../interpreter/nodes/cause/OrCauseNode.java | 5 +- .../nodes/cause/ValueListener.java | 4 + .../nodes/cause/ValueProvider.java | 4 +- .../nodes/cause/ComparisonCauseNodeTest.java | 254 +++++++++++++++--- 13 files changed, 316 insertions(+), 69 deletions(-) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt index 89d79af..273597b 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt @@ -3,27 +3,35 @@ package cambio.tltea.interpreter.nodes import cambio.tltea.interpreter.nodes.cause.* import cambio.tltea.interpreter.utils.ASTManipulator import cambio.tltea.parser.core.* +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo +import cambio.tltea.parser.core.temporal.TemporalUnaryOperationASTNode class CauseInterpreter { private val listeners = mutableListOf() - fun interpretLTL(root: ASTNode): CauseDescription { - val interpretedRoot: CauseNode = interpretAsCause(root) + fun interpretMTLCause( + root: ASTNode, + temporalContext: TemporalOperatorInfo = TemporalOperatorInfo(OperatorToken.GLOBALLY, "[0,inf]") + ): CauseDescription { + val interpretedRoot: CauseNode = interpretAsCause(root, temporalContext) return CauseDescription(interpretedRoot, listeners) } - private fun interpretAsCause(root: ASTNode): CauseNode { + private fun interpretAsCause(root: ASTNode, temporalContext: TemporalOperatorInfo): CauseNode { return when (root) { + is TemporalUnaryOperationASTNode -> { + return interpretAsCause(root.child, root.toTemporalOperatorInfo()) + } is ValueASTNode -> { interpretAsCauseEvent(root) } is UnaryOperationASTNode -> { - interpretAsCause(root) + interpretAsCause(root, temporalContext) } is BinaryOperationASTNode -> { - interpretAsCause(root) + interpretAsCause(root, temporalContext) } else -> { throw IllegalArgumentException("Unsupported ASTNode type: ${root.javaClass.name}"); @@ -32,15 +40,15 @@ class CauseInterpreter { } private fun interpretAsCause( - unNode: UnaryOperationASTNode + unNode: UnaryOperationASTNode, temporalContext: TemporalOperatorInfo ): CauseNode { when (unNode.operator) { OperatorToken.NOT -> { if (unNode.child is ValueASTNode) { @Suppress("UNCHECKED_CAST") - return NotCauseNode(interpretAsCauseEvent(unNode.child as ValueASTNode)) - } else return (interpretAsCause(ASTManipulator.applyNot(unNode))) + return NotCauseNode(interpretAsCauseEvent(unNode.child as ValueASTNode), temporalContext) + } else return (interpretAsCause(ASTManipulator.applyNot(unNode), temporalContext)) } else -> { throw UnsupportedOperationException("Operator not supported for cause description (left side of implication): " + unNode.getOperator()); @@ -76,15 +84,15 @@ class CauseInterpreter { } - private fun interpretAsCause(binaryNode: BinaryOperationASTNode): CauseNode { + private fun interpretAsCause(binaryNode: BinaryOperationASTNode, temporalContext: TemporalOperatorInfo): CauseNode { return when (binaryNode.operator) { OperatorToken.AND -> { - val children = flattenCause(binaryNode) - AndCauseNode(*children.toTypedArray()) + val children = flattenCause(binaryNode, temporalContext) + AndCauseNode(temporalContext, *children.toTypedArray()) } OperatorToken.OR -> { - val children = flattenCause(binaryNode) - OrCauseNode(*children.toTypedArray()) + val children = flattenCause(binaryNode, temporalContext) + OrCauseNode(temporalContext, *children.toTypedArray()) } else -> { if (OperatorToken.ComparisonOperatorTokens.contains(binaryNode.operator) @@ -108,21 +116,21 @@ class CauseInterpreter { } } - private fun flattenCause(root: BinaryOperationASTNode): List { + private fun flattenCause(root: BinaryOperationASTNode, temporalContext: TemporalOperatorInfo): List { val children = mutableListOf() val leftChild = root.leftChild if (leftChild is BinaryOperationASTNode && leftChild.operator == root.operator) { - children.addAll(flattenCause(leftChild)) + children.addAll(flattenCause(leftChild, temporalContext)) } else { - children.add(interpretAsCause(leftChild)) + children.add(interpretAsCause(leftChild, temporalContext)) } val rightChild = root.rightChild if (rightChild is BinaryOperationASTNode && rightChild.operator == root.operator) { - children.addAll(flattenCause(rightChild)) + children.addAll(flattenCause(rightChild, temporalContext)) } else { - children.add(interpretAsCause(rightChild)) + children.add(interpretAsCause(rightChild, temporalContext)) } return children diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt index cb46617..01dda6d 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt @@ -257,7 +257,7 @@ class ConsequenceInterpreter { val left = root.leftChild val right = root.rightChild - val cause = CauseInterpreter().interpretLTL(left) + val cause = CauseInterpreter().interpretMTLCause(left,temporalContext) val consequence = ConsequenceInterpreter().interpretAsMTL(right, consequenceDescription.triggerManager) consequenceDescription.triggerManager.eventActivationListeners.addAll(cause.listeners) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java index 5961b88..7282229 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/StateChangedPublisher.java @@ -17,7 +17,7 @@ public final void unsubscribe(StateChangeListener listener) { subscribers.remove(listener); } - protected final void notifySubscribers(StateChangeEvent event) { + protected void notifySubscribers(StateChangeEvent event) { for (StateChangeListener listener : subscribers) { listener.onEvent(event); } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java index a2472b7..fa0696e 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/AndCauseNode.java @@ -2,6 +2,7 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; @@ -16,7 +17,8 @@ public class AndCauseNode extends CauseNode implements StateChangeListener { + private final TemporalOperatorInfo temporalContext; + + public CauseNode(TemporalOperatorInfo temporalContext) { + this.temporalContext = temporalContext; + } + public abstract Boolean getCurrentValue(); + protected final boolean satisfiesTemporalContext(ITemporalValue activationTime) { + if (temporalContext.temporalValueExpression() instanceof TemporalInterval interval) { + if (activationTime instanceof TemporalInterval activationInterval) { + return interval.contains(activationInterval); + } else if (activationTime instanceof TimeInstance timeInstance) { + return interval.contains(timeInstance.getTime()); + } + } else if (temporalContext.temporalValueExpression() instanceof TimeInstance timeInstance) { + if (activationTime instanceof TimeInstance activationTimeInstance) { + return timeInstance.equals(activationTimeInstance); + } + } else if (temporalContext.temporalValueExpression() instanceof TemporalEventDescription temporalEventDescription) { + if (activationTime instanceof TemporalEventDescription activationTemporalEventDescription) { + return temporalEventDescription.equals(activationTemporalEventDescription); + } + } + return false; + } + + @Override + protected void notifySubscribers(StateChangeEvent event) { + if (satisfiesTemporalContext(event.when())) { + super.notifySubscribers(event); + } + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java index 5517546..cc9e418 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNode.java @@ -18,6 +18,7 @@ public ComparisonCauseNode(OperatorToken operator, TemporalOperatorInfo temporalContext, ValueProvider left, ValueProvider right) { + super(temporalContext); if (!OperatorToken.ComparisonOperatorTokens.contains(operator)) { throw new IllegalArgumentException("Operator not supported as comparison: " + operator); } @@ -36,7 +37,7 @@ public ComparisonCauseNode(OperatorToken operator, } - //TODO: optimization we always take the same path through this method therefore we may be able to optimize + //TODO: optimization: we always take the same path through this method therefore we may be able to optimize @Override public Boolean getCurrentValue() { return lastValue = compareSides(); @@ -49,6 +50,9 @@ private boolean compareSides() { if (val1 == null || val2 == null) { return false; } + if (val1 == val2) { + return operator == OperatorToken.EQ; + } if (val1 instanceof String && val2 instanceof String) { return switch (operator) { case EQ -> val1.equals(val2); @@ -69,11 +73,17 @@ private boolean compareSides() { try { int compareValue = 0; if (val1 instanceof Comparable c1) { - compareValue = c1.compareTo(val2); - } else //noinspection ConstantConditions - if (val2 instanceof Comparable c2) { - compareValue = -c2.compareTo(val1);//need to be reversed because we are comparing the other way around + try { + compareValue = c1.compareTo(val2); + } catch (Exception e) { + if (val2 instanceof Comparable c2) { + compareValue = -c2.compareTo(val1);//need to be reversed because we are comparing the other way around + } } + } else { + compareValue = -((Comparable) val2).compareTo(val1);//need to be reversed because we are comparing the other way around + } + return switch (operator) { case EQ -> compareValue == 0; case NEQ -> compareValue != 0; diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java index 28ba017..bdf2150 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ConstantValueProvider.java @@ -10,4 +10,7 @@ public ConstantValueProvider(T value) { this.currentValue = value; } + public ConstantValueProvider clone() { + return new ConstantValueProvider<>(currentValue); + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java index c917d77..31e4935 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/EventActivationListener.java @@ -1,6 +1,8 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.parser.core.temporal.ITemporalValue; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; /** * @author Lion Wagner @@ -37,4 +39,8 @@ public void reset(ITemporalValue time) { public void deactivate(ITemporalValue time) { changeStateAndNotify(false, time); } + + public @NotNull EventActivationListener clone() { + return new EventActivationListener(eventName); + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java index 4a1871a..838667e 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/NotCauseNode.java @@ -2,6 +2,7 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; /** * @author Lion Wagner @@ -10,7 +11,8 @@ public final class NotCauseNode extends CauseNode implements StateChangeListener private final CauseNode child; - public NotCauseNode(CauseNode child) { + public NotCauseNode(CauseNode child, TemporalOperatorInfo temporalContext) { + super(temporalContext); this.child = child; child.subscribe(this); } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java index 9302155..e05c5ae 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/OrCauseNode.java @@ -2,6 +2,7 @@ import cambio.tltea.interpreter.nodes.StateChangeEvent; import cambio.tltea.interpreter.nodes.StateChangeListener; +import cambio.tltea.parser.core.temporal.TemporalOperatorInfo; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; @@ -17,7 +18,8 @@ public class OrCauseNode extends CauseNode implements StateChangeListener event) { + if (event.getNewValue() != event.getOldValue()) { if (event.getNewValue()) { trueCount.incrementAndGet(); diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java index 90616d5..8d46bd1 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueListener.java @@ -10,4 +10,8 @@ public class ValueListener extends ValueProvider { public void updateValue(T value, ITemporalValue time) { super.changeStateAndNotify(value, time); } + + public ValueListener clone() { + return new ValueListener<>(); + } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java index ef00de5..dafbb80 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/cause/ValueProvider.java @@ -4,7 +4,7 @@ import cambio.tltea.interpreter.nodes.StateChangedPublisher; import cambio.tltea.parser.core.temporal.ITemporalValue; -public abstract class ValueProvider extends StateChangedPublisher { +public abstract class ValueProvider extends StateChangedPublisher{ private boolean isListening; protected T currentValue; @@ -27,4 +27,6 @@ public void startListening() { public void stopListening() { isListening = false; } + + public abstract ValueProvider clone(); } diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java index 839c9e3..e19c86c 100644 --- a/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java +++ b/interpreter/src/test/java/cambio/tltea/interpreter/nodes/cause/ComparisonCauseNodeTest.java @@ -1,59 +1,233 @@ package cambio.tltea.interpreter.nodes.cause; import cambio.tltea.parser.core.OperatorToken; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.Random; +import java.util.function.BiConsumer; + class ComparisonCauseNodeTest { + + private static void testComparison(boolean expected, + ValueProvider value1, + ValueProvider value2, + OperatorToken op) { + ComparisonCauseNode node = new ComparisonCauseNode(op, null, value1, value2); + Assertions.assertEquals(expected, node.getCurrentValue()); + } + + private static void testThrowsException(ValueProvider value1, ValueProvider value2, OperatorToken op) { + try { + new ComparisonCauseNode(op, null, value1, value2).getCurrentValue(); + } catch (IllegalStateException | IllegalArgumentException e) { + return; + } + Assertions.fail("Expected IllegalStateException or IllegalArgumentException"); + } + + private static void testEQNEQ(ConstantValueProvider value, + ConstantValueProvider differentValue) { + testComparison(true, value, value, OperatorToken.EQ); //identity + testComparison(false, value, value, OperatorToken.NEQ); //inverted identity + testComparison(true, value, value.clone(), OperatorToken.EQ); //equality + testComparison(false, value, value.clone(), OperatorToken.NEQ); //inverted equality + testComparison(false, value, differentValue, OperatorToken.EQ); //difference + testComparison(true, value, differentValue, OperatorToken.NEQ); //inverted difference + } + + @Test void stringComparisonTest() { ConstantValueProvider value = new ConstantValueProvider<>("a"); - ConstantValueProvider clone = new ConstantValueProvider<>("a"); ConstantValueProvider other = new ConstantValueProvider<>("B"); - testEQNEQ(value, clone, other); + testEQNEQ(value, other); + testThrowsException(value, other, OperatorToken.GT); + testThrowsException(value, other, OperatorToken.GEQ); + testThrowsException(value, other, OperatorToken.LT); + testThrowsException(value, other, OperatorToken.LEQ); + + } - ComparisonCauseNode failing = new ComparisonCauseNode(OperatorToken.LT, null, value, value); - Assertions.assertThrows(IllegalStateException.class, failing::getCurrentValue); + private static void testComparisonOperators(ValueProvider smallProvider, + ValueProvider largeProvider) { + testComparison(true, smallProvider, smallProvider, OperatorToken.EQ); + testComparison(true, smallProvider, smallProvider.clone(), OperatorToken.EQ); + testComparison(false, smallProvider, smallProvider, OperatorToken.NEQ); + testComparison(false, smallProvider, smallProvider.clone(), OperatorToken.NEQ); + testComparison(true, smallProvider, largeProvider, OperatorToken.LT); + testComparison(false, smallProvider, largeProvider, OperatorToken.LT.invert()); + testComparison(true, smallProvider, largeProvider, OperatorToken.LEQ); + testComparison(false, smallProvider, largeProvider, OperatorToken.LEQ.invert()); + testComparison(false, smallProvider, largeProvider, OperatorToken.GT); + testComparison(true, smallProvider, largeProvider, OperatorToken.GT.invert()); + testComparison(false, smallProvider, largeProvider, OperatorToken.GEQ); + testComparison(true, smallProvider, largeProvider, OperatorToken.GEQ.invert()); } @Test - void integerComparisonTest() { - ConstantValueProvider value = new ConstantValueProvider<>(1); - ConstantValueProvider clone = new ConstantValueProvider<>(1); - ConstantValueProvider other = new ConstantValueProvider<>(2); - testEQNEQ(value, clone, other); - - testWithInversion(true, value, value, OperatorToken.EQ); - testWithInversion(true, value, clone, OperatorToken.EQ); - testWithInversion(false, value, value, OperatorToken.NEQ); - testWithInversion(false, value, clone, OperatorToken.NEQ); - testWithInversion(true, value, other, OperatorToken.LT); - testWithInversion(true, value, other, OperatorToken.LEQ); - testWithInversion(false, value, other, OperatorToken.GT); - testWithInversion(false, value, other, OperatorToken.GEQ); - } - - private void testEQNEQ(ConstantValueProvider value, - ConstantValueProvider equalValue, - ConstantValueProvider otherValue) { - ComparisonCauseNode identityNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, value); - ComparisonCauseNode invertedIdentityNode = new ComparisonCauseNode(OperatorToken.NEQ, null, value, value); - ComparisonCauseNode equalNode = new ComparisonCauseNode(OperatorToken.EQ, null, value, equalValue); - ComparisonCauseNode neqNode = new ComparisonCauseNode(OperatorToken.NEQ, null, value, otherValue); - - Assertions.assertTrue(identityNode.getCurrentValue()); - Assertions.assertFalse(invertedIdentityNode.getCurrentValue()); - Assertions.assertTrue(equalNode.getCurrentValue()); - Assertions.assertTrue(neqNode.getCurrentValue()); - } - - private void testWithInversion(boolean expected, - ValueProvider value1, - ValueProvider value2, - OperatorToken op) { - ComparisonCauseNode node = new ComparisonCauseNode(op, null, value1, value2); - Assertions.assertEquals(expected, node.getCurrentValue()); + void numberComparisonTest() { + + Random rng = new Random(); + + BiConsumer constantNumberProviderTest = (smaller, larger) -> { + ConstantValueProvider smallProvider = new ConstantValueProvider<>(smaller); + ConstantValueProvider largeProvider = new ConstantValueProvider<>(larger); + + testEQNEQ(smallProvider, largeProvider); + + testComparisonOperators(smallProvider, largeProvider); + + Arrays.stream(OperatorToken.values()) + .filter(op -> !OperatorToken.ComparisonOperatorTokens.contains(op)) + .forEach(op -> testThrowsException(smallProvider, largeProvider, op)); + }; + + + for (int i = 0; i < 1000; i++) { + int other, value = rng.nextInt(); + + do { + other = rng.nextInt(); + } while (other >= value); + + constantNumberProviderTest.accept(other, value); + } + + for (int i = 0; i < 1000; i++) { + double other, value = Integer.MAX_VALUE * rng.nextDouble(); + + do { + other = Integer.MAX_VALUE * rng.nextDouble(); + } while (other >= value); + + constantNumberProviderTest.accept(other, value); + } + } + + abstract static class Parent implements Comparable> { + protected final T value; + + @Override + public abstract int compareTo(@NotNull ComparisonCauseNodeTest.Parent o); + + public Parent(T value) { + this.value = value; + } + + } + + static class Child1 extends Parent { + + public Child1(T value) { + super(value); + } + + @Override + public int compareTo(@NotNull ComparisonCauseNodeTest.Parent o) { + return value == o.value ? 0 : value.hashCode() - o.value.hashCode(); + } + } + + static class Child2 extends Parent { + + public Child2(T value) { + super(value); + } + + @Override + public int compareTo(@NotNull ComparisonCauseNodeTest.Parent o) { + return value == o.value ? 0 : value.hashCode() - o.value.hashCode(); + } + } + + + static class IntComparable implements Comparable{ + + private final int value; + + public IntComparable(int value) { + this.value = value; + } + + @Override + public int compareTo(@NotNull Integer o) { + return value == o ? 0 : value - o; + } + } + + static class NotComparable { + public final int value; + NotComparable(int value) { + this.value = value; + } + } + static class NotComparableComparable implements Comparable{ + public final int value; + NotComparableComparable(int value) { + this.value = value; + } + + @Override + public int compareTo(@NotNull ComparisonCauseNodeTest.NotComparable o) { + return value == o.value ? 0 : value - o.value; + } + } + + @Test + void objectComparisonTest() { + Parent parent1 = new Child1<>(1); + Parent parent2 = new Child2<>(2); + + var smallProvider = new ConstantValueProvider<>(parent1); + var largeProvider = new ConstantValueProvider<>(parent2); + + testComparison(true, smallProvider, smallProvider, OperatorToken.EQ); + testComparison(true, smallProvider, smallProvider.clone(), OperatorToken.EQ); + testComparison(false, smallProvider, smallProvider, OperatorToken.NEQ); + testComparison(false, smallProvider, smallProvider.clone(), OperatorToken.NEQ); + testComparison(true, smallProvider, largeProvider, OperatorToken.LT); + testComparison(false, smallProvider, largeProvider, OperatorToken.LT.invert()); + testComparison(true, smallProvider, largeProvider, OperatorToken.LEQ); + testComparison(false, smallProvider, largeProvider, OperatorToken.LEQ.invert()); + testComparison(false, smallProvider, largeProvider, OperatorToken.GT); + testComparison(true, smallProvider, largeProvider, OperatorToken.GT.invert()); + testComparison(false, smallProvider, largeProvider, OperatorToken.GEQ); + testComparison(true, smallProvider, largeProvider, OperatorToken.GEQ.invert()); + + } + + @Test + void oneWayObjectComparisonTest(){ + + var smallProvider2 = new ConstantValueProvider<>(1); + var largeProvider2 = new ConstantValueProvider<>(new IntComparable(2)); + + testComparison(true, smallProvider2, smallProvider2, OperatorToken.EQ); + testComparison(true, smallProvider2, smallProvider2.clone(), OperatorToken.EQ); + testComparison(false, smallProvider2, smallProvider2, OperatorToken.NEQ); + testComparison(false, smallProvider2, smallProvider2.clone(), OperatorToken.NEQ); + testComparison(true, smallProvider2, largeProvider2, OperatorToken.LT); + testComparison(false, smallProvider2, largeProvider2, OperatorToken.LT.invert()); + testComparison(true, smallProvider2, largeProvider2, OperatorToken.LEQ); + testComparison(false, smallProvider2, largeProvider2, OperatorToken.LEQ.invert()); + testComparison(false, smallProvider2, largeProvider2, OperatorToken.GT); + testComparison(true, smallProvider2, largeProvider2, OperatorToken.GT.invert()); + testComparison(false, smallProvider2, largeProvider2, OperatorToken.GEQ); + testComparison(true, smallProvider2, largeProvider2, OperatorToken.GEQ.invert()); + + + + var notComparable = new ConstantValueProvider<>(new NotComparable(1)); + var notComparableComparable = new ConstantValueProvider<>(new NotComparableComparable(1)); + + testComparison(true, notComparable, notComparableComparable, OperatorToken.EQ); + testComparison(true, notComparable, notComparableComparable.clone(), OperatorToken.EQ); + testComparison(false, notComparable, notComparableComparable, OperatorToken.NEQ); + testComparison(false, notComparable, notComparableComparable.clone(), OperatorToken.NEQ); } } \ No newline at end of file From 3123f696965d8b35312b9397ebe83c10d5edc1cd Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 10 May 2022 05:54:55 +0200 Subject: [PATCH 13/17] Fixed missing argument --- .../cambio/tltea/interpreter/nodes/CauseInterpreter.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt index 273597b..fe1bd87 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/CauseInterpreter.kt @@ -25,7 +25,7 @@ class CauseInterpreter { return interpretAsCause(root.child, root.toTemporalOperatorInfo()) } is ValueASTNode -> { - interpretAsCauseEvent(root) + interpretAsCauseEvent(root, temporalContext) } is UnaryOperationASTNode -> { interpretAsCause(root, temporalContext) @@ -47,7 +47,7 @@ class CauseInterpreter { OperatorToken.NOT -> { if (unNode.child is ValueASTNode) { @Suppress("UNCHECKED_CAST") - return NotCauseNode(interpretAsCauseEvent(unNode.child as ValueASTNode), temporalContext) + return NotCauseNode(interpretAsCauseEvent(unNode.child as ValueASTNode, temporalContext), temporalContext) } else return (interpretAsCause(ASTManipulator.applyNot(unNode), temporalContext)) } else -> { @@ -56,13 +56,13 @@ class CauseInterpreter { } } - private fun interpretAsCauseEvent(valueNode: ValueASTNode): CauseNode { + private fun interpretAsCauseEvent(valueNode: ValueASTNode, temporalContext: TemporalOperatorInfo): CauseNode { if (valueNode.containsEventName()) { val eventActivationListener = EventActivationListener(valueNode.eventName) listeners.add(eventActivationListener) //wrap event activation in a ==True comparison - return ComparisonCauseNode(OperatorToken.EQ, null, eventActivationListener, ConstantValueProvider(true)) + return ComparisonCauseNode(OperatorToken.EQ, temporalContext, eventActivationListener, ConstantValueProvider(true)) } else if (valueNode.value.contains("$")) { TODO("A value watcher cannot be created yet.") } From 88542efa160ffdcfbdb650f099c52f5535c17b59 Mon Sep 17 00:00:00 2001 From: LWagner Date: Tue, 10 May 2022 23:43:12 +0200 Subject: [PATCH 14/17] Fixed wrong cloning of nodes --- .../cambio/tltea/parser/core/OperatorASTNode.java | 5 +++++ .../temporal/TemporalBinaryOperationASTNode.java | 11 +++++++++-- .../temporal/TemporalUnaryOperationASTNode.java | 7 ++++++- .../tltea/parser/core/temporal/TimeInstance.java | 14 ++++++++++++++ .../java/cambio/tltea/parser/core/ASTNodeTest.java | 11 +++++++++++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java index 4bcbb47..6a266a8 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/OperatorASTNode.java @@ -18,4 +18,9 @@ public OperatorASTNode(OperatorToken operator) { public OperatorToken getOperator() { return operator; } + + @Override + public String toString() { + return operator.toString(); + } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java index 3d81514..86b883b 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalBinaryOperationASTNode.java @@ -21,7 +21,7 @@ public TemporalBinaryOperationASTNode(TemporalOperatorInfo operatorInfo, ASTNode } @Override - public TemporalOperatorInfo toTemporalOperatorInfo(){ + public TemporalOperatorInfo toTemporalOperatorInfo() { return new TemporalOperatorInfo(this.getOperator(), this.getTemporalValue()); } @@ -37,7 +37,14 @@ public ITemporalValue getTemporalValue() { @Override public String toFormulaString() { - return super.toFormulaString() + this.getTemporalValue().toString(); + return super.toFormulaString() + this.getTemporalValue().toString(); + } + + @Override + public ASTNode clone() { + return new TemporalBinaryOperationASTNode(this.toTemporalOperatorInfo(), + this.getLeftChild().clone(), + this.getRightChild().clone()); } } \ No newline at end of file diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java index 94ab23c..c9ff6ad 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TemporalUnaryOperationASTNode.java @@ -42,6 +42,11 @@ public ITemporalValue getTemporalValue() { @Override public String toFormulaString() { - return super.toFormulaString() + this.getTemporalValue().toString(); + return super.toFormulaString() + this.getTemporalValue().toString(); + } + + @Override + public ASTNode clone() { + return new TemporalUnaryOperationASTNode(this.toTemporalOperatorInfo(), this.getChild().clone()); } } diff --git a/parser/src/main/java/cambio/tltea/parser/core/temporal/TimeInstance.java b/parser/src/main/java/cambio/tltea/parser/core/temporal/TimeInstance.java index 76178c2..68244d8 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/temporal/TimeInstance.java +++ b/parser/src/main/java/cambio/tltea/parser/core/temporal/TimeInstance.java @@ -1,5 +1,7 @@ package cambio.tltea.parser.core.temporal; +import org.jetbrains.annotations.NotNull; + import java.util.Objects; public final class TimeInstance implements ITemporalValue { @@ -9,6 +11,18 @@ public TimeInstance(double time) { this.time = time; } + public TimeInstance(int time) { + this.time = time; + } + + public TimeInstance(@NotNull TimeInstance other) { + this.time = other.time; + } + + public TimeInstance(@NotNull Number time) { + this.time = time.doubleValue(); + } + public double getTime() { return time; } diff --git a/parser/src/test/java/cambio/tltea/parser/core/ASTNodeTest.java b/parser/src/test/java/cambio/tltea/parser/core/ASTNodeTest.java index 0924f35..06d81bd 100644 --- a/parser/src/test/java/cambio/tltea/parser/core/ASTNodeTest.java +++ b/parser/src/test/java/cambio/tltea/parser/core/ASTNodeTest.java @@ -4,6 +4,8 @@ import cambio.tltea.parser.core.BinaryOperationASTNode; import cambio.tltea.parser.core.UnaryOperationASTNode; import cambio.tltea.parser.core.ValueASTNode; +import cambio.tltea.parser.mtl.generated.MTLParser; +import cambio.tltea.parser.mtl.generated.ParseException; import cambio.tltea.parser.testhelper.ASTTreeComparison; import org.junit.jupiter.api.Test; @@ -43,4 +45,13 @@ void cloneTest() { assertNotSame(root, clone); ASTTreeComparison.compareAST(root, clone); } + + + @Test + void cloneTest2() throws ParseException { + MTLParser parser = new MTLParser("G[0,1]((A)&(B)|F[A](C)->!(F))"); + ASTNode result = parser.parse(); + ASTNode clone = result.clone(); + ASTTreeComparison.compareAST(result, clone); + } } \ No newline at end of file From cc5d705dcd9c5d8afe0b9fcf4af95e72b6fca965 Mon Sep 17 00:00:00 2001 From: LWagner Date: Wed, 11 May 2022 01:03:50 +0200 Subject: [PATCH 15/17] Code cleanup --- .../tltea/interpreter/BehaviorInterpretationResult.kt | 9 ++++----- .../tltea/interpreter/nodes/ConsequenceInterpreter.kt | 2 +- .../interpreter/nodes/ISubscribableTriggerNotifier.kt | 6 +++++- .../cambio/tltea/interpreter/nodes/TriggerManager.kt | 10 +++++----- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt index ab27f3f..16d3cc6 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/BehaviorInterpretationResult.kt @@ -18,9 +18,8 @@ class BehaviorInterpretationResult internal constructor( ISubscribableTriggerNotifier { - fun activateProcessing() { - consequenceDescription.activateConsequence() + consequenceDescription.activateConsequence() } // ----- delegating the subscriptions to the trigger manager----- @@ -28,9 +27,9 @@ class BehaviorInterpretationResult internal constructor( consequenceDescription.triggerManager.subscribeEventListener(listener) } - override fun subscribeEventListenerWithFilter( - listener: Consumer>, - filter: Class> + override fun > subscribeEventListenerWithFilter( + listener: Consumer, + filter: Class ) { consequenceDescription.triggerManager.subscribeEventListenerWithFilter(listener, filter) } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt index 01dda6d..2bf63ce 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ConsequenceInterpreter.kt @@ -225,7 +225,7 @@ class ConsequenceInterpreter { } } else { - throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") + throw IllegalArgumentException("Cannot interpret node of type ${node.javaClass.simpleName}") } } diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt index badda3a..4aa9991 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/ISubscribableTriggerNotifier.kt @@ -5,6 +5,10 @@ import java.util.function.Consumer interface ISubscribableTriggerNotifier { fun subscribeEventListener(listener: Consumer>) - fun subscribeEventListenerWithFilter(listener: Consumer>, filter: Class>) + fun > subscribeEventListenerWithFilter( + listener: Consumer, + filter: Class + ) + fun unsubscribe(listener: Consumer>) } \ No newline at end of file diff --git a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt index 3d66bb2..6f5bddb 100644 --- a/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt +++ b/interpreter/src/main/java/cambio/tltea/interpreter/nodes/TriggerManager.kt @@ -13,21 +13,21 @@ class TriggerManager : ISubscribableTriggerNotifier { private val anySubscribers: MutableCollection>> = HashSet() - private val filteredSubscribers: HashMap>, MutableSet>>> = + private val filteredSubscribers: HashMap, MutableSet>>> = HashMap() override fun subscribeEventListener(listener: Consumer>) { anySubscribers.add(listener) } - override fun subscribeEventListenerWithFilter( - listener: Consumer>, - filter: Class> + override fun > subscribeEventListenerWithFilter( + listener: Consumer, + filter: Class ) { if (!filteredSubscribers.containsKey(filter)) { filteredSubscribers[filter] = HashSet() } - filteredSubscribers[filter]!!.add(listener) + filteredSubscribers[filter]!!.add(listener as Consumer>) } override fun unsubscribe(listener: Consumer>) { From df8e8ab83b63c1972361190a80eadfc8bef4299d Mon Sep 17 00:00:00 2001 From: LWagner Date: Wed, 11 May 2022 01:04:15 +0200 Subject: [PATCH 16/17] Added test for temporal modifiers --- .../interpreter/BehaviorInterpreterTest.kt | 2 +- .../tltea/interpreter/InterpreterTest.kt | 68 ++++++++++++++++++ .../tltea/interpreter/testutils/TestBase.kt | 70 +++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/InterpreterTest.kt create mode 100644 interpreter/src/test/java/cambio/tltea/interpreter/testutils/TestBase.kt diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt index 9469470..a400dd4 100644 --- a/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt +++ b/interpreter/src/test/java/cambio/tltea/interpreter/BehaviorInterpreterTest.kt @@ -10,7 +10,7 @@ internal class BehaviorInterpreterTest { @Test @Throws(ParseException::class) fun debugTest() { - val input = "((P)&(!!(C))&(D))->((Q)==1234)" + val input = "((P)&(!!(C))|!(D))->((Q)==1234)" val ast = MTLParser(input).parse() val result = interpretAsBehavior(ast) result.activateProcessing(); diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/InterpreterTest.kt b/interpreter/src/test/java/cambio/tltea/interpreter/InterpreterTest.kt new file mode 100644 index 0000000..98405c8 --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/InterpreterTest.kt @@ -0,0 +1,68 @@ +package cambio.tltea.interpreter + +import cambio.tltea.interpreter.testutils.TestBase +import cambio.tltea.parser.core.temporal.TemporalEventDescription +import cambio.tltea.parser.core.temporal.TimeInstance +import cambio.tltea.parser.mtl.generated.ParseException +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test + +internal class InterpreterTest : TestBase() { + + @Test + fun testFailOnEmptyString() { + assertThrows(ParseException::class.java) { + val res = interpretFormula("") + } + assertThrows(ParseException::class.java) { + interpretFormula(" ") + } + } + + + @Test + fun timeInstanceInIntervalTest() { + interpretFormula("G[5,10]((A)->(B))") + + activateEvent("A", TimeInstance(4.0)) + activateEvent("A", TimeInstance(5.0)) + activateEvent("A", TimeInstance(7.5)) + activateEvent("A", TimeInstance(10.0)) + activateEvent("A", TimeInstance(11.0)) + + assertLogSizes(3,0,0) + } + + + @Test + fun eventIntervalTest() { + interpretFormula("G[A]((A)->(B))") + getEventListeners("A")?.activate(TemporalEventDescription("A")) + getEventListeners("A")?.activate(TemporalEventDescription("B")) + + assertLogSizes(1,0,0) + } + + @Test + fun exactTimeInstanceTest() { + interpretFormula("G[1]((A)->(B))") + activateEvent("A", TimeInstance(0)) + activateEvent("A", TimeInstance(1)) + activateEvent("A", TimeInstance(2)) + + assertLogSizes(1,0,0) + } + + @Test + fun complexScenario1() { + interpretFormula("(A)->((B)->(C))") + activateEvent("A", TimeInstance(0)) + assertLogSizes(0,0,0) + activateEvent("B", TimeInstance(0)) + assertLogSizes(1,0,0) + deactivateEvent("A", TimeInstance(0)) + activateEvent("B", TimeInstance(0)) + assertLogSizes(1,0,0) + } +} \ No newline at end of file diff --git a/interpreter/src/test/java/cambio/tltea/interpreter/testutils/TestBase.kt b/interpreter/src/test/java/cambio/tltea/interpreter/testutils/TestBase.kt new file mode 100644 index 0000000..4f26277 --- /dev/null +++ b/interpreter/src/test/java/cambio/tltea/interpreter/testutils/TestBase.kt @@ -0,0 +1,70 @@ +package cambio.tltea.interpreter.testutils + +import cambio.tltea.interpreter.BehaviorInterpretationResult +import cambio.tltea.interpreter.Interpreter +import cambio.tltea.interpreter.nodes.TriggerManager +import cambio.tltea.interpreter.nodes.cause.EventActivationListener +import cambio.tltea.interpreter.nodes.consequence.EventActivationData +import cambio.tltea.interpreter.nodes.consequence.EventPreventionData +import cambio.tltea.interpreter.nodes.consequence.ValueEventActivationData +import cambio.tltea.parser.core.temporal.ITemporalValue +import cambio.tltea.parser.mtl.generated.MTLParser +import org.junit.jupiter.api.Assertions.assertEquals + +open class TestBase { + + protected lateinit var currentInterpretationResult: BehaviorInterpretationResult + protected lateinit var triggerManager: TriggerManager + protected lateinit var generalActivationLog: MutableList + protected lateinit var eventActivationLog: MutableList + protected lateinit var eventPreventionLog: MutableList + protected lateinit var valueEventActivationLog: MutableList + + + protected fun interpretFormula(formula: String): BehaviorInterpretationResult { + val interpretAsBehavior = Interpreter.interpretAsBehavior(MTLParser.parse(formula)) + + currentInterpretationResult = interpretAsBehavior + triggerManager = interpretAsBehavior.triggerManager + generalActivationLog = mutableListOf() + eventActivationLog = mutableListOf() + eventPreventionLog = mutableListOf() + valueEventActivationLog = mutableListOf() + + triggerManager.subscribeEventListener { t -> generalActivationLog.add(t.toString()) } + triggerManager.subscribeEventListenerWithFilter( + { t -> eventActivationLog.add(t.toString()) }, + EventActivationData::class.java + ) + triggerManager.subscribeEventListenerWithFilter( + { t -> eventPreventionLog.add(t.toString()) }, + EventPreventionData::class.java + ) + triggerManager.subscribeEventListenerWithFilter( + { t -> valueEventActivationLog.add(t.toString()) }, + ValueEventActivationData::class.java + ) + + interpretAsBehavior.activateProcessing() + return interpretAsBehavior + } + + protected fun getEventListeners(eventName: String): EventActivationListener? { + return triggerManager.eventActivationListeners.find { eventActivationListener -> eventActivationListener.eventName == eventName } + } + + protected fun assertLogSizes(eventActivation: Int, eventPrevention: Int, valueEvents: Int) { + assertEquals(eventActivation, eventActivationLog.size) + assertEquals(eventPrevention, eventPreventionLog.size) + assertEquals(valueEvents, valueEventActivationLog.size) + assertEquals(eventActivation + eventPrevention + valueEvents, generalActivationLog.size) + } + + protected fun activateEvent(eventName: String, `when`: ITemporalValue) { + getEventListeners(eventName)?.activate(`when`) + } + + protected fun deactivateEvent(eventName: String, `when`: ITemporalValue) { + getEventListeners(eventName)?.deactivate(`when`) + } +} \ No newline at end of file From 1a274f0290c10b61272a162a12ef475f8ba1aadf Mon Sep 17 00:00:00 2001 From: LWagner Date: Wed, 11 May 2022 01:11:09 +0200 Subject: [PATCH 17/17] Fixed missing operator registration --- .../java/cambio/tltea/parser/core/OperatorTokenImageMap.java | 1 + 1 file changed, 1 insertion(+) diff --git a/parser/src/main/java/cambio/tltea/parser/core/OperatorTokenImageMap.java b/parser/src/main/java/cambio/tltea/parser/core/OperatorTokenImageMap.java index e68c417..0948c0a 100644 --- a/parser/src/main/java/cambio/tltea/parser/core/OperatorTokenImageMap.java +++ b/parser/src/main/java/cambio/tltea/parser/core/OperatorTokenImageMap.java @@ -30,6 +30,7 @@ public enum OperatorTokenImageMap { INSTANCE.put(OperatorToken.GLOBALLY, "G", "g", "☐"); INSTANCE.put(OperatorToken.FINALLY, "F", "f", "◇"); INSTANCE.put(OperatorToken.UNTIL, "U", "u"); + INSTANCE.put(OperatorToken.SINCE, "S", "s"); INSTANCE.put(OperatorToken.RELEASE, "R", "r"); INSTANCE.put(OperatorToken.WEAKUNTIL, "W", "w"); }