diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst/src/main/jastadd/DumpAst.relast index 7a3e31f2cfc389af9e9cd14228697b59c5929dc1..6e640de4559dd6055123c34d9e8d5415abcafb97 100644 --- a/dumpAst/src/main/jastadd/DumpAst.relast +++ b/dumpAst/src/main/jastadd/DumpAst.relast @@ -1,12 +1,15 @@ DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ; rel DumpAst.RootNode -> DumpNode ; -BuildConfig ::= GlobalPatternCollection:PatternCollection ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* <TypeIgnorePattern> <IncludeEmptyString:boolean> <Debug:boolean> ; +BuildConfig ::= GlobalPatternCollection:PatternCollection StyleInformation ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* <TypeIgnorePattern> <IncludeEmptyString:boolean> <Debug:boolean>; TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ; PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ; +StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod>; + PrintConfig ::= <Scale:double> <Version> Header* ; Header ::= <Value> ; -DumpNode ::= <Name> <Label> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ; + +DumpNode ::= <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ; InnerDumpNode ; rel InnerDumpNode.DumpNode -> DumpNode ; diff --git a/dumpAst/src/main/jastadd/GenerationBackend.jadd b/dumpAst/src/main/jastadd/GenerationBackend.jadd index ce550ca7fc0cdc85e7326a649635b7cba8a1698f..d9ba8d9c3dd7280632eb496a2fdd18be437e52ac 100644 --- a/dumpAst/src/main/jastadd/GenerationBackend.jadd +++ b/dumpAst/src/main/jastadd/GenerationBackend.jadd @@ -40,101 +40,104 @@ aspect GenerationBackend { } else { node = new DumpNode(); node.setObject(obj); - node.setLabel(objClassName + "@" + obj.hashCode()); node.setName("node" + tti.transformed.size()); tti.transformed.put(obj, node); this.addDumpNode(node); } - if (node.isAstNode()) { - // do not process node further if coming from a relation - if (source == Source.RELATION) { - tti.relationTargetsUnprocessed.put(node, true); - return node; + if (!node.isAstNode()) { + return node; + } + node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj)); + node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj)); + node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj)); + // do not process node further if coming from a relation + if (source == Source.RELATION) { + tti.relationTargetsUnprocessed.put(node, true); + return node; + } + if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) { + node.setInvisible(true); + } + final ClassAnalysisResult car = analyzeClass(obj.getClass()); + // -- singleChild -- + for (SingleChildMethod singleChildMethod : car.singleChildMethods()) { + Object target = singleChildMethod.getMethod().invoke(obj); + String childName = singleChildMethod.getName(); + DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName))); + if (target != null && targetNode != null) { + DumpNormalChildNode normalChild = new DumpNormalChildNode(); + normalChild.setName(childName); + normalChild.setDumpNode(targetNode); + normalChild.setComputed(singleChildMethod.isNTASingleChildMethod()); + node.addDumpChildNode(normalChild); } - if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) { - node.setInvisible(true); - } - final ClassAnalysisResult car = analyzeClass(obj.getClass()); - // -- singleChild -- - for (SingleChildMethod singleChildMethod : car.singleChildMethods()) { - Object target = singleChildMethod.getMethod().invoke(obj); - String childName = singleChildMethod.getName(); - DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName))); + } + // -- listChild -- + for (ListChildMethod listChildMethod : car.listChildMethods()) { + Iterable<?> targetList = (Iterable<?>) listChildMethod.getMethod().invoke(obj); + DumpListChildNode listChild = new DumpListChildNode(); + listChild.setComputed(listChildMethod.isNTAListChildMethod()); + String childName = listChildMethod.getName(); + boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName); + listChild.setName(childName); + for (Object target : targetList) { + DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble)); if (target != null && targetNode != null) { - DumpNormalChildNode normalChild = new DumpNormalChildNode(); - normalChild.setName(childName); - normalChild.setDumpNode(targetNode); - normalChild.setComputed(singleChildMethod.isNTASingleChildMethod()); - node.addDumpChildNode(normalChild); + listChild.addInnerDumpNode(new InnerDumpNode(targetNode)); } } - // -- listChild -- - for (ListChildMethod listChildMethod : car.listChildMethods()) { - Iterable<?> targetList = (Iterable<?>) listChildMethod.getMethod().invoke(obj); - DumpListChildNode listChild = new DumpListChildNode(); - listChild.setComputed(listChildMethod.isNTAListChildMethod()); - String childName = listChildMethod.getName(); - boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName); - listChild.setName(childName); - for (Object target : targetList) { - DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble)); - if (target != null && targetNode != null) { - listChild.addInnerDumpNode(new InnerDumpNode(targetNode)); - } - } - if (listChild.getNumInnerDumpNode() > 0) { - node.addDumpChildNode(listChild); - } + if (listChild.getNumInnerDumpNode() > 0) { + node.addDumpChildNode(listChild); } - // -- singleRelation -- - for (SingleRelationMethod singleRelationMethod : car.singleRelationMethods()) { - Object target = singleRelationMethod.getMethod().invoke(obj); + } + // -- singleRelation -- + for (SingleRelationMethod singleRelationMethod : car.singleRelationMethods()) { + Object target = singleRelationMethod.getMethod().invoke(obj); + DumpNode targetNode = transform(tti, target, Source.RELATION); + if (target != null && targetNode != null) { + DumpNormalRelation normalRelation = new DumpNormalRelation(); + normalRelation.setName(singleRelationMethod.getName()); + normalRelation.setDumpNode(targetNode); + node.addDumpRelation(normalRelation); + } + } + // -- listRelation -- + for (ListRelationMethod listRelationMethod : car.listRelationMethods()) { + Iterable<?> targetList = (Iterable<?>) listRelationMethod.getMethod().invoke(obj); + DumpListRelation listRelation = new DumpListRelation(); + listRelation.setName(listRelationMethod.getName()); + for (Object target : targetList) { DumpNode targetNode = transform(tti, target, Source.RELATION); if (target != null && targetNode != null) { - DumpNormalRelation normalRelation = new DumpNormalRelation(); - normalRelation.setName(singleRelationMethod.getName()); - normalRelation.setDumpNode(targetNode); - node.addDumpRelation(normalRelation); + listRelation.addInnerDumpNode(new InnerDumpNode(targetNode)); } } - // -- listRelation -- - for (ListRelationMethod listRelationMethod : car.listRelationMethods()) { - Iterable<?> targetList = (Iterable<?>) listRelationMethod.getMethod().invoke(obj); - DumpListRelation listRelation = new DumpListRelation(); - listRelation.setName(listRelationMethod.getName()); - for (Object target : targetList) { - DumpNode targetNode = transform(tti, target, Source.RELATION); - if (target != null && targetNode != null) { - listRelation.addInnerDumpNode(new InnerDumpNode(targetNode)); - } - } - if (listRelation.getNumInnerDumpNode() > 0) { - node.addDumpRelation(listRelation); - } + if (listRelation.getNumInnerDumpNode() > 0) { + node.addDumpRelation(listRelation); } - // -- token -- - for (TokenMethod tokenMethod : car.tokenMethods()) { - Object target = tokenMethod.getMethod().invoke(obj); - if (target != null) { - DumpNode targetNode = transform(tti, target, Source.RELATION); - DumpToken token = null; - // TODO check, if Iterable.isAssignableFrom(target.getClass()). - // if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's - if (targetNode != null && targetNode.isAstNode()) { - token = new DumpReferenceToken().setValue(targetNode); - } else { - if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) { - DumpValueToken valueToken = new DumpValueToken(); - valueToken.setValue(target); - token = valueToken; - } - } - if (token != null) { - token.setName(tokenMethod.getName()); - token.setComputed(tokenMethod.isAttributeMethod()); - node.addDumpToken(token); + } + // -- token -- + for (TokenMethod tokenMethod : car.tokenMethods()) { + Object target = tokenMethod.getMethod().invoke(obj); + if (target != null) { + DumpNode targetNode = transform(tti, target, Source.RELATION); + DumpToken token = null; + // TODO check, if Iterable.isAssignableFrom(target.getClass()). + // if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's + if (targetNode != null && targetNode.isAstNode()) { + token = new DumpReferenceToken().setValue(targetNode); + } else { + if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) { + DumpValueToken valueToken = new DumpValueToken(); + valueToken.setValue(target); + token = valueToken; } } + if (token != null) { + token.setName(tokenMethod.getName()); + token.setComputed(tokenMethod.isAttributeMethod()); + node.addDumpToken(token); + } } } return node; @@ -450,6 +453,14 @@ aspect GenerationBackend { return result; } + syn String DumpNode.labelAndTextColor() { + if (getTextColor().isEmpty()) { + return getLabel(); + } else { + return "<color:" + getTextColor() + ">" + getLabel() + "</color>"; + } + } + class TransformationTransferInformation { java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>(); java.util.Map<DumpNode, Boolean> relationTargetsUnprocessed = new java.util.HashMap<>(); @@ -558,4 +569,17 @@ aspect GenerationBackend { public void close() { } } + + static StyleInformation StyleInformation.createDefault() { + StyleInformation result = new StyleInformation(); + result.setNameMethod(n -> n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode())); + result.setBackgroundColorMethod(n -> ""); + result.setTextColorMethod(n -> ""); + return result; + } + + @FunctionalInterface + public interface StyleMethod<ASTNODE> { + String get(ASTNODE node); + } } diff --git a/dumpAst/src/main/jastadd/GenerationFrontend.jadd b/dumpAst/src/main/jastadd/GenerationFrontend.jadd index 26466b1cd9ae3b1aa6cb9dec45acccd8437a2dfc..8fd24b449c6226cc784d95e82c494252f2b10715 100644 --- a/dumpAst/src/main/jastadd/GenerationFrontend.jadd +++ b/dumpAst/src/main/jastadd/GenerationFrontend.jadd @@ -62,6 +62,7 @@ public class DumpBuilder { this.target = target; buildConfig = new BuildConfig(); buildConfig.setGlobalPatternCollection(new PatternCollection()); + buildConfig.setStyleInformation(StyleInformation.createDefault()); printConfig = new PrintConfig(); printConfig.setScale(1); printConfig.setVersion(readVersion()); @@ -321,6 +322,21 @@ public class DumpBuilder { return this; } + public <ASTNODE> DumpBuilder setNameMethod(StyleMethod<ASTNODE> nameMethod) { + buildConfig.getStyleInformation().setNameMethod(nameMethod); + return this; + } + + public <ASTNODE> DumpBuilder setBackgroundColorMethod(StyleMethod<ASTNODE> colorMethod) { + buildConfig.getStyleInformation().setBackgroundColorMethod(colorMethod); + return this; + } + + public <ASTNODE> DumpBuilder setTextColorMethod(StyleMethod<ASTNODE> colorMethod) { + buildConfig.getStyleInformation().setTextColorMethod(colorMethod); + return this; + } + public DumpBuilder setScale(double value) { printConfig.setScale(value); return this; diff --git a/dumpAst/src/main/resources/dumpAst.mustache b/dumpAst/src/main/resources/dumpAst.mustache index b0c05305e6ff1c6431d593d7628101c90b3230bc..b15a984f7cf81a153569b39faa4f71353605583d 100644 --- a/dumpAst/src/main/resources/dumpAst.mustache +++ b/dumpAst/src/main/resources/dumpAst.mustache @@ -9,7 +9,7 @@ scale {{Scale}} {{#DumpNodes}} {{#isAstNode}} {{^Invisible}} -object "{{label}}" as {{name}} { +object "{{{labelAndTextColor}}}" as {{name}} {{#backgroundColor}}#{{{backgroundColor}}}{{/backgroundColor}} { {{#DumpTokens}} {{#isDumpValueToken}} {{label}} = {{{Value}}} diff --git a/testDumper/src/main/jastadd/testDumper.jrag b/testDumper/src/main/jastadd/testDumper.jrag index a0ef867b1fe9da0ef2b7f5c91cb9cfc9877800ea..4cedce8cfa75749d2fb90adcb0ef5766e36e0ca1 100644 --- a/testDumper/src/main/jastadd/testDumper.jrag +++ b/testDumper/src/main/jastadd/testDumper.jrag @@ -29,6 +29,9 @@ aspect GrammarGlobal { syn int Root.simpleAttr() = 42; syn A Root.referenceAttr() = getA(); + + syn boolean ASTNode.isA() = false; + eq A.isA() = true; } aspect GrammarTypeLevel { diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java index fc3d4c80558d64cf5dc882522e8afd11db04258a..f7699f6ab2aff927b2ef9ef05847e69b0a564a0c 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java @@ -30,6 +30,7 @@ public class TestDumperMain { TestUtils.ExposingDumpBuilder builder = new TestUtils.ExposingDumpBuilder(root); builder.includeAttributes("simpleAttr") .includeNonterminalAttributes("getCalculated"); + builder.setNameMethod(n -> n.getClass().getSimpleName()); System.out.println(">> PlantUml"); System.out.println(builder.build().toPlantUml()); diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java index 507250f1e1dc2b74c794f8b1980a550d105913d5..fd6c961ee329df3ab36c7e477858dcf4de68fec7 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java @@ -1,10 +1,7 @@ package de.tudresden.inf.st.jastadd.testDumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; -import org.jastadd.testDumper.ast.C; -import org.jastadd.testDumper.ast.D; -import org.jastadd.testDumper.ast.Root; -import org.jastadd.testDumper.ast.SubC; +import org.jastadd.testDumper.ast.*; import org.junit.jupiter.api.Test; import java.util.List; @@ -183,4 +180,43 @@ public class TestSimple { entry(TOKEN_LABEL_UNWANTED, 5)); } + @Test + public void testLabel() { + Root root = createRoot(createA(A_NAME), null); + + List<DumpNode> nodes = TestUtils.dumpModel(root, + builder -> builder.<ASTNode<?>>setNameMethod(n -> n.isA() ? "A" : "Not A")); + DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); + assertEquals("Not A", actualRoot.getLabel()); + + DumpNode actualA = TestUtils.findByName(nodes, A_NAME); + assertEquals("A", actualA.getLabel()); + } + + @Test + public void testTextColor() { + Root root = createRoot(createA(A_NAME), null); + + List<DumpNode> nodes = TestUtils.dumpModel(root, + builder -> builder.<ASTNode<?>>setTextColorMethod(n -> n.isA() ? "red" : "")); + DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); + assertEquals("", actualRoot.getTextColor()); + + DumpNode actualA = TestUtils.findByName(nodes, A_NAME); + assertEquals("red", actualA.getTextColor()); + } + + @Test + public void testBackgroundColor() { + Root root = createRoot(createA(A_NAME), null); + + List<DumpNode> nodes = TestUtils.dumpModel(root, + builder -> builder.<ASTNode<?>>setBackgroundColorMethod(n -> n.isA() ? "green" : "")); + DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); + assertEquals("", actualRoot.getBackgroundColor()); + + DumpNode actualA = TestUtils.findByName(nodes, A_NAME); + assertEquals("green", actualA.getBackgroundColor()); + } + }