From 0a2769f0e1ff4d5d35b4bb09cfcdf5fa83df92ae Mon Sep 17 00:00:00 2001
From: Johannes Mey <johannes.mey@tu-dresden.de>
Date: Sun, 24 Feb 2019 21:10:46 +0100
Subject: [PATCH] initial version of relast with parser support (i.e.,
 semi-automatic reference resolving)

---
 src/main/jastadd/Analysis.jrag                |   8 ++
 src/main/jastadd/Backend.jadd                 | 125 ++++++++++++++++++
 src/main/jastadd/RelAst.ast                   |   1 +
 .../org/jastadd/relast/compiler/Compiler.java |  28 ++++
 4 files changed, 162 insertions(+)

diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 62c0f54..20f11a5 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -17,6 +17,14 @@ aspect TypeAnalysis {
   syn boolean TypeDecl.isAlreadyDeclared()
     = lookupType(getID()) != this;
   inh TypeDecl TypeDecl.lookupType(String name);
+
+  syn TypeDecl TypeDecl.mostGeneralSuperType() {
+    if (!hasSuper()) {
+      return this;
+    } else {
+      return getSuper().decl().mostGeneralSuperType();
+    }
+  }
 }
 
 aspect ComponentAnalysis {
diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd
index 1ddf8be..e526107 100644
--- a/src/main/jastadd/Backend.jadd
+++ b/src/main/jastadd/Backend.jadd
@@ -1,6 +1,7 @@
 aspect BackendAbstractGrammar {
 
   public static String ASTNode.listClass = "ArrayList";
+  public static boolean ASTNode.resolverHelper = false;
 
   public String Program.generateAbstractGrammar() {
     StringBuilder sb = new StringBuilder();
@@ -212,6 +213,11 @@ aspect BackendDirectedAPI {
   public void RelationComponent.generateGetOne(StringBuilder sb) {
     sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl());
     sb.append(".get" + nameCapitalized() + "() {\n");
+    if (resolverHelper) {
+      sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null && get" + getImplAttributeName() + "().unresolved()) {\n");
+      sb.append(ind(3) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "(get" + getImplAttributeName() + "().asUnresolved" + ofTypeDecl() + "().get__token()));\n");
+      sb.append(ind(2) + "}\n");
+    }
     sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n");
     sb.append(ind(1) + "}\n");
   }
@@ -511,6 +517,125 @@ aspect LowerBoundCheck {
   }
 }
 
+aspect NameResolutionHelper {
+
+  syn boolean TypeDecl.isUnresolved() = false;
+  eq UnresolvedTypeDecl.isUnresolved() = true;
+
+  syn UnresolvedTypeDecl TypeDecl.asUnresolved() = null;
+  eq UnresolvedTypeDecl.asUnresolved() = this;
+
+  public String Program.generateRewriteToSuperTypeStub() {
+    StringBuilder sb = new StringBuilder();
+    generateRewriteToSuperTypeStub(sb);
+    return sb.toString();
+  }
+
+  public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) {
+    sb.append("aspect RefResolverStubs {\n\n");
+
+    for (Relation r: getRelations()) {
+      r.generateContextDependentNameResolution(sb);
+    }
+
+    for (TypeDecl decl : getTypeDeclList()) {
+      if (decl.isUnresolved()) {
+        decl.asUnresolved().generateContextIndependentNameResolution(sb);
+        sb.append("\n");
+      }
+    }
+    sb.append("}\n\n");
+
+    sb.append("aspect ReferenceCreation {\n\n");
+
+    for (TypeDecl decl : getTypeDeclList()) {
+      if (decl.isUnresolved()) {
+        decl.asUnresolved().createReferenceCreator(sb);
+      }
+    }
+
+    sb.append("}\n\n");
+
+    sb.append("aspect RefResolverHelpers {\n\n");
+
+    sb.append(ind(1) + "syn boolean ASTNode.unresolved() = false;\n");
+    for (TypeDecl decl : getTypeDeclList()) {
+      if (decl.isUnresolved()) {
+        sb.append(ind(1) + "eq " + decl.getID() + ".unresolved() = true;\n");
+      }
+    }
+    sb.append("\n");
+    for (TypeDecl decl : getTypeDeclList()) {
+      if (decl.isUnresolved()) {
+        sb.append(ind(1) + "syn " + decl.getID() + " " + decl.getSuper().decl().getID() + ".asUnresolved" + decl.getSuper().decl().getID() + "() = null;\n");
+        sb.append(ind(1) + "eq " + decl.getID() + ".asUnresolved" + decl.getSuper().decl().getID() + "() = this;\n");
+      }
+    }
+
+    sb.append("\n}\n");
+  }
+
+  public void UnresolvedTypeDecl.createReferenceCreator(StringBuilder sb) {
+
+    String superType = this.getSuper().getID();
+
+    sb.append(ind(1) + "public static " + superType + " " + superType + ".createRef(String ref) {\n");
+      sb.append(ind(2) + getID() + " unresolvedNode = new " + getID() + "();\n");
+      sb.append(ind(2) + "unresolvedNode.set__token(ref);\n");
+      sb.append(ind(2) + "return unresolvedNode;\n");
+    sb.append(ind(1) + "}\n");
+  }
+
+  public void UnresolvedTypeDecl.generateContextIndependentNameResolution(StringBuilder sb) {
+
+    String superType = this.getSuper().getID();
+
+    sb.append(ind(1) + "// context-independent name resolution\n");
+    sb.append(ind(1) + "syn " + superType + " ASTNode.resolve" + superType + "(String id) {\n");
+      sb.append(ind(2) + "// perform context independent name resolution here using the id\n");
+      sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for "+ superType + " not implemented.\");\n");
+    sb.append(ind(1) + "}\n");
+  }
+
+  public void Relation.generateContextDependentNameResolution(StringBuilder sb) {
+    sb.append(ind(1) + "// " + prettyPrint() + "\n");
+    getDirection().generateContextDependentNameResolution(sb);
+    sb.append("\n");
+  }
+
+  public abstract void Direction.generateContextDependentNameResolution(StringBuilder sb);
+  public void RightDirection.generateContextDependentNameResolution(StringBuilder sb) {
+    relation().getLeft().generateContextDependentNameResolution(sb);
+  }
+  public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) {
+    // TODO
+  }
+
+  public abstract void RelationComponent.generateContextDependentNameResolution(StringBuilder sb);
+  public void OneRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
+    generateDirectedContextDependentNameResolution(sb);
+  }
+  public void OptionalRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
+    // TODO
+  }
+  public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
+    // TODO
+  }
+
+  public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) {
+    // // context-dependent name resolution
+    // NamedElement A.resolveRel1(String id) {
+    //   // default to context-independent name resolution
+    //   return resolveNamedElement(id);
+    // }
+    sb.append(ind(1) + "// context-dependent name resolution\n");
+    sb.append(ind(1) + "syn " + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "(String id) {\n");
+      sb.append(ind(2) + "// default to context-independent name resolution\n");
+      sb.append(ind(2) + "return resolve" + ofTypeDecl() + "(id);\n");
+    sb.append(ind(1) + "}\n");
+  }
+}
+
 aspect PrettyPrint {
   public String Relation.prettyPrint() {
     return "rel "
diff --git a/src/main/jastadd/RelAst.ast b/src/main/jastadd/RelAst.ast
index 3a17c0c..5098ece 100644
--- a/src/main/jastadd/RelAst.ast
+++ b/src/main/jastadd/RelAst.ast
@@ -1,5 +1,6 @@
 Program ::= TypeDecl* Relation*;
 TypeDecl ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
+UnresolvedTypeDecl:TypeDecl;
 
 abstract Component ::= <ID>;
 abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java
index 2c1ebe5..0eee730 100644
--- a/src/main/java/org/jastadd/relast/compiler/Compiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java
@@ -20,6 +20,7 @@ public class Compiler {
   private FlagOption optionPrintAST;
   private StringOption optionListClass;
   private StringOption optionGrammarName;
+  private FlagOption optionResolverHelper;
   private CommandLine commandLine;
 
   public Compiler(String[] args) throws CommandLineException {
@@ -34,8 +35,28 @@ public class Compiler {
     }
 
     List<String> filenames = commandLine.getArguments();
+    List<TypeDecl> unresolvedDecls = new ArrayList<>();
     Program p = parseProgram(filenames);
 
+    if (optionResolverHelper.isSet()) {
+      // get a list of all (abstract or not) non-terminals
+      List<TypeDecl> nonTerminals = new ArrayList<>();
+      for (TypeDecl typeDecl : p.getTypeDecls()) {
+        nonTerminals.add(typeDecl);
+      }
+
+      // add a new typeDecl with a prefix "Unresolved"
+      for (TypeDecl typeDecl : nonTerminals) {
+        UnresolvedTypeDecl unresolvedDecl = new UnresolvedTypeDecl();
+        unresolvedDecl.setID("__unresolved" + typeDecl.getID());
+        unresolvedDecl.setAbstract(false);
+        unresolvedDecl.setSuper(new SimpleTypeUse(typeDecl.getID()));
+        unresolvedDecl.addComponent(new TokenComponent("__token", new SimpleTypeUse("String")));
+        p.addTypeDecl(unresolvedDecl);
+        unresolvedDecls.add(unresolvedDecl);
+      }
+    }
+
     if (!p.errors().isEmpty()) {
       if (optionPrintAST.isSet()) {
         System.out.println(p.dumpTree());
@@ -58,6 +79,12 @@ public class Compiler {
       }
 
       if (optionWriteToFile.isSet()) {
+
+        if (optionResolverHelper.isSet()) {
+          ASTNode.resolverHelper = true;
+          writeToFile(grammarName + "RefResolver.jadd", p.generateRewriteToSuperTypeStub());
+        }
+
         writeToFile(grammarName + ".ast", p.generateAbstractGrammar());
         writeToFile(grammarName + ".jadd", p.generateAspect());
       } else if (optionPrintAST.isSet()) {
@@ -94,6 +121,7 @@ public class Compiler {
     optionPrintAST = addOption(new FlagOption("ast", "print AST"));
     optionListClass = addOption(new StringOption("listClass", "determine the class name of the nonterminal reference list"));
     optionGrammarName = addOption(new StringOption("grammarName", "name of the generated grammar and aspect (without file extension)"));
+    optionResolverHelper = addOption(new FlagOption("resolverHelper", "create a subtype for each type containing a string that can be used to resolve the type later"));
   }
 
   private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
-- 
GitLab