From c469a7d9f0d5c70dcbdfa8c3de95f6a7414f4f12 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Wed, 12 Oct 2022 17:01:07 +0200 Subject: [PATCH] 3.0.0 - prepare new release - finished styling of lists --- dumpAst.base/src/main/jastadd/DumpAst.relast | 18 +-- .../src/main/jastadd/GeneratedNavigation.jrag | 13 ++ dumpAst.base/src/main/jastadd/Navigation.jrag | 5 +- .../src/main/jastadd/TemplateContext.jrag | 32 +++-- dumpAst.base/src/main/jastadd/ToYaml.jrag | 43 ++++--- dumpAst.base/src/main/jastadd/Transform.jadd | 119 +++++++++++------- .../src/main/jastadd/TransformPlus.jadd | 24 +++- .../src/main/resources/dumpAst.mustache | 16 +-- .../src/main/jastadd/featureTest.relast | 6 + .../jastadd/featureTest/FeatureTestMain.java | 96 +++++++++++--- .../inf/st/jastadd/testDumper/TestUtils.java | 2 +- pages/docs/using.md | 6 +- 12 files changed, 253 insertions(+), 127 deletions(-) diff --git a/dumpAst.base/src/main/jastadd/DumpAst.relast b/dumpAst.base/src/main/jastadd/DumpAst.relast index e6b8d57..572b8b9 100644 --- a/dumpAst.base/src/main/jastadd/DumpAst.relast +++ b/dumpAst.base/src/main/jastadd/DumpAst.relast @@ -5,24 +5,24 @@ DumpNode ::= DumpChildNode* DumpToken* DumpRelation* <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> <Computed:boolean> <ManualStereotypes> /InvisiblePath/ ; -InnerDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; +InnerDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; //TODO remove colors (and label?) rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner? ; -InnerRelationDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; +InnerRelationDumpNode ::= <OriginalIndex:int> <Label> <LineColor> <TextColor> ; //TODO remove colors (and label?) rel InnerRelationDumpNode.DumpNode <-> DumpNode.ContainerOfRelationInner* ; -abstract DumpChildNode ::= <Label> <Computed:boolean> ; -DumpNormalChildNode : DumpChildNode ::= <LineColor> <TextColor> ; +abstract DumpChildNode ::= <Label> <Computed:boolean> <LineColor> <TextColor> ; +DumpNormalChildNode : DumpChildNode ::= ; rel DumpNormalChildNode.DumpNode <-> DumpNode.ContainerOfNormalChild? ; DumpListChildNode : DumpChildNode ::= InnerDumpNode* <Name> ; abstract DumpToken ::= <Label> <Computed:boolean> ; -DumpReferenceToken : DumpToken ; -rel DumpReferenceToken.Value -> DumpNode ; -DumpReferenceListToken : DumpToken ::= InnerRelationDumpNode* <Name> ; +DumpReferenceToken : DumpToken ::= <LineColor> <TextColor> ; +rel DumpReferenceToken.DumpNode -> DumpNode ; +DumpReferenceListToken : DumpToken ::= InnerRelationDumpNode* <Name> <LineColor> <TextColor> ; DumpValueToken : DumpToken ::= <Value:Object> ; -abstract DumpRelation ::= <Label> <Bidirectional:boolean> ; -DumpNormalRelation : DumpRelation ::= <LineColor> <TextColor> ; +abstract DumpRelation ::= <Label> <Bidirectional:boolean> <LineColor> <TextColor> ; +DumpNormalRelation : DumpRelation ::= ; rel DumpNormalRelation.DumpNode -> DumpNode ; DumpListRelation : DumpRelation ::= InnerRelationDumpNode* <Name> ; diff --git a/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag index 723bfba..c7ab004 100644 --- a/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag +++ b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag @@ -108,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' */ @@ -233,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 2c420a7..2bdae26 100644 --- a/dumpAst.base/src/main/jastadd/Navigation.jrag +++ b/dumpAst.base/src/main/jastadd/Navigation.jrag @@ -14,6 +14,7 @@ aspect Navigation { inh BuildConfig InnerRelationDumpNode.buildConfig(); inh BuildConfig DumpChildNode.buildConfig(); inh BuildConfig DumpRelation.buildConfig(); + inh BuildConfig DumpToken.buildConfig(); eq DumpAst.getChild().buildConfig() = getBuildConfig(); // --- printConfig --- @@ -29,6 +30,8 @@ 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; @@ -101,7 +104,7 @@ aspect Navigation { // --- innerNotNullOrEmpty --- syn boolean DumpNormalRelation.innerNotNullOrEmpty() = !printConfig().getRelationWithRank() && getDumpNode() != null && getDumpNode().getObject() != null && getDumpNode().getObject() != DumpAst.EMPTY; - syn boolean DumpReferenceToken.innerNotNullOrEmpty() = !printConfig().getRelationWithRank() && getValue() != null && getValue().getObject() != null && getValue().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 === diff --git a/dumpAst.base/src/main/jastadd/TemplateContext.jrag b/dumpAst.base/src/main/jastadd/TemplateContext.jrag index db8fb1d..f7c0941 100644 --- a/dumpAst.base/src/main/jastadd/TemplateContext.jrag +++ b/dumpAst.base/src/main/jastadd/TemplateContext.jrag @@ -41,24 +41,24 @@ aspect TemplateContext { 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(); + syn String DumpReferenceToken.innerNodeName() = getDumpNode().name(); // --- label --- - syn String DumpChildNode.label() = getLabel() + (getComputed() ? "()" : ""); - syn String DumpRelation.label() = getLabel(); - syn String DumpToken.label() = getLabel() + (getComputed() ? "()" : ""); - syn String DumpNode.label() = getLabel(); + 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 - (inner.getDumpNode().isEmpty() ? "" : "[" + chooseIndex(inner.getOriginalIndex(), index) + "]"); + return safeLabel( + (inner.getDumpNode().isEmpty() ? "" : "[" + chooseIndex(inner.getOriginalIndex(), index) + "]")); } eq DumpListRelation.getInnerRelationDumpNode(int index).label() { InnerRelationDumpNode inner = getInnerRelationDumpNode(index); - return (inner.isComputed() ? " " : inner.getLabel()) + - (inner.getDumpNode().isEmpty() ? "" : "[" + chooseIndex(inner.getOriginalIndex(), 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; @@ -66,6 +66,10 @@ aspect TemplateContext { 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(); @@ -102,18 +106,12 @@ 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>"; } } - // --- hasLineColor --- - syn boolean InnerDumpNode.needRelationStyling() = !getLineColor().isEmpty() || !getTextColor().isEmpty(); - syn boolean InnerRelationDumpNode.needRelationStyling() = !getLineColor().isEmpty() || !getTextColor().isEmpty(); - syn boolean DumpNormalChildNode.needRelationStyling() = !getLineColor().isEmpty() || !getTextColor().isEmpty(); - syn boolean DumpNormalRelation.needRelationStyling() = !getLineColor().isEmpty() || !getTextColor().isEmpty(); - // --- stereotypeList --- syn String DumpNode.stereotypeList() { StringBuilder sb = new StringBuilder(getManualStereotypes()); diff --git a/dumpAst.base/src/main/jastadd/ToYaml.jrag b/dumpAst.base/src/main/jastadd/ToYaml.jrag index 7f1cf01..82fd9ab 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("OrderChildren", getOrderChildren()); result.put("Scale", getScale()); result.put("Version", getVersion()); - result.put("OrderChildren", getOrderChildren()); // attributes result.put("debug", debug()); @@ -61,10 +61,9 @@ aspect ToYaml { // tokens result.put("Name", getName()); if (!fromRelation) { - result.put("Computed", getComputed()); result.put("BackgroundColor", getBackgroundColor()); - result.put("TextColor", getTextColor()); result.put("Invisible", getInvisible()); + result.put("TextColor", getTextColor()); } // attributes @@ -91,11 +90,13 @@ aspect ToYaml { MappingElement result = new MappingElement(); // tokens - 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; @@ -104,14 +105,9 @@ aspect ToYaml { syn MappingElement DumpNormalChildNode.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); - // tokens - result.put("LineColor", getLineColor()); - result.put("TextColor", getTextColor()); - // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); - result.put("needRelationStyling", needRelationStyling()); return result; } @@ -129,13 +125,10 @@ aspect ToYaml { syn MappingElement DumpToken.toYaml(boolean fromRelation) { MappingElement result = new MappingElement(); - // tokens - result.put("Computed", getComputed()); - // attributes + result.put("isDumpValueToken", isDumpValueToken()); result.put("isList", isList()); result.put("label", label()); - result.put("isDumpValueToken", isDumpValueToken()); return result; } @@ -150,9 +143,14 @@ aspect ToYaml { 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("innerNotNullOrEmpty", innerNotNullOrEmpty()); + result.put("needRelationStyling", needRelationStyling()); result.put("outerNodeName", outerNodeName()); return result; } @@ -162,11 +160,14 @@ aspect ToYaml { // 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; } @@ -176,10 +177,13 @@ aspect ToYaml { // tokens 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; } @@ -187,15 +191,10 @@ aspect ToYaml { syn MappingElement DumpNormalRelation.toYaml(boolean fromRelation) { MappingElement result = super.toYaml(fromRelation); - // tokens - result.put("LineColor", getLineColor()); - result.put("TextColor", getTextColor()); - // attributes result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); result.put("innerNotNullOrEmpty", innerNotNullOrEmpty()); - result.put("needRelationStyling", needRelationStyling()); return result; } @@ -220,9 +219,9 @@ aspect ToYaml { // 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; } @@ -237,9 +236,9 @@ aspect ToYaml { result.put("bothVisible", bothVisible()); result.put("innerNodeName", innerNodeName()); result.put("innerNotNullOrEmpty", innerNotNullOrEmpty()); - result.put("outerNodeName", outerNodeName()); result.put("label", label()); result.put("needRelationStyling", needRelationStyling()); + result.put("outerNodeName", outerNodeName()); return result; } @@ -279,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 9606b1b..eecc082 100644 --- a/dumpAst.base/src/main/jastadd/Transform.jadd +++ b/dumpAst.base/src/main/jastadd/Transform.jadd @@ -192,6 +192,7 @@ aspect Transform { listChild.setLabel(childName); listChild.setName(tti.nextName()); node.addDumpChildNode(listChild); + RelationStyle style = applyStyle(listChild); int index = -1; for (Object target : targetList) { @@ -203,14 +204,14 @@ aspect Transform { if (target != null && targetNode != null) { InnerDumpNode inner = new InnerDumpNode().setDumpNode(targetNode).setOriginalIndex(index); listChild.addInnerDumpNode(inner); - applyStyle(inner); + inner.applyStyle(style); } } if (listChild.getNumInnerDumpNode() == 0) { InnerDumpNode inner = new InnerDumpNode().setDumpNode(transform(tti, EMPTY, options.asNormal(false).allowNullObjectsOnce())); listChild.addInnerDumpNode(inner); - applyStyle(inner); + inner.applyStyle(style); } return true; } @@ -254,19 +255,15 @@ aspect Transform { listChild.setComputed(computed); listChild.setLabel(childName); listChild.setName(tti.nextName()); + node.addDumpChildNode(listChild); + RelationStyle style = applyStyle(listChild); - boolean notAddedYet = true; 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); - if (notAddedYet) { - // list child has to be added before application of style, thus inline adding with condition - node.addDumpChildNode(listChild); - notAddedYet = false; - } - applyStyle(inner); + inner.applyStyle(style); } } return true; @@ -301,6 +298,7 @@ aspect Transform { listRelation.setLabel(otherMethod.getName()); listRelation.setName(tti.nextName()); node.addDumpRelation(listRelation); + RelationStyle style = applyStyle(listRelation); int index = -1; for (Object target : targetList) { @@ -312,14 +310,14 @@ aspect Transform { if (target != null && targetNode != null) { InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(targetNode).setOriginalIndex(index); listRelation.addInnerRelationDumpNode(inner); - applyStyle(inner); + inner.applyStyle(style); } } if (listRelation.getNumInnerRelationDumpNode() == 0) { InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(transform(tti, EMPTY, options.asNormal(false).allowNullObjectsOnce())); listRelation.addInnerRelationDumpNode(inner); - applyStyle(inner); + inner.applyStyle(style); } return true; } @@ -336,14 +334,19 @@ aspect Transform { 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) { - 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; + Iterable<?> iterable = (Iterable<?>) target; for (Object element : iterable) { - // TODO check if isAstNode for first non-null. if yes, use DumpReferenceListToken, other DumpValueToken + // 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()) { @@ -353,30 +356,29 @@ aspect Transform { if (atLeastOneASTNode) { DumpReferenceListToken listToken = new DumpReferenceListToken(); listToken.setName(tti.nextName()); + setMemberAndAdd.accept(listToken); + RelationStyle style = applyStyle(listToken); nodes.forEach(element -> { - listToken.addInnerRelationDumpNode(new InnerRelationDumpNode().setDumpNode(element)); + InnerRelationDumpNode inner = new InnerRelationDumpNode().setDumpNode(element); + listToken.addInnerRelationDumpNode(inner); + inner.applyStyle(style); }); - token = listToken; } } if (!atLeastOneASTNode) { DumpNode targetNode = transform(tti, target, options.asRelation()); if (targetNode != null && targetNode.isAstNode()) { - token = new DumpReferenceToken().setValue(targetNode); + 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); - token = valueToken; + setMemberAndAdd.accept(valueToken); } } } - if (token != null) { - token.setLabel(otherMethod.getName()); - token.setComputed(otherMethod.asTokenMethod().isAttributeMethod()); - node.addDumpToken(token); - // TODO apply style - } } return true; } @@ -411,14 +413,9 @@ aspect Transform { } // === RelationStyle === - interface RelationStylable<SELF> { + interface RelationStyleDefinable { // more methods in TransformPlus.jadd - // tokens - SELF setLabel(String name); - SELF setTextColor(String textColor); - SELF setLineColor(String lineColor); - // attributes BuildConfig buildConfig(); boolean isComputed(); @@ -427,28 +424,56 @@ aspect Transform { DumpNode containingDumpNode(); DumpNode getDumpNode(); } - DumpNormalChildNode implements RelationStylable<DumpNormalChildNode>; - syn String DumpNormalChildNode.initialLabel() = getLabel(); - syn boolean DumpNormalChildNode.isComputed() = getComputed(); - syn boolean DumpNormalChildNode.isContainment() = true; + interface RelationStylable<SELF> { + // more methods in TransformPlus.jadd - InnerDumpNode implements RelationStylable<InnerDumpNode>; - syn String InnerDumpNode.initialLabel() = containingDumpListChildNode().getLabel(); - syn boolean InnerDumpNode.isComputed() = containingDumpListChildNode().getComputed(); - syn boolean InnerDumpNode.isContainment() = true; + // tokens + String getTextColor(); + String getLineColor(); - DumpNormalRelation implements RelationStylable<DumpNormalRelation>; - syn String DumpNormalRelation.initialLabel() = getLabel(); - syn boolean DumpNormalRelation.isComputed() = false; - syn boolean DumpNormalRelation.isContainment() = false; + 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>; - syn String InnerRelationDumpNode.initialLabel() = containingDumpListRelation().getLabel(); - syn boolean InnerRelationDumpNode.isComputed() = containingDumpListRelation() == null; - syn boolean InnerRelationDumpNode.isContainment() = false; - private void DumpAst.applyStyle(RelationStylable<?> stylable) { - stylable.applyStyle(getPrintConfig().getRelationStyleDefinition()); + 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 --- diff --git a/dumpAst.base/src/main/jastadd/TransformPlus.jadd b/dumpAst.base/src/main/jastadd/TransformPlus.jadd index 2296ad7..ff3b8e5 100644 --- a/dumpAst.base/src/main/jastadd/TransformPlus.jadd +++ b/dumpAst.base/src/main/jastadd/TransformPlus.jadd @@ -1,19 +1,35 @@ // more stuff from Transform that is not correctly handled by the IntelliJ plugin aspect Transform { - interface RelationStylable<SELF> { + interface RelationStyleDefinable { default RelationStyle createDefaultStyle() { return new RelationStyle() .setLabel(initialLabel()) - .setTextColor(isComputed() ? buildConfig().getStyleInformation().getComputedColor() : "") + .setLineColor(isComputed() ? buildConfig().getStyleInformation().getComputedColor() : "") .setTextColor(isComputed() ? buildConfig().getStyleInformation().getComputedColor() : ""); } - default void applyStyle(RelationStyleDefinition relationStyleDefinition) { + default RelationStyle getStyle(RelationStyleDefinition relationStyleDefinition) { RelationStyle style = createDefaultStyle(); - relationStyleDefinition.style(containingDumpNode().getObject(), getDumpNode().getObject(), + 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/resources/dumpAst.mustache b/dumpAst.base/src/main/resources/dumpAst.mustache index 4cc8283..5785dd7 100644 --- a/dumpAst.base/src/main/resources/dumpAst.mustache +++ b/dumpAst.base/src/main/resources/dumpAst.mustache @@ -42,16 +42,16 @@ object "{{{labelAndTextColor}}}" as {{{Name}}} {{{stereotypeList}}} {{#Backgroun {{^Invisible}} {{#isList}} circle " " as {{{Name}}} -{{{outerNodeName}}} .-[norank{{#Computed}},#{{{computedColor}}}{{/Computed}}]-> {{{Name}}}{{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} .-[norank]-> {{{Name}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{#InnerRelationDumpNode}} {{#bothVisible}} -{{{Name}}} .[#black{{#Computed}},#{{{computedColor}}}{{/Computed}}{{#innerNotNullOrEmpty}},norank{{/innerNotNullOrEmpty}}].> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}}{{#label}} : {{{label}}}{{/label}} +{{{Name}}} .{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}.> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerRelationDumpNode}} {{/isList}} {{^isList}} {{^isDumpValueToken}} -{{{outerNodeName}}} .[#black{{#Computed}},#{{{computedColor}}}{{/Computed}}{{#innerNotNullOrEmpty}},norank{{/innerNotNullOrEmpty}}].> {{{innerNodeName}}}{{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} .{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}.> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/isDumpValueToken}} {{/isList}} {{/Invisible}} @@ -59,16 +59,16 @@ circle " " as {{{Name}}} {{#DumpChildNodes}} {{#isList}} circle " " as {{{Name}}} -{{{outerNodeName}}} *-{{#Computed}}[#{{{computedColor}}}]{{/Computed}}- {{{Name}}} {{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} *-- {{{Name}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{#InnerDumpNodes}} {{#bothVisible}} -{{{Name}}} -{{#Computed}}[#{{{computedColor}}}]{{/Computed}}- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}}{{#label}} : {{{label}}}{{/label}} +{{{Name}}} -- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} *-{{#Computed}}[#{{{computedColor}}}]{{/Computed}}- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}}{{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} *-- {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/isList}} {{/DumpChildNodes}} @@ -76,13 +76,13 @@ circle " " as {{{Name}}} {{#isList}} {{#InnerRelationDumpNode}} {{#bothVisible}} -{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}}{{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/InnerRelationDumpNode}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}}{{#label}} : {{{label}}}{{/label}} +{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}-{{#innerNotNullOrEmpty}}[norank]{{/innerNotNullOrEmpty}}-> {{{innerNodeName}}} {{#needRelationStyling}}{{>RelationStyle}}{{/needRelationStyling}} : "{{{label}}}" {{/bothVisible}} {{/isList}} {{/DumpRelations}} diff --git a/dumpAst.prototyping/src/main/jastadd/featureTest.relast b/dumpAst.prototyping/src/main/jastadd/featureTest.relast index 7e108fe..003417c 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 3a6c733..bebca7d 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,6 +19,38 @@ 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"); @@ -38,10 +71,7 @@ public class FeatureTestMain { 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() @@ -55,7 +85,8 @@ public class FeatureTestMain { if (parentNode instanceof Root && childNode instanceof B) { return !"B3".equals(((B) childNode).getName()); } - return !contextName.equals("MyC"); +// return !contextName.equals("MyC"); + return true; }) .includeRelation((sourceNode, targetNode, roleName) -> !(sourceNode instanceof B) || !((B) sourceNode).getName().equals("B6.1.1")) @@ -74,15 +105,27 @@ public class FeatureTestMain { }) .skinParam(SkinParamBooleanSetting.Shadowing, false) .relationStyle((source, target, isComputed, isContainment, style) -> { - System.out.println(style.getLabel() + ", computed: " + isComputed + ", containment: " + isContainment); + 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(""); } - if (style.getLabel().equals("ManyA")) { - style.setLabel("ManyA of " + ((Nameable) source).getName()); - } else if (style.getLabel().equals("OneA") || style.getLabel().equals("MaybeC?")) { - style.setTextColor("red"); - style.setLineColor("green"); + 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) -> { @@ -94,10 +137,33 @@ public class FeatureTestMain { } 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/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 5246c9f..c1228e0 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 @@ -212,7 +212,7 @@ 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.getLabel(), target); } diff --git a/pages/docs/using.md b/pages/docs/using.md index 26cd6c0..f01ec77 100644 --- a/pages/docs/using.md +++ b/pages/docs/using.md @@ -31,7 +31,7 @@ public class Main { style.useSimpleName(); // (4) style.setBackgroundColor(node.size() > 30 ? "blue" : "white"); // (5) }) - .relationStyle((source, target, style) -> { + .relationStyle((source, target, isComputed, isContainment, style) -> { if (style.getLabel().equals("EndEffector")) { style.setLabel(""); // (6) } @@ -57,9 +57,9 @@ The steps in detail: - (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()` and (b) indices are always appended to the set label. +- (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). +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). -- GitLab