From b459d31103dc4d31a7ed47655a95afa50deb6488 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Fri, 19 Mar 2021 15:59:53 +0100
Subject: [PATCH] Fixing some resolving and parser problems.

- begin to use resolving features of relast
- moved resolving attributes to separate aspect file
- add rudimentary prettyPrint for Rule
---
 .../src/main/jastadd/AdditionalTypes.jadd     |  13 ++-
 eraser-base/src/main/jastadd/Navigation.jrag  |  98 ----------------
 eraser-base/src/main/jastadd/Printing.jrag    |  41 ++++---
 eraser-base/src/main/jastadd/Resolving.jrag   | 106 ++++++++++++++++++
 eraser-base/src/main/jastadd/Rules.jrag       |   5 +-
 eraser-base/src/main/jastadd/Rules.relast     |   5 +-
 eraser-base/src/main/jastadd/eraser.parser    |  33 +++++-
 eraser-base/src/main/jastadd/shem.relast      |   2 +-
 .../st/eraser/parser/EraserParserHelper.java  |  30 +----
 .../inf/st/eraser/util/MemberPrinter.java     |  18 +--
 10 files changed, 185 insertions(+), 166 deletions(-)
 create mode 100644 eraser-base/src/main/jastadd/Resolving.jrag

diff --git a/eraser-base/src/main/jastadd/AdditionalTypes.jadd b/eraser-base/src/main/jastadd/AdditionalTypes.jadd
index 32651117..8abddb34 100644
--- a/eraser-base/src/main/jastadd/AdditionalTypes.jadd
+++ b/eraser-base/src/main/jastadd/AdditionalTypes.jadd
@@ -1,16 +1,19 @@
 aspect AdditionalTypes {
-  public class StringList extends beaver.Symbol implements Iterable<String> {
-    private java.util.Deque<String> delegatee = new java.util.ArrayDeque<>();
+  public class ReversedList<T> extends beaver.Symbol implements Iterable<T> {
+    private java.util.Deque<T> delegatee = new java.util.ArrayDeque<>();
 
-    public java.util.Iterator<String> iterator() {
+    public java.util.Iterator<T> iterator() {
       return delegatee.descendingIterator();
     }
 
-    public void add(String s) {
-      delegatee.add(s);
+    public void add(T t) {
+      delegatee.add(t);
     }
   }
 
+  public class StringList extends ReversedList<String> {}
+  public class ItemList extends ReversedList<Item> {}
+
   public class TypedKeyMap<T> extends beaver.Symbol implements Iterable<AbstractMap.SimpleEntry<T, String>> {
     private java.util.Deque<AbstractMap.SimpleEntry<T, String>> delegatee = new java.util.ArrayDeque<>();
 
diff --git a/eraser-base/src/main/jastadd/Navigation.jrag b/eraser-base/src/main/jastadd/Navigation.jrag
index 3e34287f..dd4e283a 100644
--- a/eraser-base/src/main/jastadd/Navigation.jrag
+++ b/eraser-base/src/main/jastadd/Navigation.jrag
@@ -29,104 +29,6 @@ aspect Navigation {
     return result;
   }
 
-  //--- resolveThingType ---
-  syn java.util.Optional<ThingType> SmartHomeEntityModel.resolveThingType(String thingTypeId) {
-    for (ThingType thingType : this.getThingTypeList()) {
-      if (thingType.getID().equals(thingTypeId)) {
-        return java.util.Optional.of(thingType);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveChannel ---
-  syn java.util.Optional<Channel> SmartHomeEntityModel.resolveChannel(String channelId) {
-    for (Thing thing : this.getThingList()) {
-      for (Channel channel : thing.getChannelList()) {
-        if (channel.getID().equals(channelId)) {
-          return java.util.Optional.of(channel);
-        }
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveChannelType ---
-  syn java.util.Optional<ChannelType> SmartHomeEntityModel.resolveChannelType(String channelTypeId) {
-    for (ChannelType channelType : this.getChannelTypeList()) {
-      if (channelType.getID().equals(channelTypeId)) {
-        return java.util.Optional.of(channelType);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveItem ---
-  syn java.util.Optional<Item> SmartHomeEntityModel.resolveItem(String itemId) {
-    if ("activity".equals(itemId)) {
-      return Optional.of(getActivityItem());
-    }
-    for (Item item : items()) {
-      if (item.getID().equals(itemId)) {
-        return java.util.Optional.of(item);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveGroup ---
-  syn java.util.Optional<Group> SmartHomeEntityModel.resolveGroup(String groupId) {
-    for (Group group : this.getGroupList()) {
-      if (group.getID().equals(groupId)) {
-        return java.util.Optional.of(group);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveMqttTopic ---
-  syn java.util.Optional<MqttTopic> Root.resolveMqttTopic(String mqttTopicId) {
-    return this.getMqttRoot().resolveTopic(mqttTopicId);
-  }
-
-  //--- resolveItemCategory ---
-  syn java.util.Optional<ItemCategory> SmartHomeEntityModel.resolveItemCategory(String categoryName) {
-    for (ItemCategory category : getItemCategoryList()) {
-      if (category.getName().equals(categoryName)) {
-        return java.util.Optional.of(category);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveActivity ---
-  syn java.util.Optional<Activity> Root.resolveActivity(int identifier) {
-    for (Activity activity : getMachineLearningRoot().getActivityList()) {
-      if (activity.getIdentifier() == identifier) {
-        return java.util.Optional.of(activity);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-  syn java.util.Optional<Activity> Root.resolveActivity(String label) {
-    for (Activity activity : getMachineLearningRoot().getActivityList()) {
-      if (activity.getLabel().equals(label)) {
-        return java.util.Optional.of(activity);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
-  //--- resolveChangeEvent ---
-  syn java.util.Optional<ChangeEvent> Root.resolveChangeEvent(int identifier) {
-    for (ChangeEvent changeEvent : getMachineLearningRoot().getChangeEventList()) {
-      if (changeEvent.getIdentifier() == identifier) {
-        return java.util.Optional.of(changeEvent);
-      }
-    }
-    return java.util.Optional.empty();
-  }
-
   //--- containingThing ---
   inh Thing Channel.containingThing();
   eq Thing.getChannel().containingThing() = this;
diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag
index 0b454039..80661e43 100644
--- a/eraser-base/src/main/jastadd/Printing.jrag
+++ b/eraser-base/src/main/jastadd/Printing.jrag
@@ -3,7 +3,7 @@ aspect Printing {
 
   String ASTNode.safeID(ModelElement elem) { return elem == null ? "NULL" : elem.getID(); }
 
-  syn String Root.prettyPrint() {
+  eq Root.prettyPrint() {
     StringBuilder sb = new StringBuilder();
     sb.append(getSmartHomeEntityModel().prettyPrint());
     sb.append(getMqttRoot().prettyPrint());
@@ -13,7 +13,7 @@ aspect Printing {
   }
 
 //--- SmartHomeEntityModel.prettyPrint() ---
-  syn String SmartHomeEntityModel.prettyPrint() {
+  eq SmartHomeEntityModel.prettyPrint() {
     StringBuilder sb = new StringBuilder();
     for (Thing t : getThingList()) {
       sb.append(t.prettyPrint());
@@ -40,7 +40,7 @@ aspect Printing {
   }
 
 //Thing: id="" label="" type="" channels=["CHANNEL_ID", "CHANNEL_ID"] ;
-  syn String Thing.prettyPrint() {
+  eq Thing.prettyPrint() {
     return new MemberPrinter("Thing")
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -50,7 +50,7 @@ aspect Printing {
   }
 
 //ITEM_TYPE Item: id="" label="" state="" category="" topic="";
-  syn String Item.prettyPrint() {
+  eq Item.prettyPrint() {
     return new MemberPrinter(prettyPrintType())
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -79,7 +79,7 @@ aspect Printing {
   eq DefaultItem.prettyPrintType() = "Item" ;
 
   // special ActivityItem printing. Always omit state.
-  syn String ActivityItem.prettyPrint() {
+  eq ActivityItem.prettyPrint() {
     return new MemberPrinter(prettyPrintType())
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -94,7 +94,7 @@ aspect Printing {
 
 //Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation=AGG;
 //       AGG either '"agg-name"', or '"agg-name" ("param1", "param2")'
-  syn String Group.prettyPrint() {
+  eq Group.prettyPrint() {
     return new MemberPrinter("Group")
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -104,7 +104,6 @@ aspect Printing {
         .build();
   }
 
-  syn String GroupAggregationFunction.prettyPrint();
   eq SimpleGroupAggregationFunction.prettyPrint() {
     if (getFunctionName() == SimpleGroupAggregationFunctionName.EQUALITY) {
       return "";
@@ -120,7 +119,7 @@ aspect Printing {
   }
 
 //ThingType: id="" label="" description="" parameters=["PARAM_ID", "PARAM_ID"] channelTypes=["CHANNEL_TYPE_ID", "CHANNEL_TYPE_ID"];
-  syn String ThingType.prettyPrint() {
+  eq ThingType.prettyPrint() {
     return new MemberPrinter("ThingType")
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -131,7 +130,7 @@ aspect Printing {
   }
 
 //Parameter: id="" label="" description="" type="" default="" required;
-  syn String Parameter.prettyPrint() {
+  eq Parameter.prettyPrint() {
     return new MemberPrinter("Parameter")
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -144,7 +143,7 @@ aspect Printing {
   }
 
 //ChannelType: id="" label="" description="" itemType="" category="" readyOnly;
-  syn String ChannelType.prettyPrint() {
+  eq ChannelType.prettyPrint() {
     return new MemberPrinter("ChannelType")
         .addRequired("id", getID())
         .addNonDefault("label", getLabel())
@@ -160,7 +159,7 @@ aspect Printing {
   syn String SimpleChannelCategory.prettyPrint() = getValue();
 
 //Channel: id="" type="" links=["ITEM_ID", "ITEM_ID"];
-  syn String Channel.prettyPrint() {
+  eq Channel.prettyPrint() {
     return new MemberPrinter("Channel")
         .addRequired("id", getID())
         .addRequired("type", getType(), ChannelType::getID)
@@ -178,7 +177,7 @@ aspect Printing {
   }
 
 //Mqtt: incoming="" outgoing="" host="";
-  syn String MqttRoot.prettyPrint() {
+  eq MqttRoot.prettyPrint() {
     return new MemberPrinter("Mqtt")
         .addNonDefault("incoming", getIncomingPrefix())
         .addNonDefault("outgoing", getOutgoingPrefix())
@@ -187,7 +186,7 @@ aspect Printing {
   }
 
 //Influx: user="" password="" dbName="" host="" ;
-  syn String InfluxRoot.prettyPrint() {
+  eq InfluxRoot.prettyPrint() {
     return new MemberPrinter("Influx")
         .addNonDefault("user", getUser(), DEFAULT_USER)
         .addNonDefault("password", getPassword(), DEFAULT_PASSWORD)
@@ -197,7 +196,7 @@ aspect Printing {
   }
 
 // Activities: { index: "name" }
-  syn String MachineLearningRoot.prettyPrint() {
+  eq MachineLearningRoot.prettyPrint() {
     return new MemberPrinter("ML")
         .addNodes("activities", getNumActivity(), getActivityList(),
                   activity -> activity.getIdentifier() + ":\"" + activity.getLabel() + "\"",
@@ -215,7 +214,7 @@ aspect Printing {
   syn String PowerExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " ^ " + getRightOperand().prettyPrint() + ")";
   syn String ParenthesizedLogicalExpression.prettyPrint()  = "(" + getOperand().prettyPrint() + ")";
   syn String NotExpression.prettyPrint()  = "!" + getOperand().prettyPrint();
-  syn String ComparingExpression.prettyPrint() {
+  eq ComparingExpression.prettyPrint() {
     switch (getComparator()) {
       case NotEquals: return "(" + getLeftOperand().prettyPrint() + " != " + getRightOperand().prettyPrint() + ")";
       case Equals: return "(" + getLeftOperand().prettyPrint() + " == " + getRightOperand().prettyPrint() + ")";
@@ -230,4 +229,16 @@ aspect Printing {
   syn String OrExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " | " + getRightOperand().prettyPrint() + ")";
   syn String Designator.prettyPrint() = getItem().getID();
 
+  // Rules
+  eq Rule.prettyPrint() {
+    return new MemberPrinter("Rule")
+        .addIds("TriggeringItems", getObserverList().size(), getObserverList(),
+                  io -> io.observedItem().getID())
+        .addNodes("Condition", getNumCondition(), getConditionList(),
+                  Condition::toString)
+        .addNodes("Action", getNumAction(), getActionList(),
+                  Action::toString)
+        .build();
+  }
+
 }
diff --git a/eraser-base/src/main/jastadd/Resolving.jrag b/eraser-base/src/main/jastadd/Resolving.jrag
new file mode 100644
index 00000000..e1d793c1
--- /dev/null
+++ b/eraser-base/src/main/jastadd/Resolving.jrag
@@ -0,0 +1,106 @@
+aspect Resolving {
+
+  //--- resolveThingType ---
+  syn java.util.Optional<ThingType> SmartHomeEntityModel.resolveThingType(String thingTypeId) {
+    for (ThingType thingType : this.getThingTypeList()) {
+      if (thingType.getID().equals(thingTypeId)) {
+        return java.util.Optional.of(thingType);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveChannel ---
+  syn java.util.Optional<Channel> SmartHomeEntityModel.resolveChannel(String channelId) {
+    for (Thing thing : this.getThingList()) {
+      for (Channel channel : thing.getChannelList()) {
+        if (channel.getID().equals(channelId)) {
+          return java.util.Optional.of(channel);
+        }
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveChannelType ---
+  syn java.util.Optional<ChannelType> SmartHomeEntityModel.resolveChannelType(String channelTypeId) {
+    for (ChannelType channelType : this.getChannelTypeList()) {
+      if (channelType.getID().equals(channelTypeId)) {
+        return java.util.Optional.of(channelType);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveItem ---
+  syn java.util.Optional<Item> SmartHomeEntityModel.resolveItem(String itemId) {
+    if ("activity".equals(itemId)) {
+      return Optional.of(getActivityItem());
+    }
+    for (Item item : items()) {
+      if (item.getID().equals(itemId)) {
+        return java.util.Optional.of(item);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveGroup ---
+  syn java.util.Optional<Group> SmartHomeEntityModel.resolveGroup(String groupId) {
+    for (Group group : this.getGroupList()) {
+      if (group.getID().equals(groupId)) {
+        return java.util.Optional.of(group);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveMqttTopic ---
+  syn java.util.Optional<MqttTopic> Root.resolveMqttTopic(String mqttTopicId) {
+    return this.getMqttRoot().resolveTopic(mqttTopicId);
+  }
+
+  //--- resolveItemCategory ---
+  syn java.util.Optional<ItemCategory> SmartHomeEntityModel.resolveItemCategory(String categoryName) {
+    for (ItemCategory category : getItemCategoryList()) {
+      if (category.getName().equals(categoryName)) {
+        return java.util.Optional.of(category);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveActivity ---
+  syn java.util.Optional<Activity> Root.resolveActivity(int identifier) {
+    for (Activity activity : getMachineLearningRoot().getActivityList()) {
+      if (activity.getIdentifier() == identifier) {
+        return java.util.Optional.of(activity);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+  syn java.util.Optional<Activity> Root.resolveActivity(String label) {
+    for (Activity activity : getMachineLearningRoot().getActivityList()) {
+      if (activity.getLabel().equals(label)) {
+        return java.util.Optional.of(activity);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  //--- resolveChangeEvent ---
+  syn java.util.Optional<ChangeEvent> Root.resolveChangeEvent(int identifier) {
+    for (ChangeEvent changeEvent : getMachineLearningRoot().getChangeEventList()) {
+      if (changeEvent.getIdentifier() == identifier) {
+        return java.util.Optional.of(changeEvent);
+      }
+    }
+    return java.util.Optional.empty();
+  }
+
+  // implementing resolving for relations
+  refine RefResolverStubs eq StateSyncGroup.resolveTargetItemByToken(String id, int position) {
+    return getRoot().getSmartHomeEntityModel().resolveItem(id).orElseThrow(() -> new RuntimeException("Item '" + id + "' not found!"));
+  }
+
+}
diff --git a/eraser-base/src/main/jastadd/Rules.jrag b/eraser-base/src/main/jastadd/Rules.jrag
index 743ccc5b..2eed4ff4 100644
--- a/eraser-base/src/main/jastadd/Rules.jrag
+++ b/eraser-base/src/main/jastadd/Rules.jrag
@@ -116,14 +116,13 @@ aspect Rules {
 aspect StateSyncGroup {
   rewrite StateSyncGroup {
     to Rule {
-      Item controllingItem = ((ItemObserver)getParent()).observedItem();
       Rule rule = new Rule();
 
-      for (Item item : getItems()) {
+      for (Item item : getTargetItemList()) {
         rule.addAction(new SetStateFromTriggeringItemAction(item));
         rule.addObserver(item.getItemObserver());
       }   
-      
+
       return rule;
     }
   }
diff --git a/eraser-base/src/main/jastadd/Rules.relast b/eraser-base/src/main/jastadd/Rules.relast
index 79d24a42..22176613 100644
--- a/eraser-base/src/main/jastadd/Rules.relast
+++ b/eraser-base/src/main/jastadd/Rules.relast
@@ -29,6 +29,5 @@ MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ;
 ItemObserver ::= ;
 rel ItemObserver.TriggeredRule* <-> Rule.Observer* ;
 
-
-StateSyncGroup : Rule ::= Item*;
-
+StateSyncGroup : Rule ;
+rel StateSyncGroup.TargetItem* -> Item;
diff --git a/eraser-base/src/main/jastadd/eraser.parser b/eraser-base/src/main/jastadd/eraser.parser
index 00ade60d..1a055ec6 100644
--- a/eraser-base/src/main/jastadd/eraser.parser
+++ b/eraser-base/src/main/jastadd/eraser.parser
@@ -44,6 +44,7 @@ Root goal =
   |  thing.t                            {: return eph.createRoot(t); :}
   |  item.i                             {: return eph.createRoot(); :}
   |  group.g                            {: return eph.createRoot(g); :}
+  |  state_sync_group.ss                {: return eph.createRoot(ss); :}
   |  thing_type.tt                      {: return eph.createRoot(tt); :}
   |  parameter                          {: return eph.createRoot(); :}
   |  channel_type.ct                    {: return eph.createRoot(ct); :}
@@ -139,6 +140,10 @@ Item item_body =
   |                                     {: return eph.createItem(); :}
   ;
 
+Item item_ref =
+     TEXT.n                                 {: return Item.createRef(n); :}
+  ;
+
 Group group =
      GROUP COLON group_body.gb SEMICOLON    {: return gb; :}
   ;
@@ -157,15 +162,18 @@ Group group_body =
   ;
 
 
-
-
-
 StateSyncGroup state_sync_group = SYNCSTATE COLON syncstate_body.ssb SEMICOLON {: return ssb; :};
 
 // SyncState: items=["ITEM_ID", "ITEM_ID"];
 StateSyncGroup syncstate_body =
-     ITEMS EQUALS string_list.items syncstate_body.ss       {: return eph.setItems(ss, items); :}
-  |                                                         {: return new StateSyncGroup(); :}
+     ITEMS EQUALS item_list.items syncstate_body.ss
+     {:
+       for (Item item : items) {
+         ss.addTargetItem(item);
+       }
+       return ss;
+     :}
+  |                                         {: return new StateSyncGroup(); :}
   ;
 
 ThingType thing_type =
@@ -298,6 +306,21 @@ StringList string_list_body =
     :}
   ;
 
+ItemList item_list =
+     LB_SQUARE item_list_body.ilb RB_SQUARE         {: return ilb; :}
+  |  LB_SQUARE RB_SQUARE                            {: return new ItemList(); :}
+  ;
+
+ItemList item_list_body =
+     item_ref.ir COMMA item_list_body.ilb           {: ilb.add(ir); return ilb; :}
+  |  item_ref.ir
+    {:
+       ItemList result = new ItemList();
+       result.add(ir);
+       return result;
+    :}
+  ;
+
 StringList round_string_list =
      LB_ROUND round_string_list_body.slb RB_ROUND     {: return slb; :}
   |  LB_ROUND RB_ROUND                                {: return new StringList(); :}
diff --git a/eraser-base/src/main/jastadd/shem.relast b/eraser-base/src/main/jastadd/shem.relast
index ef377929..a71a0ede 100644
--- a/eraser-base/src/main/jastadd/shem.relast
+++ b/eraser-base/src/main/jastadd/shem.relast
@@ -25,7 +25,7 @@ rel Channel.LinkedItem* <-> Item.Channel? ;
 Parameter : DescribableModelElement ::= <Type:ParameterValueType> [DefaultValue:ParameterDefaultValue] <Context:String> <Required:boolean> ;
 ParameterDefaultValue ::= <Value:String> ;
 
-abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/
+abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/;
 
 
 rel Item.Category? -> ItemCategory ;
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
index e8843f8c..c907c68e 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
@@ -24,7 +24,6 @@ public class EraserParserHelper {
   private Map<String, Parameter> parameterMap = new HashMap<>();
   private Map<String, Item> itemMap = new HashMap<>();
   private Map<String, Group> groupMap = new HashMap<>();
-  private Map<String, StateSyncGroup> stateSyncMap = new HashMap<>();
 
   private Map<Thing, String> missingThingTypeMap = new HashMap<>();
   private Map<Channel, String> missingChannelTypeMap = new HashMap<>();
@@ -37,7 +36,6 @@ public class EraserParserHelper {
   private Map<Item, Iterable<String>> missingControllingListMap = new HashMap<>();
   private Map<Group, Iterable<String>> missingSubGroupListMap = new HashMap<>();
   private Map<Group, Iterable<String>> missingItemListMap = new HashMap<>();
-  private Map<StateSyncGroup, Iterable<String>> missingSyncItemListMap = new HashMap<>();
   private Map<ThingType, Iterable<String>> missingChannelTypeListMap = new HashMap<>();
   private Map<ThingType, Iterable<String>> missingParameterListMap = new HashMap<>();
 
@@ -75,6 +73,7 @@ public class EraserParserHelper {
       // when parsing expressions
       this.root = EraserParserHelper.initialRoot != null ? EraserParserHelper.initialRoot : createRoot();
     }
+
     if (checkUnusedElements) {
       fillUnused();
     }
@@ -95,21 +94,19 @@ public class EraserParserHelper {
     resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem);
     resolveList(groupMap, missingSubGroupListMap, Group::addGroup);
     resolveList(itemMap, missingItemListMap, this::addItemToGroup);
-    resolveList(itemMap, missingSyncItemListMap, this::addItemToStateSync);
 
     resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType);
     resolveList(parameterMap, missingParameterListMap, ThingType::addParameter);
     resolveList(itemMap, missingControllingListMap, Item::addControlling);
 
-    // TODO: activate state sync stuff
-    this.activateStateSyncItems();
-
     createUnknownGroupIfNecessary();
     createChannelCategories();
     createItemCategories();
     if (checkUnusedElements) {
       checkUnusedElements();
     }
+
+    this.root.treeResolveAll();
   }
 
   private void addItemToGroup(Group group, Item item) {
@@ -117,12 +114,6 @@ public class EraserParserHelper {
     group.addItem(item);
   }
 
-  private void addItemToStateSync(StateSyncGroup stateSyncGroup, Item item) {
-    stateSyncGroup.addItem(item);
-  }
-
-
-
   private void fillUnused() {
     unusedElements.addAll(thingTypeMap.values());
     unusedElements.addAll(channelTypeMap.values());
@@ -208,14 +199,6 @@ public class EraserParserHelper {
     action.accept(elem, value);
   }
 
-    private void activateStateSyncItems() {
-    for (StateSyncGroup stateSyncGroup : new ArrayList<StateSyncGroup>()) {
-
-      for (Item item : stateSyncGroup.getItems()) {
-      }
-    }
-  }
-
   //--- Thing and ThingType ---
 
   public Thing addThingType(Thing t, String typeName) {
@@ -494,13 +477,6 @@ public class EraserParserHelper {
     return result;
   }
 
-  //--- SyncState ---
-  public StateSyncGroup setItems(StateSyncGroup ssg, StringList itemNames) {
-    missingSyncItemListMap.put(ssg, itemNames);
-    return ssg;
-  }
-
-
   public Rule createRule(Condition c, Action a) {
     Rule result = new Rule();
     result.addCondition(c);
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MemberPrinter.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MemberPrinter.java
index a6c89a42..53acf152 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MemberPrinter.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MemberPrinter.java
@@ -80,9 +80,9 @@ public class MemberPrinter {
    * @param listOfNodes the list of nodes
    * @param mapping a function to map a node to a ModelElement
    */
-  private <T extends ASTNode> void concatIds(Iterable<T> listOfNodes,
-                                             Function<T, ? extends ModelElement> mapping) {
-    concatNodes(listOfNodes, t -> mapping.apply(t).getID(), true);
+  private <T extends ASTNode<?>> void concatIds(Iterable<T> listOfNodes,
+                                             Function<T, String> mapping) {
+    concatNodes(listOfNodes, mapping, true);
   }
 
   /**
@@ -91,7 +91,7 @@ public class MemberPrinter {
    * @param listOfNodes the list of nodes
    * @param mapping a function to map a node to a String
    */
-  private <T extends ASTNode> void concatNodes(Iterable<T> listOfNodes,
+  private <T extends ASTNode<?>> void concatNodes(Iterable<T> listOfNodes,
                                                Function<T, String> mapping,
                                                boolean quote) {
     boolean first = true;
@@ -146,9 +146,9 @@ public class MemberPrinter {
    * @param mapping     A function to map a node to a ModelElement
    * @return this
    */
-  public <T extends ASTNode> MemberPrinter addIds(
+  public <T extends ASTNode<?>> MemberPrinter addIds(
       String name, int count, Iterable<T> listOfNodes,
-      Function<T, ? extends ModelElement> mapping) {
+      Function<T, String> mapping) {
     if (count > 0) {
       sb.append(' ').append(name).append("=[");
       concatIds(listOfNodes, mapping);
@@ -168,7 +168,7 @@ public class MemberPrinter {
    * @param <T>         The type of all nodes
    * @return this
    */
-  public <T extends ASTNode> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
+  public <T extends ASTNode<?>> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
                                 Function<T, String> mapping) {
     return addNodes(name, count, listOfNodes, mapping, ListBracketType.SQUARE);
   }
@@ -183,7 +183,7 @@ public class MemberPrinter {
    * @param bracketType The type of brackets to enclose the list with
    * @return this
    */
-  public <T extends ASTNode> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
+  public <T extends ASTNode<?>> MemberPrinter addNodes(String name, int count, Iterable<T> listOfNodes,
                                                     Function<T, String> mapping, ListBracketType bracketType) {
     if (count > 0) {
       sb.append(' ').append(name).append("=").append(bracketType.begin);
@@ -214,7 +214,7 @@ public class MemberPrinter {
    * @param child       The child to append
    * @return this
    */
-  public MemberPrinter addOptionalPrettyPrint(ASTNode child) {
+  public MemberPrinter addOptionalPrettyPrint(ASTNode<?> child) {
     if (child != null) {
       this.empty = false;
       sb.append(child.prettyPrint());
-- 
GitLab