From f11bded4f94392ff578d97393ffb88ccdadde530 Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Sat, 28 Mar 2020 19:13:17 +0100 Subject: [PATCH] only create reference creation and resolution methods for types that can be instantiated --- src/main/jastadd/Analysis.jrag | 40 +++++- src/main/jastadd/backend/NameResolution.jadd | 40 +++--- src/main/jastadd/backend/Serializer.jadd | 114 +++++++++--------- src/test/jastadd/relations/Relations.relast | 2 + src/test/jastadd/resolver/Resolver.relast | 2 + src/test/jastadd/resolver2/Resolver.relast | 2 + .../Serializer.relast | 2 + .../serializer-manual/Serializer.relast | 2 + .../serializer-names/Serializer.relast | 2 + .../serializer-pointer/Serializer.relast | 2 + src/test/jastadd/serializer/Serializer.relast | 2 + 11 files changed, 132 insertions(+), 78 deletions(-) diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag index 2145633..4157275 100644 --- a/src/main/jastadd/Analysis.jrag +++ b/src/main/jastadd/Analysis.jrag @@ -160,11 +160,39 @@ aspect ComponentAnalysis { return set; } - //--- needUnresolvedClass --- - syn boolean TypeDecl.needUnresolvedClass() { - // a TypeDecl needs an unresolved class, if it can appear in a relation - // TODO - return true; + /** + * @return a set of all types that refer to this type using a non-containment relation + */ + coll Set<TypeDecl> TypeDecl.referencingTypes() [new HashSet<TypeDecl>()]; + RelationComponent contributes opposite().getTypeUse().decl() + when opposite().isNavigable() + to TypeDecl.referencingTypes() + for getTypeUse().decl(); + + /** + * @return true, if the type can be the target of a non-containment relation + */ + syn boolean TypeDecl.isReferenceTarget() { + return !referencingTypes().isEmpty(); + } + + /** + * @return true, if the type or one of its abstract supertypes can be the target of a non-containment relation + */ + syn boolean TypeDecl.requiresUresolvedClass() { + if (referencingTypes().isEmpty()) { + // if the type is not referenced itself, it may still be required by an abstract supertype that is referenced + TypeDecl decl = this; + while (decl.hasSuper()) { + decl = decl.getSuper().decl(); + if (decl.getAbstract() && !decl.referencingTypes().isEmpty()) { + return true; + } + } + return false; + } else { + return true; + } } //--- isList --- @@ -201,6 +229,8 @@ aspect InstanceSupplier { return subDecls; } + syn boolean TypeDecl.instantiable() = instantiableSubType() != null; + //--- instantiableSubType --- syn TypeDecl TypeDecl.instantiableSubType() { if (getAbstract() == false) { diff --git a/src/main/jastadd/backend/NameResolution.jadd b/src/main/jastadd/backend/NameResolution.jadd index 9b47dc1..8080fa0 100644 --- a/src/main/jastadd/backend/NameResolution.jadd +++ b/src/main/jastadd/backend/NameResolution.jadd @@ -149,7 +149,9 @@ aspect NameResolutionHelper { sb.append("aspect ReferenceCreation {\n\n"); for (TypeDecl decl : getTypeDeclList()) { - decl.createReferenceCreator(sb); + if (decl.isReferenceTarget()) { + decl.createReferenceCreator(sb); + } } sb.append("}\n\n"); @@ -172,7 +174,7 @@ aspect NameResolutionHelper { sb.append(ind(1) + "}\n\n"); for (TypeDecl td: getTypeDecls()) { - if (td.needUnresolvedClass()) { + if (td.requiresUresolvedClass()) { td.generateUnresolvedClass(sb); } } @@ -182,24 +184,24 @@ aspect NameResolutionHelper { public void TypeDecl.createReferenceCreator(StringBuilder sb) { - TypeDecl instantiableSubType = instantiableSubType(); - if (instantiableSubType == null) { - throw new RuntimeException("unable to find instantiable subtype for " + getID()); - } - - sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefMethod + "(String ref) {\n"); - sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n"); - sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n"); - sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(true);\n"); - sb.append(ind(2) + "return unresolvedNode;\n"); - sb.append(ind(1) + "}\n"); + if (!instantiable()) { + System.out.println("WARNING: unable to find instantiable subtype for " + getID() + "! Skipping the creation of reference creator methods."); + } else { + TypeDecl instantiableSubType = instantiableSubType(); + sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefMethod + "(String ref) {\n"); + sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n"); + sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n"); + sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(true);\n"); + sb.append(ind(2) + "return unresolvedNode;\n"); + sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefDirectionMethod + "(String ref) {\n"); - sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n"); - sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n"); - sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(false);\n"); - sb.append(ind(2) + "return unresolvedNode;\n"); - sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "public static " + getID() + " " + getID() + "." + createRefDirectionMethod + "(String ref) {\n"); + sb.append(ind(2) + unresolvedPrefix + instantiableSubType.getID() + " unresolvedNode = new " + unresolvedPrefix + instantiableSubType.getID() + "();\n"); + sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "Token(ref);\n"); + sb.append(ind(2) + "unresolvedNode.set" + unresolvedPrefix + "ResolveOpposite(false);\n"); + sb.append(ind(2) + "return unresolvedNode;\n"); + sb.append(ind(1) + "}\n"); + } } public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) { diff --git a/src/main/jastadd/backend/Serializer.jadd b/src/main/jastadd/backend/Serializer.jadd index 21db37f..ac811f1 100644 --- a/src/main/jastadd/backend/Serializer.jadd +++ b/src/main/jastadd/backend/Serializer.jadd @@ -268,67 +268,73 @@ aspect Serializer { public void TypeDecl.deserialize(StringBuilder sb) { sb.append(ind(1) + "public static " + getID() + " " + getID() + ".deserialize(java.io.File file) throws DeserializationException {\n"); - sb.append(ind(2) + "try {\n"); - sb.append(ind(3) + "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n"); - sb.append(ind(3) + "com.fasterxml.jackson.core.JsonFactory factory = mapper.getFactory();\n"); - sb.append(ind(3) + "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(file);\n"); - sb.append(ind(3) + getID() + " result = deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));\n"); - sb.append(ind(3) + "parser.close();\n"); - sb.append(ind(3) + "return result;\n"); - sb.append(ind(2) + "} catch (java.io.IOException e) {\n"); - sb.append(ind(3) + "throw new DeserializationException(\"unable to deserialize \" + file.getAbsolutePath(), e);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "public static " + getID() + " " + getID() + ".deserialize(" + jsonNodeType + " node) throws DeserializationException {\n"); - sb.append(ind(2) + getID() + " element;\n"); - if (getAbstract()) { - // switch case between all implementations of the abstract class - sb.append(ind(2) + "switch (node" + jsonNodeTypeAccessor + ") {\n"); - for (TypeDecl subType : subTypeDecls()) { - sb.append(ind(3) + "case \"" + subType.getID() + "\":\n"); - sb.append(ind(4) + "element = " + subType.getID() + ".deserialize(node);\n"); - sb.append(ind(4) + "break;\n"); - } - sb.append(ind(3) + "default:\n"); - sb.append(ind(4) + "throw new DeserializationException(\"Unable to deserialize child of unexpected type \" + node" + jsonNodeTypeAccessor + " + \"(" + getID() + " expected)\");\n"); + if (instantiable()) { + + sb.append(ind(2) + "try {\n"); + sb.append(ind(3) + "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n"); + sb.append(ind(3) + "com.fasterxml.jackson.core.JsonFactory factory = mapper.getFactory();\n"); + sb.append(ind(3) + "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(file);\n"); + sb.append(ind(3) + getID() + " result = deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));\n"); + sb.append(ind(3) + "parser.close();\n"); + sb.append(ind(3) + "return result;\n"); + sb.append(ind(2) + "} catch (java.io.IOException e) {\n"); + sb.append(ind(3) + "throw new DeserializationException(\"unable to deserialize \" + file.getAbsolutePath(), e);\n"); sb.append(ind(2) + "}\n"); - } else { - sb.append(ind(2) + "element = new " + getID() + "();\n"); - } + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "public static " + getID() + " " + getID() + ".deserialize(" + jsonNodeType + " node) throws DeserializationException {\n"); + sb.append(ind(2) + getID() + " element;\n"); + if (getAbstract()) { + // switch case between all implementations of the abstract class + sb.append(ind(2) + "switch (node" + jsonNodeTypeAccessor + ") {\n"); + for (TypeDecl subType : subTypeDecls()) { + sb.append(ind(3) + "case \"" + subType.getID() + "\":\n"); + sb.append(ind(4) + "element = " + subType.getID() + ".deserialize(node);\n"); + sb.append(ind(4) + "break;\n"); + } + sb.append(ind(3) + "default:\n"); + sb.append(ind(4) + "throw new DeserializationException(\"Unable to deserialize child of unexpected type \" + node" + jsonNodeTypeAccessor + " + \"(" + getID() + " expected)\");\n"); + sb.append(ind(2) + "}\n"); + } else { + sb.append(ind(2) + "element = new " + getID() + "();\n"); + } - if (!jsonPointer && !manualReferences) { - // deserialize id - sb.append(ind(2) + "if (node.has(\"id\")) {\n"); - sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); - sb.append(ind(2) + "}\n"); - } + if (!jsonPointer && !manualReferences) { + // deserialize id + sb.append(ind(2) + "if (node.has(\"id\")) {\n"); + sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); + sb.append(ind(2) + "}\n"); + } - // deserialize containment children - if (componentsTransitive().size() > 0) { - sb.append(ind(2) + "if (node.has(\"children\")) {\n"); - sb.append(ind(3) + jsonNodeType + " children = node.get(\"children\");\n"); - for (Component component : componentsTransitive()) { - sb.append(ind(3) + "if (children.has(\"" + component.getID() + "\")) {\n"); - component.deserialize(sb, 4); - sb.append(ind(3) + "}\n"); + // deserialize containment children + if (componentsTransitive().size() > 0) { + sb.append(ind(2) + "if (node.has(\"children\")) {\n"); + sb.append(ind(3) + jsonNodeType + " children = node.get(\"children\");\n"); + for (Component component : componentsTransitive()) { + sb.append(ind(3) + "if (children.has(\"" + component.getID() + "\")) {\n"); + component.deserialize(sb, 4); + sb.append(ind(3) + "}\n"); + } + sb.append(ind(2) + "}\n"); } - sb.append(ind(2) + "}\n"); - } - // deserialize non-containment children - Set<RelationComponent> relationComponents = relationComponents(); - if (relationComponents.size() > 0) { - sb.append(ind(2) + "if (node.has(\"relations\")) {\n"); - sb.append(ind(3) + jsonNodeType + " relations = node.get(\"relations\");\n"); - for (RelationComponent component : relationComponents) { - sb.append(ind(3) + "if (relations.has(\"" + component.getID() + "\")) {\n"); - component.deserialize(sb, 4); - sb.append(ind(3) + "}\n"); + // deserialize non-containment children + Set<RelationComponent> relationComponents = relationComponents(); + if (relationComponents.size() > 0) { + sb.append(ind(2) + "if (node.has(\"relations\")) {\n"); + sb.append(ind(3) + jsonNodeType + " relations = node.get(\"relations\");\n"); + for (RelationComponent component : relationComponents) { + sb.append(ind(3) + "if (relations.has(\"" + component.getID() + "\")) {\n"); + component.deserialize(sb, 4); + sb.append(ind(3) + "}\n"); + } + sb.append(ind(2) + "}\n"); } - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return element;\n"); + sb.append(ind(2) + "return element;\n"); + } else { + sb.append(ind(2) + "throw new DeserializationException(\"Unable to deserialize type \\\"" + getID() + "\\\" because it is not instantiable.\");\n"); + } sb.append(ind(1) + "}\n"); } diff --git a/src/test/jastadd/relations/Relations.relast b/src/test/jastadd/relations/Relations.relast index 12f132e..6df99c3 100644 --- a/src/test/jastadd/relations/Relations.relast +++ b/src/test/jastadd/relations/Relations.relast @@ -62,3 +62,5 @@ G : C ::= [D] ; // line comment with special symbols like |, *, ->, <-, <->, [A], B ::= C, :, \n, \r, ~, #, /A/ /* block comment with special symbols like |, *, ->, <-, <->, [A], B ::= C, :, \n, \r, ~, #, /A/ */ + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/resolver/Resolver.relast b/src/test/jastadd/resolver/Resolver.relast index 5cbaecf..b5c34e0 100644 --- a/src/test/jastadd/resolver/Resolver.relast +++ b/src/test/jastadd/resolver/Resolver.relast @@ -21,3 +21,5 @@ rel A.Bi6? <-> B.Bi6*; rel A.Bi7* <-> B.Bi7; rel A.Bi8* <-> B.Bi8?; rel A.Bi9* <-> B.Bi9*; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/resolver2/Resolver.relast b/src/test/jastadd/resolver2/Resolver.relast index 93a5201..c51e717 100644 --- a/src/test/jastadd/resolver2/Resolver.relast +++ b/src/test/jastadd/resolver2/Resolver.relast @@ -21,3 +21,5 @@ rel A.Bi6l? <-> B.Bi6*; rel A.Bi7l* <-> B.Bi7; rel A.Bi8l* <-> B.Bi8?; rel A.Bi9l* <-> B.Bi9*; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/serializer-manual-relative/Serializer.relast b/src/test/jastadd/serializer-manual-relative/Serializer.relast index 0e850a7..f6928d1 100644 --- a/src/test/jastadd/serializer-manual-relative/Serializer.relast +++ b/src/test/jastadd/serializer-manual-relative/Serializer.relast @@ -21,3 +21,5 @@ rel A.Bi6? <-> B.Bi6*; rel A.Bi9* <-> B.Bi9*; rel Root.D <-> D.Root?; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/serializer-manual/Serializer.relast b/src/test/jastadd/serializer-manual/Serializer.relast index 0e850a7..f6928d1 100644 --- a/src/test/jastadd/serializer-manual/Serializer.relast +++ b/src/test/jastadd/serializer-manual/Serializer.relast @@ -21,3 +21,5 @@ rel A.Bi6? <-> B.Bi6*; rel A.Bi9* <-> B.Bi9*; rel Root.D <-> D.Root?; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/serializer-names/Serializer.relast b/src/test/jastadd/serializer-names/Serializer.relast index 9106765..aa7e099 100644 --- a/src/test/jastadd/serializer-names/Serializer.relast +++ b/src/test/jastadd/serializer-names/Serializer.relast @@ -32,3 +32,5 @@ rel A.Bi5? <-> B.Bi5?; rel A.Bi6? <-> B.Bi6*; rel A.Bi9* <-> B.Bi9*; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/serializer-pointer/Serializer.relast b/src/test/jastadd/serializer-pointer/Serializer.relast index 0e850a7..f6928d1 100644 --- a/src/test/jastadd/serializer-pointer/Serializer.relast +++ b/src/test/jastadd/serializer-pointer/Serializer.relast @@ -21,3 +21,5 @@ rel A.Bi6? <-> B.Bi6*; rel A.Bi9* <-> B.Bi9*; rel Root.D <-> D.Root?; + +abstract Uninstantiable:A; diff --git a/src/test/jastadd/serializer/Serializer.relast b/src/test/jastadd/serializer/Serializer.relast index 9106765..aa7e099 100644 --- a/src/test/jastadd/serializer/Serializer.relast +++ b/src/test/jastadd/serializer/Serializer.relast @@ -32,3 +32,5 @@ rel A.Bi5? <-> B.Bi5?; rel A.Bi6? <-> B.Bi6*; rel A.Bi9* <-> B.Bi9*; + +abstract Uninstantiable:A; -- GitLab