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

move to handlebars, merge two packages into one

parent 8e910ed0
Pipeline #12810 failed with stages
in 2 minutes and 17 seconds
......@@ -14,8 +14,11 @@ 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: 'com.github.jknack', name: 'handlebars', version: '4.2.0'
implementation group: 'org.yaml', name: 'snakeyaml', version: '1.27'
}
File dumpAstGrammar = file('./src/main/jastadd/DumpAst.relast')
......
......@@ -491,8 +491,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);
......@@ -597,85 +597,6 @@ 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();
......
......@@ -406,5 +406,32 @@ public class DumpBuilder {
}
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;
}
}
}
aspect GenerationMustache {
syn String DumpAst.toPlantUml() {
StringBuilder sb = new StringBuilder();
com.github.mustachejava.reflect.ReflectionObjectHandler roh = new com.github.mustachejava.reflect.ReflectionObjectHandler() {
@Override
public com.github.mustachejava.Binding createBinding(String name, final com.github.mustachejava.TemplateContext tc, com.github.mustachejava.Code code) {
return new com.github.mustachejava.reflect.GuardedBinding(this, name, tc, code) {
@Override
protected synchronized com.github.mustachejava.util.Wrapper getWrapper(String name, java.util.List<Object> scopes) {
com.github.mustachejava.util.Wrapper wrapper = super.getWrapper(name, scopes);
if (wrapper instanceof com.github.mustachejava.reflect.MissingWrapper) {
throw new com.github.mustachejava.MustacheException(name + " not found in " + tc);
}
return wrapper;
}
};
}
};
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);
return sb.toString();
}
}
aspect GenerationToPlantUml {
syn String DumpAst.toPlantUml() {
try {
//Context context = Context
// .newBuilder(this)
// .resolver(
// com.github.jknack.handlebars.context.JavaBeanValueResolver.INSTANCE,
// com.github.jknack.handlebars.context.MethodValueResolver.INSTANCE
// )
// .build();
String yaml = this.toYaml(false);
Object context = new org.yaml.snakeyaml.Yaml().load(new StringReader(yaml));
return getTemplate("dumpAst").apply(context);
} catch (java.io.IOException e) {
return "\nAn Error occured:\n" + e.getMessage();
}
}
private static void DumpAst.applyTemplate(String templateFileName, String outputFileName, Object context) throws java.io.IOException {
try (java.io.Writer w = new java.io.FileWriter(outputFileName)) {
getTemplate(templateFileName).apply(context, w);
w.flush();
}
}
private static com.github.jknack.handlebars.Template DumpAst.getTemplate(String templateFileName) throws java.io.IOException {
com.github.jknack.handlebars.io.TemplateLoader loader = new com.github.jknack.handlebars.io.ClassPathTemplateLoader();
loader.setSuffix(".mustache"); // the default is ".hbs"
com.github.jknack.handlebars.Handlebars handlebars = new com.github.jknack.handlebars.Handlebars(loader);
handlebars.registerHelperMissing(new Helper<Object>() {
@Override
public CharSequence apply(final Object context, final Options options) throws IOException {
return options.fn.text();
}
});
handlebars.prettyPrint(true); // set handlebars to mustache mode (skip some whitespace)
return handlebars.compile(templateFileName);
}
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() {
}
}
}
aspect GenerationToYaml {
syn String DumpAst.toYaml(boolean prependCreationComment) {
Document doc = new Document();
doc.setRootElement(this.toYaml());
return doc.prettyPrint(prependCreationComment);
}
// todo: default impl should actually be abstract instead
syn MappingElement ASTNode.toYaml() = new MappingElement();
static MappingElement ASTNode.safeToYaml(ASTNode node) {
if (node == null) {
return null;
}
return node.toYaml();
}
syn MappingElement DumpAst.toYaml() {
MappingElement result = new MappingElement();
// children
result.put("PrintConfig", safeToYaml(getPrintConfig()));
addYamledList(result, "DumpNodes", getDumpNodeList());
return result;
}
static void ASTNode.addYamledList(MappingElement base, String key, Iterable<? extends ASTNode<?>> iterable) {
ListElement innerList = new ListElement();
for (ASTNode node : iterable) {
innerList.add(safeToYaml(node));
}
base.put(key, innerList);
}
syn MappingElement PrintConfig.toYaml() {
MappingElement result = new MappingElement();
// children
addYamledList(result, "Headers", getHeaderList());
// tokens
result.put("scale", getScale());
result.put("version", getVersion());
result.put("orderChildren", getOrderChildren());
// attributes
result.put("debug", debug());
return result;
}
syn MappingElement Header.toYaml() {
MappingElement result = new MappingElement();
// tokens
result.put("value", getValue());
return result;
}
syn MappingElement DumpNode.toYaml() {
return toYaml(false);
}
syn MappingElement DumpNode.toYaml(boolean fromMyChildren) {
MappingElement result = new MappingElement();
// children
if (!fromMyChildren) {
addYamledList(result, "DumpChildNodes", getDumpChildNodeList());
addYamledList(result, "DumpTokens", getDumpTokenList());
addYamledList(result, "DumpRelations", getDumpRelationList());
}
// tokens
result.put("name", getName());
if (!fromMyChildren) {
result.put("label", getLabel());
result.put("backgroundColor", getBackgroundColor());
result.put("textColor", getTextColor());
result.put("invisible", getInvisible());
}
// attributes
if (!fromMyChildren) {
result.put("isAstNode", isAstNode());
result.put("labelAndTextColor", labelAndTextColor());
addYamledList(result, "myChildren", myChildren());
}
result.put("hasSuccessor", hasSuccessor());
result.put("successor", safeToYaml(successor()));
// NTAs
if (!fromMyChildren) {
result.put("InvisiblePath", safeToYaml(getInvisiblePath()));
}
return result;
}
syn MappingElement DumpChildNode.toYaml() {
MappingElement result = new MappingElement();
// tokens
result.put("name", getName());
// attributes
result.put("label", label());
result.put("isList", isList());
result.put("outerNodeName", outerNodeName());
return result;
}
syn MappingElement DumpNormalChildNode.toYaml() {
MappingElement result = super.toYaml();
// attributes
result.put("bothVisible", bothVisible());
result.put("innerNodeName", innerNodeName());
return result;
}
syn MappingElement DumpListChildNode.toYaml() {
MappingElement result = super.toYaml();
// children
addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList());
return result;
}
syn MappingElement DumpToken.toYaml() {
MappingElement result = new MappingElement();
// tokens
result.put("name", getName());
// attributes
result.put("label", label());
result.put("isDumpValueToken", isDumpValueToken());
return result;
}
syn MappingElement DumpValueToken.toYaml() {
MappingElement result = super.toYaml();
// tokens
result.put("value", getValue().toString());
return result;
}
syn MappingElement DumpReferenceToken.toYaml() {
MappingElement result = super.toYaml();
// tokens
result.put("innerNodeName", innerNodeName());
result.put("outerNodeName", outerNodeName());
return result;
}
syn MappingElement DumpRelation.toYaml() {
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() {
MappingElement result = super.toYaml();
// attributes
result.put("bothVisible", bothVisible());
result.put("innerNodeName", innerNodeName());
return result;
}
syn MappingElement InnerDumpNode.toYaml() {
MappingElement result = new MappingElement();
// attributes
result.put("bothVisible", bothVisible());
result.put("innerNodeName", innerNodeName());
result.put("outerNodeName", outerNodeName());
return result;
}
syn MappingElement InvisiblePath.toYaml() {
MappingElement result = super.toYaml();
// children
addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList());
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);
}
}
import java.io.*;
import java.util.*;
import com.github.jknack.handlebars.*;
import com.github.jknack.handlebars.io.*;
aspect Imports {}
......@@ -7,6 +7,7 @@ aspect Navigation {
// --- buildConfig ---
inh BuildConfig DumpNode.buildConfig();
inh BuildConfig PrintConfig.buildConfig();
eq DumpAst.getChild().buildConfig() = getBuildConfig();
// --- printConfig ---
......
@startuml
{{#PrintConfig}}
scale {{{Scale}}}
scale {{{scale}}}
{{#Headers}}
{{{Value}}}
{{{value}}}
{{/Headers}}
{{/PrintConfig}}
{{#DumpNodes}}
{{#isAstNode}}
{{^Invisible}}
{{^invisible}}
object "{{{labelAndTextColor}}}" as {{{name}}} {{#backgroundColor}}#{{{backgroundColor}}}{{/backgroundColor}} {
{{#DumpTokens}}
{{#isDumpValueToken}}
{{{label}}} = {{{Value}}}
{{{label}}} = {{{value}}}
{{/isDumpValueToken}}
{{/DumpTokens}}
}
{{/Invisible}}
{{/invisible}}
{{/isAstNode}}
{{/DumpNodes}}
{{#DumpNodes}}
{{#DumpTokens}}
{{^Invisible}}
{{^invisible}}
{{^isDumpValueToken}}
{{{outerNodeName}}} ..> {{{innerNodeName}}} : {{{label}}}
{{/isDumpValueToken}}
{{/Invisible}}
{{/invisible}}
{{/DumpTokens}}
{{#DumpChildNodes}}
{{#isList}}
......@@ -46,23 +46,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}}
......@@ -71,13 +71,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
#Thu Feb 24 09:45:15 CET 2022
version=0.3.6
#Tue Mar 01 11:14:25 CET 2022
version=0.4.0
build
src/gen-res/
src/gen/
out/
*.class
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