From ba15586d0cd0c62d8b026e25ac4bddc34cda3b14 Mon Sep 17 00:00:00 2001 From: Manuel Krombholz <s3866577@msx.tu-dresden.de> Date: Wed, 14 Jul 2021 04:13:38 +0200 Subject: [PATCH] ExpressionCondition + SetStateFromExpressionAction --- eraser-base/src/main/jastadd/Printing.jrag | 12 ++++ eraser-base/src/main/jastadd/Rules.jrag | 5 +- eraser-base/src/main/jastadd/Rules.relast | 4 +- eraser-base/src/main/jastadd/eraser.flex | 2 + eraser-base/src/main/jastadd/eraser.parser | 10 ++- .../de/tudresden/inf/st/eraser/RulesTest.java | 61 +------------------ .../test/resources/tests/ppc6/input.eraser | 2 + .../test/resources/tests/ppc6/output.eraser | 2 + pages/docs/DSL.md | 2 + 9 files changed, 27 insertions(+), 73 deletions(-) diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag index b697c548..b1761f17 100644 --- a/eraser-base/src/main/jastadd/Printing.jrag +++ b/eraser-base/src/main/jastadd/Printing.jrag @@ -293,6 +293,11 @@ aspect Printing { return "Condition: ItemStateChange " + getItem().getID(); } + //ExpressionCondition + eq ExpressionCondition.prettyPrint() { + return "Condition: Expression " + getLogicalExpression().prettyPrint(); + } + //TriggerRuleAction eq TriggerRuleAction.prettyPrint() { @@ -318,6 +323,13 @@ aspect Printing { eq MultiplyDoubleToStateAction.prettyPrint() { return "Action: SetStateFromTrigger " + getAffectedItem().getID() + " " + getMultiplier(); } + + //SetStateFromExpressionAction + eq SetStateFromExpressionAction.prettyPrint() { + return "Action: StateFromExpression " + getNumberExpression().prettyPrint() + " " + getAffectedItem().getID(); + } + + diff --git a/eraser-base/src/main/jastadd/Rules.jrag b/eraser-base/src/main/jastadd/Rules.jrag index 0b4faca1..10360244 100644 --- a/eraser-base/src/main/jastadd/Rules.jrag +++ b/eraser-base/src/main/jastadd/Rules.jrag @@ -80,7 +80,7 @@ aspect Rules { public void TriggerRuleAction.applyFor(Item item) { getRule().trigger(item); } - public void SetStateFromExpression.applyFor(Item item) { + public void SetStateFromExpressionAction.applyFor(Item item) { getAffectedItem().setStateFromDouble(getNumberExpression().eval()); } public void SetStateFromConstantStringAction.applyFor(Item item) { @@ -93,9 +93,6 @@ aspect Rules { } item.copyStateTo(target); } - public void SetStateFromItemsAction.applyFor(Item item) { - getAffectedItem().setStateFromString(getCombinator().apply(getSourceItems())); - } public void AddDoubleToStateAction.applyFor(Item item) { getAffectedItem().setStateFromDouble(getAffectedItem().getStateAsDouble() + getIncrement()); } diff --git a/eraser-base/src/main/jastadd/Rules.relast b/eraser-base/src/main/jastadd/Rules.relast index 82ada645..b78d52a0 100644 --- a/eraser-base/src/main/jastadd/Rules.relast +++ b/eraser-base/src/main/jastadd/Rules.relast @@ -14,13 +14,11 @@ rel TriggerRuleAction.Rule -> Rule ; abstract SetStateAction : Action ; rel SetStateAction.AffectedItem -> Item ; -SetStateFromExpression : SetStateAction ::= NumberExpression ; +SetStateFromExpressionAction : SetStateAction ::= NumberExpression ; SetStateFromConstantStringAction : SetStateAction ::= <NewState:String> ; SetStateFromTriggeringItemAction : SetStateAction ::= ; -SetStateFromItemsAction : SetStateAction ::= <Combinator:ItemsToStringFunction> ; -rel SetStateFromItemsAction.SourceItem* -> Item ; AddDoubleToStateAction : SetStateAction ::= <Increment:double> ; MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ; diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex index dd31393f..c1c6b52e 100644 --- a/eraser-base/src/main/jastadd/eraser.flex +++ b/eraser-base/src/main/jastadd/eraser.flex @@ -74,10 +74,12 @@ Comment = "//" [^\n\r]+ // actions and conditions "ItemStateCheck" { return sym(Terminals.ITEM_STATE_CHECK); } "ItemStateChange" { return sym(Terminals.ITEM_STATE_CHANGE); } +"Expression" { return sym(Terminals.EXPRESSION); } "Noop" { return sym(Terminals.NOOP_ACTION); } "TriggerRule" { return sym(Terminals.TRIGGER_RULE_ACTION); } "SetStateFromConstant" { return sym(Terminals.STATE_FROM_CONST_ACTION); } "SetStateFromTrigger" { return sym(Terminals.STATE_FROM_TRIGGER_ACTION); } +"StateFromExpression" { return sym(Terminals.STATE_FROM_EXPRESSION_ACTION); } // within specification "Action" { return sym(Terminals.ACTION); } "activities" { return sym(Terminals.ACTIVITIES); } diff --git a/eraser-base/src/main/jastadd/eraser.parser b/eraser-base/src/main/jastadd/eraser.parser index 025094bb..456027b1 100644 --- a/eraser-base/src/main/jastadd/eraser.parser +++ b/eraser-base/src/main/jastadd/eraser.parser @@ -95,7 +95,7 @@ import java.util.HashMap; rule.addCondition(condition); break; case AltGoals.number_expression: - SetStateFromExpression action = new SetStateFromExpression(); + SetStateFromExpressionAction action = new SetStateFromExpressionAction(); action.setNumberExpression(exp.asNumberExpression()); rule.addAction(action); break; @@ -400,7 +400,8 @@ ConditionActionPack capack = Condition condition = ITEM_STATE_CHECK isccondition.iscc {: return iscc; :} - | ITEM_STATE_CHANGE ischconditon.iscc {: return iscc; :} + | ITEM_STATE_CHANGE NAME.n {: return new ItemStateChangeCondition(Item.createRef(n)); :} + | EXPRESSION logical_expression.le {: return new ExpressionCondition(le); :} ; @@ -408,10 +409,6 @@ ItemStateCheckCondition isccondition = comparator.cp REAL.r {: return new ItemStateCheckCondition().setItemStateCheck(new ItemStateNumberCheck().setValue(Double.parseDouble(r)).setComparator(cp.getIt())); :} | comparator.cp TEXT.n {: return new ItemStateCheckCondition().setItemStateCheck(new ItemStateStringCheck().setValue(n).setComparator(cp.getIt())); :} -ItemStateChangeCondition ischconditon = - NAME.n {: return new ItemStateChangeCondition(Item.createRef(n)); :} - ; - ComparatorBox comparator = NE {: return new ComparatorBox(ComparatorType.NotEquals); :} | EQ {: return new ComparatorBox(ComparatorType.Equals); :} @@ -429,6 +426,7 @@ Action action = | STATE_FROM_CONST_ACTION NAME.i TEXT.s {: return new SetStateFromConstantStringAction().setNewState(s).setAffectedItem(Item.createRef(i)); :} | STATE_FROM_TRIGGER_ACTION NAME.i {: return new SetStateFromTriggeringItemAction().setAffectedItem(Item.createRef(i)); :} | STATE_FROM_TRIGGER_ACTION NAME.i REAL.r {: return new MultiplyDoubleToStateAction().setMultiplier(Double.parseDouble(r)).setAffectedItem(Item.createRef(i)); :} + | STATE_FROM_EXPRESSION_ACTION number_expression.ne NAME.i {: return new SetStateFromExpressionAction().setNumberExpression(ne).setAffectedItem(Item.createRef(i)); :} ; diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java index bd5acd61..fa910360 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/RulesTest.java @@ -627,65 +627,6 @@ public class RulesTest { assertEquals("7.0", item2.getState(), "Change of item state should set the state of the affected item"); } - @Test - public void testSetStateFromItemsAction() { - TestUtils.ModelAndItem modelAndItem = createModelAndItem(3); - Root root = modelAndItem.model.getRoot(); - NumberItem item = modelAndItem.item; - NumberItem item2 = TestUtils.addItemTo(root.getSmartHomeEntityModel(), 4, true); - StringItem affectedItem = addStringItem(root.getSmartHomeEntityModel(), "1"); - - Rule rule = new Rule(); - SetStateFromItemsAction action = new SetStateFromItemsAction().setCombinator(items -> - Long.toString(StreamSupport.stream(items.spliterator(), false) - .mapToLong(inner -> (long) inner.asItemWithDoubleState().getState()) - .sum())); - action.addSourceItem(item); - action.addSourceItem(item2); - action.setAffectedItem(affectedItem); - rule.addAction(action); - CountingAction counter = new CountingAction(); - rule.addAction(counter); - root.addRule(rule); - rule.activateFor(item); - - assertEquals(0, counter.get(item), "Counter not initialized correctly"); - assertEquals("1", affectedItem.getState(), "Affected item not initialized correctly"); - - // 5 + 4 = 9 - setState(item, 5); - assertEquals(1, counter.get(item), "Change of item state should trigger the rule"); - assertEquals("9", affectedItem.getState(), "Change of item state should set the state of the affected item"); - - // still 5 + 4 = 9, as rule does not trigger for item2 - setState(item2, 5); - assertEquals(1, counter.get(item), "Change of item2 state should not trigger the rule"); - assertEquals("9", affectedItem.getState(), "Change of item2 state should not set the state of the affected item"); - - // still 5 + 4 = 9, as rule should not trigger - setState(item, 5); - assertEquals(1, counter.get(item), "Change of item to same state should not trigger the rule"); - assertEquals("9", affectedItem.getState(), "Change of item to same state should not set the state of the affected item"); - - // 7 + 5 = 12 - setState(item, 7); - assertEquals(2, counter.get(item), "Change of item state should trigger the rule"); - assertEquals("12", affectedItem.getState(), "Change of item state should set the state of the affected item"); - - // add new item to sum - NumberItem item3 = TestUtils.addItemTo(root.getSmartHomeEntityModel(), -4, true); - action.addSourceItem(item3); - - // still 7 + 5 = 12, as rule should not trigger - setState(item, 7); - assertEquals(2, counter.get(item), "Change of item to same state should not trigger the rule"); - assertEquals("12", affectedItem.getState(), "Change of item to same state should not set the state of the affected item"); - - // 8 + 5 - 4 = 9 - setState(item, 8); - assertEquals(3, counter.get(item), "Change of item state should trigger the rule"); - assertEquals("9", affectedItem.getState(), "Change of item state should set the state of the affected item"); - } @Test public void testAddDoubleToStateAction() { @@ -813,7 +754,7 @@ public class RulesTest { NumberItem affectedItem = TestUtils.addItemTo(root.getSmartHomeEntityModel(), 5, true); Rule rule = new Rule(); - SetStateFromExpression action = new SetStateFromExpression(); + SetStateFromExpressionAction action = new SetStateFromExpressionAction(); // TODO item1 should be referred to as triggering item action.setNumberExpression(ParserUtils.parseNumberExpression("(" + item1.getID() + " + " + item2.getID() + ")", root)); action.setAffectedItem(affectedItem); diff --git a/eraser-base/src/test/resources/tests/ppc6/input.eraser b/eraser-base/src/test/resources/tests/ppc6/input.eraser index 630554f2..96c46e6e 100644 --- a/eraser-base/src/test/resources/tests/ppc6/input.eraser +++ b/eraser-base/src/test/resources/tests/ppc6/input.eraser @@ -9,3 +9,5 @@ Rule: name="testRule456" items=["iris1_item"] [Action: Noop] ; Rule: name="testRule46" items=["iris1_item"] [Action: SetStateFromConstant iris1_item "K"] ; Rule: name="testRule8" items=["iris1_item"] [Action: SetStateFromTrigger iris2_item] ; Rule: name="testRul118" items=["iris1_item"] [Action: SetStateFromTrigger iris2_item 2.0] ; +Rule: name="testR8" items=["iris1_item"] [Condition: Expression (2.0<3.0)] ; +Rule: name="testR8556" items=["iris1_item"] [Action: StateFromExpression (2.0 + 3.0) iris1_item] ; diff --git a/eraser-base/src/test/resources/tests/ppc6/output.eraser b/eraser-base/src/test/resources/tests/ppc6/output.eraser index 4f67c545..1212e8bb 100644 --- a/eraser-base/src/test/resources/tests/ppc6/output.eraser +++ b/eraser-base/src/test/resources/tests/ppc6/output.eraser @@ -1,6 +1,8 @@ Color Item: id="iris1_item" label="Iris 1" state="121,88,68" topic="iris1_item/state" ; Color Item: id="iris2_item" label="Iris 2" state="121,88,68" topic="iris1_item/state" ; Group: id="Unknown" items=["iris1_item", "iris2_item"] ; +Rule: name="testR8556" items=["iris1_item"] [Action: StateFromExpression (2.0 + 3.0) iris1_item] ; +Rule: name="testR8" items=["iris1_item"] [Condition: Expression (2.0<3.0)] ; Rule: name="testRul118" items=["iris1_item"] [Action: SetStateFromTrigger iris2_item 2.0] ; Rule: name="testRule8" items=["iris1_item"] [Action: SetStateFromTrigger iris2_item] ; Rule: name="testRule46" items=["iris1_item"] [Action: SetStateFromConstant iris1_item "K"] ; diff --git a/pages/docs/DSL.md b/pages/docs/DSL.md index f9d57abf..b8f12e6a 100644 --- a/pages/docs/DSL.md +++ b/pages/docs/DSL.md @@ -119,6 +119,7 @@ Rule: name="" items=["ITEM_ID", "ITEM_ID"] [Condition: CONDITION_CONSTRUCTOR, Co | ItemStateNumberCheck | compares the state with NUMBER using the OPERATOR | ItemStateCheck OPERATOR NUMBER | ItemStateCheck < 5 | | ItemStateTextCheck | compares the state with TEXT using the OPERATOR | ItemStateCheck OPERATOR TEXT | ItemStateCheck < "abc" | | ItemStateChange | triggers if specified ITEM changed its value | ItemStateChange ITEM ItemStateChange | ItemStateChange item1 | +| ExpressionCondition | triggers if the LOGICAL_EXPRESSION is true | Expression LOGICAL_EXPRESSION | Expression (2<3) | @@ -131,5 +132,6 @@ Rule: name="" items=["ITEM_ID", "ITEM_ID"] [Condition: CONDITION_CONSTRUCTOR, Co | SetStateFromConstantStringAction | apply specified VALUE to the ITEM | SetStateFromConstant ITEM VALUE | SetStateFromConstant item1 "LMNOP" | | SetStateFromTriggeringItemAction | copies state from triggering device to specified ITEM | SetStateFromTrigger ITEM | SetStateFromTrigger item1 | | MultiplyDoubleToStateAction | copies state multiplied by MULTIPLIER from triggering item to specified ITEM | SetStateFromTrigger ITEM MULTIPLIER | SetStateFromTrigger item1 2.0 | +| StateFromExpressionAction | apply the evaluated NUMBER_EXPRESSION as state to ITEM | StateFromExpression NUMBER_EXPRESSION ITEM | StateFromExpression (2.0 + 3.0) item2 | -- GitLab