diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag index b697c548025d40d231ca8e9be32685416f032354..b1761f17cdf003877f1f6b4ccb9b4314bfd51c8c 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 0b4faca1186fffc3001f8dddfcc1eb7805580767..1036024413db67e7b6d7adb0fe4d405868d8442f 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 82ada645b48ab71ed33417ff9d975e06b4f433b4..b78d52a079f206a31064f1f98c03672a51c666c8 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 dd31393fe908cd5e6042b4b3487a97f3f3f6fde0..c1c6b52ebbc7c591f22b87d384e0d20f1026dcbe 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 025094bba1d26f801ff2d9e088e2dbcd18433315..456027b12235de42421b539218f7d82fca904871 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 bd5acd61dde4c2a456be66955de956b32f3b73c8..fa91036013bab2f16cf0e4c1428b1b5c7e318e60 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 630554f204aa0a6e92894f1c79206d036da7f5d8..96c46e6ef18fa7e37786ded8b443e56ff6e5fd86 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 4f67c54529f85d1627e54d91a1c0640072054574..1212e8bb59a23982c38e183c25a6cd18e0095db8 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 f9d57abffeeca2f38e6d7ecfdb507d82b1385740..b8f12e6a6c6dde69012955204ee63556cdb38275 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 |