diff --git a/dumpAst/build.gradle b/dumpAst/build.gradle index b6793149b06ba134d59ad0886d55eda83be58b20..e751cf080448a433aeb67649de7dfc781c22f8d9 100644 --- a/dumpAst/build.gradle +++ b/dumpAst/build.gradle @@ -14,8 +14,10 @@ plugins { apply plugin: 'jastadd' dependencies { - jastadd2 "org.jastadd:jastadd:2.3.4" - implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "${mustache_java_version}" + jastadd2 "org.jastadd:jastadd:2.3.5" + implementation fileTree(include: ['plantuml.jar'], dir: '../libs') + implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "0.9.10" + implementation group: 'org.yaml', name: 'snakeyaml', version: '1.27' } File dumpAstGrammar = file('./src/main/jastadd/DumpAst.relast') diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst/src/main/jastadd/DumpAst.relast index 779452c6cedcfa553835a1f74b0eef5e306faef0..7f41406c376d88fcb9dede390a41a7ab454d7724 100644 --- a/dumpAst/src/main/jastadd/DumpAst.relast +++ b/dumpAst/src/main/jastadd/DumpAst.relast @@ -1,18 +1,8 @@ DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ; rel DumpAst.RootNode -> DumpNode ; -BuildConfig ::= StyleInformation GlobalPatternCollection:PatternCollection - ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* - <TypeIgnorePattern> <IncludeEmptyString:boolean> <ExcludeNullNodes:boolean> <Debug:boolean>; -TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ; -PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ; -StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod>; - -PrintConfig ::= <Scale:double> <Version> <OrderChildren:boolean> Header* ; -Header ::= <Value> ; - DumpNode ::= DumpChildNode* DumpToken* DumpRelation* - <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> <Computed:boolean> + <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> <Computed:boolean> <ManualStereotypes> /InvisiblePath/ ; InnerDumpNode ; rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ; @@ -52,3 +42,21 @@ ListRelationMethod : AnalysedMethod ; abstract TokenMethod : AnalysedMethod ; IntrinsicTokenMethod : TokenMethod ; AttributeMethod : TokenMethod ; + +BuildConfig ::= StyleInformation + GlobalPatternCollection:PatternCollection + ExcludeTypePattern:TypePatternCollectionMapping* + IncludeTypePattern:TypePatternCollectionMapping* + <TypeIgnorePattern> + <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>; + +PrintConfig ::= Header* + <Scale:double> + <Version> + <OrderChildren:boolean> ; +Header ::= <Value> ; diff --git a/dumpAst/src/main/jastadd/GenerationBackend.jadd b/dumpAst/src/main/jastadd/GenerationBackend.jadd index 022b5226b160f434dfce25199a0c0e9fcad502e9..ca04a6046c498bd4fb84102976bddcb2aa81f51b 100644 --- a/dumpAst/src/main/jastadd/GenerationBackend.jadd +++ b/dumpAst/src/main/jastadd/GenerationBackend.jadd @@ -5,6 +5,53 @@ aspect GenerationBackend { } } + class TransformationOptions { + // todo should be read-only, i.e., copy-on-write + public boolean relation = false; + public boolean invisible = false; + public boolean root = false; + public boolean allowNullObject = false; + public boolean computed = false; + + public static TransformationOptions with() { + return new TransformationOptions(); + } + + public TransformationOptions relationTrue() { + TransformationOptions copy = new TransformationOptions(this); + copy.relation = true; + return copy; + } + public TransformationOptions invisibleTrue() { + TransformationOptions copy = new TransformationOptions(this); + copy.invisible = true; + return copy; + } + public TransformationOptions rootTrue() { + TransformationOptions copy = new TransformationOptions(this); + copy.root = true; + return copy; + } + public TransformationOptions allowNullObjectTrue() { + TransformationOptions copy = new TransformationOptions(this); + copy.allowNullObject = true; + return copy; + } + public TransformationOptions computedTrue() { + TransformationOptions copy = new TransformationOptions(this); + copy.computed = true; + return copy; + } + protected TransformationOptions() {} + protected TransformationOptions(TransformationOptions prototype) { + this.relation = prototype.relation; + this.invisible = prototype.invisible; + this.root = prototype.root; + this.allowNullObject = prototype.allowNullObject; + this.computed = prototype.computed; + } + } + // --- 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 { @@ -196,6 +243,7 @@ aspect GenerationBackend { 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)); } private Source DumpAst.nextSource(Source currentSource, boolean shouldBeInvisible) { @@ -491,8 +539,8 @@ aspect GenerationBackend { return p.matcher(input).matches(); } - // --- version --- (mustache has buildConfig as context) - syn String BuildConfig.version() = printConfig().getVersion(); + // --- debug --- (mustache has printConfig as context) + syn boolean PrintConfig.debug() = buildConfig().getDebug(); private static String DumpAst.invokeName(java.lang.annotation.Annotation annotation) { return (String) invokeMethod("name", annotation); @@ -567,6 +615,30 @@ aspect GenerationBackend { } } + // --- stereotypeList --- + syn String DumpNode.stereotypeList() { + StringBuilder sb = new StringBuilder(getManualStereotypes()); + if (!automaticStereotypes().isEmpty()) { + // add automatic stereotypes, if there are any + if (!getManualStereotypes().isEmpty()) { + // add a comma between manual and automatic, if both are present + sb.append(","); + } + sb.append(automaticStereotypes()); + } + String manualAndAutomaticStereotypes = sb.toString(); + if (manualAndAutomaticStereotypes.isEmpty()) { + return ""; + } + sb = new StringBuilder(); + for (String stereotype : manualAndAutomaticStereotypes.split(",")) { + sb.append(" <<").append(stereotype).append(">>"); + } + return sb.toString(); + } + // --- manualAndAutomaticStereotypes --- + syn String DumpNode.automaticStereotypes() = getComputed() ? "NTA" : ""; + // --- myChildren --- syn java.util.List<DumpNode> DumpNode.myChildren() { java.util.List<DumpNode> result = new java.util.ArrayList<>(); @@ -602,94 +674,19 @@ aspect GenerationBackend { int nodeCounter = 0; } - syn String DumpAst.toYaml(boolean prependCreationComment) { - Document doc = new Document(); - doc.setRootElement(getRootNode().toYaml()); - return doc.prettyPrint(prependCreationComment); - } - - syn MappingElement DumpNode.toYaml() { - MappingElement result = new MappingElement(); - // tokens are key-value-pairs - for (DumpToken token : getDumpTokenList()) { - if (token.isDumpValueToken()) { - result.put(token.getName(), makeValueElement(token.asDumpValueToken().getValue())); - } else { - result.put(token.getName(), token.asDumpReferenceToken().getValue().toYaml()); - } - } - // children - for (DumpChildNode child : getDumpChildNodeList()) { - ListElement list = new ListElement(); - for (DumpNode inner : child.innerNodes(true)) { - list.add(inner.toYaml()); - } - if (child.isList()) { - result.put(child.getName(), list); - } else if (list.getNumElement() == 1) { - result.put(child.getName(), list.getElement(0)); - } - } - // relations - for (DumpRelation relation : getDumpRelationList()) { - ListElement list = new ListElement(); - for (DumpNode inner : relation.innerNodes(true)) { - list.add(inner.toYaml()); - } - if (relation.isList()) { - result.put(relation.getName(), list); - } else if (list.getNumElement() == 1) { - result.put(relation.getName(), list.getElement(0)); - } - } - return result; - } - - private static ComplexElement ASTNode.HELPER_COMPLEX_ELEMENT = new MappingElement(); - protected static Element ASTNode.makeValueElement(Object obj) { - if (obj instanceof Integer) { - return ValueElement.of((int) obj); - } else if (obj instanceof Boolean) { - return ValueElement.of((boolean) obj); - } else { - return HELPER_COMPLEX_ELEMENT.makeStringElement(obj.toString()); - } - } - - public class AppendableWriter extends java.io.Writer { - private final StringBuilder sb; - - public AppendableWriter(StringBuilder sb) { - this.sb = sb; - } - - @Override - public void write(char[] chars, int off, int len) { - sb.append(chars, off, len); - } - - @Override - public void write(String str) { - sb.append(str); - } - - @Override - public void flush() { - } - - @Override - public void close() { - } - } 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; } + syn String DumpAst.computedColor() = getBuildConfig().getStyleInformation().getComputedColor(); + @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 97b622a1ba1d333ad23e44dabb0a8571721cf6ab..2bc0d68ebb8f61d335a180ec70342b49c683c7e1 100644 --- a/dumpAst/src/main/jastadd/GenerationFrontend.jadd +++ b/dumpAst/src/main/jastadd/GenerationFrontend.jadd @@ -347,6 +347,16 @@ public class DumpBuilder { return this; } + public <ASTNODE> DumpBuilder setStereotypeMethod(StyleMethod<ASTNODE> stereotypeMethod) { + buildConfig.getStyleInformation().setStereotypeMethod(stereotypeMethod); + return this; + } + + public DumpBuilder setComputedColor(String color) { + buildConfig.getStyleInformation().setComputedColor(color); + return this; + } + public DumpBuilder setScale(double value) { printConfig.setScale(value); return this; @@ -400,11 +410,38 @@ public class DumpBuilder { } public DumpBuilder dumpAsYaml(java.nio.file.Path destination, boolean prependCreationComment) throws java.io.IOException { - String content = build().toYaml(prependCreationComment); + String content = build().printYaml(prependCreationComment); try (java.io.Writer writer = java.nio.file.Files.newBufferedWriter(destination)) { writer.write(content); } return this; } + + /** + * Write out content as PNG image generated by plantuml. + * @param destination path of destination file + * @return this + * @throws java.io.IOException if an I/O error happend during opening or writing in that file + */ + public DumpBuilder dumpAsPNG(java.nio.file.Path destination) throws java.io.IOException { + String content = build().toPlantUml(); + net.sourceforge.plantuml.SourceStringReader reader = new net.sourceforge.plantuml.SourceStringReader(content); + reader.outputImage(java.nio.file.Files.newOutputStream(destination)); + return this; + } + + /** + * Write out content as SVG image generated by plantuml. + * @param destination path of destination file + * @return this + * @throws java.io.IOException if an I/O error happend during opening or writing in that file + */ + public DumpBuilder dumpAsSVG(java.nio.file.Path destination) throws java.io.IOException { + String content = build().toPlantUml(); + net.sourceforge.plantuml.SourceStringReader reader = new net.sourceforge.plantuml.SourceStringReader(content); + reader.outputImage(java.nio.file.Files.newOutputStream(destination), + new net.sourceforge.plantuml.FileFormatOption(net.sourceforge.plantuml.FileFormat.SVG)); + return this; + } } } diff --git a/dumpAst/src/main/jastadd/GenerationMustache.jrag b/dumpAst/src/main/jastadd/GenerationMustache.jrag index d69f4fba573580285101ce63946da0fda5ce52fd..cf9f53455aab8a2cef109e9e8d53a27e8fac4951 100644 --- a/dumpAst/src/main/jastadd/GenerationMustache.jrag +++ b/dumpAst/src/main/jastadd/GenerationMustache.jrag @@ -19,7 +19,35 @@ aspect GenerationMustache { com.github.mustachejava.DefaultMustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory(); mf.setObjectHandler(roh); com.github.mustachejava.Mustache m = mf.compile("dumpAst.mustache"); - m.execute(new java.io.PrintWriter(new AppendableWriter(sb)), this); + String yaml = this.printYaml(false); + Object context = new org.yaml.snakeyaml.Yaml().load(new StringReader(yaml)); + m.execute(new java.io.PrintWriter(new AppendableWriter(sb)), context); return sb.toString(); } + + public class AppendableWriter extends java.io.Writer { + private final StringBuilder sb; + + public AppendableWriter(StringBuilder sb) { + this.sb = sb; + } + + @Override + public void write(char[] chars, int off, int len) { + sb.append(chars, off, len); + } + + @Override + public void write(String str) { + sb.append(str); + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + } } diff --git a/dumpAst/src/main/jastadd/GenerationToYaml.jrag b/dumpAst/src/main/jastadd/GenerationToYaml.jrag new file mode 100644 index 0000000000000000000000000000000000000000..30a093c9f2495e68f4b552cedf9ce16d77e7ed06 --- /dev/null +++ b/dumpAst/src/main/jastadd/GenerationToYaml.jrag @@ -0,0 +1,221 @@ +aspect GenerationToYaml { + syn String DumpAst.printYaml(boolean prependCreationComment) { + Document doc = new Document(); + doc.setRootElement(this.toYaml(false)); + return doc.prettyPrint(prependCreationComment); + } + + // todo: default impl should actually be abstract instead + syn MappingElement ASTNode.toYaml(boolean fromRelation) = new MappingElement(); + + static MappingElement ASTNode.safeToYaml(ASTNode node, boolean fromRelation) { + if (node == null) { + return null; + } + return node.toYaml(fromRelation); + } + + syn MappingElement DumpAst.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // children + result.put("PrintConfig", safeToYaml(getPrintConfig(), fromRelation)); + addYamledList(result, "DumpNodes", getDumpNodeList(), fromRelation); + + // attributes + result.put("computedColor", computedColor()); + return result; + } + + static void ASTNode.addYamledList(MappingElement base, String key, Iterable<? extends ASTNode<?>> iterable, boolean fromRelation) { + ListElement innerList = new ListElement(); + for (ASTNode node : iterable) { + innerList.add(safeToYaml(node, fromRelation)); + } + base.put(key, innerList); + } + + syn MappingElement PrintConfig.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // children + addYamledList(result, "Headers", getHeaderList(), fromRelation); + + // tokens + result.put("scale", getScale()); + result.put("version", getVersion()); + result.put("orderChildren", getOrderChildren()); + + // attributes + result.put("debug", debug()); + return result; + } + + syn MappingElement Header.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // tokens + result.put("value", getValue()); + return result; + } + + syn MappingElement DumpNode.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + + // children + if (!fromRelation) { + addYamledList(result, "DumpChildNodes", getDumpChildNodeList(), fromRelation); + addYamledList(result, "DumpTokens", getDumpTokenList(), fromRelation); + addYamledList(result, "DumpRelations", getDumpRelationList(), fromRelation); + } + + // tokens + 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()); + } + + // attributes + if (!fromRelation) { + result.put("isNull", isNull()); + result.put("isAstNode", isAstNode()); + result.put("labelAndTextColor", labelAndTextColor()); + result.put("stereotypeList", stereotypeList()); + addYamledList(result, "myChildren", myChildren(), true); + } + result.put("hasSuccessor", hasSuccessor()); + result.put("successor", safeToYaml(successor(), true)); + + // NTAs + if (!fromRelation) { + result.put("InvisiblePath", safeToYaml(getInvisiblePath(), true)); + } + return result; + } + + syn MappingElement DumpChildNode.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // tokens + result.put("name", getName()); + result.put("computed", getComputed()); + // attributes + result.put("label", label()); + result.put("isList", isList()); + result.put("outerNodeName", outerNodeName()); + + return result; + } + + syn MappingElement DumpNormalChildNode.toYaml(boolean fromRelation) { + MappingElement result = super.toYaml(fromRelation); + // attributes + result.put("bothVisible", bothVisible()); + result.put("innerNodeName", innerNodeName()); + return result; + } + + syn MappingElement DumpListChildNode.toYaml(boolean fromRelation) { + MappingElement result = super.toYaml(fromRelation); + // children + addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation); + return result; + } + + syn MappingElement DumpToken.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // tokens + result.put("name", getName()); + result.put("computed", getComputed()); + // attributes + 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()); + return result; + } + + syn MappingElement DumpReferenceToken.toYaml(boolean fromRelation) { + MappingElement result = super.toYaml(fromRelation); + // tokens + result.put("innerNodeName", innerNodeName()); + 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()); + // attributes + result.put("isList", isList()); + result.put("label", label()); + 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()); + return result; + } + + syn MappingElement DumpListRelation.toYaml(boolean fromRelation) { + MappingElement result = super.toYaml(fromRelation); + // children + addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation); + return result; + } + + syn MappingElement InnerDumpNode.toYaml(boolean fromRelation) { + MappingElement result = new MappingElement(); + // attributes + result.put("bothVisible", bothVisible()); + result.put("innerNodeName", innerNodeName()); + result.put("outerNodeName", outerNodeName()); + result.put("label", label()); + return result; + } + + syn MappingElement InvisiblePath.toYaml(boolean fromRelation) { + MappingElement result = super.toYaml(fromRelation); + // children + addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation); + return result; + } + + // extension for mustache + public static ValueElement ValueElement.of(double value) { + return new ValueElement(false, String.valueOf(value)); + } + public MappingElement MappingElement.put(String key, double value) { + addKeyValuePair(key, ValueElement.of(value)); + return this; + } + + refine Helpers public void MappingElement.addKeyValuePair(String key, Element value) { + if (value == null) { + return; + } + refined(key, value); + } + + refine Helpers protected SimpleElement ComplexElement.makeStringElement(String value) { + if (value == null || value.equals("null")) { + return StringElement.of("null"); + } + if (value.isEmpty()) { + return StringElement.of(value); + } + return refined(value); + } + +} diff --git a/dumpAst/src/main/jastadd/Imports.jadd b/dumpAst/src/main/jastadd/Imports.jadd new file mode 100644 index 0000000000000000000000000000000000000000..41dcef642656cbdbe35aac8444a7d2c1dc2e7110 --- /dev/null +++ b/dumpAst/src/main/jastadd/Imports.jadd @@ -0,0 +1,4 @@ +import java.io.*; +import java.util.*; + +aspect Imports {} diff --git a/dumpAst/src/main/jastadd/Navigation.jrag b/dumpAst/src/main/jastadd/Navigation.jrag index 05f722dc7d9cf9097f960598bc45b9c7f1a3a260..c69141d3208bc5f99ee866d6417b043daaac9a03 100644 --- a/dumpAst/src/main/jastadd/Navigation.jrag +++ b/dumpAst/src/main/jastadd/Navigation.jrag @@ -7,6 +7,7 @@ aspect Navigation { // --- buildConfig --- inh BuildConfig DumpNode.buildConfig(); + inh BuildConfig PrintConfig.buildConfig(); eq DumpAst.getChild().buildConfig() = getBuildConfig(); // --- printConfig --- @@ -38,7 +39,7 @@ aspect Navigation { // --- innerNodes --- syn java.util.List<DumpNode> DumpChildNode.innerNodes(boolean onlyVisible); - eq DumpNormalChildNode.innerNodes(boolean onlyVisible) = onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ? + eq DumpNormalChildNode.innerNodes(boolean onlyVisible) = getDumpNode() == null || onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ? java.util.Collections.emptyList() : java.util.Collections.singletonList(getDumpNode()); eq DumpListChildNode.innerNodes(boolean onlyVisible) { @@ -47,9 +48,15 @@ aspect Navigation { } java.util.List<DumpNode> result = new java.util.ArrayList<>(); getInnerDumpNodeList().forEach(inner -> { - if (!onlyVisible || !inner.getDumpNode().getInvisible()) { - result.add(inner.getDumpNode()); + if (inner == null || inner.getDumpNode() == null) { + //noinspection UnnecessaryReturnStatement + return; + } + if (onlyVisible && inner.getDumpNode().getInvisible()) { + //noinspection UnnecessaryReturnStatement + return; } + result.add(inner.getDumpNode()); }); return result; } diff --git a/dumpAst/src/main/jastadd/Printing.jrag b/dumpAst/src/main/jastadd/Printing.jrag index 9531e51ed148310607301ad644e5d5550cdad32f..e4565af809152de0c654dd6bc613dd5aab2c3e02 100644 --- a/dumpAst/src/main/jastadd/Printing.jrag +++ b/dumpAst/src/main/jastadd/Printing.jrag @@ -7,9 +7,9 @@ aspect Printing { eq DumpNode.getChild().outerNodeName() = name(); // --- innerNodeName --- - syn String InnerDumpNode.innerNodeName() = getDumpNode().name(); - syn String DumpNormalChildNode.innerNodeName() = getDumpNode().name(); - syn String DumpNormalRelation.innerNodeName() = getDumpNode().name(); + syn String InnerDumpNode.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 --- @@ -20,6 +20,10 @@ aspect Printing { syn String DumpRelation.label() = getName(); syn String DumpToken.label() = getName() + (getComputed() ? "()" : ""); syn String DumpNode.label() = getLabel(); + inh String InnerDumpNode.label(); + eq DumpListChildNode.getInnerDumpNode(int index).label() = label() + "[" + index + "]"; + eq DumpListRelation.getInnerDumpNode(int index).label() = label() + "[" + index + "]"; + eq InvisiblePath.getInnerDumpNode(int index).label() = null; // --- bothVisible --- boolean ASTNode.bothVisible(DumpNode one, DumpNode two) { diff --git a/dumpAst/src/main/resources/dumpAst.mustache b/dumpAst/src/main/resources/dumpAst.mustache index c7afbafc09dfbbf33ecd095627076cd005c72a10..9f8fb93ebe582514a1244429d449b21d8ae2e46b 100644 --- a/dumpAst/src/main/resources/dumpAst.mustache +++ b/dumpAst/src/main/resources/dumpAst.mustache @@ -1,47 +1,54 @@ @startuml +skinparam object<<null>> { + BorderColor transparent + BackgroundColor transparent + shadowing false +} +hide <<null>> stereotype + {{#PrintConfig}} -scale {{{Scale}}} +scale {{{scale}}} {{#Headers}} -{{{Value}}} +{{{value}}} {{/Headers}} {{/PrintConfig}} {{#DumpNodes}} - {{^Invisible}} + {{^invisible}} {{#isNull}} -diamond {{{name}}} +object "null" as {{{name}}}<<null>> {{/isNull}} {{#isAstNode}} -object "{{{labelAndTextColor}}}" as {{{name}}} {{#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}} {{^isDumpValueToken}} -{{{outerNodeName}}} .{{#Computed}}[#blue]{{/Computed}}.> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} .{{#computed}}[#{{{computedColor}}}]{{/computed}}.> {{{innerNodeName}}} : {{{label}}} {{/isDumpValueToken}} - {{/Invisible}} + {{/invisible}} {{/DumpTokens}} {{#DumpChildNodes}} {{#isList}} {{#InnerDumpNodes}} {{#bothVisible}} -{{{outerNodeName}}} *-{{#Computed}}[#blue]{{/Computed}}- {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} *-{{#computed}}[#{{{computedColor}}}]{{/computed}}- {{{innerNodeName}}} : {{{label}}} {{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} *-{{#Computed}}[#blue]{{/Computed}}- {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} *-{{#computed}}[#{{{computedColor}}}]{{/computed}}- {{{innerNodeName}}} : {{{label}}} {{/bothVisible}} {{/isList}} {{/DumpChildNodes}} @@ -49,23 +56,23 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{#backgroundColor}}#{{{backgroun {{#isList}} {{#InnerDumpNodes}} {{#bothVisible}} -{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}--> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} {{#bidirectional}}<{{/bidirectional}}--> {{{innerNodeName}}} : {{{label}}} {{/bothVisible}} {{/InnerDumpNodes}} {{/isList}} {{^isList}} {{#bothVisible}} -{{{outerNodeName}}} {{#Bidirectional}}<{{/Bidirectional}}--> {{{innerNodeName}}} : {{{label}}} +{{{outerNodeName}}} {{#bidirectional}}<{{/bidirectional}}--> {{{innerNodeName}}} : {{{label}}} {{/bothVisible}} {{/isList}} {{/DumpRelations}} - {{^Invisible}} + {{^invisible}} {{#InvisiblePath}} {{#InnerDumpNodes}} {{{outerNodeName}}} o.. {{{innerNodeName}}} {{/InnerDumpNodes}} {{/InvisiblePath}} - {{/Invisible}} + {{/invisible}} {{#PrintConfig}}{{#orderChildren}} {{#myChildren}} {{#hasSuccessor}} @@ -74,13 +81,13 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{#backgroundColor}}#{{{backgroun {{/myChildren}} {{/orderChildren}}{{/PrintConfig}} {{/DumpNodes}} -{{#BuildConfig}} - {{#Debug}} +{{#PrintConfig}} + {{#debug}} legend right %date() dumpAst: {{{version}}} plantuml: %version() endlegend - {{/Debug}} -{{/BuildConfig}} + {{/debug}} +{{/PrintConfig}} @enduml diff --git a/dumpAst/src/main/resources/dumpAstVersion.properties b/dumpAst/src/main/resources/dumpAstVersion.properties index e0a9ca936f23641719ffee3bfed385ca97d946b8..267b305fb5715a7403fdf5094444f7947c070451 100644 --- a/dumpAst/src/main/resources/dumpAstVersion.properties +++ b/dumpAst/src/main/resources/dumpAstVersion.properties @@ -1,2 +1,2 @@ -#Thu Feb 24 09:45:15 CET 2022 -version=0.3.6 +#Wed Mar 02 15:04:33 CET 2022 +version=0.3.7 diff --git a/dumpAstWithPlantuml/.gitignore b/dumpAstWithPlantuml/.gitignore deleted file mode 100644 index 87b4cdd3d7c6a41502ca98703abeeb69a1d536fb..0000000000000000000000000000000000000000 --- a/dumpAstWithPlantuml/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -build -src/gen-res/ -src/gen/ -out/ -*.class diff --git a/dumpAstWithPlantuml/build.gradle b/dumpAstWithPlantuml/build.gradle deleted file mode 100644 index 03e3324a59b067b1c8f45dc1f7b44975194b779e..0000000000000000000000000000000000000000 --- a/dumpAstWithPlantuml/build.gradle +++ /dev/null @@ -1,99 +0,0 @@ -buildscript { - repositories.mavenLocal() - repositories.mavenCentral() - dependencies { - classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3' - } -} - -plugins { - id 'relast2uml.java-jastadd-conventions' - id 'relast2uml.java-publishing-conventions' -} - -apply plugin: 'jastadd' - -dependencies { - implementation fileTree(include: ['plantuml.jar'], dir: '../libs') - - implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "${mustache_java_version}" -} - -File dumpAstGrammar = file('../dumpAst/src/main/jastadd/DumpAst.relast') - -task relast(type: JavaExec) { - group = 'Build' - main = "-jar" - - doFirst { - delete "src/gen/jastadd/*.ast" - delete "src/gen/jastadd/DumpAst.jadd" - delete "src/gen/jastadd/DumpAstRefResolver.jadd" - delete "src/gen/jastadd/DumpAstResolverStubs.jrag" - mkdir "src/gen/jastadd/" - } - - args = [ - "../libs/relast.jar", - dumpAstGrammar, -// "./src/main/jastadd/MustacheNodes.relast", - "--listClass=java.util.ArrayList", - "--jastAddList=JastAddList", - "--useJastAddNames", - "--file", - "--resolverHelper", - "--grammarName=./src/gen/jastadd/DumpAst" - ] - - inputs.files(file("../libs/relast.jar"), - dumpAstGrammar) - outputs.files(file("./src/gen/jastadd/DumpAst.ast"), - file("./src/gen/jastadd/DumpAst.jadd"), - file("./src/gen/jastadd/DumpAstRefResolver.jadd"), - file('./src/gen/jastadd/DumpAstResolverStubs.jrag')) -} - -jastadd { - configureModuleBuild() - modules { - //noinspection GroovyAssignabilityCheck - module("DumpAstWithPlantuml") { - - java { - basedir "." - include "src/main/**/*.java" - include "src/gen/**/*.java" - } - - jastadd { - basedir ".." - include "dumpAst/src/main/jastadd/**/*.ast" - include "dumpAst/src/main/jastadd/**/*.jadd" - include "dumpAst/src/main/jastadd/**/*.jrag" - include "dumpAstWithPlantuml/src/main/jastadd/**/*.jadd" - include "dumpAst/src/gen/jastadd/**/*.ast" - include "dumpAst/src/gen/jastadd/**/*.jadd" - include "dumpAst/src/gen/jastadd/**/*.jrag" - } - } - } - - cleanGen.doFirst { - delete "src/gen/java/de" - delete "src/gen-res/BuildInfo.properties" - } - - preprocessParser.doFirst { - - args += ["--no-beaver-symbol"] - - } - - module = "DumpAstWithPlantuml" - astPackage = 'de.tudresden.inf.st.jastadd.dumpAst.ast' - genDir = 'src/gen/java' - buildInfoDir = 'src/gen-res' - jastaddOptions = ["--lineColumnNumbers", "--List=JastAddList", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"] -} - -generateAst.dependsOn relast diff --git a/dumpAstWithPlantuml/src/main/jastadd/Generation.jadd b/dumpAstWithPlantuml/src/main/jastadd/Generation.jadd deleted file mode 100644 index 35905af0dc789adfc17971ed23ede287db032d52..0000000000000000000000000000000000000000 --- a/dumpAstWithPlantuml/src/main/jastadd/Generation.jadd +++ /dev/null @@ -1,29 +0,0 @@ -aspect Generation { - - /** - * Write out content as PNG image generated by plantuml. - * @param destination path of destination file - * @return this - * @throws java.io.IOException if an I/O error happend during opening or writing in that file - */ - public DumpBuilder DumpBuilder.dumpAsPNG(java.nio.file.Path destination) throws java.io.IOException { - String content = build().toPlantUml(); - net.sourceforge.plantuml.SourceStringReader reader = new net.sourceforge.plantuml.SourceStringReader(content); - reader.outputImage(java.nio.file.Files.newOutputStream(destination)); - return this; - } - - /** - * Write out content as SVG image generated by plantuml. - * @param destination path of destination file - * @return this - * @throws java.io.IOException if an I/O error happend during opening or writing in that file - */ - public DumpBuilder DumpBuilder.dumpAsSVG(java.nio.file.Path destination) throws java.io.IOException { - String content = build().toPlantUml(); - net.sourceforge.plantuml.SourceStringReader reader = new net.sourceforge.plantuml.SourceStringReader(content); - reader.outputImage(java.nio.file.Files.newOutputStream(destination), - new net.sourceforge.plantuml.FileFormatOption(net.sourceforge.plantuml.FileFormat.SVG)); - return this; - } -} \ No newline at end of file diff --git a/dumpAstWithPlantuml/src/main/resources/dumpAst.mustache b/dumpAstWithPlantuml/src/main/resources/dumpAst.mustache deleted file mode 120000 index e549bf371db8fa4554a0b276e52a3c5b978af0a3..0000000000000000000000000000000000000000 --- a/dumpAstWithPlantuml/src/main/resources/dumpAst.mustache +++ /dev/null @@ -1 +0,0 @@ -../../../../dumpAst/src/main/resources/dumpAst.mustache \ No newline at end of file diff --git a/dumpAstWithPlantuml/src/main/resources/dumpAstWithPlantumlVersion.properties b/dumpAstWithPlantuml/src/main/resources/dumpAstWithPlantumlVersion.properties deleted file mode 120000 index 19186b38f76bfc2fb8f855e0c5bafe020db4bae4..0000000000000000000000000000000000000000 --- a/dumpAstWithPlantuml/src/main/resources/dumpAstWithPlantumlVersion.properties +++ /dev/null @@ -1 +0,0 @@ -../../../../dumpAst/src/main/resources/dumpAstVersion.properties \ No newline at end of file diff --git a/featureTest/build.gradle b/featureTest/build.gradle index 52ffc696ca865fb537d26c180f9f9f0413a2c6ed..2bbb3d752fcac220b8544eea1747784d09c3fda8 100644 --- a/featureTest/build.gradle +++ b/featureTest/build.gradle @@ -19,7 +19,7 @@ repositories { mainClassName = 'de.tudresden.inf.st.jastadd.featureTest.FeatureTestMain' dependencies { - implementation project(":dumpAstWithPlantuml") + implementation project(":dumpAst") testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' diff --git a/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java b/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java index 1b51ef9f3265dfff1dc9398f886649f5a0993398..298298c64c1ce5ff4f1a646c9aaacc2c465cf70f 100644 --- a/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java +++ b/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java @@ -51,4 +51,9 @@ public class FeatureTestMain { .dumpAsYaml(pathToYaml, true) .dumpAsPNG(pathToPng); } + + private void m() { + //noinspection UnnecessaryReturnStatement + return; + } } diff --git a/settings.gradle b/settings.gradle index 4199c73d5d37f24eae0180262f0f7910a0996148..3eb76f1e946e81f5037864327765fdf452bf8c5c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,6 @@ rootProject.name = 'relast2uml' include 'relast.preprocessor' include 'dumpAst' -include 'dumpAstWithPlantuml' include 'testDumper' include 'featureTest' diff --git a/testDumper/build.gradle b/testDumper/build.gradle index 1c0603dc55c06e22ddea0a727ea178102ece369a..d07d71cbaf03eabd96f26322d0570d0334ee6da6 100644 --- a/testDumper/build.gradle +++ b/testDumper/build.gradle @@ -8,14 +8,17 @@ buildscript { plugins { id 'relast2uml.java-jastadd-conventions' + id 'relast2uml.java-application-conventions' } apply plugin: 'jastadd' dependencies { - testImplementation project(':dumpAst') + implementation project(':dumpAst') } +mainClassName = 'de.tudresden.inf.st.jastadd.testDumper.TestDumperMain' + File testingGrammar = file('./src/main/jastadd/testDumper.relast') task relast(type: JavaExec) { diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java b/testDumper/src/main/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java similarity index 66% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java rename to testDumper/src/main/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java index a031f27abe944729ff46aee2c4e021af8efacaf1..300d62e4429c77ded3f52832d7754b42cf98882d 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java +++ b/testDumper/src/main/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java @@ -1,6 +1,7 @@ package de.tudresden.inf.st.jastadd.testDumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpAst; +import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpListChildNode; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; import org.jastadd.testDumper.ast.A; @@ -8,14 +9,46 @@ import org.jastadd.testDumper.ast.B; import org.jastadd.testDumper.ast.C; import org.jastadd.testDumper.ast.Root; -import java.util.Arrays; -import java.util.List; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.function.Function; import java.util.stream.Collectors; +@SuppressWarnings({"unused", "CommentedOutCode"}) public class TestDumperMain { - public static void main(String[] args) { - Root root = new Root(); + private Root root; + private DumpAst dumpAst; + + public static void main(String[] args) throws IOException { + new TestDumperMain().run(); + } + + void run() throws IOException { + createRoot(); + + ExposingDumpBuilder builder = new ExposingDumpBuilder(root); + String preamble = "{<\n>\n}"; + builder.includeAttributes("simpleAttr") + .orderChildren() + .includeNonterminalAttributes("getCalculated") + .setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName()) + .customPreamble(preamble); + + System.out.println(">> PlantUml"); + dumpAst = builder.build(); + System.out.println(dumpAst.toPlantUml()); + + Path path = Paths.get("src/gen/resources/"); + Files.createDirectories(path); + builder.dumpAsYaml(path.resolve("testDumperMain.yaml"), true); + +// printAdditionalInformation(); + } + + private void createRoot() { + root = new Root(); root.setName("Root1"); A a = new A(); a.setName("A2"); @@ -34,20 +67,9 @@ public class TestDumperMain { root.addB(b1); root.addB(b2); root.setC(c); + } - TestUtils.ExposingDumpBuilder builder = new TestUtils.ExposingDumpBuilder(root); - builder.includeAttributes("simpleAttr") - .orderChildren() - .includeNonterminalAttributes("getCalculated") - .setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName()); - - System.out.println(">> PlantUml"); - DumpAst dumpAst = builder.build(); - System.out.println(dumpAst.toPlantUml()); - - String[] b = new String[]{"1"}; - List<String> l = Arrays.asList(b); - + private void printAdditionalInformation() { DumpNode node = dumpAst.getDumpNode(0); System.out.println(node.getName()); Function<? super DumpNode, String> printInfo = d -> @@ -72,4 +94,17 @@ public class TestDumperMain { // System.out.println(builder.build().toYaml(true)); // System.out.println(">> YAML end"); } + + static class ExposingDumpBuilder extends DumpBuilder { + + protected ExposingDumpBuilder(Object target) { + super(target); + } + + @Override + public DumpAst build() { + return super.build(); + } + } + } 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 0e6a927baafd60e60f09e9368308776f602ebc80..1b9be71cc6a27b381a94127d8cab991f06a87479 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 @@ -6,6 +6,10 @@ import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; import org.jastadd.testDumper.ast.*; 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 java.util.Optional; @@ -28,11 +32,16 @@ public class TestSimple { } @Test - public void testCustomPreamble() { + public void testCustomPreamble() throws IOException { Root root = createRoot(null, null); String preamble = "{<\n>\n}"; ExposingDumpBuilder builder = new ExposingDumpBuilder(root); builder.excludeNullNodes().customPreamble(preamble); + + Path path = Paths.get("src/gen/resources/"); + Files.createDirectories(path); + builder.dumpAsYaml(path.resolve("customPreamble.yaml"), true); + DumpAst dumpAst = builder.build(); String puml = dumpAst.toPlantUml(); assertThat(puml).contains(preamble);