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