diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag index 21456331346ac897ee8f597c52e93c1ac8edb498..41572756a45d2c14eb763e280075d3c2b03d256d 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 9b47dc1cee3a14f4ad114c8028b0f446392ad064..8080fa0450cc08da31eca31222144a78199a25b7 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 21db37f69f93f2c852528ab334245ce5f3e3d9e0..ac811f1598a2fd0578ae3618c2510e27190cb09a 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 12f132e5e58968baff38120d79fde1090151acf8..6df99c3d62d07071dd97599555de011de752a4a4 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 5cbaecfeda6d8445cd880245733847721ef4b8b9..b5c34e0716682dcb212c706aee6db82b919dca57 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 93a52019c56ee00c4a7af797a3d806f9d80da4ee..c51e717e56e0e0ac0f6eeabbd1646b492c254c73 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 0e850a74f81791809b4a80e40be4e4a329d69abb..f6928d1293b2299f1f09914b330163ecc9152e56 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 0e850a74f81791809b4a80e40be4e4a329d69abb..f6928d1293b2299f1f09914b330163ecc9152e56 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 9106765c6ee6b8016de898c75efa2f3c38903050..aa7e099caa1aeaf7756854995cf9544a51e91b89 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 0e850a74f81791809b4a80e40be4e4a329d69abb..f6928d1293b2299f1f09914b330163ecc9152e56 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 9106765c6ee6b8016de898c75efa2f3c38903050..aa7e099caa1aeaf7756854995cf9544a51e91b89 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;