From 8e910ed0ae90598db35bee2e09c9cd67a3c2a84f Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Fri, 25 Feb 2022 19:33:17 +0100 Subject: [PATCH] Null nodes have separate ids, and working ordered output. - grammar order was not taken into account so far, but is now, see #7 - whenever a DumpNode is created, a counter is increased, so all null nodes get different ids, see #10 - some relations seem to point to null after this change, maybe resulting in new bugs, let's see --- dumpAst/src/main/jastadd/DumpAst.relast | 2 +- .../src/main/jastadd/GeneratedNavigation.jrag | 224 ++++++++++++++++ .../src/main/jastadd/GenerationBackend.jadd | 250 ++++++++++++------ dumpAst/src/main/jastadd/Navigation.jrag | 25 -- dumpAst/src/main/jastadd/Printing.jrag | 9 +- .../st/jastadd/testDumper/TestDumperMain.java | 25 +- .../inf/st/jastadd/testDumper/TestSimple.java | 33 ++- .../inf/st/jastadd/testDumper/TestUtils.java | 4 +- 8 files changed, 448 insertions(+), 124 deletions(-) create mode 100644 dumpAst/src/main/jastadd/GeneratedNavigation.jrag diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst/src/main/jastadd/DumpAst.relast index 2fad59a..3701605 100644 --- a/dumpAst/src/main/jastadd/DumpAst.relast +++ b/dumpAst/src/main/jastadd/DumpAst.relast @@ -35,7 +35,7 @@ DumpListRelation : DumpRelation ::= InnerDumpNode* ; // type of NTA InvisiblePath ::= InnerDumpNode* ; -ClassAnalysisResult ::= AnalysedMethod* ; +ClassAnalysisResult ::= ContainmentMethod:AnalysedMethod* OtherMethod:AnalysedMethod* ; abstract AnalysedMethod ::= <Method:java.lang.reflect.Method> <Name> ; abstract SingleChildMethod : AnalysedMethod ; diff --git a/dumpAst/src/main/jastadd/GeneratedNavigation.jrag b/dumpAst/src/main/jastadd/GeneratedNavigation.jrag new file mode 100644 index 0000000..be7166a --- /dev/null +++ b/dumpAst/src/main/jastadd/GeneratedNavigation.jrag @@ -0,0 +1,224 @@ +aspect Navigation { + + /** Tests if TokenMethod is a IntrinsicTokenMethod. + * @return 'true' if this is a IntrinsicTokenMethod, otherwise 'false' + */ + syn boolean TokenMethod.isIntrinsicTokenMethod() = false; + eq IntrinsicTokenMethod.isIntrinsicTokenMethod() = true; + + /** Tests if TokenMethod is a AttributeMethod. + * @return 'true' if this is a AttributeMethod, otherwise 'false' + */ + syn boolean TokenMethod.isAttributeMethod() = false; + eq AttributeMethod.isAttributeMethod() = true; + + /** Tests if AnalysedMethod is a SingleChildMethod. + * @return 'true' if this is a SingleChildMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isSingleChildMethod() = false; + eq SingleChildMethod.isSingleChildMethod() = true; + + /** Tests if AnalysedMethod is a ListChildMethod. + * @return 'true' if this is a ListChildMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isListChildMethod() = false; + eq ListChildMethod.isListChildMethod() = true; + + /** Tests if AnalysedMethod is a SingleRelationMethod. + * @return 'true' if this is a SingleRelationMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isSingleRelationMethod() = false; + eq SingleRelationMethod.isSingleRelationMethod() = true; + + /** Tests if AnalysedMethod is a ListRelationMethod. + * @return 'true' if this is a ListRelationMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isListRelationMethod() = false; + eq ListRelationMethod.isListRelationMethod() = true; + + /** Tests if AnalysedMethod is a TokenMethod. + * @return 'true' if this is a TokenMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isTokenMethod() = false; + eq TokenMethod.isTokenMethod() = true; + + /** Tests if DumpRelation is a DumpNormalRelation. + * @return 'true' if this is a DumpNormalRelation, otherwise 'false' + */ + syn boolean DumpRelation.isDumpNormalRelation() = false; + eq DumpNormalRelation.isDumpNormalRelation() = true; + + /** Tests if DumpRelation is a DumpListRelation. + * @return 'true' if this is a DumpListRelation, otherwise 'false' + */ + syn boolean DumpRelation.isDumpListRelation() = false; + eq DumpListRelation.isDumpListRelation() = true; + + /** Tests if DumpChildNode is a DumpNormalChildNode. + * @return 'true' if this is a DumpNormalChildNode, otherwise 'false' + */ + syn boolean DumpChildNode.isDumpNormalChildNode() = false; + eq DumpNormalChildNode.isDumpNormalChildNode() = true; + + /** Tests if DumpChildNode is a DumpListChildNode. + * @return 'true' if this is a DumpListChildNode, otherwise 'false' + */ + syn boolean DumpChildNode.isDumpListChildNode() = false; + eq DumpListChildNode.isDumpListChildNode() = true; + + /** Tests if ListChildMethod is a NormalListChildMethod. + * @return 'true' if this is a NormalListChildMethod, otherwise 'false' + */ + syn boolean ListChildMethod.isNormalListChildMethod() = false; + eq NormalListChildMethod.isNormalListChildMethod() = true; + + /** Tests if ListChildMethod is a NTAListChildMethod. + * @return 'true' if this is a NTAListChildMethod, otherwise 'false' + */ + syn boolean ListChildMethod.isNTAListChildMethod() = false; + eq NTAListChildMethod.isNTAListChildMethod() = true; + + /** Tests if SingleChildMethod is a NormalSingleChildMethod. + * @return 'true' if this is a NormalSingleChildMethod, otherwise 'false' + */ + syn boolean SingleChildMethod.isNormalSingleChildMethod() = false; + eq NormalSingleChildMethod.isNormalSingleChildMethod() = true; + + /** Tests if SingleChildMethod is a NTASingleChildMethod. + * @return 'true' if this is a NTASingleChildMethod, otherwise 'false' + */ + syn boolean SingleChildMethod.isNTASingleChildMethod() = false; + eq NTASingleChildMethod.isNTASingleChildMethod() = true; + + /** Tests if DumpToken is a DumpReferenceToken. + * @return 'true' if this is a DumpReferenceToken, otherwise 'false' + */ + syn boolean DumpToken.isDumpReferenceToken() = false; + eq DumpReferenceToken.isDumpReferenceToken() = true; + + /** Tests if DumpToken is a DumpValueToken. + * @return 'true' if this is a DumpValueToken, otherwise 'false' + */ + syn boolean DumpToken.isDumpValueToken() = false; + eq DumpValueToken.isDumpValueToken() = true; + + /** casts a TokenMethod into a IntrinsicTokenMethod if possible. + * @return 'this' cast to a IntrinsicTokenMethod or 'null' + */ + syn IntrinsicTokenMethod TokenMethod.asIntrinsicTokenMethod(); + eq TokenMethod.asIntrinsicTokenMethod() = null; + eq IntrinsicTokenMethod.asIntrinsicTokenMethod() = this; + + /** casts a TokenMethod into a AttributeMethod if possible. + * @return 'this' cast to a AttributeMethod or 'null' + */ + syn AttributeMethod TokenMethod.asAttributeMethod(); + eq TokenMethod.asAttributeMethod() = null; + eq AttributeMethod.asAttributeMethod() = this; + + /** casts a AnalysedMethod into a SingleChildMethod if possible. + * @return 'this' cast to a SingleChildMethod or 'null' + */ + syn SingleChildMethod AnalysedMethod.asSingleChildMethod(); + eq AnalysedMethod.asSingleChildMethod() = null; + eq SingleChildMethod.asSingleChildMethod() = this; + + /** casts a AnalysedMethod into a ListChildMethod if possible. + * @return 'this' cast to a ListChildMethod or 'null' + */ + syn ListChildMethod AnalysedMethod.asListChildMethod(); + eq AnalysedMethod.asListChildMethod() = null; + eq ListChildMethod.asListChildMethod() = this; + + /** casts a AnalysedMethod into a SingleRelationMethod if possible. + * @return 'this' cast to a SingleRelationMethod or 'null' + */ + syn SingleRelationMethod AnalysedMethod.asSingleRelationMethod(); + eq AnalysedMethod.asSingleRelationMethod() = null; + eq SingleRelationMethod.asSingleRelationMethod() = this; + + /** casts a AnalysedMethod into a ListRelationMethod if possible. + * @return 'this' cast to a ListRelationMethod or 'null' + */ + syn ListRelationMethod AnalysedMethod.asListRelationMethod(); + eq AnalysedMethod.asListRelationMethod() = null; + eq ListRelationMethod.asListRelationMethod() = this; + + /** casts a AnalysedMethod into a TokenMethod if possible. + * @return 'this' cast to a TokenMethod or 'null' + */ + syn TokenMethod AnalysedMethod.asTokenMethod(); + eq AnalysedMethod.asTokenMethod() = null; + eq TokenMethod.asTokenMethod() = this; + + /** casts a DumpRelation into a DumpNormalRelation if possible. + * @return 'this' cast to a DumpNormalRelation or 'null' + */ + syn DumpNormalRelation DumpRelation.asDumpNormalRelation(); + eq DumpRelation.asDumpNormalRelation() = null; + eq DumpNormalRelation.asDumpNormalRelation() = this; + + /** casts a DumpRelation into a DumpListRelation if possible. + * @return 'this' cast to a DumpListRelation or 'null' + */ + syn DumpListRelation DumpRelation.asDumpListRelation(); + eq DumpRelation.asDumpListRelation() = null; + eq DumpListRelation.asDumpListRelation() = this; + + /** casts a DumpChildNode into a DumpNormalChildNode if possible. + * @return 'this' cast to a DumpNormalChildNode or 'null' + */ + syn DumpNormalChildNode DumpChildNode.asDumpNormalChildNode(); + eq DumpChildNode.asDumpNormalChildNode() = null; + eq DumpNormalChildNode.asDumpNormalChildNode() = this; + + /** casts a DumpChildNode into a DumpListChildNode if possible. + * @return 'this' cast to a DumpListChildNode or 'null' + */ + syn DumpListChildNode DumpChildNode.asDumpListChildNode(); + eq DumpChildNode.asDumpListChildNode() = null; + eq DumpListChildNode.asDumpListChildNode() = this; + + /** casts a ListChildMethod into a NormalListChildMethod if possible. + * @return 'this' cast to a NormalListChildMethod or 'null' + */ + syn NormalListChildMethod ListChildMethod.asNormalListChildMethod(); + eq ListChildMethod.asNormalListChildMethod() = null; + eq NormalListChildMethod.asNormalListChildMethod() = this; + + /** casts a ListChildMethod into a NTAListChildMethod if possible. + * @return 'this' cast to a NTAListChildMethod or 'null' + */ + syn NTAListChildMethod ListChildMethod.asNTAListChildMethod(); + eq ListChildMethod.asNTAListChildMethod() = null; + eq NTAListChildMethod.asNTAListChildMethod() = this; + + /** casts a SingleChildMethod into a NormalSingleChildMethod if possible. + * @return 'this' cast to a NormalSingleChildMethod or 'null' + */ + syn NormalSingleChildMethod SingleChildMethod.asNormalSingleChildMethod(); + eq SingleChildMethod.asNormalSingleChildMethod() = null; + eq NormalSingleChildMethod.asNormalSingleChildMethod() = this; + + /** casts a SingleChildMethod into a NTASingleChildMethod if possible. + * @return 'this' cast to a NTASingleChildMethod or 'null' + */ + syn NTASingleChildMethod SingleChildMethod.asNTASingleChildMethod(); + eq SingleChildMethod.asNTASingleChildMethod() = null; + eq NTASingleChildMethod.asNTASingleChildMethod() = this; + + /** casts a DumpToken into a DumpReferenceToken if possible. + * @return 'this' cast to a DumpReferenceToken or 'null' + */ + syn DumpReferenceToken DumpToken.asDumpReferenceToken(); + eq DumpToken.asDumpReferenceToken() = null; + eq DumpReferenceToken.asDumpReferenceToken() = this; + + /** casts a DumpToken into a DumpValueToken if possible. + * @return 'this' cast to a DumpValueToken or 'null' + */ + syn DumpValueToken DumpToken.asDumpValueToken(); + eq DumpToken.asDumpValueToken() = null; + eq DumpValueToken.asDumpValueToken() = this; + +} diff --git a/dumpAst/src/main/jastadd/GenerationBackend.jadd b/dumpAst/src/main/jastadd/GenerationBackend.jadd index beeb183..44f6283 100644 --- a/dumpAst/src/main/jastadd/GenerationBackend.jadd +++ b/dumpAst/src/main/jastadd/GenerationBackend.jadd @@ -52,7 +52,7 @@ aspect GenerationBackend { } else { node = new DumpNode(); node.setObject(obj); - node.setName("node" + tti.transformed.size()); + node.setName("node" + (tti.nodeCounter++)); tti.transformed.put(obj, node); this.addDumpNode(node); } @@ -73,85 +73,119 @@ aspect GenerationBackend { return node; } final ClassAnalysisResult car = analyzeClass(obj.getClass()); - // -- singleChild -- - for (SingleChildMethod singleChildMethod : car.singleChildMethods()) { - Object target = singleChildMethod.getMethod().invoke(obj); - String childName = singleChildMethod.getName(); - DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes()); - if (targetNode != null) { - DumpNormalChildNode normalChild = new DumpNormalChildNode(); - normalChild.setName(childName); - normalChild.setDumpNode(targetNode); - normalChild.setComputed(singleChildMethod.isNTASingleChildMethod()); - node.addDumpChildNode(normalChild); - } - } - // -- listChild -- - for (ListChildMethod listChildMethod : car.listChildMethods()) { - Iterable<?> targetList = (Iterable<?>) listChildMethod.getMethod().invoke(obj); - DumpListChildNode listChild = new DumpListChildNode(); - listChild.setComputed(listChildMethod.isNTAListChildMethod()); - String childName = listChildMethod.getName(); - boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName); - listChild.setName(childName); - for (Object target : targetList) { - DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble)); - if (target != null && targetNode != null) { - listChild.addInnerDumpNode(new InnerDumpNode(targetNode)); + for (AnalysedMethod containmentMethod : car.getContainmentMethodList()) { + if (containmentMethod.isSingleChildMethod()) { + // -- singleChild -- + Object target = containmentMethod.getMethod().invoke(obj); + String childName = containmentMethod.getName(); + DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes()); + if (targetNode != null) { + DumpNormalChildNode normalChild = new DumpNormalChildNode(); + normalChild.setName(childName); + normalChild.setDumpNode(targetNode); + normalChild.setComputed(false); + node.addDumpChildNode(normalChild); } - } - if (listChild.getNumInnerDumpNode() > 0) { - node.addDumpChildNode(listChild); - } - } - // -- singleRelation -- - for (SingleRelationMethod singleRelationMethod : car.singleRelationMethods()) { - Object target = singleRelationMethod.getMethod().invoke(obj); - DumpNode targetNode = transform(tti, target, Source.RELATION); - if (target != null && targetNode != null) { - DumpNormalRelation normalRelation = new DumpNormalRelation(); - normalRelation.setName(singleRelationMethod.getName()); - normalRelation.setDumpNode(targetNode); - node.addDumpRelation(normalRelation); + } else if (containmentMethod.isListChildMethod()) { + // -- listChild -- + Iterable<?> targetList = (Iterable<?>) containmentMethod.getMethod().invoke(obj); + DumpListChildNode listChild = new DumpListChildNode(); + listChild.setComputed(false); + String childName = containmentMethod.getName(); + boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName); + listChild.setName(childName); + for (Object target : targetList) { + DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble)); + if (target != null && targetNode != null) { + listChild.addInnerDumpNode(new InnerDumpNode().setDumpNode(targetNode)); + } + } + if (listChild.getNumInnerDumpNode() > 0) { + node.addDumpChildNode(listChild); + } + } else { + throw new RuntimeException("Unknown containment method type " + containmentMethod); } } - // -- listRelation -- - for (ListRelationMethod listRelationMethod : car.listRelationMethods()) { - Iterable<?> targetList = (Iterable<?>) listRelationMethod.getMethod().invoke(obj); - DumpListRelation listRelation = new DumpListRelation(); - listRelation.setName(listRelationMethod.getName()); - for (Object target : targetList) { + for (AnalysedMethod otherMethod : car.getOtherMethodList()) { + if (otherMethod.isSingleChildMethod()) { + // -- singleChild -- + Object target = otherMethod.getMethod().invoke(obj); + String childName = otherMethod.getName(); + DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes()); + if (targetNode != null) { + DumpNormalChildNode normalChild = new DumpNormalChildNode(); + normalChild.setName(childName); + normalChild.setDumpNode(targetNode); + normalChild.setComputed(otherMethod.asSingleChildMethod().isNTASingleChildMethod()); + node.addDumpChildNode(normalChild); + } + } else if (otherMethod.isListChildMethod()) { + // -- listChild -- + Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); + DumpListChildNode listChild = new DumpListChildNode(); + listChild.setComputed(otherMethod.asListChildMethod().isNTAListChildMethod()); + String childName = otherMethod.getName(); + boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName); + listChild.setName(childName); + for (Object target : targetList) { + DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble)); + if (target != null && targetNode != null) { + listChild.addInnerDumpNode(new InnerDumpNode().setDumpNode(targetNode)); + } + } + if (listChild.getNumInnerDumpNode() > 0) { + node.addDumpChildNode(listChild); + } + } else if (otherMethod.isSingleRelationMethod()) { + // -- singleRelation -- + Object target = otherMethod.getMethod().invoke(obj); DumpNode targetNode = transform(tti, target, Source.RELATION); if (target != null && targetNode != null) { - listRelation.addInnerDumpNode(new InnerDumpNode(targetNode)); + DumpNormalRelation normalRelation = new DumpNormalRelation(); + normalRelation.setName(otherMethod.getName()); + normalRelation.setDumpNode(targetNode); + node.addDumpRelation(normalRelation); } - } - if (listRelation.getNumInnerDumpNode() > 0) { - node.addDumpRelation(listRelation); - } - } - // -- token -- - for (TokenMethod tokenMethod : car.tokenMethods()) { - Object target = tokenMethod.getMethod().invoke(obj); - if (target != null) { - DumpNode targetNode = transform(tti, target, Source.RELATION); - DumpToken token = null; - // TODO check, if Iterable.isAssignableFrom(target.getClass()). - // if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's - if (targetNode != null && targetNode.isAstNode()) { - token = new DumpReferenceToken().setValue(targetNode); - } else { - if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) { - DumpValueToken valueToken = new DumpValueToken(); - valueToken.setValue(target); - token = valueToken; + } else if (otherMethod.isListRelationMethod()) { + // -- listRelation -- + Iterable<?> targetList = (Iterable<?>) otherMethod.getMethod().invoke(obj); + DumpListRelation listRelation = new DumpListRelation(); + listRelation.setName(otherMethod.getName()); + for (Object target : targetList) { + DumpNode targetNode = transform(tti, target, Source.RELATION); + if (target != null && targetNode != null) { + listRelation.addInnerDumpNode(new InnerDumpNode(targetNode)); } } - if (token != null) { - token.setName(tokenMethod.getName()); - token.setComputed(tokenMethod.isAttributeMethod()); - node.addDumpToken(token); + if (listRelation.getNumInnerDumpNode() > 0) { + node.addDumpRelation(listRelation); } + } else if (otherMethod.isTokenMethod()) { + // -- token -- + Object target = otherMethod.getMethod().invoke(obj); + if (target != null) { + DumpNode targetNode = transform(tti, target, Source.RELATION); + DumpToken token = null; + // TODO check, if Iterable.isAssignableFrom(target.getClass()). + // if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's + if (targetNode != null && targetNode.isAstNode()) { + token = new DumpReferenceToken().setValue(targetNode); + } else { + if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) { + DumpValueToken valueToken = new DumpValueToken(); + valueToken.setValue(target); + token = valueToken; + } + } + if (token != null) { + token.setName(otherMethod.getName()); + token.setComputed(otherMethod.asTokenMethod().isAttributeMethod()); + node.addDumpToken(token); + } + } + } else { + throw new RuntimeException("Unknown other method type " + otherMethod); } } return node; @@ -172,39 +206,43 @@ aspect GenerationBackend { syn nta ClassAnalysisResult DumpAst.analyzeClass(java.lang.Class<?> clazz) { ClassAnalysisResult result = new ClassAnalysisResult(); String clazzName = clazz.getSimpleName(); + java.util.List<String> targetOrder = targetOrder(clazz); 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(); + String contextNameToAdd = null; + AnalysedMethod containmentMethodToAdd = null; switch (simpleName) { case "Child": - String singleChildName = invokeName(annotation); + contextNameToAdd = invokeName(annotation); NormalSingleChildMethod singleChildMethod = new NormalSingleChildMethod(); singleChildMethod.setMethod(method); - singleChildMethod.setName(singleChildName); - result.addAnalysedMethod(singleChildMethod); + singleChildMethod.setName(contextNameToAdd); + containmentMethodToAdd = singleChildMethod; break; case "OptChild": - String optChildName = invokeName(annotation); + contextNameToAdd = invokeName(annotation); try { // the annotated method is "get???Opt", but we want "get???" - java.lang.reflect.Method realGetter = clazz.getMethod("get" + optChildName); + java.lang.reflect.Method realGetter = clazz.getMethod("get" + contextNameToAdd); NormalSingleChildMethod normalSingleChildMethod = new NormalSingleChildMethod(); normalSingleChildMethod.setMethod(realGetter); - normalSingleChildMethod.setName(optChildName); - result.addAnalysedMethod(normalSingleChildMethod); + normalSingleChildMethod.setName(contextNameToAdd); + containmentMethodToAdd = normalSingleChildMethod; } catch (NoSuchMethodException e) { - System.err.println("Could not find getter for Opt-child " + optChildName + " in " + clazzName); + System.err.println("Could not find getter for Opt-child " + contextNameToAdd + " in " + clazzName); throw new RuntimeException(e); } break; case "ListChild": String listChildName = invokeName(annotation); + contextNameToAdd = listChildName; NormalListChildMethod normalListChildMethod = new NormalListChildMethod(); normalListChildMethod.setMethod(method); normalListChildMethod.setName(listChildName); - result.addAnalysedMethod(normalListChildMethod); + containmentMethodToAdd = normalListChildMethod; break; case "Token": // heuristic for relations @@ -218,7 +256,7 @@ aspect GenerationBackend { SingleRelationMethod singleRelationMethod = new SingleRelationMethod(); singleRelationMethod.setMethod(relationMethod); singleRelationMethod.setName(relationName); - result.addAnalysedMethod(singleRelationMethod); + result.addOtherMethod(singleRelationMethod); } continue; } catch (NoSuchMethodException e) { @@ -232,7 +270,7 @@ aspect GenerationBackend { ListRelationMethod listRelationMethod = new ListRelationMethod(); listRelationMethod.setMethod(relationMethod); listRelationMethod.setName(relationName); - result.addAnalysedMethod(listRelationMethod); + result.addOtherMethod(listRelationMethod); } continue; } catch (NoSuchMethodException e) { @@ -243,7 +281,7 @@ aspect GenerationBackend { IntrinsicTokenMethod tokenMethod = new IntrinsicTokenMethod(); tokenMethod.setMethod(method); tokenMethod.setName(tokenName); - result.addAnalysedMethod(tokenMethod); + result.addOtherMethod(tokenMethod); } break; case "Attribute": @@ -263,12 +301,12 @@ aspect GenerationBackend { NTAListChildMethod ntaListChildMethod = new NTAListChildMethod(); ntaListChildMethod.setMethod(method); ntaListChildMethod.setName(attributeName); - result.addAnalysedMethod(ntaListChildMethod); + result.addOtherMethod(ntaListChildMethod); } else { NTASingleChildMethod ntaSingleChildMethod = new NTASingleChildMethod(); ntaSingleChildMethod.setMethod(method); ntaSingleChildMethod.setName(attributeName); - result.addAnalysedMethod(ntaSingleChildMethod); + result.addOtherMethod(ntaSingleChildMethod); } } } else if (isAttributeEnabled(clazzName, attributeName)) { @@ -276,16 +314,53 @@ aspect GenerationBackend { AttributeMethod attributeMethod = new AttributeMethod(); attributeMethod.setMethod(method); attributeMethod.setName(attributeName); - result.addAnalysedMethod(attributeMethod); + result.addOtherMethod(attributeMethod); } break; } + if (containmentMethodToAdd != null) { + int indexOfContextInTarget = targetOrder.indexOf(contextNameToAdd); + if (indexOfContextInTarget == 0) { + result.getContainmentMethodList().insertChild(containmentMethodToAdd, 0); + continue; + } + if (indexOfContextInTarget == targetOrder.size() - 1) { + result.addContainmentMethod(containmentMethodToAdd); + continue; + } + + for (int i = 0, size = result.getNumContainmentMethod(); i < size; i++) { + String currentContextName = result.getContainmentMethod(i).getName(); + int indexOfCurrentInTarget = targetOrder.indexOf(currentContextName); + if (indexOfCurrentInTarget > indexOfContextInTarget) { + result.getContainmentMethodList().insertChild(containmentMethodToAdd, i); + break; + } + } + result.addContainmentMethod(containmentMethodToAdd); + } } } } return result; } + syn java.util.List<String> DumpAst.targetOrder(Class<?> clazz) { + for (java.lang.reflect.Constructor<?> method : clazz.getConstructors()) { + for (java.lang.annotation.Annotation annotation : method.getAnnotations()) { + String canonicalName = annotation.annotationType().getCanonicalName(); + if (canonicalName.startsWith(astNodeAnnotationPrefix())) { + String simpleName = annotation.annotationType().getSimpleName(); + if (simpleName.equals("Constructor")) { + return java.util.Arrays.asList((String[]) invokeMethod("name", annotation)); + } + } + } + } + // there is no constructor with an annotation, iff the nonterminal has no children + return null; + } + private String DumpAst.titleCase(String s) { if (s.isEmpty()) { return s; @@ -468,7 +543,7 @@ aspect GenerationBackend { java.util.List<DumpNode> result = new java.util.ArrayList<>(); for (DumpChildNode childNode : getDumpChildNodeList()) { for (DumpNode inner : childNode.innerNodes(false)) { - if (inner.getInvisible()) { + if (inner != null && inner.getInvisible()) { result.addAll(inner.reachableThroughInvisible()); } else if (this.getInvisible()) { result.add(inner); @@ -519,6 +594,7 @@ aspect GenerationBackend { class TransformationTransferInformation { java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>(); java.util.Map<DumpNode, Boolean> relationTargetsUnprocessed = new java.util.HashMap<>(); + int nodeCounter = 0; } syn String DumpAst.toYaml(boolean prependCreationComment) { diff --git a/dumpAst/src/main/jastadd/Navigation.jrag b/dumpAst/src/main/jastadd/Navigation.jrag index 3f04c9c..05f722d 100644 --- a/dumpAst/src/main/jastadd/Navigation.jrag +++ b/dumpAst/src/main/jastadd/Navigation.jrag @@ -5,18 +5,6 @@ aspect Navigation { syn boolean DumpRelation.isList() = false; eq DumpListRelation.isList() = true; - // --- isDumpValueToken --- - syn boolean DumpToken.isDumpValueToken() = false; - eq DumpValueToken.isDumpValueToken() = true; - - // --- asDumpValueToken --- - syn DumpValueToken DumpToken.asDumpValueToken() = null; - eq DumpValueToken.asDumpValueToken() = this; - - // --- asDumpReferenceToken --- - syn DumpReferenceToken DumpToken.asDumpReferenceToken() = null; - eq DumpReferenceToken.asDumpReferenceToken() = this; - // --- buildConfig --- inh BuildConfig DumpNode.buildConfig(); eq DumpAst.getChild().buildConfig() = getBuildConfig(); @@ -97,17 +85,4 @@ aspect Navigation { coll java.util.List<TokenMethod> ClassAnalysisResult.tokenMethods() [new java.util.ArrayList<>()] root ClassAnalysisResult; TokenMethod contributes this to ClassAnalysisResult.tokenMethods(); - - // --- isAttributeMethod --- - syn boolean TokenMethod.isAttributeMethod() = false; - eq AttributeMethod.isAttributeMethod() = true; - - // --- isNTASingleChildMethod --- - syn boolean SingleChildMethod.isNTASingleChildMethod() = false; - eq NTASingleChildMethod.isNTASingleChildMethod() = true; - - // --- isNTAListChildMethod --- - syn boolean ListChildMethod.isNTAListChildMethod() = false; - eq NTAListChildMethod.isNTAListChildMethod() = true; - } diff --git a/dumpAst/src/main/jastadd/Printing.jrag b/dumpAst/src/main/jastadd/Printing.jrag index 362451e..9531e51 100644 --- a/dumpAst/src/main/jastadd/Printing.jrag +++ b/dumpAst/src/main/jastadd/Printing.jrag @@ -22,7 +22,10 @@ aspect Printing { syn String DumpNode.label() = getLabel(); // --- bothVisible --- - syn boolean InnerDumpNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); - syn boolean DumpNormalChildNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); - syn boolean DumpNormalRelation.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible(); + boolean ASTNode.bothVisible(DumpNode one, DumpNode two) { + return one != null && two != null && !one.getInvisible() && !two.getInvisible(); + } + syn boolean InnerDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + syn boolean DumpNormalChildNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); + syn boolean DumpNormalRelation.bothVisible() = bothVisible(containingDumpNode(), getDumpNode()); } diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java index d7b1404..a031f27 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestDumperMain.java @@ -1,12 +1,16 @@ package de.tudresden.inf.st.jastadd.testDumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpAst; +import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpListChildNode; import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode; import org.jastadd.testDumper.ast.A; 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.util.function.Function; import java.util.stream.Collectors; public class TestDumperMain { @@ -41,9 +45,28 @@ public class TestDumperMain { DumpAst dumpAst = builder.build(); System.out.println(dumpAst.toPlantUml()); + String[] b = new String[]{"1"}; + List<String> l = Arrays.asList(b); + DumpNode node = dumpAst.getDumpNode(0); System.out.println(node.getName()); - System.out.println(node.myChildren().stream().map(DumpNode::getName).collect(Collectors.joining(", "))); + Function<? super DumpNode, String> printInfo = d -> + d.getName() + "(" + d.getLabel() + + ", container: " + d.container() + + ", succ: " + (d.successor() == null ? "null" : d.successor().getName()) + + ", has_succ: " + d.hasSuccessor() + ")"; + dumpAst.flushTreeCache(); + dumpAst.treeResolveAll(); + dumpAst.getRootNode().getDumpChildNodeList().forEach(d -> { + if (d instanceof DumpListChildNode) { + System.out.println("dump-list-node " + d.getName()); + ((DumpListChildNode) d).getInnerDumpNodeList().forEach(inner -> { + System.out.println(" inner: " + inner.getDumpNode().getName()); + System.out.println(" <- " + inner.getDumpNode().getContainerOfInner()); + }); + } + }); + System.out.println(node.myChildren().stream().map(printInfo).collect(Collectors.joining(", "))); // System.out.println(">> YAML begin"); // System.out.println(builder.build().toYaml(true)); 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 1f79691..0e6a927 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 @@ -11,8 +11,7 @@ import java.util.Optional; import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*; import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class TestSimple { @@ -91,10 +90,11 @@ public class TestSimple { @Test public void testOrderedListChildren() { - Root root = createRoot(null, null, createB(B1_NAME), createB(B2_NAME), createB(B3_NAME)); + Root root = createRoot(createA(A_NAME), createC(C_NAME), createB(B1_NAME), createB(B2_NAME), createB(B3_NAME)); List<DumpNode> nodes = TestUtils.dumpModel(root, DumpBuilder::orderChildren); - assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, B1_NAME, B2_NAME, B3_NAME); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder( + ROOT_NAME, A_NAME, B1_NAME, B2_NAME, B3_NAME, C_NAME); DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); // in grammar: DumpAst ::= [...] DumpNode* [...]; @@ -102,7 +102,30 @@ public class TestSimple { assertTrue(((DumpAst) actualRoot.getParent().getParent()).getPrintConfig().getOrderChildren()); List<DumpNode> children = actualRoot.myChildren(); - assertThat(children).extracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(B1_NAME, B2_NAME, B3_NAME); + assertThat(children).extracting(NAME_EXTRACTOR).containsExactly( + A_NAME, B1_NAME, B2_NAME, B3_NAME, C_NAME); + + DumpNode actualA = TestUtils.findByName(nodes, A_NAME); + DumpNode actualB1 = TestUtils.findByName(nodes, B1_NAME); + DumpNode actualB2 = TestUtils.findByName(nodes, B2_NAME); + DumpNode actualB3 = TestUtils.findByName(nodes, B3_NAME); + DumpNode actualC = TestUtils.findByName(nodes, C_NAME); + + for (DumpNode d : children) { + System.out.println(d.getName() + "/" + d.getLabel() + " = " + d); + } + + assertEquals(actualB1, actualA.successor(), actualA.successor().getName()); + assertEquals(actualB2, actualB1.successor(), actualB1.successor().getName()); + assertEquals(actualB3, actualB2.successor(), actualB2.successor().getName()); + assertEquals(actualC, actualB3.successor(), actualB3.successor().getName()); + assertNull(actualC.successor()); + + assertTrue(actualA.hasSuccessor()); + assertTrue(actualB1.hasSuccessor()); + assertTrue(actualB2.hasSuccessor()); + assertTrue(actualB3.hasSuccessor()); + assertFalse(actualC.hasSuccessor()); } @Test diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java index 10a0859..3a8dbc3 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java +++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java @@ -187,7 +187,7 @@ public class TestUtils { if (!dumpChildNode.isList()) { // then it is a DumpNormalChildNode DumpNode target = ((DumpNormalChildNode) dumpChildNode).getDumpNode(); - if (!target.getInvisible()) { + if (target != null && !target.getInvisible()) { result.put(dumpChildNode.getName(), target); } } @@ -201,7 +201,7 @@ public class TestUtils { if (dumpChildNode.isList()) { // then it is a DumpListChildNode ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner -> { - if (!inner.getDumpNode().getInvisible()) { + if (inner.getDumpNode() != null && !inner.getDumpNode().getInvisible()) { result.computeIfAbsent(dumpChildNode.getName(), key -> new ArrayList<>()).add(inner.getDumpNode()); } }); -- GitLab