diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b6bf4858b97068488b069297326a1ec70aeaa19b..dfad4ae3915b8a1254351676aaf3cf62a292f138 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,43 +1,18 @@ stages: - build - test -- jar build: image: openjdk:8 stage: build script: - - ./gradlew --console=plain --build-cache assemble - cache: - key: "$CI_COMMIT_REF_NAME" - policy: push + - ./gradlew --console=plain assemble jar + artifacts: paths: - - build - - .gradle + - "/builds/jastadd/relational-rags/build/libs/relast-*.jar" test: image: openjdk:8 stage: test script: - - ./gradlew --continue --console=plain --info check - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - build - - .gradle - -jar: - image: openjdk:8 - stage: jar - script: - - ./gradlew --continue --console=plain --info jar - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - build - - .gradle - artifacts: - paths: - - "/builds/jastadd/*/build/libs/*relast*.jar" + - ./gradlew --console=plain --info test diff --git a/README.md b/README.md index da4ab0d84628e3cf7f193d23e55f6e0a5350ace5..b49c377f9290f661896b992cc1d363d9334d0053 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -[](/../pipelines) - -# RelAST Preprocessor Version 0.2.4 +# RelAST Preprocessor  +See [releases page](/../../releases) for the latest version. + The RelAST preprocessor takes a `.relast` file as input comprising AST rules and relations. It produces files that afterwards are processed by JastAdd to generated Java code. To use it in your project, build the JAR file running diff --git a/build.gradle b/build.gradle index 068c1f63ec3bc3e4f09a87e14198f696307c1bf9..58840b2af00e93024da6e17fd940b68c202997ad 100644 --- a/build.gradle +++ b/build.gradle @@ -74,6 +74,8 @@ jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + + archiveBaseName = 'relast' } jastadd { 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/main/resources/RelASTVersion.properties b/src/main/resources/RelASTVersion.properties index 303d3960d73d851da19fa2207d452846829cae3e..909fca73c343468a25475a043d5e03ca356550cf 100644 --- a/src/main/resources/RelASTVersion.properties +++ b/src/main/resources/RelASTVersion.properties @@ -1,2 +1,2 @@ -#Thu Jan 16 09:42:49 CET 2020 -version=0.2.4-28-g22c4762 +#Thu Apr 16 11:22:48 CEST 2020 +version=0.3.0 diff --git a/src/test/jastadd/relations/Relations.relast b/src/test/jastadd/relations/Relations.relast index b519a442e963f8fbdd184cec3b006a67e8228f68..cccea4744ba0eb7904e04e1803cfb64c064797d2 100644 --- a/src/test/jastadd/relations/Relations.relast +++ b/src/test/jastadd/relations/Relations.relast @@ -63,3 +63,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;