diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 8f586cea6bbd0abd286b15a8fb618ff5660067f3..8959b7b1280f5e1594d436ca369ff3b1da4aede7 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 5401260ffed8245a5dcd999f3d2d13a8811f6312..cde27fe6206c11bdd9f562df733de2443874b48d 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 2b468e91198a0c103a4a6fdc5d2ab0f543f22ca8..9b29df1e866d7b2d4cb87e414aa16f9a3fa5feeb 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 68b2ebfe461ff2b1e35403f25af755bd04449a9e..7cccbe3c484522ca126427e3df9a57681c52d8d4 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 24fb22b1a05e7fe0b150ad543ced5febc04095c6..0a097391b2519dd89a44746e0ae092cbfb6af0c0 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 1a2605fc1db58827aa37302b5b318269e536beec..22b6168a311daab77f2119a93a0d33e26f6a7a64 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 0000000000000000000000000000000000000000..155d0ec5110a4f6156e71033e92137a6aebb0492
--- /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 0000000000000000000000000000000000000000..e381449c06b7f0223b36b8b0936f417c5811bb7b
--- /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 0000000000000000000000000000000000000000..ef568b501af914f79b4dfeb6c0d958c3198ca2f7
--- /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 0000000000000000000000000000000000000000..a63c2668bb0c27348947fbbb8a8f0a72b173d096
--- /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 0000000000000000000000000000000000000000..4c2b802fb6b18485a702049349343899940219af
--- /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 0000000000000000000000000000000000000000..c0ac803ccb82f9d34aa7653938f041e1d7c71b7d
--- /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 0000000000000000000000000000000000000000..9ee592259ec471097d0f0758df2b451584f9f820
--- /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 6a5622902d79ebffe1b679c291fa84dd12b35f67..892ad39a767a72be44ff1cba5d61c98e2998fa6f 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 8154c198c346527271bbd8768e35bf5e4eaa0394..718c049708281b26dea16e8792062be067c2938e 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 a23d9982f0c6a8c3464e3f16dc0edb298f40a527..4ad3a15effc046f926b49a47d8cd792c3b3fcd89 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;