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

1.0.1

- extract Dumper and DumpBuilder into Java files
- add missing documentation for methods in DumpBuilder
- remove relast.preprocessor
- use packaged relast
parent 469f5036
Pipeline #13158 passed with stages
in 2 minutes and 20 seconds
variables:
GIT_SUBMODULE_STRATEGY: recursive
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
cache:
paths:
- .gradle/wrapper
- .gradle/caches
stages:
- build
- test
......
[submodule "relast.preprocessor"]
path = relast.preprocessor
url = ../relast-preprocessor.git
[submodule "dumpAst/src/main/jastadd/mustache"]
path = dumpAst/src/main/jastadd/mustache
url = ../mustache
plugins {
id 'com.github.ben-manes.versions' version '0.36.0'
id 'java'
}
java.toolchain.languageVersion = JavaLanguageVersion.of(11)
// --- Buildscripts (must be at the top) ---
buildscript {
repositories.mavenLocal()
repositories.mavenCentral()
dependencies {
classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
......@@ -9,23 +8,30 @@ buildscript {
// --- Plugin definitions ---
plugins {
id 'com.github.ben-manes.versions'
id 'java'
id 'idea'
id 'com.github.ben-manes.versions'
id 'org.jastadd'
id 'java-library'
id 'maven-publish'
}
apply plugin: 'jastadd'
// --- Dependencies ---
repositories {
mavenCentral()
maven {
name 'gitlab-maven'
url 'https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven'
}
}
configurations {
relast
}
dependencies {
jastadd2 "org.jastadd:jastadd:2.3.5"
// https://mvnrepository.com/artifact/net.sourceforge.plantuml/plantuml
relast group: 'org.jastadd', name: 'relast', version: "${relast_version}"
implementation group: 'net.sourceforge.plantuml', name: 'plantuml', version: '1.2022.2'
api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "0.9.10"
......@@ -42,18 +48,15 @@ File mustacheGrammar = file('./src/main/jastadd/mustache/Mustache.relast')
task relast(type: JavaExec) {
group = 'Build'
main = "-jar"
classpath = configurations.relast
mainClass = 'org.jastadd.relast.compiler.Compiler'
doFirst {
delete "src/gen/jastadd/*.ast"
delete "src/gen/jastadd/DumpAst.jadd"
delete "src/gen/jastadd/DumpAstRefResolver.jadd"
delete "src/gen/jastadd/DumpAstResolverStubs.jrag"
delete "src/gen/jastadd/*"
mkdir "src/gen/jastadd/"
}
args = [
"../libs/relast.jar",
dumpAstGrammar,
mustacheGrammar,
"--listClass=java.util.ArrayList",
......@@ -63,14 +66,6 @@ task relast(type: JavaExec) {
"--resolverHelper",
"--grammarName=./src/gen/jastadd/DumpAst"
]
inputs.files(file("../libs/relast.jar"),
dumpAstGrammar,
mustacheGrammar)
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 ---
......@@ -121,6 +116,16 @@ jastadd {
// --- Versioning and Publishing ---
group = 'de.tudresden.inf.st'
task fatJar(type: Jar) {
dependsOn jar
group = "build"
archiveAppendix = "fatjar"
from sourceSets.main.output
from {
configurations.runtimeClasspath.collect {it.isDirectory() ? it : zipTree(it) }
}
}
def versionFile = "src/main/resources/${project.getName()}Version.properties"
try {
......
aspect GenerationFrontend {
public class Dumper {
/**
* Prepare to read in the given object. Use the <code>dump*</code> methods to actually dump its content.
* @param obj the object to dump
* @return a builder to adjust dump options
*/
public static DumpBuilder read(Object obj) {
return new DumpBuilder(obj);
}
}
public enum SkinParamBooleanSetting {
/** Print in grayscale? */
Monochrome,
/** Use shadows? */
Shadowing,
/** Use handwritten style? */
Handwritten
}
public enum SkinParamStringSetting {
/** Set color of background */
backgroundColor
}
/**
* Building a dump.
* <p>
*
* <h3>Inclusion and Exclusion of Types</h3>
* Types can be only be disabled, see {@link #disableTypes(String[])}.
*
* <h3>Inclusion and Exclusion of Childrens, tokens and relations</h3>
* Childrens, tokens and relations are included by default.
* This can be changed using exclusions and inclusion, both in general and per-type.
* They are applied in the following order making later conditions take precedence over the first ones.
* <ol>
* <li>Include everything as default.
* <li>Exclude general.
* <li>Include per type.
* <li>Exclude per type.
* </ol>
*
* <h3>Inclusion and Exclusion of Attributes</h3>
* Attributes are excluded by default, i.e., not shown.
* This can be changed using inclusions and exclusions, both in general and per-type.
* They are applied in the following order making later conditions take precedence over the first ones.
* <ol>
* <li> Exclude everything as default.
* <li> Include general.
* <li> Exclude per type.
* <li> Include per type
* </ol>
*/
public class DumpBuilder {
private final Object target;
private String packageName;
private DumpAst result;
private final BuildConfig buildConfig;
private final PrintConfig printConfig;
protected DumpBuilder(Object target) {
this.target = target;
buildConfig = new BuildConfig();
buildConfig.setGlobalPatternCollection(new PatternCollection());
buildConfig.setStyleInformation(StyleInformation.createDefault());
printConfig = new PrintConfig();
printConfig.setScale(1);
printConfig.setVersion(readVersion());
}
/**
* Add debug information in dumped content, mainly version numbers.
* @return this
*/
public DumpBuilder enableDebug() {
buildConfig.setDebug(true);
return this;
}
/**
* Include empty strings for all tokens
* @return this
*/
public DumpBuilder includeEmptyStringsOnTokens() {
buildConfig.setIncludeEmptyString(true);
return this;
}
/**
* Disable all objects with types matching at least one of the given regex strings.
* Disabled objects won't be included in any output. However, their children are still processed.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes patterns to match type names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder disableTypes(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getTypeIgnorePattern(),
s -> buildConfig.setTypeIgnorePattern(s),
regex, moreRegexes);
return this;
}
/**
* Exclude tokens and their value if the token name matches at least one of the given regex strings.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes regex patterns to match token names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder excludeTokens(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getGlobalPatternCollection().getTokenPattern(),
s -> buildConfig.getGlobalPatternCollection().setTokenPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder excludeTokensFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex);
updateRegexes(() -> collection.getTokenPattern(),
s -> collection.setTokenPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder excludeChildrenFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex);
updateRegexes(() -> collection.getChildPattern(),
s -> collection.setChildPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder excludeRelationsFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex);
updateRegexes(() -> collection.getRelationPattern(),
s -> collection.setRelationPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder excludeAttributesFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex);
updateRegexes(() -> collection.getAttributePattern(),
s -> collection.setAttributePattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder excludeNonterminalAttributesFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateExcludePatternCollection(typeRegex);
updateRegexes(() -> collection.getNonterminalAttributePattern(),
s -> collection.setNonterminalAttributePattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder includeTokensFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex);
updateRegexes(() -> collection.getTokenPattern(),
s -> collection.setTokenPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder includeChildrenFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex);
updateRegexes(() -> collection.getChildPattern(),
s -> collection.setChildPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder includeRelationsFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex);
updateRegexes(() -> collection.getRelationPattern(),
s -> collection.setRelationPattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder includeAttributesFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex);
updateRegexes(() -> collection.getAttributePattern(),
s -> collection.setAttributePattern(s),
regex, moreRegexes);
return this;
}
/** TODO: document, implement, sort */
public DumpBuilder includeNonterminalAttributesFor(String typeRegex, String regex, String... moreRegexes) {
PatternCollection collection = findOrCreateIncludePatternCollection(typeRegex);
updateRegexes(() -> collection.getNonterminalAttributePattern(),
s -> collection.setNonterminalAttributePattern(s),
regex, moreRegexes);
return this;
}
/**
* Include attributes (as tokens) and their value if the attribute name matches at least on of the given regex strings.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes regex patterns to match token names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder includeAttributes(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getGlobalPatternCollection().getAttributePattern(),
s -> buildConfig.getGlobalPatternCollection().setAttributePattern(s),
regex, moreRegexes);
return this;
}
/**
* Includes nonterminal-attributes (as children) and their values if
* their attribute name matches at least on of the given regex strings.
* <br>
* <b>Note</b>: A leading "get" and a trailing "List" in the name will be removed prior to matching.
* Thus, it should not be contained in the regex either.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes regex patterns to match token names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder includeNonterminalAttributes(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getGlobalPatternCollection().getNonterminalAttributePattern(),
s -> buildConfig.getGlobalPatternCollection().setNonterminalAttributePattern(s),
regex, moreRegexes);
return this;
}
/**
* Exclude every child whose name (i.e., context) matches at least on of the given regex strings.
* This means, that the complete object and its (transitive) children will never be included in any output.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes regex patterns to match child names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder excludeChildren(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getGlobalPatternCollection().getChildPattern(),
s -> buildConfig.getGlobalPatternCollection().setChildPattern(s),
regex, moreRegexes);
return this;
}
/**
* Exclude every relation whose role-name matches at least on of the given regex strings.
* This means two things: a) the relation to any potential target object(s) is never shown, and b) the target
* object(s) are not shown unless they are reachable by another relation or by containment.
* <p>
* See {@link DumpBuilder} for details on inclusion and exclusion precedence.
* @param regexes regex patterns to match child names
* @return this
* @see java.util.regex.Pattern#compile(java.lang.String)
*/
public DumpBuilder excludeRelations(String regex, String... moreRegexes) {
updateRegexes(() -> buildConfig.getGlobalPatternCollection().getRelationPattern(),
s -> buildConfig.getGlobalPatternCollection().setRelationPattern(s),
regex, moreRegexes);
return this;
}
private PatternCollection findOrCreateIncludePatternCollection(String typeRegex) {
PatternCollection result = buildConfig.findIncludePatternCollection(typeRegex);
if (result == null) {
TypePatternCollectionMapping mapping = new TypePatternCollectionMapping();
mapping.setTypeRegex(typeRegex);
result = new PatternCollection();
mapping.setPatternCollection(result);
buildConfig.addIncludeTypePattern(mapping);
}
return result;
}
private PatternCollection findOrCreateExcludePatternCollection(String typeRegex) {
PatternCollection result = buildConfig.findExcludePatternCollection(typeRegex);
if (result == null) {
TypePatternCollectionMapping mapping = new TypePatternCollectionMapping();
mapping.setTypeRegex(typeRegex);
result = new PatternCollection();
mapping.setPatternCollection(result);
buildConfig.addExcludeTypePattern(mapping);
}
return result;
}
private void updateRegexes(java.util.function.Supplier<String> getter, java.util.function.Consumer<String> setter, String regex, String... moreRegexes) {
if (getter.get().isEmpty()) {
setter.accept(regex);
} else {
setter.accept(getter.get() + "|" + regex);
}
for (String value : moreRegexes) {
setter.accept(getter.get() + "|" + value);
}
}
public DumpBuilder excludeNullNodes() {
buildConfig.setExcludeNullNodes(true);
return this;
}
public DumpBuilder includeNullNodes() {
buildConfig.setExcludeNullNodes(false);
return this;
}
public DumpBuilder customPreamble(String option) {
printConfig.addHeader(new Header(option));
return this;
}
public DumpBuilder skinParam(SkinParamStringSetting setting, String value) {
customPreamble("skinparam " + setting.toString() + " " + value);
return this;
}
public DumpBuilder skinParam(SkinParamBooleanSetting setting, boolean value) {
customPreamble("skinparam " + setting.toString() + " " + value);
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 <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;
}
public DumpBuilder orderChildren() {
printConfig.setOrderChildren(true);
return this;
}
private String readVersion() {
try {
java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("dumpAstVersion");
return resources.getString("version");
} catch (java.util.MissingResourceException e) {
return "version ?";
}
}
protected DumpAst build() {
if (result == null) {
result = new DumpAst();
final String packageNameToUse;
if (this.packageName != null) {
packageNameToUse = this.packageName;
} else {
if (this.target == null) {
packageNameToUse = null;
} else {
packageNameToUse = this.target.getClass().getPackage().getName();
}
}
result.setPackageName(packageNameToUse);
result.setBuildConfig(this.buildConfig);
result.setPrintConfig(this.printConfig);
try {
result.transform(new TransformationTransferInformation(), this.target);
} catch (java.lang.reflect.InvocationTargetException e) {
throw new RuntimeException("Could not transform :(", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not transform :(", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not transform :(", e);
}
}
return result;
}
/**
* Write out content as plantuml source code.
* @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 dumpAsSource(java.nio.file.Path destination) throws java.io.IOException {
String content = build().toPlantUml();
try (java.io.Writer writer = java.nio.file.Files.newBufferedWriter(destination)) {
writer.write(content);
}
return this;
}
public DumpBuilder dumpAsYaml(java.nio.file.Path destination, boolean prependCreationComment) throws java.io.IOException {
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;
}
}
}
package de.tudresden.inf.st.jastadd.dumpAst.ast;
/**
* Entrypoint for dumpAst.
*
* @author rschoene - Initial contribution
*/
public class Dumper {
/**
* Prepare to read in the given object. Use the <code>dump*</code> methods to actually dump its content.
* @param obj the object to dump
* @return a builder to adjust dump options
*/
public static DumpBuilder read(Object obj) {
return new DumpBuilder(obj);
}
}
package de.tudresden.inf.st.jastadd.dumpAst.ast;
public enum SkinParamBooleanSetting {
/**
* Print in grayscale?
*/
Monochrome,
/**
* Use shadows?
*/
Shadowing,
/**
* Use handwritten style?
*/
Handwritten
}
package de.tudresden.inf.st.jastadd.dumpAst.ast;
public enum SkinParamStringSetting {
/**