diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d3399cf3b1ba870b9d5c54978254134113d1d1b1..48ac46a416713cdf46c48e1286a73b8285529126 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -44,8 +44,8 @@ publish_dev: script: - "./gradlew setDevVersionForCI" - "./gradlew publish" - except: - - main + only: + - dev publish_main: image: openjdk:11 @@ -60,7 +60,6 @@ publish_main: ragdoc_build: image: name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder" - entrypoint: [""] stage: ragdoc needs: - build @@ -68,6 +67,9 @@ ragdoc_build: - JAVA_FILES=$(find dumpAst.base/src/ -name '*.java') - echo $JAVA_FILES | wc -l - /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES + only: + - dev + - main artifacts: paths: - "data/" @@ -75,7 +77,6 @@ ragdoc_build: ragdoc_view: image: name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations" - entrypoint: [""] stage: ragdoc needs: - ragdoc_build @@ -84,7 +85,7 @@ ragdoc_view: - mkdir -p pages/docs/ragdoc - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR - - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR + - BASE_HREF=/dumpAst/ragdoc/ /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR only: - dev - main @@ -92,7 +93,7 @@ ragdoc_view: paths: - "pages/docs/ragdoc" -pages: +build_pages: image: python:3.10.0-bullseye stage: publish needs: @@ -105,5 +106,14 @@ pages: artifacts: paths: - public/ - only: - - main + +pages: + stage: publish + needs: + - build_pages + script: [ "true" ] + artifacts: + paths: + - public + rules: + - if: '$CI_COMMIT_BRANCH == "main"' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80ee387db7b9df0b0b18117b75678097761d8513 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, TU Dresden, Software Technology Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dumpAst.base/build.gradle b/dumpAst.base/build.gradle index 96fd0c021d8d68a9b5cb57b7c433a157a6896a29..88ccfde78f90ad7ccb280fab03e417a534ccced3 100644 --- a/dumpAst.base/build.gradle +++ b/dumpAst.base/build.gradle @@ -147,7 +147,7 @@ task newVersion() { task setDevVersionForCI() { doFirst { def props = new Properties() - props['version'] = version + "-$System.env.CI_PIPELINE_IID" + props['version'] = version + "-dev-$System.env.CI_PIPELINE_IID" props.store(file(versionFile).newWriter(), null) } } @@ -179,6 +179,15 @@ publishing { } } +// --- Misc --- +task ensureNoTrainlingNewlineForRelationStyleMustache() { + doFirst { + def text = project.file("src/main/resources/RelationStyle.mustache").text + project.file("src/main/resources/RelationStyle.mustache").write(text.strip()) + } +} + // --- Task order --- +compileJava.dependsOn ensureNoTrainlingNewlineForRelationStyleMustache generateAst.dependsOn relast publish.dependsOn jar diff --git a/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag b/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag index fdd6052df4fc03bb14e50d12eb11c36ec37d5f43..6558bc1eeb13ad3f63c0413ff0e212ea0d8bd635 100644 --- a/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag +++ b/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag @@ -48,29 +48,28 @@ aspect ClassAnalysis { String tokenName = invokeName(annotation); if (tokenName.startsWith("_impl_")) { String relationName = titleCase(tokenName.substring(6)); - try { - java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName); + if (present(getMethod(clazz, "get" + relationName), relationMethod -> { // normal get + token-name -> singleRelation - SingleRelationMethod singleRelationMethod = new SingleRelationMethod(); + SingleRelationMethod singleRelationMethod = getMethod(clazz, "has" + relationName).isPresent() ? + new OptRelationMethod() : new SingleRelationMethod(); singleRelationMethod.setMethod(relationMethod); singleRelationMethod.setName(relationName); result.addOtherMethod(singleRelationMethod); + })) { continue; - } catch (NoSuchMethodException e) { - // ignore, but we know this is probably not a single relation } + // we know here this is probably not a single or opt relation // try list-relation next - try { - java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName + "List"); + if (present(getMethod(clazz, "get" + relationName + "List"), relationMethod -> { // normal get + token-name + "List" -> listRelation ListRelationMethod listRelationMethod = new ListRelationMethod(); listRelationMethod.setMethod(relationMethod); listRelationMethod.setName(relationName); result.addOtherMethod(listRelationMethod); + })) { continue; - } catch (NoSuchMethodException e) { - // ignore, but we know this is probably not a relation at all } + // we know here this is probably not a relation at all } IntrinsicTokenMethod tokenMethod = new IntrinsicTokenMethod(); tokenMethod.setMethod(method); @@ -201,6 +200,20 @@ aspect ClassAnalysis { } } + private static java.util.Optional<java.lang.reflect.Method> DumpAst.getMethod(Class<?> clazz, String methodName) { + try { + java.lang.reflect.Method method = clazz.getMethod(methodName); + return java.util.Optional.of(method); + } catch (NoSuchMethodException e) { + return java.util.Optional.empty(); + } + } + + private static <T> boolean DumpAst.present(java.util.Optional<T> optional, java.util.function.Consumer<T> callback) { + optional.ifPresent(callback); + return optional.isPresent(); + } + // --- astNodeAnnotationPrefix --- syn String DumpAst.astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation"; inh String DumpNode.astNodeAnnotationPrefix(); diff --git a/dumpAst.base/src/main/jastadd/DumpAst.relast b/dumpAst.base/src/main/jastadd/DumpAst.relast index fcfd923c0e47bc6648f3e397ecaa99b5ff1007a7..572b8b95a027c1f73e8503d4d39b2c45ad0b1276 100644 --- a/dumpAst.base/src/main/jastadd/DumpAst.relast +++ b/dumpAst.base/src/main/jastadd/DumpAst.relast @@ -5,26 +5,26 @@ DumpNode ::= DumpChildNode* DumpToken* DumpRelation* <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> <Computed:boolean> <ManualStereotypes> /InvisiblePath/ ; -InnerDumpNode ; -rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ; -InnerRelationDumpNode; -rel InnerRelationDumpNode.DumpNode -> DumpNode ; // .ContainerOfInner* +InnerDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; //TODO remove colors (and label?) +rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner? ; +InnerRelationDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; //TODO remove colors (and label?) +rel InnerRelationDumpNode.DumpNode <-> DumpNode.ContainerOfRelationInner* ; -abstract DumpChildNode ::= <Name> <Computed:boolean> ; -DumpNormalChildNode : DumpChildNode ; -rel DumpNormalChildNode.DumpNode <-> DumpNode.ContainerOfNormalChild ; -DumpListChildNode : DumpChildNode ::= InnerDumpNode* ; +abstract DumpChildNode ::= <Label> <Computed:boolean> <LineColor> <TextColor> ; +DumpNormalChildNode : DumpChildNode ::= ; +rel DumpNormalChildNode.DumpNode <-> DumpNode.ContainerOfNormalChild? ; +DumpListChildNode : DumpChildNode ::= InnerDumpNode* <Name> ; -abstract DumpToken ::= <Name> <Computed:boolean> ; -DumpReferenceToken : DumpToken ; -rel DumpReferenceToken.Value -> DumpNode ; -DumpReferenceListToken : DumpToken ::= InnerRelationDumpNode* ; +abstract DumpToken ::= <Label> <Computed:boolean> ; +DumpReferenceToken : DumpToken ::= <LineColor> <TextColor> ; +rel DumpReferenceToken.DumpNode -> DumpNode ; +DumpReferenceListToken : DumpToken ::= InnerRelationDumpNode* <Name> <LineColor> <TextColor> ; DumpValueToken : DumpToken ::= <Value:Object> ; -abstract DumpRelation ::= <Name> <Bidirectional:boolean> ; -DumpNormalRelation : DumpRelation ; +abstract DumpRelation ::= <Label> <Bidirectional:boolean> <LineColor> <TextColor> ; +DumpNormalRelation : DumpRelation ::= ; rel DumpNormalRelation.DumpNode -> DumpNode ; -DumpListRelation : DumpRelation ::= InnerRelationDumpNode* ; +DumpListRelation : DumpRelation ::= InnerRelationDumpNode* <Name> ; // type of NTA InvisiblePath ::= InnerRelationDumpNode* ; @@ -45,6 +45,7 @@ NormalListChildMethod : ListChildMethod ; NTAListChildMethod : ListChildMethod ; SingleRelationMethod : AnalysedMethod ; +OptRelationMethod : SingleRelationMethod ; ListRelationMethod : AnalysedMethod ; // TODO can the refine bug also happen for refined attributes? @@ -53,9 +54,6 @@ IntrinsicTokenMethod : TokenMethod ::= <Refined:boolean> ; AttributeMethod : TokenMethod ; BuildConfig ::= StyleInformation - GlobalPatternCollection:PatternCollection - ExcludeTypePattern:TypePatternCollectionMapping* - IncludeTypePattern:TypePatternCollectionMapping* <IncludeRelationMethod:IncludeRelationMethod> <IncludeChildMethod:IncludeChildMethod> <IncludeAttributeMethod:IncludeAttributeMethod> @@ -64,13 +62,16 @@ BuildConfig ::= StyleInformation <IncludeEmptyString:boolean> <ExcludeNullNodes:boolean> <Debug:boolean>; -TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ; -PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ; -StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod> <StereotypeMethod:StyleMethod> <ComputedColor>; +StyleInformation ::= <ComputedColor>; PrintConfig ::= Header* <Scale:double> <Version> <RelationWithRank:boolean> - <OrderChildren:boolean> ; + <OrderChildren:boolean> + <NodeStyleDefinition:NodeStyleDefinition> + <RelationStyleDefinition:RelationStyleDefinition>; Header ::= <Value> ; + +NodeStyle ::= <Label> <BackgroundColor> <TextColor> <StereoTypes> ; +RelationStyle ::= <Label> <LineColor> <TextColor> ; diff --git a/dumpAst.base/src/main/jastadd/Frontend.jrag b/dumpAst.base/src/main/jastadd/Frontend.jrag index f5bf7c2fa2034bffb1b8a35c347abbc7eca1cc9b..eaaf02de2cef1576494e311800f539f2e5cc541e 100644 --- a/dumpAst.base/src/main/jastadd/Frontend.jrag +++ b/dumpAst.base/src/main/jastadd/Frontend.jrag @@ -1,36 +1,27 @@ aspect Frontend { - - // --- match{In,Ex}cludePatternCollection --- - syn PatternCollection BuildConfig.matchIncludePatternCollection(String typeName) { - for (TypePatternCollectionMapping mapping : getIncludeTypePatternList()) { - if (matches(mapping.typePattern(), typeName)) { - return mapping.getPatternCollection(); - } - } - return null; - } - syn PatternCollection BuildConfig.matchExcludePatternCollection(String typeName) { - for (TypePatternCollectionMapping mapping : getExcludeTypePatternList()) { - if (matches(mapping.typePattern(), typeName)) { - return mapping.getPatternCollection(); - } - } - return null; - } - static StyleInformation StyleInformation.createDefault() { StyleInformation result = new StyleInformation(); - result.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode())); - result.setBackgroundColorMethod(n -> ""); - result.setTextColorMethod(n -> ""); - result.setStereotypeMethod(n -> ""); result.setComputedColor("blue"); return result; } @FunctionalInterface - public interface StyleMethod<ASTNODE> { - String get(ASTNODE node); + public interface NodeStyleDefinition<ASTNODE> { + void style(ASTNODE node, NodeStyle style); + } + + @FunctionalInterface + public interface RelationStyleDefinition<ASTNODE> { + void style(ASTNODE source, ASTNODE target, boolean isComputed, boolean isContainment, RelationStyle style); + } + + public void NodeStyle.useSimpleLabel() { + setLabel(node.getObject() == null ? "null" : node.getObject().getClass().getSimpleName()); + } + + public void NodeStyle.useSimpleLabelWithHashCode() { + setLabel(node.getObject() == null ? "null" : + node.getObject().getClass().getSimpleName() + "@" + Integer.toHexString(node.getObject().hashCode())); } @FunctionalInterface diff --git a/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag index 4ef4b469c69254a667aa3449d9735b6a4a254bc6..c7ab0047767b4b12ff2598edce03d3809573028c 100644 --- a/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag +++ b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag @@ -36,6 +36,12 @@ aspect Navigation { syn boolean AnalysedMethod.isSingleRelationMethod() = false; eq SingleRelationMethod.isSingleRelationMethod() = true; + /** Tests if SingleRelationMethod is a OptRelationMethod. + * @return 'true' if this is a OptRelationMethod, otherwise 'false' + */ + syn boolean SingleRelationMethod.isOptRelationMethod() = false; + eq OptRelationMethod.isOptRelationMethod() = true; + /** Tests if AnalysedMethod is a ListRelationMethod. * @return 'true' if this is a ListRelationMethod, otherwise 'false' */ @@ -102,6 +108,12 @@ aspect Navigation { syn boolean DumpToken.isDumpReferenceToken() = false; eq DumpReferenceToken.isDumpReferenceToken() = true; + /** Tests if DumpToken is a DumpReferenceListToken. + * @return 'true' if this is a DumpReferenceListToken, otherwise 'false' + */ + syn boolean DumpToken.isDumpReferenceListToken() = false; + eq DumpReferenceListToken.isDumpReferenceListToken() = true; + /** Tests if DumpToken is a DumpValueToken. * @return 'true' if this is a DumpValueToken, otherwise 'false' */ @@ -227,6 +239,13 @@ aspect Navigation { eq DumpToken.asDumpReferenceToken() = null; eq DumpReferenceToken.asDumpReferenceToken() = this; + /** casts a DumpToken into a DumpReferenceListToken if possible. + * @return 'this' cast to a DumpReferenceListToken or 'null' + */ + syn DumpReferenceListToken DumpToken.asDumpReferenceListToken(); + eq DumpToken.asDumpReferenceListToken() = null; + eq DumpReferenceListToken.asDumpReferenceListToken() = this; + /** casts a DumpToken into a DumpValueToken if possible. * @return 'this' cast to a DumpValueToken or 'null' */ diff --git a/dumpAst.base/src/main/jastadd/Navigation.jrag b/dumpAst.base/src/main/jastadd/Navigation.jrag index dc4ce9a3e857777d7305d07f48a436fb18c0bfc7..2bdae26788a81b697f720568b055d736d458b4a6 100644 --- a/dumpAst.base/src/main/jastadd/Navigation.jrag +++ b/dumpAst.base/src/main/jastadd/Navigation.jrag @@ -10,6 +10,11 @@ aspect Navigation { // --- buildConfig --- inh BuildConfig DumpNode.buildConfig(); inh BuildConfig PrintConfig.buildConfig(); + inh BuildConfig InnerDumpNode.buildConfig(); + inh BuildConfig InnerRelationDumpNode.buildConfig(); + inh BuildConfig DumpChildNode.buildConfig(); + inh BuildConfig DumpRelation.buildConfig(); + inh BuildConfig DumpToken.buildConfig(); eq DumpAst.getChild().buildConfig() = getBuildConfig(); // --- printConfig --- @@ -25,11 +30,23 @@ aspect Navigation { inh DumpNode InnerRelationDumpNode.containingDumpNode(); inh DumpNode DumpChildNode.containingDumpNode(); inh DumpNode DumpRelation.containingDumpNode(); + inh DumpNode DumpReferenceToken.containingDumpNode(); + inh DumpNode DumpReferenceListToken.containingDumpNode(); eq DumpNode.getDumpChildNode().containingDumpNode() = this; eq DumpNode.getDumpRelation().containingDumpNode() = this; eq DumpNode.getDumpToken().containingDumpNode() = this; eq DumpNode.getInvisiblePath().containingDumpNode() = this; + // --- containingDumpListChildNode --- + inh DumpListChildNode InnerDumpNode.containingDumpListChildNode(); + eq DumpListChildNode.getInnerDumpNode().containingDumpListChildNode() = this; + + // --- containingDumpListRelation --- + inh DumpListRelation InnerRelationDumpNode.containingDumpListRelation(); + eq DumpListRelation.getInnerRelationDumpNode().containingDumpListRelation() = this; + eq DumpReferenceListToken.getInnerRelationDumpNode().containingDumpListRelation() = null; + eq InvisiblePath.getInnerRelationDumpNode().containingDumpListRelation() = null; + // --- container --- syn DumpNode DumpNode.container() { if (getContainerOfNormalChild() != null) { @@ -85,10 +102,10 @@ aspect Navigation { return result; } - // --- innerNotNull --- - syn boolean DumpNormalRelation.innerNotNull() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null; - syn boolean DumpReferenceToken.innerNotNull() = !printConfig().getRelationWithRank() && getValue() != null && getValue().getObject() != null; - syn boolean InnerRelationDumpNode.innerNotNull() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null; + // --- innerNotNullOrEmpty --- + syn boolean DumpNormalRelation.innerNotNullOrEmpty() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null && getDumpNode().getObject() != DumpAst.EMPTY; + syn boolean DumpReferenceToken.innerNotNullOrEmpty() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null && getDumpNode().getObject() != DumpAst.EMPTY; + syn boolean InnerRelationDumpNode.innerNotNullOrEmpty() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null && getDumpNode().getObject() != DumpAst.EMPTY; // === Method naviagtion === coll java.util.List<SingleChildMethod> ClassAnalysisResult.singleChildMethods() [new java.util.ArrayList<>()] root ClassAnalysisResult; diff --git a/dumpAst.base/src/main/jastadd/Printing.jrag b/dumpAst.base/src/main/jastadd/Printing.jrag index f42e6fabd2035376057f4655ce36674261d27376..5b0c51589e911873d9b87ff45bc763a829b61773 100644 --- a/dumpAst.base/src/main/jastadd/Printing.jrag +++ b/dumpAst.base/src/main/jastadd/Printing.jrag @@ -1,43 +1,6 @@ aspect Printing { - // --- outerNodeName --- - inh String InnerDumpNode.outerNodeName(); - inh String InnerRelationDumpNode.outerNodeName(); - inh String DumpChildNode.outerNodeName(); - inh String DumpRelation.outerNodeName(); - inh String DumpToken.outerNodeName(); - inh String DumpReferenceToken.outerNodeName(); - eq DumpNode.getChild().outerNodeName() = name(); - - // --- innerNodeName --- - syn String InnerDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; - syn String InnerRelationDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; - syn String DumpNormalChildNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; - syn String DumpNormalRelation.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; - syn String DumpReferenceToken.innerNodeName() = getValue().name(); - // --- name --- syn String DumpNode.name() = getName(); // might change in the future - - // --- label --- - syn String DumpChildNode.label() = getName() + (getComputed() ? "()" : ""); - syn String DumpRelation.label() = getName(); - syn String DumpToken.label() = getName() + (getComputed() ? "()" : ""); - syn String DumpNode.label() = getLabel(); - inh String InnerDumpNode.label(); - inh String InnerRelationDumpNode.label(); - eq DumpListChildNode.getInnerDumpNode(int index).label() = label() + "[" + index + "]"; - eq DumpListRelation.getInnerRelationDumpNode(int index).label() = label() + "[" + index + "]"; - eq DumpReferenceListToken.getInnerRelationDumpNode(int index).label() = label() + "[" + index + "]"; - eq InvisiblePath.getInnerRelationDumpNode(int index).label() = null; - - // --- bothVisible --- - boolean ASTNode.bothVisible(DumpNode one, DumpNode two) { - return one != null && two != null && !one.getInvisible() && !two.getInvisible(); - } - syn boolean InnerDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); - syn boolean InnerRelationDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); - syn boolean DumpNormalChildNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); - syn boolean DumpNormalRelation.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); } aspect Debugging { diff --git a/dumpAst.base/src/main/jastadd/TemplateContext.jrag b/dumpAst.base/src/main/jastadd/TemplateContext.jrag index e8d5549ccd5722276c53c6063ee381610e9f57c3..f7c0941d1442df026fc174fd892d7b699b829026 100644 --- a/dumpAst.base/src/main/jastadd/TemplateContext.jrag +++ b/dumpAst.base/src/main/jastadd/TemplateContext.jrag @@ -8,6 +8,11 @@ aspect TemplateContext { return getObject() == null; } + // --- isEmpty --- + syn boolean DumpNode.isEmpty() { + return getObject() == DumpAst.EMPTY; + } + // --- isAstNode --- syn boolean DumpNode.isAstNode() { if (getObject() == null) { @@ -22,11 +27,63 @@ aspect TemplateContext { return false; } + // --- outerNodeName --- + inh String InnerDumpNode.outerNodeName(); + inh String InnerRelationDumpNode.outerNodeName(); + inh String DumpChildNode.outerNodeName(); + inh String DumpRelation.outerNodeName(); + inh String DumpToken.outerNodeName(); + inh String DumpReferenceToken.outerNodeName(); + eq DumpNode.getChild().outerNodeName() = name(); + + // --- innerNodeName --- + syn String InnerDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; + syn String InnerRelationDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; + syn String DumpNormalChildNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; + syn String DumpNormalRelation.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null; + syn String DumpReferenceToken.innerNodeName() = getDumpNode().name(); + + // --- label --- + syn String DumpChildNode.label() = safeLabel(getLabel() + (getComputed() ? "()" : "")); + syn String DumpRelation.label() = safeLabel(getLabel()); + syn String DumpToken.label() = safeLabel(getLabel() + (getComputed() ? "()" : "")); + syn String DumpNode.label() = safeLabel(getLabel()); + inh String InnerDumpNode.label(); + inh String InnerRelationDumpNode.label(); + eq DumpListChildNode.getInnerDumpNode(int index).label() { + InnerDumpNode inner = getInnerDumpNode(index); + return safeLabel( + (inner.getDumpNode().isEmpty() ? "" : "[" + chooseIndex(inner.getOriginalIndex(), index) + "]")); + } + eq DumpListRelation.getInnerRelationDumpNode(int index).label() { + InnerRelationDumpNode inner = getInnerRelationDumpNode(index); + return safeLabel(inner.getLabel() + + (inner.getDumpNode().isEmpty() ? "" : "[" + chooseIndex(inner.getOriginalIndex(), index) + "]")); + } + eq DumpReferenceListToken.getInnerRelationDumpNode(int index).label() = "[" + index + "]"; + eq InvisiblePath.getInnerRelationDumpNode(int index).label() = null; + protected int ASTNode.chooseIndex(int originalIndex, int inheritedIndex) { + return originalIndex != 0 ? originalIndex : inheritedIndex; + } + + static String ASTNode.safeLabel(String s) { + return s.isEmpty() ? " " : s; + } + + // --- bothVisible --- + boolean ASTNode.bothVisible(DumpNode one, DumpNode two) { + return one != null && two != null && !one.getInvisible() && !two.getInvisible(); + } + syn boolean InnerDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + syn boolean InnerRelationDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + syn boolean DumpNormalChildNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + syn boolean DumpNormalRelation.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + // --- NTA: InvisiblePath --- syn InvisiblePath DumpNode.getInvisiblePath() { InvisiblePath result = new InvisiblePath(); for (DumpNode successor : reachableThroughInvisible()) { - result.addInnerRelationDumpNode(new InnerRelationDumpNode(successor)); + result.addInnerRelationDumpNode(new InnerRelationDumpNode().setDumpNode(successor)); } return result; } @@ -49,9 +106,9 @@ aspect TemplateContext { // --- labelAndTextColor --- syn String DumpNode.labelAndTextColor() { if (getTextColor().isEmpty()) { - return getLabel(); + return label(); } else { - return "<color:" + getTextColor() + ">" + getLabel() + "</color>"; + return "<color:" + getTextColor() + ">" + label() + "</color>"; } } diff --git a/dumpAst.base/src/main/jastadd/ToYaml.jrag b/dumpAst.base/src/main/jastadd/ToYaml.jrag index 0df35a8701bd1a8b4d5b93ab04d47a327ce21436..82fd9ab239bfa90fc8bdddb8d9685a452fd56032 100644 --- a/dumpAst.base/src/main/jastadd/ToYaml.jrag +++ b/dumpAst.base/src/main/jastadd/ToYaml.jrag @@ -32,9 +32,9 @@ aspect ToYaml { addYamledList(result, "Headers", getHeaderList(), fromRelation); // tokens - result.put("scale", getScale()); - result.put("version", getVersion()); - result.put("orderChildren", getOrderChildren()); + result.put("OrderChildren", getOrderChildren()); + result.put("Scale", getScale()); + result.put("Version", getVersion()); // attributes result.put("debug", debug()); @@ -44,7 +44,7 @@ aspect ToYaml { syn MappingElement Header.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); // tokens - result.put("value", getValue()); + result.put("Value", getValue()); return result; } @@ -59,19 +59,19 @@ aspect ToYaml { } // tokens - result.put("name", getName()); + result.put("Name", getName()); if (!fromRelation) { - result.put("computed", getComputed()); - result.put("label", getLabel()); - result.put("backgroundColor", getBackgroundColor()); - result.put("textColor", getTextColor()); - result.put("invisible", getInvisible()); + result.put("BackgroundColor", getBackgroundColor()); + result.put("Invisible", getInvisible()); + result.put("TextColor", getTextColor()); } // attributes if (!fromRelation) { result.put("isNull", isNull()); + result.put("isEmpty", isEmpty()); result.put("isAstNode", isAstNode()); + result.put("label", label()); result.put("labelAndTextColor", labelAndTextColor()); result.put("stereotypeList", stereotypeList()); addYamledList(result, "myChildren", myChildren(), true); @@ -88,12 +88,15 @@ aspect ToYaml { syn MappingElement DumpChildNode.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); + // tokens - result.put("name", getName()); - result.put("computed", getComputed()); + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // attributes - result.put("label", label()); result.put("isList", isList()); + result.put("label", label()); + result.put("needRelationStyling", needRelationStyling()); result.put("outerNodeName", outerNodeName()); return result; @@ -101,6 +104,7 @@ aspect ToYaml { syn MappingElement DumpNormalChildNode.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); @@ -109,6 +113,10 @@ aspect ToYaml { syn MappingElement DumpListChildNode.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + + // tokens + result.put("Name", getName()); + // children addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation); return result; @@ -116,28 +124,33 @@ aspect ToYaml { syn MappingElement DumpToken.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); - // tokens - result.put("name", getName()); - result.put("computed", getComputed()); + // attributes + result.put("isDumpValueToken", isDumpValueToken()); result.put("isList", isList()); result.put("label", label()); - result.put("isDumpValueToken", isDumpValueToken()); return result; } syn MappingElement DumpValueToken.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + // tokens - result.put("value", getValue().toString()); + result.put("Value", getValue().toString()); return result; } syn MappingElement DumpReferenceToken.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + + // tokens + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // attributes result.put("innerNodeName", innerNodeName()); - result.put("innerNotNull", innerNotNull()); + result.put("innerNotNullOrEmpty", innerNotNullOrEmpty()); + result.put("needRelationStyling", needRelationStyling()); result.put("outerNodeName", outerNodeName()); return result; } @@ -145,37 +158,52 @@ aspect ToYaml { syn MappingElement DumpReferenceListToken.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + // tokens + result.put("Name", getName()); + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // children addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation); // attributes + result.put("needRelationStyling", needRelationStyling()); result.put("outerNodeName", outerNodeName()); return result; } syn MappingElement DumpRelation.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); + // tokens - result.put("name", getName()); - result.put("bidirectional", getBidirectional()); + result.put("Bidirectional", getBidirectional()); + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // attributes result.put("isList", isList()); result.put("label", label()); + result.put("needRelationStyling", needRelationStyling()); result.put("outerNodeName", outerNodeName()); return result; } syn MappingElement DumpNormalRelation.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); - result.put("innerNotNull", innerNotNull()); + result.put("innerNotNullOrEmpty", innerNotNullOrEmpty()); return result; } syn MappingElement DumpListRelation.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + + // tokens + result.put("Name", getName()); + // children addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation); return result; @@ -183,27 +211,40 @@ aspect ToYaml { syn MappingElement InnerDumpNode.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); + + // tokens + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); - result.put("outerNodeName", outerNodeName()); result.put("label", label()); + result.put("needRelationStyling", needRelationStyling()); + result.put("outerNodeName", outerNodeName()); return result; } syn MappingElement InnerRelationDumpNode.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); + + // tokens + result.put("LineColor", getLineColor()); + result.put("TextColor", getTextColor()); + // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); - result.put("innerNotNull", innerNotNull()); - result.put("outerNodeName", outerNodeName()); + result.put("innerNotNullOrEmpty", innerNotNullOrEmpty()); result.put("label", label()); + result.put("needRelationStyling", needRelationStyling()); + result.put("outerNodeName", outerNodeName()); return result; } syn MappingElement InvisiblePath.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); + // children addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation); return result; @@ -237,7 +278,7 @@ aspect ToYaml { if (value == null || value.equals("null")) { return StringElement.of("null"); } - if (value.isEmpty()) { + if (value.isBlank()) { return StringElement.of(value); } return containsAny(value, ",#[{\"\n") ? diff --git a/dumpAst.base/src/main/jastadd/Transform.jadd b/dumpAst.base/src/main/jastadd/Transform.jadd index 747a59b1a71a04a008a36c8f5a5b8b054b8a8e65..eecc08257996d858cc3c1efdffa7ed843aeb9ffc 100644 --- a/dumpAst.base/src/main/jastadd/Transform.jadd +++ b/dumpAst.base/src/main/jastadd/Transform.jadd @@ -53,6 +53,8 @@ aspect Transform { return new TransformationOptions(Source.NORMAL, false, false); } + public static final Object DumpAst.EMPTY = new Object(); + // --- transform --- (need to be a method, because it alters the AST while traversing the object structure) protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj) throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { @@ -81,7 +83,7 @@ aspect Transform { } DumpNode node; String objClassName; - if (obj == null) { + if (obj == null || obj == EMPTY) { node = null; objClassName = "null"; } else { @@ -97,7 +99,7 @@ aspect Transform { } else { node = new DumpNode(); node.setObject(obj); - node.setName("node" + (tti.nodeCounter++)); + node.setName(tti.nextName()); node.setComputed(options.computed); tti.transformed.put(obj, node); this.addDumpNode(node); @@ -114,8 +116,8 @@ aspect Transform { if (options.invisible || !isTypeEnabled(objClassName)) { node.setInvisible(true); } - if (obj == null) { - // for a null object, we do not need any further analysis + if (obj == null || obj == EMPTY) { + // for a null or empty object, we do not need any further analysis return node; } final ClassAnalysisResult car = analyzeClass(obj.getClass()); @@ -124,178 +126,261 @@ aspect Transform { } for (AnalysedMethod containmentMethod : car.getContainmentMethodList()) { if (containmentMethod.isSingleChildMethod() || containmentMethod.isOptChildMethod()) { - // -- singleChild or optChild -- - Object target; - if (containmentMethod.isOptChildMethod() && !((boolean) containmentMethod.asOptChildMethod().getCheckMethod().invoke(obj))) { - if (getBuildConfig().getExcludeNullNodes()) { - continue; - //target = containmentMethod.getMethod().invoke(obj); - } else { - target = null; - } - } else { - target = containmentMethod.getMethod().invoke(obj); - } - String childName = containmentMethod.getName(); - if (!getBuildConfig().getIncludeChildMethod().shouldInclude(obj, target, childName)) { - continue; - } - DumpNode targetNode = transform(tti, target, options.asNormal(false).allowNullObjectsOnce()); - if (targetNode != null) { - DumpNormalChildNode normalChild = new DumpNormalChildNode(); - normalChild.setName(childName); - normalChild.setDumpNode(targetNode); - normalChild.setComputed(false); - node.addDumpChildNode(normalChild); - } + handleContainmentSingleOrOptChild(node, containmentMethod, obj, tti, options); } else if (containmentMethod.isListChildMethod()) { - // -- listChild -- - Iterable<?> targetList = (Iterable<?>) containmentMethod.getMethod().invoke(obj); - DumpListChildNode listChild = new DumpListChildNode(); - listChild.setComputed(false); - String childName = containmentMethod.getName(); - listChild.setName(childName); - for (Object target : targetList) { - if (!getBuildConfig().getIncludeChildMethod().shouldInclude(obj, target, childName)) { - continue; - } - DumpNode targetNode = transform(tti, target, options.asNormal(false)); - if (target != null && targetNode != null) { - listChild.addInnerDumpNode(new InnerDumpNode().setDumpNode(targetNode)); - } - } - if (listChild.getNumInnerDumpNode() > 0) { - node.addDumpChildNode(listChild); - } + handleContainmentListChild(node, containmentMethod, obj, tti, options); } else { throw new RuntimeException("Unknown containment method type " + containmentMethod); } } for (AnalysedMethod otherMethod : car.getOtherMethodList()) { if (otherMethod.isSingleChildMethod()) { - // -- singleChild -- - String childName = otherMethod.getName(); - boolean computed = otherMethod.asSingleChildMethod().isNTASingleChildMethod(); - boolean shouldInclude = computed ? - getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, childName, true, () -> catchedInvoke(otherMethod.getMethod(), obj)) : - getBuildConfig().getIncludeChildMethod().shouldInclude(obj, otherMethod.getMethod().invoke(obj), childName); - if (!shouldInclude) { - continue; - } - DumpNode targetNode = transform(tti, otherMethod.getMethod().invoke(obj), options.asNormal(false).computed(computed).allowNullObjectsOnce()); - if (targetNode != null) { - DumpNormalChildNode normalChild = new DumpNormalChildNode(); - normalChild.setName(childName); - normalChild.setDumpNode(targetNode); - normalChild.setComputed(computed); - node.addDumpChildNode(normalChild); - } + handleOtherSingleChild(node, otherMethod, obj, tti, options); } else if (otherMethod.isListChildMethod()) { - // -- listChild -- - // it is always a NTAListChildMethod - String childName = otherMethod.getName(); - if (!getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, childName, true, () -> catchedInvoke(otherMethod.getMethod(), obj))) { - continue; - } - Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); - DumpListChildNode listChild = new DumpListChildNode(); - boolean computed = otherMethod.asListChildMethod().isNTAListChildMethod(); - listChild.setComputed(computed); - listChild.setName(childName); - for (Object target : targetList) { - DumpNode targetNode = transform(tti, target, options.asNormal(false).computed(computed)); - if (target != null && targetNode != null) { - listChild.addInnerDumpNode(new InnerDumpNode().setDumpNode(targetNode)); - } - } - if (listChild.getNumInnerDumpNode() > 0) { - node.addDumpChildNode(listChild); - } + handleOtherListChild(node, otherMethod, obj, tti, options); } else if (otherMethod.isSingleRelationMethod()) { - // -- singleRelation -- - Object target = otherMethod.getMethod().invoke(obj); - if (!getBuildConfig().getIncludeRelationMethod().shouldInclude(obj, target, otherMethod.getName())) { - continue; - } - DumpNode targetNode = transform(tti, target, options.asRelation()); - if (targetNode != null) { - DumpNormalRelation normalRelation = new DumpNormalRelation(); - normalRelation.setName(otherMethod.getName()); - normalRelation.setDumpNode(targetNode); - node.addDumpRelation(normalRelation); - } + handleOtherSingleRelation(node, otherMethod, obj, tti, options); } else if (otherMethod.isListRelationMethod()) { - // -- listRelation -- - Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); - DumpListRelation listRelation = new DumpListRelation(); - listRelation.setName(otherMethod.getName()); - for (Object target : targetList) { - if (!getBuildConfig().getIncludeRelationMethod().shouldInclude(obj, target, otherMethod.getName())) { - continue; - } - DumpNode targetNode = transform(tti, target, options.asRelation()); - if (target != null && targetNode != null) { - listRelation.addInnerRelationDumpNode(new InnerRelationDumpNode(targetNode)); + handleOtherListRelation(node, otherMethod, obj, tti, options); + } else if (otherMethod.isTokenMethod()) { + handleOtherToken(node, otherMethod, obj, tti, options); + } else { + throw new RuntimeException("Unknown other method type " + otherMethod); + } + } + return node; + } + + private boolean DumpAst.handleContainmentSingleOrOptChild(DumpNode node, AnalysedMethod containmentMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- singleChild or optChild -- + Object target; + if (containmentMethod.isOptChildMethod() && !((boolean) containmentMethod.asOptChildMethod().getCheckMethod().invoke(obj))) { + if (getBuildConfig().getExcludeNullNodes()) { + return false; + } else { + target = null; + } + } else { + target = containmentMethod.getMethod().invoke(obj); + } + String childName = containmentMethod.getName(); + if (!getBuildConfig().getIncludeChildMethod().shouldInclude(obj, target, childName)) { + return false; + } + DumpNode targetNode = transform(tti, target, options.asNormal(false).allowNullObjectsOnce()); + if (targetNode != null) { + DumpNormalChildNode normalChild = new DumpNormalChildNode(); + normalChild.setLabel(childName + (containmentMethod.isOptChildMethod() ? "?" : "")); + normalChild.setDumpNode(targetNode); + normalChild.setComputed(false); + node.addDumpChildNode(normalChild); + applyStyle(normalChild); + } + return true; + } + + private boolean DumpAst.handleContainmentListChild(DumpNode node, AnalysedMethod containmentMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- listChild -- + Iterable<?> targetList = (Iterable<?>) containmentMethod.getMethod().invoke(obj); + DumpListChildNode listChild = new DumpListChildNode(); + listChild.setComputed(false); + String childName = containmentMethod.getName(); + listChild.setLabel(childName); + listChild.setName(tti.nextName()); + node.addDumpChildNode(listChild); + RelationStyle style = applyStyle(listChild); + + int index = -1; + for (Object target : targetList) { + index++; + if (!getBuildConfig().getIncludeChildMethod().shouldInclude(obj, target, childName)) { + continue; + } + DumpNode targetNode = transform(tti, target, options.asNormal(false)); + if (target != null && targetNode != null) { + InnerDumpNode inner = new InnerDumpNode().setDumpNode(targetNode).setOriginalIndex(index); + listChild.addInnerDumpNode(inner); + inner.applyStyle(style); + } + } + if (listChild.getNumInnerDumpNode() == 0) { + InnerDumpNode inner = new InnerDumpNode().setDumpNode(transform(tti, EMPTY, + options.asNormal(false).allowNullObjectsOnce())); + listChild.addInnerDumpNode(inner); + inner.applyStyle(style); + } + return true; + } + + private boolean DumpAst.handleOtherSingleChild(DumpNode node, AnalysedMethod otherMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- singleChild -- + String childName = otherMethod.getName(); + boolean computed = otherMethod.asSingleChildMethod().isNTASingleChildMethod(); + boolean shouldInclude = computed ? + getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, childName, true, () -> catchedInvoke(otherMethod.getMethod(), obj)) : + getBuildConfig().getIncludeChildMethod().shouldInclude(obj, otherMethod.getMethod().invoke(obj), childName); + if (!shouldInclude) { + return false; + } + DumpNode targetNode = transform(tti, otherMethod.getMethod().invoke(obj), options.asNormal(false).computed(computed).allowNullObjectsOnce()); + if (targetNode != null) { + DumpNormalChildNode normalChild = new DumpNormalChildNode(); + normalChild.setLabel(childName); + normalChild.setDumpNode(targetNode); + normalChild.setComputed(computed); + node.addDumpChildNode(normalChild); + applyStyle(normalChild); + } + return true; + } + + private boolean DumpAst.handleOtherListChild(DumpNode node, AnalysedMethod otherMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- listChild -- + // it is always a NTAListChildMethod + String childName = otherMethod.getName(); + if (!getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, childName, true, () -> catchedInvoke(otherMethod.getMethod(), obj))) { + return false; + } + Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); + DumpListChildNode listChild = new DumpListChildNode(); + boolean computed = otherMethod.asListChildMethod().isNTAListChildMethod(); + listChild.setComputed(computed); + listChild.setLabel(childName); + listChild.setName(tti.nextName()); + node.addDumpChildNode(listChild); + RelationStyle style = applyStyle(listChild); + + for (Object target : targetList) { + DumpNode targetNode = transform(tti, target, options.asNormal(false).computed(computed)); + if (target != null && targetNode != null) { + InnerDumpNode inner = new InnerDumpNode().setDumpNode(targetNode); + listChild.addInnerDumpNode(inner); + inner.applyStyle(style); + } + } + return true; + } + + private boolean DumpAst.handleOtherSingleRelation(DumpNode node, AnalysedMethod otherMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- singleRelation -- + Object target = otherMethod.getMethod().invoke(obj); + if (!getBuildConfig().getIncludeRelationMethod().shouldInclude(obj, target, otherMethod.getName())) { + return false; + } + DumpNode targetNode = transform(tti, target, options.asRelation()); + if (targetNode != null) { + DumpNormalRelation normalRelation = new DumpNormalRelation(); + normalRelation.setLabel(otherMethod.getName() + + (otherMethod.asSingleRelationMethod().isOptRelationMethod() ? "?" : "")); + normalRelation.setDumpNode(targetNode); + node.addDumpRelation(normalRelation); + applyStyle(normalRelation); + } + return true; + } + + private boolean DumpAst.handleOtherListRelation(DumpNode node, AnalysedMethod otherMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- listRelation -- + Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); + DumpListRelation listRelation = new DumpListRelation(); + listRelation.setLabel(otherMethod.getName()); + listRelation.setName(tti.nextName()); + node.addDumpRelation(listRelation); + RelationStyle style = applyStyle(listRelation); + + int index = -1; + for (Object target : targetList) { + index++; + if (!getBuildConfig().getIncludeRelationMethod().shouldInclude(obj, target, otherMethod.getName())) { + continue; + } + DumpNode targetNode = transform(tti, target, options.asRelation()); + if (target != null && targetNode != null) { + InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(targetNode).setOriginalIndex(index); + listRelation.addInnerRelationDumpNode(inner); + inner.applyStyle(style); + } + } + if (listRelation.getNumInnerRelationDumpNode() == 0) { + InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(transform(tti, EMPTY, + options.asNormal(false).allowNullObjectsOnce())); + listRelation.addInnerRelationDumpNode(inner); + inner.applyStyle(style); + } + return true; + } + + private boolean DumpAst.handleOtherToken(DumpNode node, AnalysedMethod otherMethod, + Object obj, TransformationTransferInformation tti, TransformationOptions options) + throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException { + // -- token -- + TokenMethod tokenMethod = otherMethod.asTokenMethod(); + boolean shouldInclude = tokenMethod.isAttributeMethod() ? + getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, otherMethod.getName(), false, () -> catchedInvoke(otherMethod.getMethod(), obj)) : + getBuildConfig().getIncludeTokenMethod().shouldInclude(obj, otherMethod.getName(), otherMethod.getMethod().invoke(obj)); + if (!shouldInclude) { + return false; + } + Object target = otherMethod.getMethod().invoke(obj); + // local function to add common member and add the token-node to the given node + java.util.function.Consumer<DumpToken> setMemberAndAdd = token -> { + token.setLabel(otherMethod.getName()); + token.setComputed(otherMethod.asTokenMethod().isAttributeMethod()); + node.addDumpToken(token); + }; + if (target != null) { + boolean atLeastOneASTNode = false; + if (Iterable.class.isAssignableFrom(target.getClass())) { + java.util.List<DumpNode> nodes = new java.util.ArrayList<>(); + Iterable<?> iterable = (Iterable<?>) target; + for (Object element : iterable) { + // check if isAstNode for first non-null. if yes, use DumpReferenceListToken, otherwise DumpValueToken + DumpNode nodeForElement = transform(tti, element, options.asRelation()); + nodes.add(nodeForElement); + if (nodeForElement != null && nodeForElement.isAstNode()) { + atLeastOneASTNode = true; } } - if (listRelation.getNumInnerRelationDumpNode() > 0) { - node.addDumpRelation(listRelation); - } - } else if (otherMethod.isTokenMethod()) { - // -- token -- - TokenMethod tokenMethod = otherMethod.asTokenMethod(); - boolean shouldInclude = tokenMethod.isAttributeMethod() ? - getBuildConfig().getIncludeAttributeMethod().shouldInclude(obj, otherMethod.getName(), false, () -> catchedInvoke(otherMethod.getMethod(), obj)) : - getBuildConfig().getIncludeTokenMethod().shouldInclude(obj, otherMethod.getName(), otherMethod.getMethod().invoke(obj)); - if (!shouldInclude) { - continue; + if (atLeastOneASTNode) { + DumpReferenceListToken listToken = new DumpReferenceListToken(); + listToken.setName(tti.nextName()); + setMemberAndAdd.accept(listToken); + RelationStyle style = applyStyle(listToken); + nodes.forEach(element -> { + InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(element); + listToken.addInnerRelationDumpNode(inner); + inner.applyStyle(style); + }); } - Object target = otherMethod.getMethod().invoke(obj); - if (target != null) { - DumpToken token = null; - boolean atLeastOneASTNode = false; - if (Iterable.class.isAssignableFrom(target.getClass())) { - java.util.List<DumpNode> nodes = new java.util.ArrayList<>(); - Iterable iterable = (Iterable) target; - for (Object element : iterable) { - // TODO check if isAstNode for first non-null. if yes, use DumpReferenceListToken, other DumpValueToken - DumpNode nodeForElement = transform(tti, element, options.asRelation()); - nodes.add(nodeForElement); - if (nodeForElement != null && nodeForElement.isAstNode()) { - atLeastOneASTNode = true; - } - } - if (atLeastOneASTNode) { - DumpReferenceListToken listToken = new DumpReferenceListToken(); - nodes.forEach(element -> { - listToken.addInnerRelationDumpNode(new InnerRelationDumpNode().setDumpNode(element)); - }); - token = listToken; - } - } - if (!atLeastOneASTNode) { - DumpNode targetNode = transform(tti, target, options.asRelation()); - if (targetNode != null && targetNode.isAstNode()) { - token = new DumpReferenceToken().setValue(targetNode); - } else { - if (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty()) { - DumpValueToken valueToken = new DumpValueToken(); - valueToken.setValue(target); - token = valueToken; - } - } - } - if (token != null) { - token.setName(otherMethod.getName()); - token.setComputed(otherMethod.asTokenMethod().isAttributeMethod()); - node.addDumpToken(token); + } + if (!atLeastOneASTNode) { + DumpNode targetNode = transform(tti, target, options.asRelation()); + if (targetNode != null && targetNode.isAstNode()) { + DumpReferenceToken token = new DumpReferenceToken().setDumpNode(targetNode); + setMemberAndAdd.accept(token); + applyStyle(token.asDumpReferenceToken()); + } else { + if (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty()) { + DumpValueToken valueToken = new DumpValueToken(); + valueToken.setValue(target); + setMemberAndAdd.accept(valueToken); } } - } else { - throw new RuntimeException("Unknown other method type " + otherMethod); } } - return node; + return true; } private Object DumpAst.catchedInvoke(java.lang.reflect.Method method, Object obj) { @@ -308,38 +393,103 @@ aspect Transform { } } + // === NodeStyle === + DumpNode NodeStyle.node; + + NodeStyle DumpNode.createDefaultStyle() { + NodeStyle result = new NodeStyle(); + result.node = this; + result.useSimpleLabelWithHashCode(); + return result; + } + private void DumpAst.applyStyle(DumpNode node) { - Object obj = node.getObject(); - node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj)); - node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj)); - node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj)); - node.setManualStereotypes(getBuildConfig().getStyleInformation().getStereotypeMethod().get(obj)); + NodeStyle style = node.createDefaultStyle(); + getPrintConfig().getNodeStyleDefinition().style(node.getObject(), style); + node.setLabel(style.getLabel()); + node.setBackgroundColor(style.getBackgroundColor()); + node.setTextColor(style.getTextColor()); + node.setManualStereotypes(style.getStereoTypes()); } - // TODO: add new attributes for: {token,child,relation,attribute,nta}Enabled(String parentType, String name). 1) just move implementation into this attribute. 2) add include/exclude on type-level to it. + // === RelationStyle === + interface RelationStyleDefinable { + // more methods in TransformPlus.jadd + + // attributes + BuildConfig buildConfig(); + boolean isComputed(); + boolean isContainment(); + String initialLabel(); + DumpNode containingDumpNode(); + DumpNode getDumpNode(); + } + interface RelationStylable<SELF> { + // more methods in TransformPlus.jadd + + // tokens + String getTextColor(); + String getLineColor(); + + SELF setLabel(String name); + SELF setTextColor(String textColor); + SELF setLineColor(String lineColor); + } + + DumpChildNode implements RelationStyleDefinable, RelationStylable<DumpChildNode>; + syn String DumpChildNode.initialLabel() = getLabel(); + syn boolean DumpChildNode.isComputed() = getComputed(); + syn boolean DumpChildNode.isContainment() = true; + + syn DumpNode DumpListChildNode.getDumpNode() = null; + + DumpRelation implements RelationStyleDefinable, RelationStylable<DumpRelation>; + syn String DumpRelation.initialLabel() = getLabel(); + syn boolean DumpRelation.isComputed() = false; + syn boolean DumpRelation.isContainment() = false; + + syn DumpNode DumpListRelation.getDumpNode() = null; + + InnerDumpNode implements RelationStylable<InnerDumpNode>; + InnerRelationDumpNode implements RelationStylable<InnerRelationDumpNode>; + + DumpReferenceListToken implements RelationStyleDefinable, RelationStylable<DumpReferenceListToken>; + syn String DumpReferenceListToken.initialLabel() = getLabel(); + syn boolean DumpReferenceListToken.isComputed() = getComputed(); + syn boolean DumpReferenceListToken.isContainment() = false; + syn DumpNode DumpReferenceListToken.getDumpNode() = null; + + DumpReferenceToken implements RelationStyleDefinable, RelationStylable<DumpReferenceToken>; + syn String DumpReferenceToken.initialLabel() = getLabel(); + syn boolean DumpReferenceToken.isComputed() = getComputed(); + syn boolean DumpReferenceToken.isContainment() = false; + + private void DumpAst.applyStyle(RelationStylable<?> stylable, RelationStyle style) { + stylable.applyStyle(style); + } + private void DumpAst.applyStyle(DumpToken token, RelationStyle style) { + if (token.isDumpReferenceListToken()) { + token.asDumpReferenceListToken().applyStyle(style); + } else if (token.isDumpReferenceToken()) { + token.asDumpReferenceToken().applyStyle(style); + } + // otherwise ignore + } // --- isTypeEnabled --- syn boolean DumpAst.isTypeEnabled(String typeName) { - return !matches(getBuildConfig().typeIgnorePattern(), typeName); + return !getBuildConfig().typeIgnorePattern().matcher(typeName).matches(); } - - // --- {typeIgnore,child,token,relation,attribute,nta}Pattern --- + // --- typeIgnorePattern --- syn java.util.regex.Pattern BuildConfig.typeIgnorePattern() = java.util.regex.Pattern.compile(getTypeIgnorePattern()); - syn java.util.regex.Pattern PatternCollection.childPattern() = java.util.regex.Pattern.compile(getChildPattern()); - syn java.util.regex.Pattern PatternCollection.tokenPattern() = java.util.regex.Pattern.compile(getTokenPattern()); - syn java.util.regex.Pattern PatternCollection.relationPattern() = java.util.regex.Pattern.compile(getRelationPattern()); - syn java.util.regex.Pattern PatternCollection.attributePattern() = java.util.regex.Pattern.compile(getAttributePattern()); - syn java.util.regex.Pattern PatternCollection.ntaPattern() = java.util.regex.Pattern.compile(getNonterminalAttributePattern()); - syn java.util.regex.Pattern TypePatternCollectionMapping.typePattern() = java.util.regex.Pattern.compile(getTypeRegex()); - - // --- matches --- - static boolean ASTNode.matches(java.util.regex.Pattern p, String input) { - return p.matcher(input).matches(); - } class TransformationTransferInformation { java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>(); java.util.Map<DumpNode, Boolean> relationTargetsUnprocessed = new java.util.HashMap<>(); int nodeCounter = 0; + + String nextName() { + return "node" + (nodeCounter++); + } } } diff --git a/dumpAst.base/src/main/jastadd/TransformPlus.jadd b/dumpAst.base/src/main/jastadd/TransformPlus.jadd new file mode 100644 index 0000000000000000000000000000000000000000..ff3b8e590f83022ccfb328bc072c700abee832e2 --- /dev/null +++ b/dumpAst.base/src/main/jastadd/TransformPlus.jadd @@ -0,0 +1,35 @@ +// more stuff from Transform that is not correctly handled by the IntelliJ plugin +aspect Transform { + interface RelationStyleDefinable { + default RelationStyle createDefaultStyle() { + return new RelationStyle() + .setLabel(initialLabel()) + .setLineColor(isComputed() ? buildConfig().getStyleInformation().getComputedColor() : "") + .setTextColor(isComputed() ? buildConfig().getStyleInformation().getComputedColor() : ""); + } + default RelationStyle getStyle(RelationStyleDefinition relationStyleDefinition) { + RelationStyle style = createDefaultStyle(); + relationStyleDefinition.style(containingDumpNode().getObject(), + getDumpNode() != null ? getDumpNode().getObject() : null, + isComputed(), isContainment(), style); + return style; + } + } + + interface RelationStylable<SELF> { + default boolean needRelationStyling() { + return !getLineColor().isEmpty() || !getTextColor().isEmpty(); + } + default void applyStyle(RelationStyle style) { + setLabel(style.getLabel()); + setTextColor(style.getTextColor()); + setLineColor(style.getLineColor()); + } + } + + private <T extends RelationStyleDefinable & RelationStylable<?>> RelationStyle DumpAst.applyStyle(T styleDefinable) { + RelationStyle result = styleDefinable.getStyle(getPrintConfig().getRelationStyleDefinition()); + styleDefinable.applyStyle(result); + return result; + } +} diff --git a/dumpAst.base/src/main/jastadd/Util.jrag b/dumpAst.base/src/main/jastadd/Util.jrag index 32c0ab008028cd8fc2b9b3aa132b94a942067f21..873e9b6ba6af303528aa3e53c82965030f3fb5fc 100644 --- a/dumpAst.base/src/main/jastadd/Util.jrag +++ b/dumpAst.base/src/main/jastadd/Util.jrag @@ -1,23 +1,4 @@ aspect Util { - // --- find{In,Ex}cludePatternCollection --- - syn PatternCollection BuildConfig.findIncludePatternCollection(String typeRegex) { - for (TypePatternCollectionMapping mapping : getIncludeTypePatternList()) { - if (mapping.getTypeRegex().equals(typeRegex)) { - return mapping.getPatternCollection(); - } - } - return null; - } - - syn PatternCollection BuildConfig.findExcludePatternCollection(String typeRegex) { - for (TypePatternCollectionMapping mapping : getExcludeTypePatternList()) { - if (mapping.getTypeRegex().equals(typeRegex)) { - return mapping.getPatternCollection(); - } - } - return null; - } - private String DumpAst.titleCase(String s) { if (s.isEmpty()) { return s; diff --git a/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java index ed87cf24a45c0d9c8cda43c612c4450080fc8504..937cf6814ce0c39d04d62818407ef6a04490ee23 100644 --- a/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java +++ b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java @@ -5,6 +5,7 @@ import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.SourceStringReader; import java.io.IOException; +import java.io.OutputStream; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; @@ -13,114 +14,37 @@ import java.util.ResourceBundle; import java.util.function.Consumer; import java.util.function.Supplier; -import static de.tudresden.inf.st.jastadd.dumpAst.ast.ASTNode.matches; - /** - * Building a dump. - * <p> - * - * <h3>Inclusion and Exclusion of Types</h3> - * Types can be only be disabled, see {@link #disableTypes(String, String...)}. - * - * <h3>Inclusion and Exclusion of children, tokens and relations</h3> - * Children, tokens and relations are included by default. - * This can be changed using exclusions and inclusion, both in general and per-type. - * They are applied in the following order making later conditions take precedence over the first ones. - * <ol> - * <li>Include everything as default. - * <li>Exclude general. - * <li>Include per type. - * <li>Exclude per type. - * </ol> - * - * <h3>Inclusion and Exclusion of Attributes</h3> - * Attributes are excluded by default, i.e., not shown. - * This can be changed using inclusions and exclusions, both in general and per-type. - * They are applied in the following order making later conditions take precedence over the first ones. - * <ol> - * <li> Exclude everything as default. - * <li> Include general. - * <li> Exclude per type. - * <li> Include per type - * </ol> + * Creating a snapshot of an AST. */ @SuppressWarnings("UnusedReturnValue") public class DumpBuilder { private final Object target; private String packageName; - private DumpAst result; - private final BuildConfig buildConfig; - private final PrintConfig printConfig; + private DumpAst dumpAst; + + private boolean built; protected DumpBuilder(Object target) { this.target = target; - buildConfig = new BuildConfig(); - buildConfig.setIncludeChildMethod((parentNode, childNode, contextName) -> { - // level 4: excluded for type? -> return no - PatternCollection excludeOnType = buildConfig.matchExcludePatternCollection(parentNode.getClass().getSimpleName()); - if (excludeOnType != null && matches(excludeOnType.childPattern(), contextName)) { - return false; - } - // level 3: included for type? -> return yes - PatternCollection includeOnType = buildConfig.matchIncludePatternCollection(parentNode.getClass().getSimpleName()); - if (includeOnType != null && matches(includeOnType.childPattern(), contextName)) { - return true; - } - // level 2: globally excluded? -> return no - // level 1: otherwise return yes - return !matches(buildConfig.getGlobalPatternCollection().childPattern(), contextName); - }); - buildConfig.setIncludeRelationMethod((sourceNode, targetNode, roleName) -> { - // level 4: excluded for type? -> return no - PatternCollection excludeOnType = buildConfig.matchExcludePatternCollection(sourceNode.getClass().getSimpleName()); - if (excludeOnType != null && matches(excludeOnType.relationPattern(), roleName)) { - return false; - } - // level 3: included for type? -> return yes - PatternCollection includeOnType = buildConfig.matchIncludePatternCollection(sourceNode.getClass().getSimpleName()); - if (includeOnType != null && matches(includeOnType.relationPattern(), roleName)) { - return true; - } - // level 2: globally excluded? -> return no - // level 1: otherwise return yes - return !matches(buildConfig.getGlobalPatternCollection().relationPattern(), roleName); - }); - buildConfig.setIncludeTokenMethod((node, tokenName, value) -> { - // level 4: excluded for type? -> return no - PatternCollection excludeOnType = buildConfig.matchExcludePatternCollection(node.getClass().getSimpleName()); - if (excludeOnType != null && matches(excludeOnType.tokenPattern(), tokenName)) { - return false; - } - // level 3: included for type? -> return yes - PatternCollection includeOnType = buildConfig.matchIncludePatternCollection(node.getClass().getSimpleName()); - if (includeOnType != null && matches(includeOnType.tokenPattern(), tokenName)) { - return true; - } - // level 2: globally excluded? -> return no - // level 1: otherwise return yes - return !matches(buildConfig.getGlobalPatternCollection().tokenPattern(), tokenName); - }); - buildConfig.setIncludeAttributeMethod((node, attributeName, isNTA, supplier) -> { - // level 4: included for type? -> return yes - PatternCollection includeOnType = buildConfig.matchIncludePatternCollection(node.getClass().getSimpleName()); - if (includeOnType != null && matches(isNTA ? includeOnType.ntaPattern() : includeOnType.attributePattern(), attributeName)) { - return true; - } - // level 3: excluded for type? -> return no - PatternCollection excludeOnType = buildConfig.matchExcludePatternCollection(node.getClass().getSimpleName()); - if (excludeOnType != null && matches(isNTA ? excludeOnType.ntaPattern() : excludeOnType.attributePattern(), attributeName)) { - return false; - } - // level 2: globally included? -> return yes - // level 1: otherwise return no - PatternCollection global = buildConfig.getGlobalPatternCollection(); - return matches(isNTA ? global.ntaPattern() : global.attributePattern(), attributeName); - }); - buildConfig.setGlobalPatternCollection(new PatternCollection()); - buildConfig.setStyleInformation(StyleInformation.createDefault()); - printConfig = new PrintConfig(); - printConfig.setScale(1); - printConfig.setVersion(readVersion()); + this.built = false; + this.dumpAst = new DumpAst(); + dumpAst.setBuildConfig(new BuildConfig()); + dumpAst.getBuildConfig().setIncludeChildMethod((parentNode, childNode, contextName) -> true); + dumpAst.getBuildConfig().setIncludeRelationMethod((sourceNode, targetNode, roleName) -> true); + dumpAst.getBuildConfig().setIncludeTokenMethod((node, tokenName, value) -> true); + dumpAst.getBuildConfig().setIncludeAttributeMethod((node, attributeName, isNTA, supplier) -> false); + dumpAst.getBuildConfig().setStyleInformation(StyleInformation.createDefault()); + dumpAst.setPrintConfig(new PrintConfig()); + dumpAst.getPrintConfig().setScale(1); + dumpAst.getPrintConfig().setVersion(readVersion()); + dumpAst.getPrintConfig().setNodeStyleDefinition((node, style) -> {}); + dumpAst.getPrintConfig().setRelationStyleDefinition((sourceNode, targetNode, isComputed, isContainment, style) -> {}); + } + + private DumpBuilder thisWithResetBuilt() { + this.built = false; + return this; } /** @@ -130,8 +54,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder enableDebug() { - buildConfig.setDebug(true); - return this; + dumpAst.getBuildConfig().setDebug(true); + return thisWithResetBuilt(); } /** @@ -141,7 +65,7 @@ public class DumpBuilder { */ public DumpBuilder setPackageName(String packageName) { this.packageName = packageName; - return this; + return thisWithResetBuilt(); } /** @@ -150,8 +74,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder includeEmptyStringsOnTokens() { - buildConfig.setIncludeEmptyString(true); - return this; + dumpAst.getBuildConfig().setIncludeEmptyString(true); + return thisWithResetBuilt(); } /** @@ -159,8 +83,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder enableRelationWithRank() { - printConfig.setRelationWithRank(true); - return this; + dumpAst.getPrintConfig().setRelationWithRank(true); + return thisWithResetBuilt(); } // --- Types --- @@ -177,353 +101,42 @@ public class DumpBuilder { * @see java.util.regex.Pattern#compile(String) */ public DumpBuilder disableTypes(String regex, String... moreRegexes) { - updateRegexes(buildConfig::getTypeIgnorePattern, - buildConfig::setTypeIgnorePattern, + updateRegexes(dumpAst.getBuildConfig()::getTypeIgnorePattern, + dumpAst.getBuildConfig()::setTypeIgnorePattern, regex, moreRegexes); - return this; + return thisWithResetBuilt(); } // --- Tokens --- - public <ASTNODE> DumpBuilder includeTokensWhen(IncludeTokenMethod<ASTNODE> spec) { - buildConfig.setIncludeTokenMethod(spec); - if (!buildConfig.getGlobalPatternCollection().getTokenPattern().isEmpty()) { - System.err.println("Overriding previous filters for tokens"); - } - return this; - } - - /** - * Exclude tokens and their value if the token name matches at least one of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param regex first pattern to match token names - * @param moreRegexes more patterns to match token names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeTokens(String regex, String... moreRegexes) { - updateRegexes(() -> buildConfig.getGlobalPatternCollection().getTokenPattern(), - s -> buildConfig.getGlobalPatternCollection().setTokenPattern(s), - regex, moreRegexes); - return this; - } - - /** - * Exclude tokens and their value within a type if the token name matches at least one of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match token names - * @param moreRegexes more patterns to match token names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeTokensFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex); - updateRegexes(collection::getTokenPattern, - collection::setTokenPattern, - regex, moreRegexes); - return this; - } - - /** - * Include tokens (again) and their value within a type if the token name matches at least one of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match token names - * @param moreRegexes more patterns to match token names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeTokensFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex); - updateRegexes(collection::getTokenPattern, - collection::setTokenPattern, - regex, moreRegexes); - return this; + public <ASTNODE> DumpBuilder includeToken(IncludeTokenMethod<ASTNODE> spec) { + dumpAst.getBuildConfig().setIncludeTokenMethod(spec); + return thisWithResetBuilt(); } // --- Children --- - public <ASTNODE> DumpBuilder includeChildWhen(IncludeChildMethod<ASTNODE> spec) { - buildConfig.setIncludeChildMethod(spec); - if (!buildConfig.getGlobalPatternCollection().getChildPattern().isEmpty()) { - System.err.println("Overriding previous filters for children"); - } - return this; - } - - /** - * Exclude every child whose name (i.e., context) matches at least on of the given regex strings. - * This means, that the complete object and its (transitive) children will never be included in any output. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeChildren(String regex, String... moreRegexes) { - updateRegexes(() -> buildConfig.getGlobalPatternCollection().getChildPattern(), - s -> buildConfig.getGlobalPatternCollection().setChildPattern(s), - regex, moreRegexes); - return this; - } - - /** - * Exclude every child within a type whose name (i.e., context) matches at least on of the given regex strings. - * This means, that the complete object and its (transitive) children will never be included in any output. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeChildrenFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex); - updateRegexes(collection::getChildPattern, - collection::setChildPattern, - regex, moreRegexes); - return this; - } - - /** - * Include every child (again) within a type whose name (i.e., context) matches at least on of the given regex strings. - * This means, that the complete object and its (transitive) children will never be included in any output. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeChildrenFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex); - updateRegexes(collection::getChildPattern, - collection::setChildPattern, - regex, moreRegexes); - return this; + public <ASTNODE> DumpBuilder includeChild(IncludeChildMethod<ASTNODE> spec) { + dumpAst.getBuildConfig().setIncludeChildMethod(spec); + return thisWithResetBuilt(); } // --- Attributes --- - public <ASTNODE> DumpBuilder includeAttributeWhen(IncludeAttributeMethod<ASTNODE> spec) { - buildConfig.setIncludeAttributeMethod(spec); - if (!buildConfig.getGlobalPatternCollection().getAttributePattern().isEmpty()) { - System.err.println("Overriding previous filters for attributes"); - } - return this; - } - - /** - * Include attributes (as tokens) and their value if the attribute name matches at least on of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeAttributes(String regex, String... moreRegexes) { - updateRegexes(() -> buildConfig.getGlobalPatternCollection().getAttributePattern(), - s -> buildConfig.getGlobalPatternCollection().setAttributePattern(s), - regex, moreRegexes); - return this; - } - - /** - * Include attributes within a type (as tokens) and their value if the attribute name matches at least on of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeAttributesFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex); - updateRegexes(collection::getAttributePattern, - collection::setAttributePattern, - regex, moreRegexes); - return this; - } - - /** - * Exclude attributes within a type (as tokens) and their value (again) if the attribute name matches at least on of the given regex strings. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeAttributesFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex); - updateRegexes(collection::getAttributePattern, - collection::setAttributePattern, - regex, moreRegexes); - return this; - } - - // --- Nonterminal-Attributes --- - - /** - * Includes nonterminal-attributes (as children) and their values if - * their attribute name matches at least on of the given regex strings. - * <br> - * <b>Note</b>: A leading "get" and a trailing "List" in the name will be removed prior to matching. - * Thus, it should not be contained in the regex either. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeNonterminalAttributes(String regex, String... moreRegexes) { - updateRegexes(() -> buildConfig.getGlobalPatternCollection().getNonterminalAttributePattern(), - s -> buildConfig.getGlobalPatternCollection().setNonterminalAttributePattern(s), - regex, moreRegexes); - return this; - } - - /** - * Includes nonterminal-attributes (as children) and their values within a type if - * their attribute name matches at least on of the given regex strings. - * <br> - * <b>Note</b>: A leading "get" and a trailing "List" in the name will be removed prior to matching. - * Thus, it should not be contained in the regex either. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeNonterminalAttributesFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex); - updateRegexes(collection::getNonterminalAttributePattern, - collection::setNonterminalAttributePattern, - regex, moreRegexes); - return this; - } - - /** - * Excludes nonterminal-attributes (as children) and their values (again) within a type if - * their attribute name matches at least on of the given regex strings. - * <br> - * <b>Note</b>: A leading "get" and a trailing "List" in the name will be removed prior to matching. - * Thus, it should not be contained in the regex either. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match attribute name - * @param moreRegexes more patterns to match attribute names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeNonterminalAttributesFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex); - updateRegexes(collection::getNonterminalAttributePattern, - collection::setNonterminalAttributePattern, - regex, moreRegexes); - return this; + public <ASTNODE> DumpBuilder includeAttribute(IncludeAttributeMethod<ASTNODE> spec) { + dumpAst.getBuildConfig().setIncludeAttributeMethod(spec); + return thisWithResetBuilt(); } // --- Relations --- - public <ASTNODE> DumpBuilder includeRelationsWhen(IncludeRelationMethod<ASTNODE> spec) { - buildConfig.setIncludeRelationMethod(spec); - if (!buildConfig.getGlobalPatternCollection().getRelationPattern().isEmpty()) { - System.err.println("Overriding previous filters for relations"); - } - return this; - } - - /** - * Exclude every relation whose role-name matches at least on of the given regex strings. - * This means two things: a) the relation to any potential target object(s) is never shown, and b) the target - * object(s) are not shown unless they are reachable by another relation or by containment. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeRelations(String regex, String... moreRegexes) { - updateRegexes(() -> buildConfig.getGlobalPatternCollection().getRelationPattern(), - s -> buildConfig.getGlobalPatternCollection().setRelationPattern(s), - regex, moreRegexes); - return this; - } - - /** - * Exclude every relation within a type whose role-name matches at least on of the given regex strings. - * This means two things: a) the relation to any potential target object(s) is never shown, and b) the target - * object(s) are not shown unless they are reachable by another relation or by containment. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder excludeRelationsFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex); - updateRegexes(collection::getRelationPattern, - collection::setRelationPattern, - regex, moreRegexes); - return this; - } - - /** - * Include every relation (again) within a type whose role-name matches at least on of the given regex strings. - * This means two things: a) the relation to any potential target object(s) is never shown, and b) the target - * object(s) are not shown unless they are reachable by another relation or by containment. - * <p> - * See {@link DumpBuilder} for details on inclusion and exclusion precedence. - * - * @param typeRegex pattern to match a nonterminal name - * @param regex first pattern to match child name - * @param moreRegexes more patterns to match child names - * @return this - * @see java.util.regex.Pattern#compile(String) - */ - public DumpBuilder includeRelationsFor(String typeRegex, String regex, String... moreRegexes) { - PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex); - updateRegexes(collection::getRelationPattern, - collection::setRelationPattern, - regex, moreRegexes); - return this; + public <ASTNODE> DumpBuilder includeRelation(IncludeRelationMethod<ASTNODE> spec) { + dumpAst.getBuildConfig().setIncludeRelationMethod(spec); + return thisWithResetBuilt(); } // --- Settings --- - /** * Omit children that are <code>null</code> (in a full AST, there are no such nodes). * @@ -531,8 +144,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder excludeNullNodes() { - buildConfig.setExcludeNullNodes(true); - return this; + dumpAst.getBuildConfig().setExcludeNullNodes(true); + return thisWithResetBuilt(); } /** @@ -542,8 +155,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder includeNullNodes() { - buildConfig.setExcludeNullNodes(false); - return this; + dumpAst.getBuildConfig().setExcludeNullNodes(false); + return thisWithResetBuilt(); } /** @@ -552,8 +165,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder customPreamble(String option) { - printConfig.addHeader(new Header(option)); - return this; + dumpAst.getPrintConfig().addHeader(new Header(option)); + return thisWithResetBuilt(); } /** @@ -564,7 +177,7 @@ public class DumpBuilder { */ public DumpBuilder skinParam(SkinParamStringSetting setting, String value) { customPreamble("skinparam " + setting.toString() + " " + value); - return this; + return thisWithResetBuilt(); } /** @@ -575,63 +188,29 @@ public class DumpBuilder { */ public DumpBuilder skinParam(SkinParamBooleanSetting setting, boolean value) { customPreamble("skinparam " + setting.toString() + " " + value); - return this; + return thisWithResetBuilt(); } /** - * Set the method defining, what name a node has (default: {@code n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode())}). - * - * <p>Example:<br> - * {@code builder.<ASTNode<?>>setNameMethod(n -> n.isA() ? "A" : "Not A")} - * @param nameMethod a style method - * @param <ASTNODE> the type of ASTNode + * Set the styling definition for all nodes to change appearance, e.g., of background color. + * @param styleDefinition the new style definition * @return this + * @param <ASTNODE> type of AstNode */ - public <ASTNODE> DumpBuilder setNameMethod(StyleMethod<ASTNODE> nameMethod) { - buildConfig.getStyleInformation().setNameMethod(nameMethod); - return this; + public <ASTNODE> DumpBuilder nodeStyle(NodeStyleDefinition<ASTNODE> styleDefinition) { + dumpAst.getPrintConfig().setNodeStyleDefinition(styleDefinition); + return thisWithResetBuilt(); } /** - * Set the method defining, what background color a node has (default: {@code n -> ""}). - * - * <p>Example:<br> - * {@code builder.<ASTNode<?>>setBackgroundColorMethod(n -> n.isA() ? "red" : "blue")} - * @param colorMethod a style method - * @param <ASTNODE> the type of ASTNode + * Set the styling definition for all relations to change appearance, e.g., of its label. + * @param styleDefinition the new style definition * @return this + * @param <ASTNODE> type of AstNode */ - public <ASTNODE> DumpBuilder setBackgroundColorMethod(StyleMethod<ASTNODE> colorMethod) { - buildConfig.getStyleInformation().setBackgroundColorMethod(colorMethod); - return this; - } - - /** - * Set the method defining, what text color a node has (default: {@code n -> ""}). - * - * <p>Example:<br> - * {@code builder.<ASTNode<?>>setTextColorMethod(n -> n.isA() ? "black" : "white")} - * @param colorMethod a style method - * @param <ASTNODE> the type of ASTNode - * @return this - */ - public <ASTNODE> DumpBuilder setTextColorMethod(StyleMethod<ASTNODE> colorMethod) { - buildConfig.getStyleInformation().setTextColorMethod(colorMethod); - return this; - } - - /** - * Set the method defining, what stereotype a node has (default: {@code n -> ""}). - * - * <p>Example:<br> - * {@code builder.<ASTNode<?>>setStereotypeMethod(n -> n.isA() ? "MyStereoType" : "")} - * @param stereotypeMethod a style method - * @param <ASTNODE> the type of ASTNode - * @return this - */ - public <ASTNODE> DumpBuilder setStereotypeMethod(StyleMethod<ASTNODE> stereotypeMethod) { - buildConfig.getStyleInformation().setStereotypeMethod(stereotypeMethod); - return this; + public <ASTNODE> DumpBuilder relationStyle(RelationStyleDefinition<ASTNODE> styleDefinition) { + dumpAst.getPrintConfig().setRelationStyleDefinition(styleDefinition); + return thisWithResetBuilt(); } /** @@ -641,8 +220,8 @@ public class DumpBuilder { * @see <a href="https://plantuml.com/en/color">https://plantuml.com/en/color</a> */ public DumpBuilder setComputedColor(String color) { - buildConfig.getStyleInformation().setComputedColor(color); - return this; + dumpAst.getBuildConfig().getStyleInformation().setComputedColor(color); + return thisWithResetBuilt(); } /** @@ -651,8 +230,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder setScale(double value) { - printConfig.setScale(value); - return this; + dumpAst.getPrintConfig().setScale(value); + return thisWithResetBuilt(); } /** @@ -660,8 +239,8 @@ public class DumpBuilder { * @return this */ public DumpBuilder orderChildren() { - printConfig.setOrderChildren(true); - return this; + dumpAst.getPrintConfig().setOrderChildren(true); + return thisWithResetBuilt(); } // --- Dump methods --- @@ -690,6 +269,16 @@ public class DumpBuilder { } } + /** + * Return content as intermediate data structure used by the template engine. + * + * @return the intermediate data structure used by the template engine + * @throws TransformationException if {@link DumpAst#transform(TransformationTransferInformation, Object) transform} was not successful + */ + public String dumpAsYaml(boolean prependCreationComment) throws TransformationException { + return build().printYaml(prependCreationComment); + } + /** * Write out content as intermediate data structure used by the template engine. * @@ -705,6 +294,17 @@ public class DumpBuilder { } } + /** + * Write out content as PNG image generated by plantuml. + * + * @param os a stream to write to + * @throws IOException if an I/O error happened during writing in that stream + * @throws TransformationException if {@link DumpAst#transform(TransformationTransferInformation, Object) transform} was not successful + */ + public void dumpAsPNG(OutputStream os) throws TransformationException, IOException { + dumpAs(os, FileFormat.PNG); + } + /** * Write out content as PNG image generated by plantuml. * @@ -716,6 +316,17 @@ public class DumpBuilder { dumpAs(destination, FileFormat.PNG); } + /** + * Write out content as SVG image generated by plantuml. + * + * @param os a stream to write to + * @throws IOException if an I/O error happened during writing in that stream + * @throws TransformationException if {@link DumpAst#transform(TransformationTransferInformation, Object) transform} was not successful + */ + public void dumpAsSVG(OutputStream os) throws TransformationException, IOException { + dumpAs(os, FileFormat.SVG); + } + /** * Write out content as SVG image generated by plantuml. * @@ -727,6 +338,20 @@ public class DumpBuilder { dumpAs(destination, FileFormat.SVG); } + /** + * Write out content as PDF image generated by plantuml. + * + * <br> + * <b>Note:</b> This requires additional dependencies, see <a href="https://plantuml.com/pdf">https://plantuml.com/pdf</a> + * + * @param os a stream to write to + * @throws IOException if an I/O error happened during writing in that stream + * @throws TransformationException if {@link DumpAst#transform(TransformationTransferInformation, Object) transform} was not successful + */ + public void dumpAsPDF(OutputStream os) throws TransformationException, IOException { + dumpAs(os, FileFormat.PDF); + } + /** * Write out content as PDF generated by plantuml. * @@ -747,11 +372,16 @@ public class DumpBuilder { reader.outputImage(Files.newOutputStream(destination), new FileFormatOption(fileFormat)); } + private void dumpAs(OutputStream os, FileFormat fileFormat) throws IOException, TransformationException { + String content = build().toPlantUml(); + SourceStringReader reader = new SourceStringReader(content); + reader.outputImage(os, new FileFormatOption(fileFormat)); + } + // --- Helper methods --- protected DumpAst build() throws TransformationException { - if (result == null) { - result = new DumpAst(); + if (!built) { final String packageNameToUse; if (this.packageName != null) { packageNameToUse = this.packageName; @@ -762,41 +392,15 @@ public class DumpBuilder { packageNameToUse = this.target.getClass().getPackage().getName(); } } - result.setPackageName(packageNameToUse); - result.setBuildConfig(this.buildConfig); - result.setPrintConfig(this.printConfig); + dumpAst.setPackageName(packageNameToUse); try { - result.transform(new TransformationTransferInformation(), this.target); + dumpAst.transform(new TransformationTransferInformation(), this.target); } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { - result = null; + dumpAst = null; throw new TransformationException(e); } } - return result; - } - - private PatternCollection findOrCreateIncludePatternCollection(String typeRegex) { - PatternCollection result = buildConfig.findIncludePatternCollection(typeRegex); - if (result == null) { - TypePatternCollectionMapping mapping = new TypePatternCollectionMapping(); - mapping.setTypeRegex(typeRegex); - result = new PatternCollection(); - mapping.setPatternCollection(result); - buildConfig.addIncludeTypePattern(mapping); - } - return result; - } - - private PatternCollection findOrCreateExcludePatternCollection(String typeRegex) { - PatternCollection result = buildConfig.findExcludePatternCollection(typeRegex); - if (result == null) { - TypePatternCollectionMapping mapping = new TypePatternCollectionMapping(); - mapping.setTypeRegex(typeRegex); - result = new PatternCollection(); - mapping.setPatternCollection(result); - buildConfig.addExcludeTypePattern(mapping); - } - return result; + return dumpAst; } private void updateRegexes(Supplier<String> getter, Consumer<String> setter, String regex, String... moreRegexes) { diff --git a/dumpAst.base/src/main/resources/RelationStyle.mustache b/dumpAst.base/src/main/resources/RelationStyle.mustache new file mode 100644 index 0000000000000000000000000000000000000000..b48a25121e6fa8e4d31d1eaecbb29bb5874e444f --- /dev/null +++ b/dumpAst.base/src/main/resources/RelationStyle.mustache @@ -0,0 +1 @@ +{{#TextColor}}#text:{{{TextColor}}}{{/TextColor}}{{#LineColor}}{{#TextColor}};{{/TextColor}}{{^TextColor}}#{{/TextColor}}line:{{{LineColor}}}{{/LineColor}} \ No newline at end of file diff --git a/dumpAst.base/src/main/resources/dumpAst.mustache b/dumpAst.base/src/main/resources/dumpAst.mustache index da993c1d4d995ea2f8b15f4129207be3bc14d08a..5785dd7460dc3c35707388cb61c515679d27498d 100644 --- a/dumpAst.base/src/main/resources/dumpAst.mustache +++ b/dumpAst.base/src/main/resources/dumpAst.mustache @@ -11,57 +11,64 @@ skinparam object<<NTA>> { hide <<NTA>> stereotype {{#PrintConfig}} -scale {{{scale}}} +scale {{{Scale}}} {{#Headers}} -{{{value}}} +{{{Value}}} {{/Headers}} {{/PrintConfig}} {{#DumpNodes}} - {{^invisible}} + {{^Invisible}} {{#isNull}} -object "null" as {{{name}}}<<null>> +object "null" as {{{Name}}}<<null>> {{/isNull}} + {{#isEmpty}} +object "[]" as {{{Name}}}<<null>> + {{/isEmpty}} {{#isAstNode}} -object "{{{labelAndTextColor}}}" as {{{name}}} {{{stereotypeList}}} {{#backgroundColor}}#{{{backgroundColor}}}{{/backgroundColor}} { +object "{{{labelAndTextColor}}}" as {{{Name}}} {{{stereotypeList}}} {{#BackgroundColor}}#{{{BackgroundColor}}}{{/BackgroundColor}} { {{#DumpTokens}} {{#isDumpValueToken}} - {{{label}}} = {{{value}}} + {{{label}}} = {{{Value}}} {{/isDumpValueToken}} {{/DumpTokens}} } {{/isAstNode}} - {{/invisible}} + {{/Invisible}} {{/DumpNodes}} {{#DumpNodes}} {{#DumpTokens}} - {{^invisible}} + {{^Invisible}} {{#isList}} +circle " " as {{{Name}}} +{{{outerNodeName}}} .-[norank]-> {{{Name}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{#InnerRelationDumpNode}} {{#bothVisible}} -{{{outerNodeName}}} .[#black{{#computed}},#{{{computedColor}}}{{/computed}}{{#innerNotNull}},norank{{/innerNotNull}}].> {{{innerNodeName}}} : {{{label}}} +{{{Name}}} .{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}.> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerRelationDumpNode}} {{/isList}} {{^isList}} {{^isDumpValueToken}} -{{{outerNodeName}}} .[#black{{#computed}},#{{{computedColor}}}{{/computed}}{{#innerNotNull}},norank{{/innerNotNull}}].> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} .{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}.> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/isDumpValueToken}} {{/isList}} - {{/invisible}} + {{/Invisible}} {{/DumpTokens}} {{#DumpChildNodes}} {{#isList}} +circle " " as {{{Name}}} +{{{outerNodeName}}} *-- {{{Name}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{#InnerDumpNodes}} {{#bothVisible}} -{{{outerNodeName}}} *-{{#computed}}[#{{{computedColor}}}]{{/computed}}- {{{innerNodeName}}} : {{{label}}} +{{{Name}}} -- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} *-{{#computed}}[#{{{computedColor}}}]{{/computed}}- {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} *-- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/isList}} {{/DumpChildNodes}} @@ -69,36 +76,36 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{{stereotypeList}}} {{#backgroun {{#isList}} {{#InnerRelationDumpNode}} {{#bothVisible}} -{{{outerNodeName}}} {{#bidirectional}}<{{/bidirectional}}-{{#innerNotNull}}[norank]{{/innerNotNull}}-> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerRelationDumpNode}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} {{#bidirectional}}<{{/bidirectional}}-{{#innerNotNull}}[norank]{{/innerNotNull}}-> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/isList}} {{/DumpRelations}} - {{^invisible}} + {{^Invisible}} {{#InvisiblePath}} {{#InnerRelationDumpNode}} {{{outerNodeName}}} o.. {{{innerNodeName}}} {{/InnerRelationDumpNode}} {{/InvisiblePath}} - {{/invisible}} - {{#PrintConfig}}{{#orderChildren}} + {{/Invisible}} + {{#PrintConfig}}{{#OrderChildren}} {{#myChildren}} {{#hasSuccessor}} -{{{name}}} -[hidden]right-> {{#successor}}{{{name}}}{{/successor}} +{{{Name}}} -[hidden]right-> {{#successor}}{{{Name}}}{{/successor}} {{/hasSuccessor}} {{/myChildren}} - {{/orderChildren}}{{/PrintConfig}} + {{/OrderChildren}}{{/PrintConfig}} {{/DumpNodes}} {{#PrintConfig}} {{#debug}} legend right %date() - dumpAst: {{{version}}} + dumpAst: {{{Version}}} plantuml: %version() endlegend {{/debug}} diff --git a/dumpAst.base/src/main/resources/dumpAstVersion.properties b/dumpAst.base/src/main/resources/dumpAstVersion.properties index 810cb294c4f21dbbf55024b562596a4775489dbd..b5c044f7e5bf4da4dd7efc9699f546899abe82ff 100644 --- a/dumpAst.base/src/main/resources/dumpAstVersion.properties +++ b/dumpAst.base/src/main/resources/dumpAstVersion.properties @@ -1,2 +1,2 @@ -#Thu Sep 08 16:46:11 CEST 2022 -version=2.0.0 +#Tue Nov 22 10:54:37 CET 2022 +version=3.0.1 diff --git a/dumpAst.prototyping/src/main/jastadd/featureTest.relast b/dumpAst.prototyping/src/main/jastadd/featureTest.relast index 7e108fe9f1949e8bdffd152e20c379b3635f14cb..003417c4f9a9a6e1c5b8f1bb101a43661ccecd45 100644 --- a/dumpAst.prototyping/src/main/jastadd/featureTest.relast +++ b/dumpAst.prototyping/src/main/jastadd/featureTest.relast @@ -24,3 +24,9 @@ T3 : AbstractT ; rel AbstractT.oneA -> A ; rel AbstractT.maybeA? -> A ; rel AbstractT.manyA* -> A ; + +OtherRoot : Nameable ::= E* F*; +E : Nameable ; +F : Nameable ; + +rel E.myF* <-> F.myE* ; diff --git a/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java b/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java index 5e758f933eedc650948ffca0992da3df19f9332b..bebca7d1cfa4301d5231bf27611d1af6c5672421 100644 --- a/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java +++ b/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java @@ -9,6 +9,7 @@ import org.jastadd.featureTest.ast.*; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; /** * Main class of feature test. @@ -18,44 +19,78 @@ import java.nio.file.Paths; public class FeatureTestMain { public static void main(String[] args) throws IOException, TransformationException { + new FeatureTestMain().run(args); + } + + private void run(String[] args) throws TransformationException, IOException { + String mode = args.length == 0 ? "default" : args[0]; + System.out.println(Arrays.toString(args) + " -> " + mode); + + final DumpBuilder builder; + + switch (mode) { + case "default": + case "withRoot": + builder = withRoot(); + break; + case "withOtherRoot": + builder = withOtherRoot(); + break; + default: + throw new UnsupportedOperationException("Unknown mode: " + mode); + } + + Path pathToYaml = Paths.get("featureTest.yml"); + Path pathToPng = Paths.get("featureTest.png"); + Path pathToSvg = Paths.get("featureTest.svg"); + + builder.dumpAsYaml(pathToYaml, true); + builder.dumpAsPNG(pathToPng); + builder.dumpAsSVG(pathToSvg); + builder.dumpAsSource(Paths.get("featureTest.puml")); + } + + private DumpBuilder withRoot() { Root root = new Root(); root.setName("Root1"); A a = new A().setName("A2"); a.setB(new B().setName("B2.1")); + a.setD(new D()); // a.setMyC(new C().setName("C2.1")); -// B b1 = new B().setName("B3").setOtherValue("some long text"); + B b1 = new B().setName("B3").setOtherValue("some long text"); // C c = new C().setName("C4"); // c.setA(new A().setName("A4.1").setB(new B().setName("B4.1.1"))); // c.setRawReference(a); // b1.setOneA(a); -// B b2 = new B().setName("B5").setOtherValue("#ff00ff"); + B b2 = new B().setName("B5").setOtherValue("#ff00ff"); // C myC = new C().setName("C6"); // c.setA(new A().setName("A6.1").setB(new B().setName("B6.1.1"))); // a.setMyC(myC); root.setA(a); -// root.addB(b1); -// root.addB(b2); + root.addB(b1); + root.addB(b2); // root.setC(c); - Path pathToYaml = Paths.get("featureTest.yml"); - Path pathToPng = Paths.get("featureTest.png"); - Path pathToSvg = Paths.get("featureTest.svg"); - DumpBuilder builder = Dumper + return Dumper // .read(null) .read(root) // .enableRelationWithRank() // .customPreamble("hide empty members") .enableDebug() .customPreamble("title My fancy title") - .includeChildWhen((parentNode, childNode, contextName) -> { - if (parentNode instanceof A && ((A) parentNode).getName().equals("A2")) { - return false; + .includeChild((parentNode, childNode, contextName) -> { +// if (parentNode instanceof A && ((A) parentNode).getName().equals("A2")) { +// return false; +// } + if (parentNode instanceof Root && childNode instanceof B) { + return !"B3".equals(((B) childNode).getName()); } - return !contextName.equals("MyC"); +// return !contextName.equals("MyC"); + return true; }) - .includeRelationsWhen((sourceNode, targetNode, roleName) -> + .includeRelation((sourceNode, targetNode, roleName) -> !(sourceNode instanceof B) || !((B) sourceNode).getName().equals("B6.1.1")) - .includeAttributeWhen((node, attributeName, isNTA, supplier) -> { + .includeAttribute((node, attributeName, isNTA, supplier) -> { switch (attributeName) { case "referenceAttr": case "collectBs": @@ -69,11 +104,66 @@ public class FeatureTestMain { } }) .skinParam(SkinParamBooleanSetting.Shadowing, false) - .setNameMethod(node -> node.getClass().getSimpleName() + ASTNode.counter++); + .relationStyle((source, target, isComputed, isContainment, style) -> { + System.out.println(style.getLabel() + ", computed: " + isComputed + ", containment: " + isContainment + ", textC: " + style.getTextColor() + ", lineC: " + style.getLineColor()); + if (isContainment && target != null && style.getLabel().equals(target.getClass().getSimpleName())) { + style.setLabel(""); + } + switch (style.getLabel()) { + case "ManyA": + style.setLabel("ManyA of " + ((Nameable) source).getName()); + break; + case "OneA": + case "MaybeC?": + style.setTextColor("red"); + style.setLineColor("green"); + break; + case "B": + style.setLineColor("orange"); + style.setTextColor("orange"); + break; + case "collectBs": + style.setLineColor("purple"); + style.setTextColor("purple"); + break; + } + }) + .<ASTNode<?>>nodeStyle((node, style) -> { + if (node.isA()) { + style.setBackgroundColor("yellow"); + } + if (node instanceof B && ((B) node).getOtherValue().startsWith("#")) { + style.setBackgroundColor(((B) node).getOtherValue().substring(1)); + } + style.setLabel(node.getClass().getSimpleName() + ASTNode.counter++); + }); + } - builder.dumpAsYaml(pathToYaml, true); - builder.dumpAsPNG(pathToPng); - builder.dumpAsSVG(pathToSvg); - builder.dumpAsSource(Paths.get("featureTest.puml")); + private DumpBuilder withOtherRoot() { + OtherRoot root = new OtherRoot(); + E e1 = new E().setName("E1"); + E e2 = new E().setName("E2"); + E e3 = new E().setName("E3"); + E e4 = new E().setName("E4"); + F f1 = new F().setName("F1"); + F f2 = new F().setName("F2"); + F f3 = new F().setName("F3"); + F f4 = new F().setName("F4"); + for (E e : new E[]{e1, e2, e3, e4}) { + root.addE(e); + } + for (F f : new F[]{f1, f2, f3, f4}) { + root.addF(f); + } + e1.addMyF(f1); + e1.addMyF(f2); + e2.addMyF(f2); + e3.addMyF(f2); + + return Dumper.read(root) + .includeToken((node, tokenName, value) -> false) + .nodeStyle((node, style) -> { + style.setLabel(((Nameable) node).getName()); + }); } } diff --git a/dumpAst.tests/src/main/jastadd/testDumper.jrag b/dumpAst.tests/src/main/jastadd/testDumper.jrag index a4e17a122827b1b54a814ddd453014a9b8beda0f..2c7c539d5311542577b0ab9f4c3f6d7d4ca8084d 100644 --- a/dumpAst.tests/src/main/jastadd/testDumper.jrag +++ b/dumpAst.tests/src/main/jastadd/testDumper.jrag @@ -39,12 +39,3 @@ aspect GrammarGlobal { return result; } } - -aspect GrammarTypeLevel { - syn int AbstractT.simpleAttr() = 43; - syn nta A AbstractT.getCalculated() { - A result = new A(); - result.setName("Calculated-" + getName()); - return result; - } -} diff --git a/dumpAst.tests/src/main/jastadd/testDumper.relast b/dumpAst.tests/src/main/jastadd/testDumper.relast index cf9d37f4899b1af59099341292e3ecd111200e4d..6bdb7aabeb555cff5e8ba8b47e79dddc0bf05c1a 100644 --- a/dumpAst.tests/src/main/jastadd/testDumper.relast +++ b/dumpAst.tests/src/main/jastadd/testDumper.relast @@ -14,17 +14,6 @@ rel C.biA1 <-> A.biC1 ; rel C.biA2* <-> A.biC2 ; rel C.biA3? <-> A.biC3 ; -// testcases with type-level inclusion/exclusion -TRoot : Nameable ::= A T1 T2 T3 ; -abstract AbstractT : Nameable ::= B Bee:B* <SomeValue> <Unwanted:int> ; -T1 : AbstractT ; -T2 : AbstractT ; -T3 : AbstractT ; - -rel AbstractT.oneA -> A ; -rel AbstractT.maybeA? -> A ; -rel AbstractT.manyA* -> A ; - Position : Nameable ::= <X:double> <Y:double> <Z:double>; Size : Nameable ::= <Length:double> <Width:double> <Height:double>; Orientation : Nameable ::= <X:double> <Y:double> <Z:double> <W:double>; diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java index 23d161c3f760e74ec0e2f398ef7f4fd7e73185bd..3e49f20365ea41a83ec4a1cac5a544e26f8b7a5b 100644 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java @@ -81,10 +81,10 @@ public class TestExcluded { tuple("BiC1", C_NAME), tuple("BiC2", C_NAME), tuple("BiC3", C_NAME)); // B assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).containsExactlyInAnyOrder( - tuple("OneA", A_NAME), tuple("MaybeC", C_NAME)); + tuple("OneA", A_NAME), tuple("MaybeC?", C_NAME)); // C assertThatMapOf(normalRelationChildren(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( - tuple("BiA1", A_NAME), tuple("BiA3", A_NAME)); + tuple("BiA1", A_NAME), tuple("BiA3?", A_NAME)); assertThatMapOf(listRelationChildren(findByName(nodes, C_NAME)), "BiA2").containsExactlyInAnyOrder(A_NAME); assertThatMapOf(referenceTokens(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( tuple(TOKEN_LABEL_RAW_REFERENCE, A_NAME)); @@ -116,7 +116,7 @@ public class TestExcluded { assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, B_NAME, C_NAME); // B assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).containsExactlyInAnyOrder( - tuple("MaybeC", (C_NAME))); + tuple("MaybeC?", (C_NAME))); // C assertThat(normalRelationChildren(findByName(nodes, C_NAME))).isEmpty(); assertThat(listRelationChildren(findByName(nodes, C_NAME))).isEmpty(); @@ -198,7 +198,8 @@ public class TestExcluded { c.setBiA1(a); })); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTokens(TOKEN_LABEL_UNWANTED)); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeToken((node, tokenName, value) -> + !tokenName.equals(TOKEN_LABEL_UNWANTED))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, C_NAME); DumpNode actualC = findByName(nodes, C_NAME); assertThat(valueTokens(actualC)).containsOnly( @@ -218,7 +219,8 @@ public class TestExcluded { c.setBiA1(a); })); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTokens(TOKEN_LABEL_UNWANTED, TOKEN_LABEL_RAW_REFERENCE)); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeToken((node, tokenName, value) -> + !tokenName.equals(TOKEN_LABEL_UNWANTED) && !tokenName.equals(TOKEN_LABEL_RAW_REFERENCE))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, C_NAME); DumpNode actualC = findByName(nodes, C_NAME); assertThat(valueTokens(actualC)).containsOnly( @@ -238,7 +240,8 @@ public class TestExcluded { c.setBiA1(a); })); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTokens("bi.*")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeToken((node, tokenName, value) -> + !tokenName.startsWith("bi"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, C_NAME); DumpNode actualC = findByName(nodes, C_NAME); assertThat(valueTokens(actualC)).containsOnly( @@ -258,7 +261,8 @@ public class TestExcluded { c.setBiA1(a); })); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTokens("Bi.*")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeToken((node, tokenName, value) -> + !tokenName.startsWith("Bi"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, C_NAME); DumpNode actualC = findByName(nodes, C_NAME); assertThat(valueTokens(actualC)).containsOnly( @@ -312,7 +316,8 @@ public class TestExcluded { }), null); root.getA().getB().setOneA(root.getA().getMyC().getA()); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeChildren("MyC")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeChild((parentNode, childNode, contextName) -> + !contextName.equals("MyC"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder( ROOT_NAME, A_NAME, B_NAME, A2_Name, B2_NAME); DumpNode actualA = findByName(nodes, A_NAME); @@ -333,16 +338,17 @@ public class TestExcluded { public void testRelationsExclude() throws TransformationException { Root root = setupAllRelations(); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeRelations("BiC1")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeRelation((sourceNode, targetNode, roleName) -> + !roleName.equals("BiC1"))); // A assertThatMapOf(normalRelationChildren(findByName(nodes, A_NAME))).containsExactlyInAnyOrder( tuple("BiC2", C_NAME), tuple("BiC3", C_NAME)); // B assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).containsExactlyInAnyOrder( - tuple("OneA", A_NAME), tuple("MaybeC", C_NAME)); + tuple("OneA", A_NAME), tuple("MaybeC?", C_NAME)); // C assertThatMapOf(normalRelationChildren(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( - tuple("BiA1", A_NAME), tuple("BiA3", A_NAME)); + tuple("BiA1", A_NAME), tuple("BiA3?", A_NAME)); assertThatMapOf(listRelationChildren(findByName(nodes, C_NAME)), "BiA2").containsExactlyInAnyOrder(A_NAME); assertThatMapOf(referenceTokens(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( tuple(TOKEN_LABEL_RAW_REFERENCE, A_NAME)); @@ -352,15 +358,16 @@ public class TestExcluded { public void testRelationsExcludeRegex1() throws TransformationException { Root root = setupAllRelations(); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeRelations("Bi.*")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeRelation((sourceNode, targetNode, roleName) -> + !roleName.startsWith("Bi"))); // A assertThat(normalRelationChildren(findByName(nodes, A_NAME))).isEmpty(); // B assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).containsExactlyInAnyOrder( - tuple("OneA", A_NAME), tuple("MaybeC", C_NAME)); + tuple("OneA", A_NAME), tuple("MaybeC?", C_NAME)); // C assertThat(normalRelationChildren(findByName(nodes, C_NAME))).isEmpty(); - assertThat(listRelationChildren(findByName(nodes, C_NAME))).isEmpty(); + assertEmpty(TestUtils.findByName(nodes, C_NAME).getDumpRelation(0)); assertThatMapOf(referenceTokens(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( tuple(TOKEN_LABEL_RAW_REFERENCE, A_NAME)); } @@ -369,16 +376,17 @@ public class TestExcluded { public void testRelationsExcludeRegex2() throws TransformationException { Root root = setupAllRelations(); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeRelations(".*A.*")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeRelation((sourceNode, targetNode, roleName) -> + !roleName.contains("A"))); // A assertThatMapOf(normalRelationChildren(findByName(nodes, A_NAME))).containsExactlyInAnyOrder( tuple("BiC1", C_NAME), tuple("BiC2", C_NAME), tuple("BiC3", C_NAME)); // B assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).containsExactlyInAnyOrder( - tuple("MaybeC", C_NAME)); + tuple("MaybeC?", C_NAME)); // C assertThat(normalRelationChildren(findByName(nodes, C_NAME))).isEmpty(); - assertThat(listRelationChildren(findByName(nodes, C_NAME))).isEmpty(); + assertEmpty(TestUtils.findByName(nodes, C_NAME).getDumpRelation(0)); assertThatMapOf(referenceTokens(findByName(nodes, C_NAME))).containsExactlyInAnyOrder( tuple(TOKEN_LABEL_RAW_REFERENCE, A_NAME)); } diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java index 4d9d20e75ecb438ed0b21c04d898ec7384c6b0d4..e03718c7c9e3935507de7ca670b901e31db85a5c 100644 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java @@ -26,7 +26,8 @@ public class TestIncluded { public void testValueAttributeIncluded() throws TransformationException { Root root = createRoot(null, null); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeAttributes("simpleAttr")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> + db.includeAttribute((node, attributeName, isNTA, value) -> !isNTA && attributeName.equals("simpleAttr"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertThat(valueTokens(actualRoot)).containsOnly(entry("Name", ROOT_NAME), entry("simpleAttr", 42)); @@ -36,7 +37,8 @@ public class TestIncluded { public void testReferenceListAttributeIncluded() throws TransformationException { Root root = createRoot(null, null, createB(B1_NAME), createB(B2_NAME), createB(B3_NAME)); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeAttributes("setOfBs")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> + db.includeAttribute((node, attributeName, isNTA, value) -> !isNTA && attributeName.equals("setOfBs"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME, B1_NAME, B2_NAME, B3_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); @@ -58,7 +60,8 @@ public class TestIncluded { public void testReferenceAttributeIncluded() throws TransformationException { Root root = createRoot(createA(A_NAME), null); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeAttributes("referenceAttr")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> + db.includeAttribute((node, attributeName, isNTA, value) -> !isNTA && attributeName.equals("referenceAttr"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME, A_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertThatMapOf(referenceTokens(actualRoot)).containsOnly(tuple("referenceAttr", A_NAME)); @@ -78,7 +81,8 @@ public class TestIncluded { public void testNormalNTAIncluded() throws TransformationException { Root root = createRoot(null, createC(C_NAME)); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeNonterminalAttributes("Calculated")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> + db.includeAttribute((node, attributeName, isNTA, value) -> isNTA && attributeName.equals("Calculated"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME, C_NAME, "Calculated-" + C_NAME); DumpNode actualC = TestUtils.findByName(nodes, C_NAME); assertThatMapOf(normalChildren(actualC)).containsOnly(tuple("Calculated", "Calculated-" + C_NAME)); @@ -99,7 +103,8 @@ public class TestIncluded { public void testListNTAIncluded() throws TransformationException { Root root = createRoot(null, createC(C_NAME)); - List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeNonterminalAttributes("AlsoCalculated")); + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> + db.includeAttribute((node, attributeName, isNTA, value) -> isNTA && attributeName.equals("AlsoCalculated"))); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME, C_NAME, "AlsoCalculated-" + C_NAME); DumpNode actualC = TestUtils.findByName(nodes, C_NAME); assertThatMapOf(listChildren(actualC), "AlsoCalculated").containsExactly("AlsoCalculated-" + C_NAME); diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestRegression.java similarity index 62% rename from dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestRegression.java index 574ec066d9d04d22bfc0f3662058f0960c516d20..a7a35cdf0200dd9726bb4f8f79e7ecda1c544a30 100644 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestRegression.java @@ -6,22 +6,28 @@ import org.jastadd.testDumper.ast.DropOffLocation; import org.jastadd.testDumper.ast.Orientation; import org.jastadd.testDumper.ast.Position; import org.jastadd.testDumper.ast.Size; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*; import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; /** - * More complex test cases. + * Regression test cases. * * @author rschoene - Initial contribution */ -public class TestComplex { +public class TestRegression { @Test - public void testRegressionIssue16() throws TransformationException { + public void regressionIssue16() throws TransformationException { DropOffLocation location = new DropOffLocation(); location.setName(ROOT_NAME); location.setPosition(new Position(T1_NAME, 1, 2, 3)); @@ -35,4 +41,11 @@ public class TestComplex { entry("Y", 2.0), entry("Z", 3.0)); } + + @Test + public void regressionNoNewlineForRelationStyleMustache() throws IOException { + Path path = Paths.get("..", "dumpAst.base", "src", "main", "resources", "RelationStyle.mustache"); + List<String> lines = Files.readAllLines(path); + assertEquals(1, lines.size(), "Ensure no trailing newline in RelationStyle.mustache"); + } } diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java index 6d6294bea952209adffda3e65963e297e07f51dd..2f4224aeb3b54fcdff79f8afc2ef1992f27f70c7 100644 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java @@ -28,7 +28,7 @@ public class TestSimple { assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals(1, actualRoot.getNumDumpToken()); - assertEquals(0, actualRoot.getNumDumpChildNode()); + assertEmpty(actualRoot.getDumpChildNode(0)); assertEquals(0, actualRoot.getNumDumpRelation()); } @@ -64,7 +64,8 @@ public class TestSimple { assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals(1, actualRoot.getNumDumpToken()); - assertEquals(1, actualRoot.getNumDumpChildNode()); + assertEquals(2, actualRoot.getNumDumpChildNode()); + assertEmpty(actualRoot.getDumpChildNode(1)); assertEquals(0, actualRoot.getNumDumpRelation()); assertThatMapOf(normalChildren(actualRoot)).containsExactlyInAnyOrder(tuple("A", A_NAME)); } @@ -86,7 +87,8 @@ public class TestSimple { ); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals(1, actualRoot.getNumDumpToken()); - assertEquals(2, actualRoot.getNumDumpChildNode()); + assertEquals(3, actualRoot.getNumDumpChildNode()); + assertEmpty(actualRoot.getDumpChildNode(1)); assertEquals(0, actualRoot.getNumDumpRelation()); DumpNode actualA = TestUtils.findByName(nodes, A_NAME); @@ -152,7 +154,7 @@ public class TestSimple { assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals(1, actualRoot.getNumDumpToken()); - assertEquals(0, actualRoot.getNumDumpChildNode()); + assertEmpty(actualRoot.getDumpChildNode(0)); assertEquals(0, actualRoot.getNumDumpRelation()); assertThatMapOf(normalChildren(actualRoot)).isEmpty(); } @@ -165,9 +167,10 @@ public class TestSimple { assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, C_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals(1, actualRoot.getNumDumpToken()); - assertEquals(1, actualRoot.getNumDumpChildNode()); + assertEquals(2, actualRoot.getNumDumpChildNode()); + assertEmpty(actualRoot.getDumpChildNode(0)); assertEquals(0, actualRoot.getNumDumpRelation()); - assertThatMapOf(normalChildren(actualRoot)).containsExactlyInAnyOrder(tuple("C", C_NAME)); + assertThatMapOf(normalChildren(actualRoot)).containsExactlyInAnyOrder(tuple("C?", C_NAME)); } @Test @@ -203,7 +206,7 @@ public class TestSimple { List<DumpNode> nodes = TestUtils.dumpModel(root); assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME); DumpNode actualB = TestUtils.findByName(nodes, B_NAME); - assertThatMapOf(normalRelationChildren(actualB)).containsExactlyInAnyOrder(tuple("MaybeC", C_NAME)); + assertThatMapOf(normalRelationChildren(actualB)).containsExactlyInAnyOrder(tuple("MaybeC?", C_NAME)); } @Test @@ -245,7 +248,7 @@ public class TestSimple { DumpNode actualA = TestUtils.findByName(nodes, A_NAME); assertThatMapOf(normalRelationChildren(actualA)).containsExactlyInAnyOrder(tuple("BiC3", C_NAME)); DumpNode actualC = TestUtils.findByName(nodes, C_NAME); - assertThatMapOf(normalRelationChildren(actualC)).containsExactlyInAnyOrder(tuple("BiA3", A_NAME)); + assertThatMapOf(normalRelationChildren(actualC)).containsExactlyInAnyOrder(tuple("BiA3?", A_NAME)); } @Test @@ -282,7 +285,7 @@ public class TestSimple { Root root = createRoot(createA(A_NAME), null); List<DumpNode> nodes = TestUtils.dumpModel(root, - builder -> builder.<ASTNode<?>>setNameMethod(n -> n.isA() ? "A" : "Not A")); + builder -> builder.<ASTNode<?>>nodeStyle((node, style) -> style.setLabel(node.isA() ? "A" : "Not A"))); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals("Not A", actualRoot.getLabel()); @@ -295,7 +298,7 @@ public class TestSimple { Root root = createRoot(createA(A_NAME), null); List<DumpNode> nodes = TestUtils.dumpModel(root, - builder -> builder.<ASTNode<?>>setTextColorMethod(n -> n.isA() ? "red" : "")); + builder -> builder.<ASTNode<?>>nodeStyle((node, style) -> style.setTextColor(node.isA() ? "red" : ""))); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals("", actualRoot.getTextColor()); @@ -308,7 +311,7 @@ public class TestSimple { Root root = createRoot(createA(A_NAME), null); List<DumpNode> nodes = TestUtils.dumpModel(root, - builder -> builder.<ASTNode<?>>setBackgroundColorMethod(n -> n.isA() ? "green" : "")); + builder -> builder.<ASTNode<?>>nodeStyle((node, style) -> style.setBackgroundColor(node.isA() ? "green" : ""))); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); assertEquals("", actualRoot.getBackgroundColor()); diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java deleted file mode 100644 index 50f27583960648d90ed9434df90f39729c49ae7d..0000000000000000000000000000000000000000 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java +++ /dev/null @@ -1,222 +0,0 @@ -package de.tudresden.inf.st.jastadd.testDumper; - -import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; -import de.tudresden.inf.st.jastadd.dumpAst.ast.TransformationException; -import org.jastadd.testDumper.ast.A; -import org.jastadd.testDumper.ast.AbstractT; -import org.jastadd.testDumper.ast.TRoot; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.function.Consumer; - -import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*; -import static org.assertj.core.api.Assertions.*; - -/** - * Testing type-level exclusions. - * <p> - * Refer to {@link de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder DumpBuilder} for levels of inclusion/exclusion. - * - * @author rschoene - Initial contribution - */ -public class TestTypeLevel3 { - - @Test - public void testTokenLevel2Excluded() throws TransformationException { - Consumer<AbstractT> setUnwanted = t -> t.setUnwanted(5); - TRoot root = createTRoot(createA(A_NAME), createT1(setUnwanted), createT2(setUnwanted), createT3(setUnwanted)); - Assertions.assertEquals(5, root.getT2().getUnwanted()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, dp -> dp.excludeTokens("Unwanted")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = TestUtils.findByName(nodes, name); - assertThat(valueTokens(actualTx)).containsOnly(entry("Name", name)); - } - } - - @Test - public void testTokenLevel3SomeIncluded() throws TransformationException { - Consumer<AbstractT> setUnwanted = t -> t.setUnwanted(5); - TRoot root = createTRoot(createA(A_NAME), createT1(setUnwanted), createT2(setUnwanted), createT3(setUnwanted)); - Assertions.assertEquals(5, root.getT2().getUnwanted()); - - List<DumpNode> nodesT2 = TestUtils.dumpModel(root, - dp -> dp.excludeTokens("Unwanted") - .includeTokensFor("T2", "Unwanted")); - assertThat(nodesT2).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(TestUtils.findByName(nodesT2, T1_NAME))).containsOnly( - entry("Name", T1_NAME)); - assertThat(valueTokens(TestUtils.findByName(nodesT2, T2_NAME))).containsOnly( - entry("Name", T2_NAME), entry("Unwanted", 5)); - assertThat(valueTokens(TestUtils.findByName(nodesT2, T3_NAME))).containsOnly( - entry("Name", T3_NAME)); - - List<DumpNode> nodesT2T3 = TestUtils.dumpModel(root, - dp -> dp.excludeTokens("Unwanted") - .includeTokensFor("T2|T3", "Unwanted")); - assertThat(nodesT2T3).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(TestUtils.findByName(nodesT2T3, T1_NAME))).containsOnly( - entry("Name", T1_NAME)); - assertThat(valueTokens(TestUtils.findByName(nodesT2T3, T2_NAME))).containsOnly( - entry("Name", T2_NAME), entry("Unwanted", 5)); - assertThat(valueTokens(TestUtils.findByName(nodesT2T3, T3_NAME))).containsOnly( - entry("Name", T3_NAME), entry("Unwanted", 5)); - } - - @Test - public void testNormalChildLevel2Excluded() throws TransformationException { - Consumer<AbstractT> setB = t -> t.setB(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(setB), createT2(setB), createT3(setB)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getB().getName()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, dp -> dp.excludeChildren("B")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = TestUtils.findByName(nodes, name); - assertThat(normalChildren(actualTx)).isEmpty(); - } - } - - @Test - public void testNormalChildLevel3SomeIncluded() throws TransformationException { - Consumer<AbstractT> setB = t -> t.setB(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(setB), createT2(setB), createT3(setB)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getB().getName()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.excludeChildren("B") - .includeChildrenFor("T2", "B")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T2_NAME + B_NAME); - assertThat(normalChildren(TestUtils.findByName(nodes, T1_NAME))).isEmpty(); - assertThatMapOf(normalChildren(TestUtils.findByName(nodes, T2_NAME))).containsOnly( - tuple("B", T2_NAME + B_NAME)); - assertThat(normalChildren(TestUtils.findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testListChildLevel2Excluded() throws TransformationException { - Consumer<AbstractT> addBee = t -> t.addBee(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(addBee), createT2(addBee), createT3(addBee)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getBee(0).getName()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.excludeChildren("Bee")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - assertThat(listChildren(TestUtils.findByName(nodes, name))).isEmpty(); - } - } - - @Test - public void testListChildLevel3SomeIncluded() throws TransformationException { - Consumer<AbstractT> addBee = t -> t.addBee(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(addBee), createT2(addBee), createT3(addBee)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getBee(0).getName()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.excludeChildren("Bee") - .includeChildrenFor("T2", "Bee")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T2_NAME + B_NAME); - assertThat(listChildren(TestUtils.findByName(nodes, T1_NAME))).isEmpty(); - assertThatMapOf(listChildren(TestUtils.findByName(nodes, T2_NAME)), "Bee").containsOnly( - T2_NAME + B_NAME); - assertThat(listChildren(TestUtils.findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testRelationLevel2Excluded() throws TransformationException { - final A a = createA(A_NAME); - Consumer<AbstractT> setOneA = t -> t.setOneA(a); - TRoot root = createTRoot(a, createT1(setOneA), createT2(setOneA), createT3(setOneA)); - Assertions.assertEquals(a, root.getT2().getOneA()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, dp -> dp.excludeRelations("OneA")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = TestUtils.findByName(nodes, name); - assertThat(normalRelationChildren(actualTx)).isEmpty(); - } - } - - @Test - public void testRelationLevel3SomeIncluded() throws TransformationException { - final A a = createA(A_NAME); - Consumer<AbstractT> setOneA = t -> t.setOneA(a); - TRoot root = createTRoot(a, createT1(setOneA), createT2(setOneA), createT3(setOneA)); - Assertions.assertEquals(a, root.getT2().getOneA()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.excludeRelations("OneA") - .includeRelationsFor("T2", "OneA")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(normalRelationChildren(TestUtils.findByName(nodes, T1_NAME))).isEmpty(); - assertThatMapOf(normalRelationChildren(TestUtils.findByName(nodes, T2_NAME))).containsOnly( - tuple("OneA", A_NAME)); - assertThat(normalRelationChildren(TestUtils.findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testAttributeLevel2Included() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.includeAttributes("simpleAttr")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = findByName(nodes, name); - assertThat(valueTokens(actualTx)).containsOnly( - entry("Name", name), - entry(TOKEN_LABEL_UNWANTED, 0), - entry("simpleAttr", 43)); - } - } - - @Test - public void testAttributeLevel3SomeExcluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.includeAttributes("simpleAttr") - .excludeAttributesFor("T2", "simpleAttr")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(findByName(nodes, T1_NAME))).containsOnly( - entry("Name", T1_NAME), entry(TOKEN_LABEL_UNWANTED, 0), entry("simpleAttr", 43)); - assertThat(valueTokens(findByName(nodes, T2_NAME))).containsOnly( - entry("Name", T2_NAME), entry(TOKEN_LABEL_UNWANTED, 0)); - assertThat(valueTokens(findByName(nodes, T3_NAME))).containsOnly( - entry("Name", T3_NAME), entry(TOKEN_LABEL_UNWANTED, 0), entry("simpleAttr", 43)); - } - - @Test - public void testNTALevel2Included() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.includeNonterminalAttributes("Calculated")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, "Calculated-" + T1_NAME, "Calculated-" + T2_NAME, "Calculated-" + T3_NAME); - for (String name : Tx_NAMES) { - assertThatMapOf(normalChildren(findByName(nodes, name))).containsOnly( - tuple("Calculated", "Calculated-" + name)); - } - } - - @Test - public void testNTALevel3SomeExcluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.includeNonterminalAttributes("Calculated") - .excludeNonterminalAttributesFor("T2", "Calculated")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, "Calculated-" + T1_NAME, "Calculated-" + T3_NAME); - assertThatMapOf(normalChildren(findByName(nodes, T1_NAME))).containsOnly( - tuple("Calculated", "Calculated-" + T1_NAME)); - assertThat(normalChildren(findByName(nodes, T2_NAME))).isEmpty(); - assertThatMapOf(normalChildren(findByName(nodes, T3_NAME))).containsOnly( - tuple("Calculated", "Calculated-" + T3_NAME)); - } - -} diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java deleted file mode 100644 index 8e9220a270c3fe96df2a767d37b565f077c64d55..0000000000000000000000000000000000000000 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java +++ /dev/null @@ -1,245 +0,0 @@ -package de.tudresden.inf.st.jastadd.testDumper; - -import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; -import de.tudresden.inf.st.jastadd.dumpAst.ast.TransformationException; -import org.jastadd.testDumper.ast.A; -import org.jastadd.testDumper.ast.AbstractT; -import org.jastadd.testDumper.ast.TRoot; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.function.Consumer; - -import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*; -import static org.assertj.core.api.Assertions.*; - -/** - * Testing type-level inclusions. - * <p> - * Refer to {@link de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder DumpBuilder} for levels of inclusion/exclusion. - * - * @author rschoene - Initial contribution - */ -public class TestTypeLevel4 { - - @Test - public void testTokenLevel3Included() throws TransformationException { - Consumer<AbstractT> setUnwanted = t -> t.setUnwanted(5); - TRoot root = createTRoot(createA(A_NAME, createC(C_NAME, c -> c.setUnwanted(6))), - createT1(setUnwanted), createT2(setUnwanted), createT3(setUnwanted)); - Assertions.assertEquals(5, root.getT2().getUnwanted()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeTokens(TOKEN_LABEL_UNWANTED) - .includeTokensFor("T.", TOKEN_LABEL_UNWANTED)); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder( - ROOT_NAME, A_NAME, C_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = findByName(nodes, name); - assertThat(valueTokens(actualTx)).containsOnly(entry("Name", name), entry(TOKEN_LABEL_UNWANTED, 5)); - } - assertThat(valueTokens(findByName(nodes, C_NAME))).containsOnly( - entry("Name", C_NAME)); - } - - @Test - public void testTokenLevel4SomeExcluded() throws TransformationException { - Consumer<AbstractT> setUnwanted = t -> t.setUnwanted(5); - TRoot root = createTRoot(createA(A_NAME, createC(C_NAME, c -> c.setUnwanted(6))), - createT1(setUnwanted), createT2(setUnwanted), createT3(setUnwanted)); - Assertions.assertEquals(5, root.getT2().getUnwanted()); - - List<DumpNode> nodesT2 = dumpModel(root, - dp -> dp.excludeTokens(TOKEN_LABEL_UNWANTED) - .includeTokensFor("T.", TOKEN_LABEL_UNWANTED) - .excludeTokensFor("T3", TOKEN_LABEL_UNWANTED)); - assertThat(nodesT2).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder( - ROOT_NAME, A_NAME, C_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(findByName(nodesT2, T1_NAME))).containsOnly( - entry("Name", T1_NAME), entry(TOKEN_LABEL_UNWANTED, 5)); - assertThat(valueTokens(findByName(nodesT2, T2_NAME))).containsOnly( - entry("Name", T2_NAME), entry(TOKEN_LABEL_UNWANTED, 5)); - assertThat(valueTokens(findByName(nodesT2, T3_NAME))).containsOnly( - entry("Name", T3_NAME)); - assertThat(valueTokens(findByName(nodesT2, C_NAME))).containsOnly( - entry("Name", C_NAME)); - - List<DumpNode> nodesT2T3 = dumpModel(root, - dp -> dp.excludeTokens(TOKEN_LABEL_UNWANTED) - .includeTokensFor("T.", TOKEN_LABEL_UNWANTED) - .excludeTokensFor("T2|T3", TOKEN_LABEL_UNWANTED)); - assertThat(nodesT2T3).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder( - ROOT_NAME, A_NAME, C_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(findByName(nodesT2T3, T1_NAME))).containsOnly( - entry("Name", T1_NAME), entry(TOKEN_LABEL_UNWANTED, 5)); - assertThat(valueTokens(findByName(nodesT2T3, T2_NAME))).containsOnly( - entry("Name", T2_NAME)); - assertThat(valueTokens(findByName(nodesT2T3, T3_NAME))).containsOnly( - entry("Name", T3_NAME)); - assertThat(valueTokens(findByName(nodesT2T3, C_NAME))).containsOnly( - entry("Name", C_NAME)); - } - - @Test - public void testNormalChildLevel3Included() throws TransformationException { - Consumer<AbstractT> setB = t -> t.setB(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(setB), createT2(setB), createT3(setB)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getB().getName()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeChildren("B") - .includeChildrenFor("T.", "B")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T1_NAME + B_NAME, T2_NAME + B_NAME, T3_NAME + B_NAME); - for (String name : Tx_NAMES) { - assertThatMapOf(normalChildren(findByName(nodes, name))).containsOnly( - tuple("B", name + B_NAME)); - } - } - - @Test - public void testNormalChildLevel4SomeExcluded() throws TransformationException { - Consumer<AbstractT> setB = t -> t.setB(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(setB), createT2(setB), createT3(setB)); - Assertions.assertEquals(T2_NAME + B_NAME, root.getT2().getB().getName()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeChildren("B") - .includeChildrenFor("T.", "B") - .excludeChildrenFor("T3", "B")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T1_NAME + B_NAME, T2_NAME + B_NAME); - assertThatMapOf(normalChildren(findByName(nodes, T1_NAME))).containsOnly( - tuple("B", T1_NAME + B_NAME)); - assertThatMapOf(normalChildren(findByName(nodes, T2_NAME))).containsOnly( - tuple("B", T2_NAME + B_NAME)); - assertThat(normalChildren(findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testListChildLevel3Included() throws TransformationException { - Consumer<AbstractT> addBee = t -> t.addBee(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(addBee), createT2(addBee), createT3(addBee)); - Assertions.assertEquals(T3_NAME + B_NAME, root.getT3().getBee(0).getName()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeChildren("Bee") - .includeChildrenFor("T.", "Bee")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T1_NAME + B_NAME, T2_NAME + B_NAME, T3_NAME + B_NAME); - for (String name : Tx_NAMES) { - assertThatMapOf(listChildren(findByName(nodes, name)), "Bee").containsOnly( - name + B_NAME); - } - } - - @Test - public void testListChildLevel4SomeExcluded() throws TransformationException { - Consumer<AbstractT> addBee = t -> t.addBee(createB(t.getName() + B_NAME)); - TRoot root = createTRoot(createA(A_NAME), createT1(addBee), createT2(addBee), createT3(addBee)); - Assertions.assertEquals(T3_NAME + B_NAME, root.getT3().getBee(0).getName()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeChildren("Bee") - .includeChildrenFor("T.", "Bee") - .excludeChildrenFor("T3", "Bee")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, T1_NAME + B_NAME, T2_NAME + B_NAME); - assertThatMapOf(listChildren(findByName(nodes, T1_NAME)), "Bee").containsOnly( - T1_NAME + B_NAME); - assertThatMapOf(listChildren(findByName(nodes, T2_NAME)), "Bee").containsOnly( - T2_NAME + B_NAME); - assertThat(listChildren(findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testRelationLevel3Included() throws TransformationException { - final A a = createA(A_NAME); - Consumer<AbstractT> setOneA = t -> t.setOneA(a); - TRoot root = createTRoot(a, createT1(setOneA), createT2(setOneA), createT3(setOneA)); - Assertions.assertEquals(a, root.getT2().getOneA()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeRelations("OneA") - .includeRelationsFor("T2", "OneA")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(normalRelationChildren(findByName(nodes, T1_NAME))).isEmpty(); - assertThatMapOf(normalRelationChildren(findByName(nodes, T2_NAME))).containsOnly( - tuple("OneA", A_NAME)); - assertThat(normalRelationChildren(findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testRelationLevel4SomeExcluded() throws TransformationException { - final A a = createA(A_NAME); - Consumer<AbstractT> setOneA = t -> t.setOneA(a); - TRoot root = createTRoot(a, createT1(setOneA), createT2(setOneA), createT3(setOneA)); - Assertions.assertEquals(a, root.getT2().getOneA()); - - List<DumpNode> nodes = dumpModel(root, - dp -> dp.excludeRelations("OneA") - .includeRelationsFor("T.", "OneA") - .excludeRelationsFor("T3", "OneA")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThatMapOf(normalRelationChildren(findByName(nodes, T1_NAME))).containsOnly( - tuple("OneA", A_NAME)); - assertThatMapOf(normalRelationChildren(findByName(nodes, T2_NAME))).containsOnly( - tuple("OneA", A_NAME)); - assertThat(normalRelationChildren(findByName(nodes, T3_NAME))).isEmpty(); - } - - @Test - public void testAttributeLevel3Excluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.includeAttributes("simpleAttr") - .excludeAttributesFor("T.", "simpleAttr")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - for (String name : Tx_NAMES) { - DumpNode actualTx = TestUtils.findByName(nodes, name); - assertThat(valueTokens(actualTx)).containsOnly( - entry("Name", name), entry(TOKEN_LABEL_UNWANTED, 0)); - } - } - - @Test - public void testAttributeLevel4SomeIncluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.includeAttributes("simpleAttr") - .excludeAttributesFor("T.", "simpleAttr") - .includeAttributesFor("T3", "simpleAttr")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - assertThat(valueTokens(TestUtils.findByName(nodes, T1_NAME))).containsOnly( - entry("Name", T1_NAME), entry(TOKEN_LABEL_UNWANTED, 0)); - assertThat(valueTokens(TestUtils.findByName(nodes, T2_NAME))).containsOnly( - entry("Name", T2_NAME), entry(TOKEN_LABEL_UNWANTED, 0)); - assertThat(valueTokens(TestUtils.findByName(nodes, T3_NAME))).containsOnly( - entry("Name", T3_NAME), entry(TOKEN_LABEL_UNWANTED, 0), entry("simpleAttr", 43)); - } - - @Test - public void testNTALevel3Excluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.includeNonterminalAttributes("Calculated") - .excludeNonterminalAttributesFor("T.", "Calculated")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME); - DumpNode actualT3 = TestUtils.findByName(nodes, T3_NAME); - assertThat(normalChildren(actualT3)).isEmpty(); - } - - @Test - public void testNTALevel4SomeIncluded() throws TransformationException { - TRoot root = createTRoot(createA(A_NAME), createT1(), createT2(), createT3()); - - List<DumpNode> nodes = TestUtils.dumpModel(root, - dp -> dp.includeNonterminalAttributes("Calculated") - .excludeNonterminalAttributesFor("T.", "Calculated") - .includeNonterminalAttributesFor("T3", "Calculated")); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, T1_NAME, T2_NAME, T3_NAME, "Calculated-" + T3_NAME); - DumpNode actualT3 = TestUtils.findByName(nodes, T3_NAME); - assertThatMapOf(normalChildren(actualT3)).containsOnly(tuple("Calculated", "Calculated-" + T3_NAME)); - } - -} diff --git a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java index 70213c50de832d945eca1cb8afa891656fc78896..c1228e049963fbd6ff22c85eea49e50b9a58af98 100644 --- a/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java @@ -11,7 +11,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Function; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.*; public class TestUtils { public static final Random rand = new Random(); @@ -30,7 +30,6 @@ public class TestUtils { public static final String T1_NAME = "T1" + Integer.toHexString(rand.nextInt(0xFFFFFF)); public static final String T2_NAME = "T2" + Integer.toHexString(rand.nextInt(0xFFFFFF)); public static final String T3_NAME = "T3" + Integer.toHexString(rand.nextInt(0xFFFFFF)); - public static final String[] Tx_NAMES = {T1_NAME, T2_NAME, T3_NAME}; public static Root createRoot(A a, C c, B... bs) { Root result = new Root(); @@ -92,50 +91,9 @@ public class TestUtils { return result; } - public static TRoot createTRoot(A a, T1 t1, T2 t2, T3 t3) { - TRoot result = new TRoot(); - result.setName(ROOT_NAME); - if (a != null) { - result.setA(a); - } - if (t1 != null) { - result.setT1(t1); - } - if (t2 != null) { - result.setT2(t2); - } - if (t3 != null) { - result.setT3(t3); - } - return result; - } - - @SafeVarargs - public static T1 createT1(Consumer<AbstractT>... additionalSettings) { - return setupAbstractT(new T1(), T1_NAME, additionalSettings); - } - - @SafeVarargs - public static T2 createT2(Consumer<AbstractT>... additionalSettings) { - return setupAbstractT(new T2(), T2_NAME, additionalSettings); - } - - @SafeVarargs - public static T3 createT3(Consumer<AbstractT>... additionalSettings) { - return setupAbstractT(new T3(), T3_NAME, additionalSettings); - } - - private static <T extends AbstractT> T setupAbstractT(T t, String name, Consumer<AbstractT>[] additionalSettings) { - t.setName(name); - for (Consumer<AbstractT> setting : additionalSettings) { - setting.accept(t); - } - return t; - } - public static final Function<DumpNode, String> NAME_EXTRACTOR = node -> { for (DumpToken dumpToken : node.getDumpTokenList()) { - if (dumpToken.getName().equals("Name")) { + if (dumpToken.getLabel().equals("Name")) { return dumpToken.asDumpValueToken().getValue().toString(); } } @@ -150,6 +108,16 @@ public class TestUtils { return Assertions.assertThat(map.get(key)).flatExtracting(NAME_EXTRACTOR); } + public static void assertEmpty(DumpChildNode node) { + assertEquals(1, node.asDumpListChildNode().getNumInnerDumpNode()); + assertTrue(node.asDumpListChildNode().getInnerDumpNode(0).getDumpNode().isEmpty()); + } + + public static void assertEmpty(DumpRelation node) { + assertEquals(1, node.asDumpListRelation().getNumInnerRelationDumpNode()); + assertTrue(node.asDumpListRelation().getInnerRelationDumpNode(0).getDumpNode().isEmpty()); + } + public static List<DumpNode> dumpModel(Object target) throws TransformationException { return dumpModel(target, db -> {}); } @@ -188,7 +156,7 @@ public class TestUtils { // then it is a DumpNormalChildNode DumpNode target = ((DumpNormalChildNode) dumpChildNode).getDumpNode(); if (target != null && !target.getInvisible()) { - result.put(dumpChildNode.getName(), target); + result.put(dumpChildNode.getLabel(), target); } } } @@ -202,7 +170,7 @@ public class TestUtils { // then it is a DumpListChildNode ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner -> { if (inner.getDumpNode() != null && !inner.getDumpNode().getInvisible()) { - result.computeIfAbsent(dumpChildNode.getName(), key -> new ArrayList<>()).add(inner.getDumpNode()); + result.computeIfAbsent(dumpChildNode.getLabel(), key -> new ArrayList<>()).add(inner.getDumpNode()); } }); } @@ -217,7 +185,7 @@ public class TestUtils { // then it is a DumpNormalRelation DumpNode target = ((DumpNormalRelation) dumpRelation).getDumpNode(); if (!target.getInvisible()) { - result.put(dumpRelation.getName(), target); + result.put(dumpRelation.getLabel(), target); } } } @@ -231,7 +199,7 @@ public class TestUtils { // then it is a DumpListRelation ((DumpListRelation) dumpRelation).getInnerRelationDumpNodeList().forEach(inner -> { if (!inner.getDumpNode().getInvisible()) { - result.computeIfAbsent(dumpRelation.getName(), key -> new ArrayList<>()).add(inner.getDumpNode()); + result.computeIfAbsent(dumpRelation.getLabel(), key -> new ArrayList<>()).add(inner.getDumpNode()); } }); } @@ -244,9 +212,9 @@ public class TestUtils { for (DumpToken dumpToken : node.getDumpTokenList()) { if (!dumpToken.isDumpValueToken() && !dumpToken.isList()) { // then it is a DumpReferenceToken - DumpNode target = ((DumpReferenceToken) dumpToken).getValue(); + DumpNode target = ((DumpReferenceToken) dumpToken).getDumpNode(); if (!target.getInvisible()) { - result.put(dumpToken.getName(), target); + result.put(dumpToken.getLabel(), target); } } } @@ -260,7 +228,7 @@ public class TestUtils { // then it is a DumpReferenceListToken ((DumpReferenceListToken) dumpToken).getInnerRelationDumpNodeList().forEach(inner -> { if (!inner.getDumpNode().getInvisible()) { - result.computeIfAbsent(dumpToken.getName(), key -> new ArrayList<>()).add(inner.getDumpNode()); + result.computeIfAbsent(dumpToken.getLabel(), key -> new ArrayList<>()).add(inner.getDumpNode()); } }); } @@ -274,7 +242,7 @@ public class TestUtils { if (dumpToken.isDumpValueToken()) { // then it is a DumpValueToken DumpValueToken dumpValueToken = (DumpValueToken) dumpToken; - result.put(dumpValueToken.getName(), dumpValueToken.getValue()); + result.put(dumpValueToken.getLabel(), dumpValueToken.getValue()); } } return result; diff --git a/pages/docs/adding.md b/pages/docs/adding.md index 2e2f9a84375a501e95467de1af6bd37e7f53d265..1babfde845699342c88a73f89413c80b72970496 100644 --- a/pages/docs/adding.md +++ b/pages/docs/adding.md @@ -4,7 +4,7 @@ Check the [package overview page](https://git-st.inf.tu-dresden.de/jastadd/dumpA To use `dumpAst`, adjust your `build.gradle` as follows. -Set up the maven package source as repository: +Set up the maven package source as a repository: ``` repositories { @@ -19,7 +19,7 @@ Add `dumpAst` as a dependency: ``` dependencies { - implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: '1.2.0' + implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: '{{dumpAst_version()}}' } ``` @@ -38,7 +38,7 @@ ls dumpAst.base/build/libs/ This jar can then be copied to your project. ```bash -cp dumpAst.base/build/libs/dumpAst.base-fatJar-<version>.jar ../your-project/libs/dumpAst.jar +cp dumpAst.base/build/libs/dumpAst.base-fatJar-{{dumpAst_version()}}.jar ../your-project/libs/dumpAst.jar cd ../your-project/ ``` diff --git a/pages/docs/img/ST-black.png b/pages/docs/img/ST-black.png new file mode 100644 index 0000000000000000000000000000000000000000..1dff814753e73b1d10ddd456817e6d72ee7b82e2 Binary files /dev/null and b/pages/docs/img/ST-black.png differ diff --git a/pages/docs/index.md b/pages/docs/index.md index 0910060203c01660960cf1904dcb8fe0a5ee3537..3d61a112efba6697ffab2feda8a1ff0b859ff515 100644 --- a/pages/docs/index.md +++ b/pages/docs/index.md @@ -1,6 +1,6 @@ # DumpAst -The tool called `DumpAst` ([see in repo](https://git-st.inf.tu-dresden.de/jastadd/dumpAst)) is used to create a snapshot of an AST and visualize it. +The tool called `DumpAst` ([see in repo](https://git-st.inf.tu-dresden.de/jastadd/dumpAst)) is used to create a snapshot of an AST and visualise it.  @@ -17,6 +17,6 @@ Then, read in the ASTNode in question: Dumper.read(astNode) ``` -Using the return value (a `DumpBuilder`), use methods to filter out unwanted parts, add styling or other settings. +Using the return value (a `DumpBuilder`), use methods to filter out unwanted parts and add styling or other settings. All methods can be chained together. -Please see the [API documentation](ragdoc/index.html) for more details. +Please see [the subpage on using DumpAst](using.md) and the [API documentation](ragdoc/index.html) for more details. diff --git a/pages/docs/using.md b/pages/docs/using.md new file mode 100644 index 0000000000000000000000000000000000000000..f01ec77314b2cd245ca6e197dd0019852f99a2ca --- /dev/null +++ b/pages/docs/using.md @@ -0,0 +1,65 @@ +# Using DumpAst + +After [adding DumpAst to your project](adding.md), you can start getting snapshot of some (part of an) AST. +Here is one example with a `Model` containing nodes of type `Robot`, `Joint` and `EndEffector` amongst others. +It is explained in detail below. + +```java +import de.tudresden.inf.st.jastadd.dumpAst.ast.*; + +import your.model.Robot; +import your.model.Model; +import your.model.ASTNode; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class Main { + public static void main(String[] args) throws IOException, TransformationException { + Model model = createModel(); // (1) + + DumpBuilder builder = Dumper.read(model) // (2) + .includeChild((parentNode, childNode, contextName) -> { // (3) + if (parentNode instanceof Robot && ((Robot) parentNode).getName().equals("Robot2")) { + return false; + } + return !contextName.equals("EndEffector"); + }) + .nodeStyle((node, style) -> { + style.useSimpleName(); // (4) + style.setBackgroundColor(node.size() > 30 ? "blue" : "white"); // (5) + }) + .relationStyle((source, target, isComputed, isContainment, style) -> { + if (style.getLabel().equals("EndEffector")) { + style.setLabel(""); // (6) + } + }) + .skinParam(SkinParamBooleanSetting.Shadowing, false); // (7) + builder.dumpAsPng(Paths.get("featureTest.png")); // (8) + builder.dumpAsSVG(Paths.get("featureTest.svg")); // (9) + OutputStream os = getMyOutputStream(); + builder.dumpAsPNG(os); // (10) + } +} +``` + +DumpAst uses the [Builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern) as well as a [fluent API](https://en.wikipedia.org/wiki/Fluent_interface). +That means, first, all settings are specified (2-6), and only after a "dump"-method is called (7,8) the actual snapshot is taken. +For filtering the output, there are various lambda functions (`include___`). +Those methods are available for children, attributes, relations and tokens. +By default, all children, relations and tokens are included in the output, whereas all attributes are excluded. + +The steps in detail: + +- (1) In the beginning, your model is somehow constructed and changed. This is indicated with the method `createModel`. +- (2) The first call is always `Dumper.read()` to which the (part of the) AST is provided as an argument. It returns an object of type [DumpBuilder](../ragdoc/#/type/DumpBuilder). With this object, the output can be changed. +- (3) [Optional] You can only include nodes of certain types by using `includeChild` and passing a lambda function, which is called for every node and should return `true` if the `childNode` shall be included in the output. It defaults to returning `true` for every node. Here, all children of a `Robot` node (except if the name of the robot is `"Robot2"`) and all children of the context named `"EndEffector"` are excluded. +- (4) and (5) [Optional] To style a node, the method `nodeStyle` is used. It accepts a lambda function, in which the style of every node can be customized by calling methods on the given `Style` object, e.g. setting the name (5) or background color (6). The default name is to use the class name along with the hashcode of the object (`node == null ? "null" : node.getClass().getSimpleName() + "@" + Integer.toHexString(node.hashCode())`). +- (6) [Optional] To style a relation, the method `relationStyle` is used. It is used similar to `nodeStyle`, but is called with source and target node of a relation (containment and non-containment). Note, that (a) the default label can be retrieved with `style.getLabel()`, (b) `target` can be `null` for lists, (c) secondary connections from a list node to the target nodes use the style of the relation and use their index as label. +- (7) [Optional] There are a few ways to style the output in general through [SkinParam](https://plantuml.com/de/skinparam). Not all of those parameters are supported; see `SkinParamBooleanSetting` and `SkinParamStringSetting`. +- (8), (9) and (10) To create an output image, use `dumpAsPng` for PNG (`dumpAsSVG` for SVG). Those methods do not return the builder object, as they produce an output. They potentially throw two kinds of exception: `IOException` (when the file could not be written) and `TransformationException` (when the AST could not be processed). As shown here, the builder object must be stored in a variable to create multiple outputs. Alternatively to a file, the result can be written to a given `OutputStream` (10). + +To summarise the required steps: Specify the AST to read in, configure the output, and write ("dump") the output. +For more configuration options, please consult the [API Docs of DumpBuilder](../ragdoc/#/type/DumpBuilder) or check out [FeatureTestMain](https://git-st.inf.tu-dresden.de/jastadd/dumpAst/-/blob/main/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java). diff --git a/pages/mkdocs.yml b/pages/mkdocs.yml index ac59250d32152419ed9a44f44d83207f2d954397..6f315aca9d3fd598aeae76d279fc9d57b9315fea 100644 --- a/pages/mkdocs.yml +++ b/pages/mkdocs.yml @@ -5,11 +5,26 @@ site_dir: ../public nav: - "DumpAst": index.md - "Add to your project": adding.md + - "Using DumpAst": using.md - "API documentation": ragdoc/index.html theme: - name: readthedocs - custom_dir: custom_theme/ + name: material + font: false + palette: + # Palette toggle for light mode + - scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + # Palette toggle for dark mode + - scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode + favicon: img/ST-black.png + icon: + logo: material/dump-truck markdown_extensions: - toc: diff --git a/pages/requirements.txt b/pages/requirements.txt index d5ae2cc06eb26afe413c3bb61d067fb9f4d1db58..25d7d3180e71c0bcdc15dc8bf7d53d08dec06173 100644 --- a/pages/requirements.txt +++ b/pages/requirements.txt @@ -1,5 +1,7 @@ -mkdocs==1.2.2 -mkdocs-git-revision-date-localized-plugin==0.10.3 -mkdocs-macros-plugin==0.6.3 -Jinja2==2.11.2 -MarkupSafe==1.1.1 +mkdocs==1.4.2 +mkdocs-git-revision-date-localized-plugin==1.1.0 +mkdocs-macros-plugin==0.7.0 +mkdocs-material==8.5.10 +mkdocs-material-extensions==1.1 +Jinja2==3.1.2 +MarkupSafe==2.1.1