From 8b3024a1a02e9fc57173569fa7aa113150bffdb7 Mon Sep 17 00:00:00 2001
From: Johannes Mey <johannes.mey@tu-dresden.de>
Date: Thu, 31 Mar 2022 13:08:59 +0200
Subject: [PATCH] add parse methods for robot world

---
 build.gradle                                  |   2 +-
 src/main/jastadd/Cleanup.relast               |  21 +++
 src/main/jastadd/Robot.relast                 |  21 ---
 src/main/jastadd/World.jadd                   | 125 +++++++++++++++++-
 src/main/jastadd/World.jrag                   |  43 ++++++
 src/main/jastadd/World.relast                 |  12 +-
 .../de/tudresden/inf/st/mg/RobotParser.java   |  54 ++++++++
 .../de/tudresden/inf/st/mg/WorldParser.java   |   2 +-
 .../inf/st/mg/common/MotionGrammarParser.java |   7 +-
 9 files changed, 257 insertions(+), 30 deletions(-)
 create mode 100644 src/main/jastadd/Cleanup.relast
 delete mode 100644 src/main/jastadd/Robot.relast
 create mode 100644 src/main/java/de/tudresden/inf/st/mg/RobotParser.java

diff --git a/build.gradle b/build.gradle
index 6fbc69c..8855bbd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -84,7 +84,7 @@ jar {
     duplicatesStrategy = DuplicatesStrategy.FAIL
 }
 
-def relastFiles = ['./src/main/jastadd/common/MotionGrammar.relast', './src/main/jastadd/World.relast', './src/main/jastadd/LoadUnload.relast', './src/main/jastadd/Robot.relast']
+def relastFiles = ['./src/main/jastadd/common/MotionGrammar.relast', './src/main/jastadd/World.relast', './src/main/jastadd/LoadUnload.relast', './src/main/jastadd/Cleanup.relast']
 def grammarPrefix = './src/gen/jastadd/MotionGrammar'
 def grammarDiagramFile = './src/gen/resources/diagrams/grammar/uml.png'
 def jastAddListName = 'JastAddList'
diff --git a/src/main/jastadd/Cleanup.relast b/src/main/jastadd/Cleanup.relast
new file mode 100644
index 0000000..fcc087b
--- /dev/null
+++ b/src/main/jastadd/Cleanup.relast
@@ -0,0 +1,21 @@
+Tidy : MotionGrammarElement ::= MoveObjectToCorrectPlace* EmptyTable;
+MoveObjectToCorrectPlace : MotionGrammarElement ::= ObjectAtWrongPlace/*provides object*/ PickUpObject/*uses object*/ DropObjectAtRightPlace/*uses object*/;
+PickUpObject/*requires object*/ : MotionGrammarElement ::= RobotIsReadyToPick Pick/*uses object*/;
+abstract RobotIsReadyToPick : MotionGrammarElement;
+RobotIsReallyReadyToPick : RobotIsReadyToPick ::= RobotIsFree;
+RobotIsNotReadyToPick    : RobotIsReadyToPick ::= RobotIsBusy Wait/*uses const "1sec"*/ RobotIsReadyToPick;
+DropObjectAtRightPlace/*requires object*/ : MotionGrammarElement ::= RightPlace/*uses object, provides place*/ Drop/*requires place*/;
+
+// Tokens
+EmptyTable                        : Token;
+ObjectAtWrongPlace                : Token ::= <Object:String>; // the Object is a variable of the token
+Pick/*requires object*/           : Token;
+RobotIsFree                       : Token ::= RobotIsIdle RobotHasNoItemAttached; // combined token. both individual tokens are parsed in parallel
+RobotIsBusy                       : Token; // TODO should be improved to express RobotIsFree can not be parsed
+RobotIsIdle                       : Token;
+RobotHasNoItemAttached            : Token;
+Wait/*requires time*/             : Token; // artificial token, which parsing takes a specified amount of time
+RightPlace/*requires object*/     : Token ::= <Place:String>;
+Drop/*requires object and place*/ : Token;
+
+
diff --git a/src/main/jastadd/Robot.relast b/src/main/jastadd/Robot.relast
deleted file mode 100644
index 6a8b7a8..0000000
--- a/src/main/jastadd/Robot.relast
+++ /dev/null
@@ -1,21 +0,0 @@
-Tidy ::= MoveObjectToCorrectPlace* EmptyTable;
-MoveObjectToCorrectPlace ::= ObjectAtWrongPlace/*provides object*/ PickUpObject/*uses object*/ DropObjectAtRightPlace/*uses object*/;
-PickUpObject/*requires object*/ ::= RobotIsReadyToPick Pick/*uses object*/;
-abstract RobotIsReadyToPick;
-RobotIsReallyReadyToPick : RobotIsReadyToPick ::= RobotIsFree;
-RobotIsNotReadyToPick    : RobotIsReadyToPick ::= RobotIsBusy Wait/*uses const "1sec"*/ RobotIsReadyToPick;
-DropObjectAtRightPlace/*requires object*/ ::= RightPlace/*uses object, provides place*/ Drop/*requires place*/;
-
-// Tokens
-EmptyTable                    : Token;
-ObjectAtWrongPlace            : Token ::= <Object:String>; // the Object is a variable of the token
-Pick/*requires object*/       : Token;
-RobotIsFree                   : Token ::= RobotIsIdle RobotHasNoItemAttached; // combined token. both individual tokens are parsed in parallel
-RobotIsBusy                   : Token; // TODO should be improved to express RobotIsFree can not be parsed
-RobotIsIdle                   : Token;
-RobotHasNoItemAttached        : Token;
-Wait/*requires time*/         : Token; // artificial token, which parsing takes a specified amount of time
-RightPlace/*requires object*/ : Token ::= <Place:String>;
-Drop/*requires object*/       : Token;
-
-
diff --git a/src/main/jastadd/World.jadd b/src/main/jastadd/World.jadd
index e11153e..e1a676a 100644
--- a/src/main/jastadd/World.jadd
+++ b/src/main/jastadd/World.jadd
@@ -6,7 +6,19 @@ aspect World {
     Container c = new Container();
     c.setCapacity(r.nextInt(MAX_CAPACITY - 1) + 1);
     c.setElementCount(r.nextInt(c.getCapacity()));
-    return new World(c);
+    Table t = new Table();
+    t.addBin(new Bin("binRed", Pose.of(-10, -10, 0), "red"));
+    t.addBin(new Bin("binGreen", Pose.of(-10, 0, 0), "green"));
+    t.addBin(new Bin("binBlue", Pose.of(-10, 10, 0), "blue"));
+    t.addMovableObject(new MovableObject("boxRed", Pose.of(-5, -10, 0), "red"));
+    t.addMovableObject(new MovableObject("boxGreen", Pose.of(-5, 0, 0), "green"));
+    t.addMovableObject(new MovableObject("boxBlue", Pose.of(-5, 10, 0), "blue"));
+    Robot b = new Robot();
+    return new World(c, t, b);
+  }
+
+  public static Pose Pose.of(double x, double y, double z) {
+    return new Pose(x,y,z,0,0,0,1);
   }
 
   @Override
@@ -44,4 +56,115 @@ aspect World {
     System.out.println("success");
     return new Unload();
   }
+
+  public EmptyTable World.parseEmptyTable() {
+    System.out.print("Trying to parse token <EmptyTable>... ");
+    if (getTable().isEmpty()) {
+      System.out.println("success");
+      return new EmptyTable();
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
+
+  public ObjectAtWrongPlace World.parseObjectAtWrongPlace() {
+    System.out.print("Trying to parse token <ObjectAtWrongPlace>... ");
+    // TODO get a *random* object?
+    for (MovableObject o : getTable().getMovableObjectList()) {
+      if (!o.isInBin()) {
+        System.out.println("success");
+        return new ObjectAtWrongPlace(o.getName());
+      }
+    }
+    System.out.println("failure");
+    return null;
+  }
+
+  public Pick World.parsePick(String objectName) {
+    System.out.print("Trying to parse token <Pick> for Object \"" + objectName + "\"... ");
+    MovableObject o = getTable().getMovableObjectByName(objectName);
+
+    if (o != null) {
+      System.out.println("success");
+      return new Pick();
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
+
+  public RobotIsFree World.parseRobotIsFree() {
+    System.out.print("Trying to parse token <RobotIsFree>... ");
+    RobotIsIdle idle = parseRobotIsIdle();
+    RobotHasNoItemAttached noItem = parseRobotHasNoItemAttached();
+    if (idle != null && noItem != null) {
+      System.out.println("success");
+      return new RobotIsFree(idle, noItem);
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
+
+  public RobotIsIdle World.parseRobotIsIdle() {
+    System.out.print("Trying to parse token <RobotIsIdle>... ");
+    if (getRobot().getIsIdle()) {
+      System.out.println("success");
+      return new RobotIsIdle();
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
+
+  public RobotHasNoItemAttached World.parseRobotHasNoItemAttached() {
+    System.out.print("Trying to parse token <RobotHasNoItemAttached>... ");
+    if (!getRobot().hasAttachedItem()) {
+      System.out.println("success");
+      return new RobotHasNoItemAttached();
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
+
+  public Wait World.parseWait(double time) {
+    System.out.print("Trying to parse token <Wait> for " + time + " seconds... ");
+    System.out.println("success");
+    return new Wait();
+  }
+
+  public RightPlace World.parseRightPlace(String objectName) {
+    System.out.print("Trying to parse token <RightPlace> for Object \"" + objectName + "\"... ");
+    MovableObject o = getTable().getMovableObjectByName(objectName);
+
+    if (o != null) {
+      for (Bin b : getTable().getBinList()) {
+        if (o.fitsIn(b)) {
+          System.out.println("success");
+          return new RightPlace(b.getName());
+        }
+      }
+      System.out.println("failure (no matching bin found)");
+      return null;
+    } else {
+      System.out.println("failure (object does not exist)");
+      return null;
+    }
+  }
+
+  public Drop World.parseDrop(String objectName, String placeName) {
+    System.out.print("Trying to parse token <Drop> for Object \"" + objectName + "\" and Bin \"" + placeName + "\"... ");
+    MovableObject o = getTable().getMovableObjectByName(objectName);
+    Bin b = getTable().getBinByName(placeName);
+
+    if (o != null && b != null) {
+      System.out.println("success");
+      return new Drop();
+    } else {
+      System.out.println("failure");
+      return null;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/main/jastadd/World.jrag b/src/main/jastadd/World.jrag
index b6b2243..c0558b4 100644
--- a/src/main/jastadd/World.jrag
+++ b/src/main/jastadd/World.jrag
@@ -1,4 +1,47 @@
 aspect World {
   syn String World.print() = "[World " + getContainer().print() + "]";
   syn String Container.print() = "[Container " + getElementCount() + "/" + getCapacity() + "]";
+
+  inh Table PhysicalObject.containingTable();
+  eq Table.getChild().containingTable() = this;
+
+  syn boolean MovableObject.isInBin() {
+    for (Bin b : containingTable().getBinList()) {
+      if (getPose().getX() == b.getPose().getX() && getPose().getY() == b.getPose().getY() && getPose().getZ() == b.getPose().getZ()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  syn boolean Table.isEmpty() {
+    for (MovableObject o : getMovableObjectList()) {
+      if (!o.isInBin()) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  syn MovableObject Table.getMovableObjectByName(String name) {
+    for (MovableObject o : getMovableObjectList()) {
+      if (o.getName().equals(name)) {
+        return o;
+      }
+    }
+    return null;
+  }
+
+  syn Bin Table.getBinByName(String name) {
+    for (Bin b : getBinList()) {
+      if (b.getName().equals(name)) {
+        return b;
+      }
+    }
+    return null;
+  }
+
+  syn boolean MovableObject.fitsIn(Bin b) {
+    return getColor().equals(b.getColor());
+  }
 }
\ No newline at end of file
diff --git a/src/main/jastadd/World.relast b/src/main/jastadd/World.relast
index 7fcedd7..946dd81 100644
--- a/src/main/jastadd/World.relast
+++ b/src/main/jastadd/World.relast
@@ -1,5 +1,15 @@
 // World Model of the Motion Grammar
 // The world contains one container with a maximum capacity and a current number of contained elements
 
-World ::= Container;
+World ::= Container Table Robot;
 Container ::= <Capacity:int> <ElementCount:int>;
+
+Table ::= MovableObject* Bin*;
+abstract PhysicalObject ::= <Name> Pose <Color>;
+MovableObject : PhysicalObject;
+Bin : PhysicalObject;
+
+Pose ::= <X:double> <Y:double> <Z:double> <QX:double> <QY:double> <QZ:double> <QW:double>;
+
+Robot ::= <IsIdle:boolean>;
+rel Robot.attachedItem? <-> MovableObject.attachedRobot?;
diff --git a/src/main/java/de/tudresden/inf/st/mg/RobotParser.java b/src/main/java/de/tudresden/inf/st/mg/RobotParser.java
new file mode 100644
index 0000000..2c285f6
--- /dev/null
+++ b/src/main/java/de/tudresden/inf/st/mg/RobotParser.java
@@ -0,0 +1,54 @@
+package de.tudresden.inf.st.mg;
+
+import de.tudresden.inf.st.mg.common.MotionGrammarParser;
+import de.tudresden.inf.st.mg.jastadd.model.*;
+
+
+public final class RobotParser extends MotionGrammarParser<Tidy> {
+
+  private static final String WORLD = "World";
+
+  private Load peekedLoad_ = null;
+  private Unload peekedUnload_ = null;
+  private Full peekedFull_ = null;
+
+  public RobotParser(World world) {
+    context_.put(WORLD, world);
+  }
+
+  private World getWorld() {
+    return (World) context_.get(WORLD);
+  }
+
+  /**
+   * Parse a motion grammar with root T
+   *
+   * @return the parsed AST of type T
+   */
+  public Tidy parseTidy() throws ParseException {
+    // don't try this at home
+    rootContainer_ = new ASTNode<>();
+    if (rootContainer_.getNumChild() == 0) {
+      rootContainer_.addChild(null);
+    }
+    printAST("initial", null);
+    parseTidy(rootContainer_, 0);
+    Tidy result = rootContainer_.getChild(0);
+    printAST("complete", null);
+    result.setParent(null);
+    rootContainer_.setChild(null, 0);
+    return result;
+  }
+
+  private void parseTidy(ASTNode<?> parent, int index) throws ParseException {
+    Tidy result;
+
+    if (true) {
+      throw new ParseException("T", Load.type(), Full.type());
+    }
+
+    // semantic action for T
+    result.action(getWorld());
+    printAST("parseT", result);
+  }
+}
diff --git a/src/main/java/de/tudresden/inf/st/mg/WorldParser.java b/src/main/java/de/tudresden/inf/st/mg/WorldParser.java
index 1e646e3..e5e634f 100644
--- a/src/main/java/de/tudresden/inf/st/mg/WorldParser.java
+++ b/src/main/java/de/tudresden/inf/st/mg/WorldParser.java
@@ -5,7 +5,7 @@ import de.tudresden.inf.st.mg.jastadd.model.*;
 
 
 
-public final class WorldParser extends MotionGrammarParser {
+public final class WorldParser extends MotionGrammarParser<T> {
 
   private static final String WORLD = "World";
 
diff --git a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
index 239c462..ae6f4d6 100644
--- a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
+++ b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
@@ -2,10 +2,7 @@ package de.tudresden.inf.st.mg.common;
 
 import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper;
 import de.tudresden.inf.st.jastadd.dumpAst.ast.SkinParamBooleanSetting;
-import de.tudresden.inf.st.mg.jastadd.model.ASTNode;
-import de.tudresden.inf.st.mg.jastadd.model.T;
-import de.tudresden.inf.st.mg.jastadd.model.Token;
-import de.tudresden.inf.st.mg.jastadd.model.TokenType;
+import de.tudresden.inf.st.mg.jastadd.model.*;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -14,7 +11,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-public abstract class MotionGrammarParser {
+public abstract class MotionGrammarParser<T extends MotionGrammarElement> {
 
   protected final Map<String, ASTNode<?>> context_ = new HashMap<>();
   protected ASTNode<T> rootContainer_;
-- 
GitLab