From db3908ff2e3c568e1e73c7b78de933fe39b5548e Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Tue, 1 Oct 2019 15:28:51 +0200
Subject: [PATCH] Add LeftDirection ('<-') for relations.

- Also add some tests for left direction
---
 src/main/jastadd/Analysis.jrag                |  6 +-
 src/main/jastadd/Backend.jadd                 |  9 ++
 src/main/jastadd/RelAst.ast                   |  1 +
 src/main/jastadd/RelAst.flex                  |  1 +
 src/main/jastadd/RelAst.parser                |  1 +
 .../org/jastadd/relast/compiler/Compiler.java |  2 +-
 src/test/jastadd/errors/ErrorsLeft.expected   |  5 +
 src/test/jastadd/errors/ErrorsLeft.relast     |  8 ++
 .../jastadd/errors/InheritanceLeft.expected   |  3 +
 .../jastadd/errors/InheritanceLeft.relast     |  6 ++
 src/test/jastadd/errors/MultipleLeft.expected |  5 +
 src/test/jastadd/errors/MultipleLeft_1.relast |  6 ++
 src/test/jastadd/errors/MultipleLeft_2.relast |  2 +
 src/test/jastadd/relations/Relations.relast   |  5 +
 .../java/org/jastadd/relast/tests/Errors.java | 15 +++
 .../org/jastadd/relast/tests/Relations.java   | 94 +++++++++++++++++++
 16 files changed, 167 insertions(+), 2 deletions(-)
 create mode 100644 src/test/jastadd/errors/ErrorsLeft.expected
 create mode 100644 src/test/jastadd/errors/ErrorsLeft.relast
 create mode 100644 src/test/jastadd/errors/InheritanceLeft.expected
 create mode 100644 src/test/jastadd/errors/InheritanceLeft.relast
 create mode 100644 src/test/jastadd/errors/MultipleLeft.expected
 create mode 100644 src/test/jastadd/errors/MultipleLeft_1.relast
 create mode 100644 src/test/jastadd/errors/MultipleLeft_2.relast

diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 8f586ce..8959b7b 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -29,11 +29,15 @@ aspect TypeAnalysis {
 
 aspect ComponentAnalysis {
   syn boolean Component.isTargetOfDirectedRelation() = false;
-  eq RelationComponent.isTargetOfDirectedRelation() = isTargetOfRightDirection();
+  eq RelationComponent.isTargetOfDirectedRelation() = isTargetOfRightDirection() | isTargetOfLeftDirection();
   inh boolean RelationComponent.isTargetOfRightDirection();
   eq Relation.getRight().isTargetOfRightDirection()
     = getDirection() instanceof RightDirection;
   eq Program.getChild().isTargetOfRightDirection() = false;
+  inh boolean RelationComponent.isTargetOfLeftDirection();
+  eq Relation.getLeft().isTargetOfLeftDirection()
+    = getDirection() instanceof LeftDirection;
+  eq Program.getChild().isTargetOfLeftDirection() = false;
 
   syn String Component.name() = getID();
 
diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd
index 5401260..cde27fe 100644
--- a/src/main/jastadd/Backend.jadd
+++ b/src/main/jastadd/Backend.jadd
@@ -216,6 +216,9 @@ aspect BackendDirectedAPI {
   public void RightDirection.generateAPI(StringBuilder sb) {
     relation().getLeft().generateDirectedAPI(sb);
   }
+  public void LeftDirection.generateAPI(StringBuilder sb) {
+    relation().getRight().generateDirectedAPI(sb);
+  }
 
   public abstract void RelationComponent.generateDirectedAPI(StringBuilder sb);
   public void OneRelationComponent.generateDirectedAPI(StringBuilder sb) {
@@ -904,6 +907,9 @@ aspect NameResolutionHelper {
   public void RightDirection.generateContextDependentNameResolution(StringBuilder sb) {
     relation().getLeft().generateContextDependentNameResolution(sb);
   }
+  public void LeftDirection.generateContextDependentNameResolution(StringBuilder sb) {
+    relation().getRight().generateContextDependentNameResolution(sb);
+  }
   public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) {
     relation().getLeft().generateContextDependentNameResolution(sb);
     relation().getRight().generateContextDependentNameResolution(sb);
@@ -1451,6 +1457,9 @@ aspect PrettyPrint {
   public String RightDirection.prettyPrint() {
     return "->";
   }
+  public String LeftDirection.prettyPrint() {
+    return "<-";
+  }
   public String Bidirectional.prettyPrint() {
     return "<->";
   }
diff --git a/src/main/jastadd/RelAst.ast b/src/main/jastadd/RelAst.ast
index 2b468e9..9b29df1 100644
--- a/src/main/jastadd/RelAst.ast
+++ b/src/main/jastadd/RelAst.ast
@@ -21,4 +21,5 @@ OptionalRelationComponent : RelationComponent;
 ManyRelationComponent : RelationComponent;
 abstract Direction;
 RightDirection : Direction;
+LeftDirection : Direction;
 Bidirectional : Direction;
diff --git a/src/main/jastadd/RelAst.flex b/src/main/jastadd/RelAst.flex
index 68b2ebf..7cccbe3 100644
--- a/src/main/jastadd/RelAst.flex
+++ b/src/main/jastadd/RelAst.flex
@@ -62,6 +62,7 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]*
 "/"          { return sym(Terminals.SLASH); }
 "?"          { return sym(Terminals.QUESTION_MARK); }
 "->"         { return sym(Terminals.RIGHT); }
+"<-"         { return sym(Terminals.LEFT); }
 "<->"        { return sym(Terminals.BIDIRECTIONAL); }
 
 // ID
diff --git a/src/main/jastadd/RelAst.parser b/src/main/jastadd/RelAst.parser
index 24fb22b..0a09739 100644
--- a/src/main/jastadd/RelAst.parser
+++ b/src/main/jastadd/RelAst.parser
@@ -101,5 +101,6 @@ RelationComponent relation_comp =
 
 Direction direction =
   RIGHT {: return new RightDirection(); :}
+  | LEFT {: return new LeftDirection(); :}
   | BIDIRECTIONAL {: return new Bidirectional(); :}
   ;
diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java
index 1a2605f..22b6168 100644
--- a/src/main/java/org/jastadd/relast/compiler/Compiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java
@@ -14,7 +14,7 @@ import java.util.List;
 
 public class Compiler {
 
-  private static final String VERSION = "0.2.2";
+  private static final String VERSION = "0.2.3";
 
   private ArrayList<Option<?>> options;
   private FlagOption optionWriteToFile;
diff --git a/src/test/jastadd/errors/ErrorsLeft.expected b/src/test/jastadd/errors/ErrorsLeft.expected
new file mode 100644
index 0000000..155d0ec
--- /dev/null
+++ b/src/test/jastadd/errors/ErrorsLeft.expected
@@ -0,0 +1,5 @@
+Errors:
+$FILENAME Line 5, column 10: Role name missing for type 'A'
+$FILENAME Line 6, column 15: Role name missing for type 'B'
+$FILENAME Line 7, column 5: The target of a directed relation cannot have a role name
+$FILENAME Line 8, column 5: The target of a directed relation may only have multiplicity 1
diff --git a/src/test/jastadd/errors/ErrorsLeft.relast b/src/test/jastadd/errors/ErrorsLeft.relast
new file mode 100644
index 0000000..e381449
--- /dev/null
+++ b/src/test/jastadd/errors/ErrorsLeft.relast
@@ -0,0 +1,8 @@
+Program ::= A* B*;
+A;
+B;
+
+rel B <- A;
+rel A.bs* <-> B*;
+rel B.b <- A.b;
+rel B* <- A.b2;
diff --git a/src/test/jastadd/errors/InheritanceLeft.expected b/src/test/jastadd/errors/InheritanceLeft.expected
new file mode 100644
index 0000000..ef568b5
--- /dev/null
+++ b/src/test/jastadd/errors/InheritanceLeft.expected
@@ -0,0 +1,3 @@
+Errors:
+$FILENAME Line 2, column 12: Component 'X' is already declared for type 'B1'
+$FILENAME Line 6, column 10: Component 'X' is already declared for type 'B2'
diff --git a/src/test/jastadd/errors/InheritanceLeft.relast b/src/test/jastadd/errors/InheritanceLeft.relast
new file mode 100644
index 0000000..a63c266
--- /dev/null
+++ b/src/test/jastadd/errors/InheritanceLeft.relast
@@ -0,0 +1,6 @@
+A ::= X;
+B1 : A ::= X;
+B2 : A;
+X;
+
+rel X <- B2.X;
diff --git a/src/test/jastadd/errors/MultipleLeft.expected b/src/test/jastadd/errors/MultipleLeft.expected
new file mode 100644
index 0000000..4c2b802
--- /dev/null
+++ b/src/test/jastadd/errors/MultipleLeft.expected
@@ -0,0 +1,5 @@
+Errors:
+$FILENAME1 Line 5, column 10: Role name missing for type 'A'
+$FILENAME1 Line 6, column 15: Role name missing for type 'B'
+$FILENAME2 Line 1, column 5: The target of a directed relation cannot have a role name
+$FILENAME2 Line 2, column 5: The target of a directed relation may only have multiplicity 1
diff --git a/src/test/jastadd/errors/MultipleLeft_1.relast b/src/test/jastadd/errors/MultipleLeft_1.relast
new file mode 100644
index 0000000..c0ac803
--- /dev/null
+++ b/src/test/jastadd/errors/MultipleLeft_1.relast
@@ -0,0 +1,6 @@
+Program ::= A* B*;
+A;
+B;
+
+rel B <- A;
+rel A.bs* <-> B*;
diff --git a/src/test/jastadd/errors/MultipleLeft_2.relast b/src/test/jastadd/errors/MultipleLeft_2.relast
new file mode 100644
index 0000000..9ee5922
--- /dev/null
+++ b/src/test/jastadd/errors/MultipleLeft_2.relast
@@ -0,0 +1,2 @@
+rel B.b <- A.b;
+rel B* <- A.b2;
diff --git a/src/test/jastadd/relations/Relations.relast b/src/test/jastadd/relations/Relations.relast
index 6a56229..892ad39 100644
--- a/src/test/jastadd/relations/Relations.relast
+++ b/src/test/jastadd/relations/Relations.relast
@@ -17,3 +17,8 @@ rel A.Bi6? <-> B.Bi6*;
 rel A.Bi7* <-> B.Bi7;
 rel A.Bi8* <-> B.Bi8?;
 rel A.Bi9* <-> B.Bi9*;
+
+rel A <- Root.AaLeft?;
+rel B <- A.Di1Left ;
+rel B <- A.Di2Left?;
+rel B <- A.Di3Left*;
diff --git a/src/test/java/org/jastadd/relast/tests/Errors.java b/src/test/java/org/jastadd/relast/tests/Errors.java
index 8154c19..718c049 100644
--- a/src/test/java/org/jastadd/relast/tests/Errors.java
+++ b/src/test/java/org/jastadd/relast/tests/Errors.java
@@ -27,16 +27,31 @@ class Errors {
     test("Errors");
   }
 
+  @Test
+  void test1Left() throws IOException {
+    test("ErrorsLeft");
+  }
+
   @Test
   void test2() throws IOException {
     test("Inheritance");
   }
 
+  @Test
+  void test2Left() throws IOException {
+    test("InheritanceLeft");
+  }
+
   @Test
   void test3() throws IOException {
     test("Multiple", "Multiple_1", "Multiple_2");
   }
 
+  @Test
+  void test3Left() throws IOException {
+    test("MultipleLeft", "MultipleLeft_1", "MultipleLeft_2");
+  }
+
   private void test(String name, String... inFilenames) throws IOException {
     List<String> inFiles = Arrays.stream(inFilenames.length > 0 ? inFilenames : new String[]{name})
         .map(f -> "./src/test/jastadd/errors/" + f + ".relast")
diff --git a/src/test/java/org/jastadd/relast/tests/Relations.java b/src/test/java/org/jastadd/relast/tests/Relations.java
index a23d998..4ad3a15 100644
--- a/src/test/java/org/jastadd/relast/tests/Relations.java
+++ b/src/test/java/org/jastadd/relast/tests/Relations.java
@@ -132,6 +132,100 @@ class Relations {
     assertEquals(a3.getDi3List(), Arrays.asList());
   }
 
+  /**
+   * rel A.Di1 -> B;
+   */
+  @Test
+  void testDi1Left() {
+    setup();
+    a1.setDi1Left(b2);
+    a2.setDi1Left(b1);
+
+    assertSame(a1.getDi1Left(), b2);
+    assertSame(a2.getDi1Left(), b1);
+
+    a2.setDi1Left(b2);
+
+    assertSame(a1.getDi1Left(), b2);
+    assertSame(a2.getDi1Left(), b2);
+
+    try {
+      a3.setDi1Left(null);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+  }
+
+
+  /**
+   * rel A.Di2? -> B;
+   */
+  @Test
+  void testDi2Left() {
+    setup();
+    a1.setDi2Left(b2);
+    a2.setDi2Left(b1);
+
+    assertSame(a1.getDi2Left(), b2);
+    assertSame(a2.getDi2Left(), b1);
+
+    a2.setDi2Left(b2);
+
+    assertSame(a1.getDi2Left(), b2);
+    assertSame(a2.getDi2Left(), b2);
+
+    a2.clearDi2Left();
+
+    assertSame(a1.getDi2Left(), b2);
+    assertNull(a2.getDi2Left());
+
+    assertTrue(a1.hasDi2Left());
+    assertFalse(a2.hasDi2Left());
+    assertFalse(a3.hasDi2Left());
+  }
+
+
+  /**
+   * rel A.Di3* -> B;
+   */
+  @Test
+  void testDi3Left() {
+    setup();
+    a1.addDi3Left(b1);
+    a1.addDi3Left(b2);
+    a1.addDi3Left(b3);
+    a2.addDi3Left(b2);
+
+    assertEquals(a1.getDi3Lefts(), Arrays.asList(b1, b2, b3));
+    assertEquals(a1.getDi3LeftList(), Arrays.asList(b1, b2, b3));
+    assertEquals(a2.getDi3Lefts(), Arrays.asList(b2));
+    assertEquals(a2.getDi3LeftList(), Arrays.asList(b2));
+    assertEquals(a3.getDi3Lefts(), Arrays.asList());
+    assertEquals(a3.getDi3LeftList(), Arrays.asList());
+
+    a1.addDi3Left(b1);
+    a2.addDi3Left(b1);
+    a2.addDi3Left(b2);
+
+    assertEquals(a1.getDi3Lefts(), Arrays.asList(b1, b2, b3, b1));
+    assertEquals(a1.getDi3LeftList(), Arrays.asList(b1, b2, b3, b1));
+    assertEquals(a2.getDi3Lefts(), Arrays.asList(b2, b1, b2));
+    assertEquals(a2.getDi3LeftList(), Arrays.asList(b2, b1, b2));
+    assertEquals(a3.getDi3Lefts(), Arrays.asList());
+    assertEquals(a3.getDi3LeftList(), Arrays.asList());
+
+    a1.removeDi3Left(b1);
+    a2.removeDi3Left(b2);
+
+    assertEquals(a1.getDi3Lefts(), Arrays.asList(b2, b3, b1));
+    assertEquals(a1.getDi3LeftList(), Arrays.asList(b2, b3, b1));
+    assertEquals(a2.getDi3Lefts(), Arrays.asList(b1, b2));
+    assertEquals(a2.getDi3LeftList(), Arrays.asList(b1, b2));
+    assertEquals(a3.getDi3Lefts(), Arrays.asList());
+    assertEquals(a3.getDi3LeftList(), Arrays.asList());
+  }
+
 
   /**
    * rel A.Bi1 <-> B.Bi1;
-- 
GitLab