Skip to content
Snippets Groups Projects
Commit 99c0fbe1 authored by René Schöne's avatar René Schöne
Browse files

WIP dumpAst

parent 06a0e684
No related branches found
No related tags found
No related merge requests found
Pipeline #7844 passed
DumpAst ::= DumpNode* <PackageName> ;
DumpNode ::= <Name> <Object:Object> DumpChildNode* DumpToken* DumpRelation* ;
DumpAst ::= DumpNode* <PackageName> <Scale:double> ;
DumpNode ::= <Name> <Label> <Object:Object> DumpChildNode* DumpToken* DumpRelation* ;
InnerDumpNode ;
rel InnerDumpNode.DumpNode -> DumpNode ;
......
......@@ -4,10 +4,12 @@ aspect Generation {
return new DumpBuilder(obj);
}
}
class DumpBuilder {
public class DumpBuilder {
private Object target;
private String packageName;
private DumpAst result;
private java.util.List<String> header = new java.util.ArrayList<>();
protected DumpBuilder(Object target) {
this.target = target;
}
......@@ -29,11 +31,14 @@ aspect Generation {
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;
}
public DumpBuilder dumpAsSource(java.nio.file.Path destination) throws java.io.IOException {
build().setScale(0.1);
String content = build().toPlantUml();
try (java.io.Writer writer = java.nio.file.Files.newBufferedWriter(destination)) {
writer.write(content);
......@@ -41,15 +46,25 @@ aspect Generation {
return this;
}
public DumpBuilder dumpAsPNG(java.nio.file.Path destination) throws java.io.IOException {
build().setScale(0.1);
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;
}
public DumpBuilder dumpAsSVG(java.nio.file.Path destination) throws java.io.IOException {
build().setScale(1);
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;
}
}
// --- transform --- (need to be a method, because it alters the AST while traversing the object structure)
// maybe return type is unncessary
protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj) throws java.lang.reflect.InvocationTargetException, IllegalAccessException {
protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null) {
return null;
}
......@@ -58,11 +73,20 @@ aspect Generation {
}
DumpNode node = new DumpNode();
node.setObject(obj);
node.setLabel(obj.getClass().getSimpleName() + "@" + obj.hashCode());
node.setName("node" + tti.transformed.size());
tti.transformed.put(obj, node);
this.addDumpNode(node);
if (node.isAstNode()) {
// only caching node.analyseClass does not help, since we want to do this only once per class of a node
ClassAnalysisResult car = tti.classAnalysisResults.computeIfAbsent(node.getClass(), clz -> node.analyseClass());
final ClassAnalysisResult car;
Class<?> clazz = obj.getClass();
if (tti.classAnalysisResults.containsKey(clazz)) {
car = tti.classAnalysisResults.get(clazz);
} else {
car = node.analyzeClass();
tti.classAnalysisResults.put(clazz, car);
}
// -- singleChild --
for (java.lang.reflect.Method method : car.singleChildMethods) {
Object target = method.invoke(obj);
......@@ -76,7 +100,7 @@ aspect Generation {
// -- listChild --
for (java.lang.reflect.Method method : car.listChildMethods) {
Iterable<?> targetList = (Iterable<?>) method.invoke(obj);
DumpListChildNode listChild = new DumpNormalChildNode();
DumpListChildNode listChild = new DumpListChildNode();
listChild.setName(car.names.get(method));
for (Object target : targetList) {
if (target != null) {
......@@ -89,23 +113,23 @@ aspect Generation {
for (java.lang.reflect.Method method : car.singleRelationMethods) {
Object target = method.invoke(obj);
if (target != null) {
DumpNormalRelation normalChild = new DumpNormalRelation();
normalChild.setName(car.names.get(method));
normalChild.setDumpNode(transform(tti, target));
node.addDumpRelation(normalChild);
DumpNormalRelation normalRelation = new DumpNormalRelation();
normalRelation.setName(car.names.get(method));
normalRelation.setDumpNode(transform(tti, target));
node.addDumpRelation(normalRelation);
}
}
// -- listChild --
for (java.lang.reflect.Method method : car.listChildMethods) {
// -- listRelation --
for (java.lang.reflect.Method method : car.listRelationMethods) {
Iterable<?> targetList = (Iterable<?>) method.invoke(obj);
DumpListRelation listChild = new DumpNormalRelation();
listChild.setName(car.names.get(method));
DumpListRelation listRelation = new DumpListRelation();
listRelation.setName(car.names.get(method));
for (Object target : targetList) {
if (target != null) {
listChild.addInnerDumpNode(new InnerDumpNode(transform(tti, target)));
listRelation.addInnerDumpNode(new InnerDumpNode(transform(tti, target)));
}
}
node.addDumpRelation(listChild);
node.addDumpRelation(listRelation);
}
// -- token --
for (java.lang.reflect.Method method : car.tokenMethods) {
......@@ -114,12 +138,12 @@ aspect Generation {
DumpNode targetNode = transform(tti, target);
DumpToken token;
if (targetNode.isAstNode()) {
token = new DumpReferenceToken();
token.setValue(targetNode);
token = new DumpReferenceToken().setValue(targetNode);
} else {
// maybe ignore empty string values here
token = new DumpValueToken();
token.setValue(target);
DumpValueToken valueToken = new DumpValueToken();
valueToken.setValue(target);
token = valueToken;
}
token.setName(car.names.get(method));
node.addDumpToken(token);
......@@ -129,28 +153,93 @@ aspect Generation {
return node;
}
syn ClassAnalysisResult DumpNode.analyseClass() {
// TODO
return null;
ClassAnalysisResult DumpNode.analyzeClass()
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
ClassAnalysisResult result = new ClassAnalysisResult();
Class<?> clazz = getObject().getClass();
for (java.lang.reflect.Method method : clazz.getMethods()) {
for (java.lang.annotation.Annotation annotation : method.getAnnotations()) {
String canonicalName = annotation.annotationType().getCanonicalName();
if (canonicalName.startsWith(astNodeAnnotationPrefix())) {
String simpleName = annotation.annotationType().getSimpleName();
switch (simpleName) {
case "Child":
case "OptChild":
result.singleChildMethods.add(method);
break;
case "ListChild":
result.listChildMethods.add(method);
break;
case "Token":
// heuristic for relations
String tokenName = invokeName(annotation);
if (tokenName.startsWith("_impl_")) {
String relationName = tokenName.substring(6);
try {
java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName);
// normal get + token-name -> singleRelation
result.singleRelationMethods.add(relationMethod);
result.names.put(relationMethod, relationName);
continue;
} catch (NoSuchMethodException e) {
// ignore, but we know this is probably not a single relation
}
// try list-relation next
try {
java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName + "List");
// normal get + token-name + "List" -> listRelation
result.listRelationMethods.add(relationMethod);
result.names.put(relationMethod, relationName);
continue;
} catch (NoSuchMethodException e) {
// ignore, but we know this is probably not a relation at all
}
}
result.tokenMethods.add(method);
break;
default:
continue;
}
result.names.put(method, invokeName(annotation));
}
}
}
return result;
}
private static String DumpNode.invokeName(java.lang.annotation.Annotation annotation)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
return (String) annotation.annotationType().getMethod("name").invoke(annotation);
}
syn boolean DumpNode.isAstNode() {
// TODO
Class<?> clazz = getObject().getClass();
for (java.lang.reflect.Constructor<?> constructor : clazz.getConstructors()) {
for (java.lang.annotation.Annotation annotation : constructor.getAnnotations()) {
if (annotation.annotationType().getCanonicalName().startsWith(astNodeAnnotationPrefix()) &&
annotation.annotationType().getSimpleName().equals("Constructor")) {
return true;
}
}
}
return false;
}
inh String DumpNode.astNodeAnnotationPrefix();
eq DumpAst.getDumpNode().astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation";
class TransformationTransferInformation {
java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>();
java.util.Map<Class<?>, ClassAnalysisResult> classAnalysisResults = new java.util.HashMap<>();
}
class ClassAnalysisResult {
java.lang.reflect.Method[] singleChildMethods;
java.lang.reflect.Method[] listChildMethods;
java.lang.reflect.Method[] singleRelationMethods;
java.lang.reflect.Method[] listRelationMethods;
java.lang.reflect.Method[] tokenMethods;
java.util.Map<java.lang.reflect.Method, String> names;
java.util.List<java.lang.reflect.Method> singleChildMethods = new java.util.ArrayList<>();
java.util.List<java.lang.reflect.Method> listChildMethods = new java.util.ArrayList<>();
java.util.List<java.lang.reflect.Method> singleRelationMethods = new java.util.ArrayList<>();
java.util.List<java.lang.reflect.Method> listRelationMethods = new java.util.ArrayList<>();
java.util.List<java.lang.reflect.Method> tokenMethods = new java.util.ArrayList<>();
java.util.Map<java.lang.reflect.Method, String> names = new java.util.HashMap<>();
}
syn String DumpAst.toPlantUml() {
......
......@@ -19,5 +19,5 @@ aspect Printing {
syn String DumpChildNode.label() = getName();
syn String DumpRelation.label() = getName();
syn String DumpToken.label() = getName();
syn String DumpNode.label() = getLabel();
}
......@@ -25,11 +25,13 @@ import static org.jastadd.dumpAst2uml.compiler.SimpleMain.Kind.*;
*
* @author rschoene - Initial contribution
*/
@SuppressWarnings("unused")
public class SimpleMain {
public static void main(String[] args) {
// printing();
createManualAST();
public static void main(String[] args) throws Exception {
printing();
// createManualAST();
// small();
}
private static void createManualAST() {
......@@ -93,7 +95,7 @@ public class SimpleMain {
System.out.println(content);
}
private static void printing() {
private static void printing() throws IOException {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("mustache.debug", "true");
Grammar2Uml model = new Grammar2Uml();
......@@ -109,7 +111,34 @@ public class SimpleMain {
model.addFolder(folder1);
model.treeResolveAll();
traverseInitial(model.toMustache());
// traverseInitial(model.toMustache());
Dumper.read(model.toMustache())
.dumpAsSource(Paths.get("temp.plantuml"))
.dumpAsSVG(Paths.get("temp.svg"));
}
private static void small() throws IOException {
Program program = new Program();
GrammarFile grammar = new GrammarFile();
grammar.setFileName("foo.relast");
program.addGrammarFile(grammar);
TypeDecl typeDeclA = new TypeDecl();
typeDeclA.setName("A");
grammar.addDeclaration(typeDeclA);
TypeDecl typeDeclB = new TypeDecl();
typeDeclB.setName("B");
grammar.addDeclaration(typeDeclB);
LeftDirectedRelation relation = new LeftDirectedRelation();
relation.setSource(new NormalRole(typeDeclA, "myB"));
relation.setTarget(new UnnamedRole(typeDeclB));
grammar.addDeclaration(relation);
Dumper.read(program)
.dumpAsSource(Paths.get("grammar.plantuml"))
.dumpAsSVG(Paths.get("grammar.svg"));
}
static final String MORE_INDENT = "| ";
......
@startuml
scale {{Scale}}
{{#DumpNodes}}
object {{name}} {
{{! tokens }}
{{#isAstNode}}
object "{{label}}" as {{name}} {
{{#DumpTokens}}
{{#isDumpValueToken}}
{{label}} = {{Value}}
{{label}} = {{{Value}}}
{{/isDumpValueToken}}
{{/DumpTokens}}
}
{{/isAstNode}}
{{/DumpNodes}}
{{#DumpNodes}}
{{#DumpTokens}}
{{^isDumpValueToken}}
{{outerNodeName}} ..> {{innerNodeName}} : {{label}}
{{/isDumpValueToken}}
{{/DumpTokens}}
{{! child nodes }}
{{#DumpChildNodes}}
{{#isList}}
{{#InnerDumpNodes}}
......@@ -24,7 +28,6 @@ object {{name}} {
{{outerNodeName}} *-- {{innerNodeName}} : {{label}}
{{/isList}}
{{/DumpChildNodes}}
{{! relations }}
{{#DumpRelations}}
{{#isList}}
{{#InnerDumpNodes}}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment