diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst/src/main/jastadd/DumpAst.relast index f1b76ce06860a121b868cdb47844d2fc33c70083..730a4245e198b562ba06b1591c91dfe73285a3b3 100644 --- a/dumpAst/src/main/jastadd/DumpAst.relast +++ b/dumpAst/src/main/jastadd/DumpAst.relast @@ -2,7 +2,7 @@ DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ; BuildConfig ::= <TypeIgnore> <TokenIgnore> <ChildIgnore> <AttributeIgnore> <RelationIgnore> <IncludeEmptyString:boolean> <Debug:boolean> ; PrintConfig ::= <Scale:double> <Version> Header* ; Header ::= <Value> ; -DumpNode ::= <Name> <Label> <Object:Object> DumpChildNode* DumpToken* DumpRelation* ; +DumpNode ::= <Name> <Label> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ; InnerDumpNode ; rel InnerDumpNode.DumpNode -> DumpNode ; @@ -20,3 +20,6 @@ abstract DumpRelation ::= <Name> <Bidirectional:boolean> ; DumpNormalRelation : DumpRelation ; rel DumpNormalRelation.DumpNode -> DumpNode ; DumpListRelation : DumpRelation ::= InnerDumpNode* ; + +// type of NTA +InvisiblePath ::= InnerDumpNode* ; diff --git a/dumpAst/src/main/jastadd/Generation.jadd b/dumpAst/src/main/jastadd/Generation.jadd index 06a8d254b133ff843108a6c02602b19167e1d282..38c7db06366d76ea4062b8a475e119966bff3388 100644 --- a/dumpAst/src/main/jastadd/Generation.jadd +++ b/dumpAst/src/main/jastadd/Generation.jadd @@ -54,6 +54,7 @@ import java.lang.String;aspect GenerationFrontend { /** * Exclude object with types matching at least one of the given regex strings. + * Exlcuding object won't be included in any output. However, their children are still processed. * @param regexes patterns to match type names * @return this * @see java.util.regex.Pattern#compile(java.lang.String) @@ -166,16 +167,17 @@ aspect GenerationBackend { if (tti.transformed.containsKey(obj)) { return tti.transformed.get(obj); } - if (matches(getBuildConfig().typeIgnorePattern(), obj.getClass().getSimpleName())) { - tti.transformed.put(obj, null); - return null; - } +// tti.transformed.put(obj, null); +// return null; DumpNode node = new DumpNode(); node.setObject(obj); node.setLabel(obj.getClass().getSimpleName() + "@" + obj.hashCode()); node.setName("node" + tti.transformed.size()); tti.transformed.put(obj, node); this.addDumpNode(node); + if (matches(getBuildConfig().typeIgnorePattern(), obj.getClass().getSimpleName())) { + node.setInvisible(true); + } if (node.isAstNode()) { // only caching node.analyseClass does not help, since we want to do this only once per class of a node final ClassAnalysisResult car; @@ -370,6 +372,7 @@ aspect GenerationBackend { return (String) annotation.annotationType().getMethod("name").invoke(annotation); } + // --- isAstNode --- syn boolean DumpNode.isAstNode() { Class<?> clazz = getObject().getClass(); for (java.lang.reflect.Constructor<?> constructor : clazz.getConstructors()) { @@ -383,9 +386,34 @@ aspect GenerationBackend { return false; } + // --- astNodeAnnotationPrefix --- inh String DumpNode.astNodeAnnotationPrefix(); eq DumpAst.getDumpNode().astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation"; + // --- NTA: InvisiblePath --- + syn InvisiblePath DumpNode.getInvisiblePath() { + InvisiblePath result = new InvisiblePath(); + for (DumpNode successor : reachableThroughInvisible()) { + result.addInnerDumpNode(new InnerDumpNode(successor)); + } + return result; + } + + // --- reachableThroughInvisible --- + syn java.util.List<DumpNode> DumpNode.reachableThroughInvisible() { + java.util.List<DumpNode> result = new java.util.ArrayList<>(); + for (DumpChildNode childNode : getDumpChildNodeList()) { + for (DumpNode inner : childNode.innerNodes(false)) { + if (inner.getInvisible()) { + result.addAll(inner.reachableThroughInvisible()); + } else if (this.getInvisible()) { + result.add(inner); + } + } + } + return result; + } + class TransformationTransferInformation { java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>(); java.util.Map<Class<?>, ClassAnalysisResult> classAnalysisResults = new java.util.HashMap<>(); diff --git a/dumpAst/src/main/jastadd/Navigation.jrag b/dumpAst/src/main/jastadd/Navigation.jrag index a8adbd2246cb45d06fb74cf1f0ed8e260afc8f42..e03dbf37a0d9c7a615de6f7641fb730460b4199b 100644 --- a/dumpAst/src/main/jastadd/Navigation.jrag +++ b/dumpAst/src/main/jastadd/Navigation.jrag @@ -20,4 +20,50 @@ aspect Navigation { // --- printConfig --- inh PrintConfig BuildConfig.printConfig(); eq DumpAst.getChild().printConfig() = getPrintConfig(); + + // --- containingDumpNode --- + inh DumpNode InnerDumpNode.containingDumpNode(); + inh DumpNode DumpChildNode.containingDumpNode(); + inh DumpNode DumpRelation.containingDumpNode(); + eq DumpNode.getDumpChildNode().containingDumpNode() = this; + eq DumpNode.getDumpRelation().containingDumpNode() = this; + eq DumpNode.getInvisiblePath().containingDumpNode() = this; + + // --- innerVisibleNodes --- + syn java.util.List<DumpNode> DumpChildNode.innerVisibleNodes() = innerNodes(true); + syn java.util.List<DumpNode> DumpRelation.innerVisibleNodes() = innerNodes(true); + + // --- innerNodes --- + syn java.util.List<DumpNode> DumpChildNode.innerNodes(boolean onlyVisible); + eq DumpNormalChildNode.innerNodes(boolean onlyVisible) = onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ? + java.util.Collections.emptyList() : + java.util.Collections.singletonList(getDumpNode()); + eq DumpListChildNode.innerNodes(boolean onlyVisible) { + if (onlyVisible && containingDumpNode().getInvisible()) { + return java.util.Collections.emptyList(); + } + java.util.List<DumpNode> result = new java.util.ArrayList<>(); + getInnerDumpNodeList().forEach(inner -> { + if (!onlyVisible || !inner.getDumpNode().getInvisible()) { + result.add(inner.getDumpNode()); + } + }); + return result; + } + syn java.util.List<DumpNode> DumpRelation.innerNodes(boolean onlyVisible); + eq DumpNormalRelation.innerNodes(boolean onlyVisible) = onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ? + java.util.Collections.emptyList() : + java.util.Collections.singletonList(getDumpNode()); + eq DumpListRelation.innerNodes(boolean onlyVisible) { + if (onlyVisible && containingDumpNode().getInvisible()) { + return java.util.Collections.emptyList(); + } + java.util.List<DumpNode> result = new java.util.ArrayList<>(); + getInnerDumpNodeList().forEach(inner -> { + if (!onlyVisible || !inner.getDumpNode().getInvisible()) { + result.add(inner.getDumpNode()); + } + }); + return result; + } } diff --git a/dumpAst/src/main/jastadd/Printing.jrag b/dumpAst/src/main/jastadd/Printing.jrag index c41f02b1052560ba2bba70e84943d98a16f7c40b..a2ba999560eb4f412895b9236016581affd2647f 100644 --- a/dumpAst/src/main/jastadd/Printing.jrag +++ b/dumpAst/src/main/jastadd/Printing.jrag @@ -20,4 +20,9 @@ aspect Printing { syn String DumpRelation.label() = getName(); syn String DumpToken.label() = getName(); syn String DumpNode.label() = getLabel(); + + // --- bothVisible --- + syn boolean InnerDumpNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); + syn boolean DumpNormalChildNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); + syn boolean DumpNormalRelation.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); } diff --git a/dumpAst/src/main/resources/dumpAst.mustache b/dumpAst/src/main/resources/dumpAst.mustache index 6b375b3706e4223af9143e095664265950d7ac2e..b8105eef93ba3054c4ff207abf38c233af8e0cb7 100644 --- a/dumpAst/src/main/resources/dumpAst.mustache +++ b/dumpAst/src/main/resources/dumpAst.mustache @@ -8,6 +8,7 @@ scale {{Scale}} {{#DumpNodes}} {{#isAstNode}} +{{^Invisible}} object "{{label}}" as {{name}} { {{#DumpTokens}} {{#isDumpValueToken}} @@ -15,35 +16,53 @@ object "{{label}}" as {{name}} { {{/isDumpValueToken}} {{/DumpTokens}} } +{{/Invisible}} {{/isAstNode}} {{/DumpNodes}} {{#DumpNodes}} {{#DumpTokens}} +{{^Invisible}} {{^isDumpValueToken}} {{outerNodeName}} ..> {{innerNodeName}} : {{label}} {{/isDumpValueToken}} +{{/Invisible}} {{/DumpTokens}} {{#DumpChildNodes}} {{#isList}} {{#InnerDumpNodes}} +{{#bothVisible}} {{outerNodeName}} *-- {{innerNodeName}} : {{label}} +{{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} +{{#bothVisible}} {{outerNodeName}} *-- {{innerNodeName}} : {{label}} +{{/bothVisible}} {{/isList}} {{/DumpChildNodes}} {{#DumpRelations}} {{#isList}} {{#InnerDumpNodes}} +{{#bothVisible}} {{outerNodeName}} {{#Bidirectional}}<{{/Bidirectional}}--> {{innerNodeName}} : {{label}} +{{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} +{{#bothVisible}} {{outerNodeName}} {{#Bidirectional}}<{{/Bidirectional}}--> {{innerNodeName}} : {{label}} +{{/bothVisible}} {{/isList}} {{/DumpRelations}} +{{^Invisible}} +{{#InvisiblePath}} +{{#InnerDumpNodes}} +{{outerNodeName}} o.. {{innerNodeName}} +{{/InnerDumpNodes}} +{{/InvisiblePath}} +{{/Invisible}} {{/DumpNodes}} {{#BuildConfig}} {{#Debug}} diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java index 16fc3b69aeda5496b62cfcb18f59540ad42c49e9..9e25685b089420f784648c8dddac2540f26722a2 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java @@ -2,9 +2,13 @@ package de.tudresden.inf.st.jastadd.testDumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; +import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper; +import org.jastadd.testDumper.ast.A; import org.jastadd.testDumper.ast.Root; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.nio.file.Paths; import java.util.List; import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*; @@ -65,11 +69,11 @@ public class TestExcluded { Root root = setupTypes(); List<DumpNode> nodes = TestUtils.dumpModel(root); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME); assertTypeDefaultMatches(nodes); } private void assertTypeDefaultMatches(List<DumpNode> nodes) { - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME); // A assertThatMapOf(normalRelationChildren(findByName(nodes, A_NAME))).containsExactlyInAnyOrder( tuple("BiC1", C_NAME), tuple("BiC2", C_NAME), tuple("BiC3", C_NAME)); @@ -89,6 +93,7 @@ public class TestExcluded { Root root = setupTypes(); List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("NonExistingType")); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME); assertTypeDefaultMatches(nodes); } @@ -97,6 +102,7 @@ public class TestExcluded { Root root = setupTypes(); List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("Nameable")); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME); assertTypeDefaultMatches(nodes); } @@ -135,6 +141,44 @@ public class TestExcluded { assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).isEmpty(); } + @Test + public void testTypesExcludeRegex() { + Root root = setupTypes(); + + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("Ro*t")); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(A_NAME, B_NAME, C_NAME); + assertTypeDefaultMatches(nodes); + } + + @Test + public void testTypesInvisiblePath() throws IOException { + final String A2_Name = "a2"; + final String A3_Name = "a3"; + final String C2_Name = "c2"; + A mostInnerA = createA(A3_Name); + mostInnerA.setB(createB(B_NAME)); + Root root = createRoot(createA(A_NAME, + createC(C_NAME, + createA(A2_Name, + createC(C2_Name, mostInnerA)))), + null); + + List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("A", "C")); + Dumper.read(root).excludeTypes("A", "C").dumpAsPNG(Paths.get("test.png")); + DumpNode actualRoot = findByName(nodes, ROOT_NAME); + assertThat(invisiblePath(actualRoot)).flatExtracting(NAME_EXTRACTOR).containsExactly(B_NAME); + } + + @Test + public void testTokenDefault() { + + } + + @Test + public void testTokenExclude() { + + } + // --- copy from below here --- @Test diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java index f35e1cdfdbbcf7a5f6d990e51cfc0475386997f3..1398494b9b4a3be62f84196285641723f63b529a 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java @@ -14,7 +14,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Function; -import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertFalse; public class TestUtils { public static final Random rand = new Random(); @@ -50,6 +50,13 @@ public class TestUtils { return result; } + public static A createA(String name, C myC) { + A result = new A(); + result.setName(name); + result.setMyC(myC); + return result; + } + public static B createB(String name) { B result = new B(); result.setName(name); @@ -69,8 +76,15 @@ public class TestUtils { return result; } - public static final Function<DumpNode, String> NAME_EXTRACTOR = dp -> { - for (DumpToken dumpToken : dp.getDumpTokenList()) { + public static C createC(String name, A optA) { + C result = new C(); + result.setName(name); + result.setA(optA); + return result; + } + + public static final Function<DumpNode, String> NAME_EXTRACTOR = node -> { + for (DumpToken dumpToken : node.getDumpTokenList()) { if (dumpToken.getName().equals("Name")) { return dumpToken.asDumpValueToken().getValue().toString(); } @@ -99,9 +113,11 @@ public class TestUtils { ExposingDumpBuilder builder = new ExposingDumpBuilder(target); options.accept(builder); DumpAst dumpAst = builder.build(); + // let mustache run, but ignore result + dumpAst.toPlantUml(); List<DumpNode> result = new ArrayList<>(); for (DumpNode dumpNode : dumpAst.getDumpNodeList()) { - if (dumpNode.isAstNode()) { + if (dumpNode.isAstNode() && !dumpNode.getInvisible()) { result.add(dumpNode); } } @@ -124,7 +140,10 @@ public class TestUtils { for (DumpChildNode dumpChildNode : node.getDumpChildNodeList()) { if (!dumpChildNode.isList()) { // then it is a DumpNormalChildNode - result.put(dumpChildNode.label(), ((DumpNormalChildNode) dumpChildNode).getDumpNode()); + DumpNode target = ((DumpNormalChildNode) dumpChildNode).getDumpNode(); + if (!target.getInvisible()) { + result.put(dumpChildNode.label(), target); + } } } return result; @@ -135,8 +154,11 @@ public class TestUtils { for (DumpChildNode dumpChildNode : node.getDumpChildNodeList()) { if (dumpChildNode.isList()) { // then it is a DumpListChildNode - ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner -> - result.computeIfAbsent(dumpChildNode.label(), key -> new ArrayList<>()).add(inner.getDumpNode())); + ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner -> { + if (!inner.getDumpNode().getInvisible()) { + result.computeIfAbsent(dumpChildNode.label(), key -> new ArrayList<>()).add(inner.getDumpNode()); + } + }); } } return result; @@ -147,7 +169,10 @@ public class TestUtils { for (DumpRelation dumpRelation : node.getDumpRelationList()) { if (!dumpRelation.isList()) { // then it is a DumpNormalRelation - result.put(dumpRelation.label(), ((DumpNormalRelation) dumpRelation).getDumpNode()); + DumpNode target = ((DumpNormalRelation) dumpRelation).getDumpNode(); + if (!target.getInvisible()) { + result.put(dumpRelation.label(), target); + } } } return result; @@ -158,8 +183,11 @@ public class TestUtils { for (DumpRelation dumpRelation : node.getDumpRelationList()) { if (dumpRelation.isList()) { // then it is a DumpListRelation - ((DumpListRelation) dumpRelation).getInnerDumpNodeList().forEach( - inner -> result.computeIfAbsent(dumpRelation.label(), key -> new ArrayList<>()).add(inner.getDumpNode())); + ((DumpListRelation) dumpRelation).getInnerDumpNodeList().forEach(inner -> { + if (!inner.getDumpNode().getInvisible()) { + result.computeIfAbsent(dumpRelation.label(), key -> new ArrayList<>()).add(inner.getDumpNode()); + } + }); } } return result; @@ -170,7 +198,10 @@ public class TestUtils { for (DumpToken dumpToken : node.getDumpTokenList()) { if (!dumpToken.isDumpValueToken()) { // then it is a DumpReferenceToken - result.put(dumpToken.label(), ((DumpReferenceToken) dumpToken).getValue()); + DumpNode target = ((DumpReferenceToken) dumpToken).getValue(); + if (!target.getInvisible()) { + result.put(dumpToken.label(), target); + } } } return result; @@ -188,6 +219,16 @@ public class TestUtils { return result; } + public static List<DumpNode> invisiblePath(DumpNode node) { + List<DumpNode> result = new ArrayList<>(); + for (InnerDumpNode inner : node.getInvisiblePath().getInnerDumpNodeList()) { + DumpNode target = inner.getDumpNode(); + assertFalse(target.getInvisible()); + result.add(target); + } + return result; + } + static class ExposingDumpBuilder extends DumpBuilder { protected ExposingDumpBuilder(Object target) {