Commit 3c10ba2e authored by René Schöne's avatar René Schöne
Browse files

Make label and colors configurable.

- let user set label, text color and background color with generic lambda function
parent 05cf8d56
Pipeline #12722 passed with stages
in 2 minutes and 18 seconds
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 ;
......
......@@ -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);
}
}
......@@ -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;
......
......@@ -9,7 +9,7 @@ scale {{Scale}}
{{#DumpNodes}}
{{#isAstNode}}
{{^Invisible}}
object "{{label}}" as {{name}} {
object "{{{labelAndTextColor}}}" as {{name}} {{#backgroundColor}}#{{{backgroundColor}}}{{/backgroundColor}} {
{{#DumpTokens}}
{{#isDumpValueToken}}
{{label}} = {{{Value}}}
......
......@@ -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 {
......
......@@ -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());
......
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());
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment