diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c1e5c728453a0d42d04550490702f9ea7857a91..d3399cf3b1ba870b9d5c54978254134113d1d1b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ build: - "./gradlew assemble" artifacts: paths: - - "dumpAst/src/gen" + - "dumpAst.base/src/gen" expire_in: 1 week test: @@ -65,7 +65,7 @@ ragdoc_build: needs: - build script: - - JAVA_FILES=$(find dumpAst/src/ -name '*.java') + - JAVA_FILES=$(find dumpAst.base/src/ -name '*.java') - echo $JAVA_FILES | wc -l - /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES artifacts: diff --git a/.gitmodules b/.gitmodules index cc5edadc2028bc1f4db584f19862852cda5830e8..5172070ff4338a2cdf5e3b2d30184c4ddb7cb9bf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "dumpAst/src/main/jastadd/mustache"] - path = dumpAst/src/main/jastadd/mustache + path = dumpAst.base/src/main/jastadd/mustache url = ../mustache diff --git a/README.md b/README.md index 1b001cb8f7f67d2362aff1ea9f911948dbd1adde..2095d42224d2b4f05aab7d403dd5d1b996282a81 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # DumpAst -For documentation, please see https://jastadd.pages.st.inf.tu-dresden.de/relast2uml/ +For documentation, please see https://jastadd.pages.st.inf.tu-dresden.de/dumpAst/ diff --git a/dumpAst/.gitignore b/dumpAst.base/.gitignore similarity index 100% rename from dumpAst/.gitignore rename to dumpAst.base/.gitignore diff --git a/dumpAst/build.gradle b/dumpAst.base/build.gradle similarity index 88% rename from dumpAst/build.gradle rename to dumpAst.base/build.gradle index 11c2716e20e3a033ab67f9f7bd8567489aaf5933..96fd0c021d8d68a9b5cb57b7c433a157a6896a29 100644 --- a/dumpAst/build.gradle +++ b/dumpAst.base/build.gradle @@ -74,21 +74,14 @@ jastadd { modules { //noinspection GroovyAssignabilityCheck module("DumpAst") { - - 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 "dumpAst/src/gen/jastadd/**/*.ast" - include "dumpAst/src/gen/jastadd/**/*.jadd" - include "dumpAst/src/gen/jastadd/**/*.jrag" + basedir "." + include "src/main/jastadd/**/*.ast" + include "src/main/jastadd/**/*.jadd" + include "src/main/jastadd/**/*.jrag" + include "src/gen/jastadd/**/*.ast" + include "src/gen/jastadd/**/*.jadd" + include "src/gen/jastadd/**/*.jrag" } } } @@ -126,7 +119,7 @@ task fatJar(type: Jar) { } } -def versionFile = "src/main/resources/${project.getName()}Version.properties" +def versionFile = "src/main/resources/${rootProject.getName()}Version.properties" try { def oldProps = new Properties() @@ -167,6 +160,8 @@ java { publishing { publications { maven(MavenPublication) { + //noinspection GroovyAssignabilityCheck + artifactId = 'dumpAst' from components.java } } diff --git a/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag b/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag new file mode 100644 index 0000000000000000000000000000000000000000..fdd6052df4fc03bb14e50d12eb11c36ec37d5f43 --- /dev/null +++ b/dumpAst.base/src/main/jastadd/ClassAnalysis.jrag @@ -0,0 +1,208 @@ +aspect ClassAnalysis { + + syn nta ClassAnalysisResult DumpAst.analyzeClass(java.lang.Class<?> clazz) { + ClassAnalysisResult result = new ClassAnalysisResult(); + String clazzName = clazz.getSimpleName(); + java.util.List<String> targetOrder = targetOrder(clazz); + methodLoop: 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": + contextNameToAdd = invokeName(annotation); + NormalSingleChildMethod singleChildMethod = new NormalSingleChildMethod(); + singleChildMethod.setMethod(method); + singleChildMethod.setName(contextNameToAdd); + containmentMethodToAdd = singleChildMethod; + break; + case "OptChild": + contextNameToAdd = invokeName(annotation); + try { + // the annotated method is "get???Opt", but we want "get???" and "has???" + java.lang.reflect.Method realGetter = clazz.getMethod("get" + contextNameToAdd); + java.lang.reflect.Method checkMethod = clazz.getMethod("has" + contextNameToAdd); + NormalOptChildMethod normalOptChildMethod = new NormalOptChildMethod(); + normalOptChildMethod.setMethod(realGetter); + normalOptChildMethod.setCheckMethod(checkMethod); + normalOptChildMethod.setName(contextNameToAdd); + containmentMethodToAdd = normalOptChildMethod; + } catch (NoSuchMethodException e) { + 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); + containmentMethodToAdd = normalListChildMethod; + break; + case "Token": + // heuristic for relations + String tokenName = invokeName(annotation); + if (tokenName.startsWith("_impl_")) { + String relationName = titleCase(tokenName.substring(6)); + try { + java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName); + // normal get + token-name -> singleRelation + SingleRelationMethod singleRelationMethod = new SingleRelationMethod(); + singleRelationMethod.setMethod(relationMethod); + singleRelationMethod.setName(relationName); + result.addOtherMethod(singleRelationMethod); + 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 + ListRelationMethod listRelationMethod = new ListRelationMethod(); + listRelationMethod.setMethod(relationMethod); + listRelationMethod.setName(relationName); + result.addOtherMethod(listRelationMethod); + continue; + } catch (NoSuchMethodException e) { + // ignore, but we know this is probably not a relation at all + } + } + IntrinsicTokenMethod tokenMethod = new IntrinsicTokenMethod(); + tokenMethod.setMethod(method); + tokenMethod.setName(tokenName); + TokenMethod previousTokenMethodWithSameName = result.getTokenMethodWithName(tokenName); + if (method.getName().startsWith("refined__")) { + tokenMethod.setRefined(true); + // check for previous non-refined method with same name + if (previousTokenMethodWithSameName != null) { + // replace previous method instead of adding + result.setOtherMethod(tokenMethod, previousTokenMethodWithSameName.myIndex()); + continue; + } + } else if (previousTokenMethodWithSameName != null && previousTokenMethodWithSameName.isIntrinsicTokenMethod() && previousTokenMethodWithSameName.asIntrinsicTokenMethod().getRefined()) { + continue; + } + result.addOtherMethod(tokenMethod); + break; + case "Attribute": + if (method.getParameterCount() > 0) { + // ignore parametrized attributes + continue; + } + String attributeName = method.getName(); + boolean isNTA = (boolean) invokeMethod("isNTA", annotation); + if (isNTA) { + // remove leading "get" + if (attributeName.startsWith("get")) { + attributeName = attributeName.substring(3); + } + // remove trailing "List" + if (attributeName.endsWith("List")) { + attributeName = attributeName.substring(0, attributeName.length() - 4); + } + if (Iterable.class.isAssignableFrom(method.getReturnType())) { + NTAListChildMethod ntaListChildMethod = new NTAListChildMethod(); + ntaListChildMethod.setMethod(method); + ntaListChildMethod.setName(attributeName); + result.addOtherMethod(ntaListChildMethod); + } else { + NTASingleChildMethod ntaSingleChildMethod = new NTASingleChildMethod(); + ntaSingleChildMethod.setMethod(method); + ntaSingleChildMethod.setName(attributeName); + result.addOtherMethod(ntaSingleChildMethod); + } + } else { + // normal attribute + AttributeMethod attributeMethod = new AttributeMethod(); + attributeMethod.setMethod(method); + attributeMethod.setName(attributeName); + result.addOtherMethod(attributeMethod); + } + break; + } + if (containmentMethodToAdd != null) { + int indexOfContextInTarget = targetOrder.indexOf(contextNameToAdd); + if (indexOfContextInTarget == 0) { + result.getContainmentMethodList().insertChild(containmentMethodToAdd, 0); + continue methodLoop; + } + if (indexOfContextInTarget == targetOrder.size() - 1) { + result.addContainmentMethod(containmentMethodToAdd); + continue methodLoop; + } + + 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); + continue methodLoop; + } + } + result.addContainmentMethod(containmentMethodToAdd); + } + } + } + } + return result; + } + + TokenMethod ClassAnalysisResult.getTokenMethodWithName(String tokenName) { + // this can not be an attribute, since ClassAnalysisResult changes, and we do not use incremental eval + for (AnalysedMethod otherMethod : getOtherMethodList()) { + if (otherMethod.isTokenMethod()) { + TokenMethod tokenMethod = otherMethod.asTokenMethod(); + if (tokenMethod.getName().equals(tokenName)) { + return tokenMethod; + } + } + } + return null; + } + + inh int AnalysedMethod.myIndex(); + eq ClassAnalysisResult.getContainmentMethod(int index).myIndex() = index; + eq ClassAnalysisResult.getOtherMethod(int index).myIndex() = index; + + 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 static String DumpAst.invokeName(java.lang.annotation.Annotation annotation) { + return (String) invokeMethod("name", annotation); + } + + private static Object DumpAst.invokeMethod(String name, java.lang.annotation.Annotation annotation) { + try { + return annotation.annotationType().getMethod(name).invoke(annotation); + } catch (java.lang.reflect.InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + // --- astNodeAnnotationPrefix --- + syn String DumpAst.astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation"; + inh String DumpNode.astNodeAnnotationPrefix(); + eq DumpAst.getDumpNode().astNodeAnnotationPrefix() = astNodeAnnotationPrefix(); +} diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst.base/src/main/jastadd/DumpAst.relast similarity index 90% rename from dumpAst/src/main/jastadd/DumpAst.relast rename to dumpAst.base/src/main/jastadd/DumpAst.relast index 337c14cb1ddc8f2ba8312a5533e2db379dda320c..fcfd923c0e47bc6648f3e397ecaa99b5ff1007a7 100644 --- a/dumpAst/src/main/jastadd/DumpAst.relast +++ b/dumpAst.base/src/main/jastadd/DumpAst.relast @@ -36,6 +36,10 @@ abstract SingleChildMethod : AnalysedMethod ; NormalSingleChildMethod : SingleChildMethod ; NTASingleChildMethod : SingleChildMethod ; +abstract OptChildMethod : AnalysedMethod ::= <CheckMethod:java.lang.reflect.Method> ; +NormalOptChildMethod : OptChildMethod ; +NTAOptChildMethod : OptChildMethod ; + abstract ListChildMethod : AnalysedMethod ; NormalListChildMethod : ListChildMethod ; NTAListChildMethod : ListChildMethod ; @@ -43,8 +47,9 @@ NTAListChildMethod : ListChildMethod ; SingleRelationMethod : AnalysedMethod ; ListRelationMethod : AnalysedMethod ; +// TODO can the refine bug also happen for refined attributes? abstract TokenMethod : AnalysedMethod ; -IntrinsicTokenMethod : TokenMethod ; +IntrinsicTokenMethod : TokenMethod ::= <Refined:boolean> ; AttributeMethod : TokenMethod ; BuildConfig ::= StyleInformation diff --git a/dumpAst.base/src/main/jastadd/Frontend.jrag b/dumpAst.base/src/main/jastadd/Frontend.jrag new file mode 100644 index 0000000000000000000000000000000000000000..f5bf7c2fa2034bffb1b8a35c347abbc7eca1cc9b --- /dev/null +++ b/dumpAst.base/src/main/jastadd/Frontend.jrag @@ -0,0 +1,56 @@ +aspect Frontend { + + // --- match{In,Ex}cludePatternCollection --- + syn PatternCollection BuildConfig.matchIncludePatternCollection(String typeName) { + for (TypePatternCollectionMapping mapping : getIncludeTypePatternList()) { + if (matches(mapping.typePattern(), typeName)) { + return mapping.getPatternCollection(); + } + } + return null; + } + syn PatternCollection BuildConfig.matchExcludePatternCollection(String typeName) { + for (TypePatternCollectionMapping mapping : getExcludeTypePatternList()) { + if (matches(mapping.typePattern(), typeName)) { + return mapping.getPatternCollection(); + } + } + return null; + } + + 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; + } + + @FunctionalInterface + public interface StyleMethod<ASTNODE> { + String get(ASTNODE node); + } + + @FunctionalInterface + public interface IncludeRelationMethod<ASTNODE> { + boolean shouldInclude(ASTNODE sourceNode, ASTNODE targetNode, String roleName); + } + + @FunctionalInterface + public interface IncludeChildMethod<ASTNODE> { + boolean shouldInclude(ASTNODE parentNode, ASTNODE childNode, String contextName); + } + + @FunctionalInterface + public interface IncludeAttributeMethod<ASTNODE> { + boolean shouldInclude(ASTNODE node, String attributeName, boolean isNTA, java.util.function.Supplier<Object> value); + } + + @FunctionalInterface + public interface IncludeTokenMethod<ASTNODE> { + boolean shouldInclude(ASTNODE node, String tokenName, Object value); + } + +} diff --git a/dumpAst/src/main/jastadd/GeneratedNavigation.jrag b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag similarity index 94% rename from dumpAst/src/main/jastadd/GeneratedNavigation.jrag rename to dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag index be7166a650a2409f5b92c914c348ca1972a64a59..4ef4b469c69254a667aa3449d9735b6a4a254bc6 100644 --- a/dumpAst/src/main/jastadd/GeneratedNavigation.jrag +++ b/dumpAst.base/src/main/jastadd/GeneratedNavigation.jrag @@ -18,6 +18,12 @@ aspect Navigation { syn boolean AnalysedMethod.isSingleChildMethod() = false; eq SingleChildMethod.isSingleChildMethod() = true; + /** Tests if AnalysedMethod is a OptChildMethod. + * @return 'true' if this is a OptChildMethod, otherwise 'false' + */ + syn boolean AnalysedMethod.isOptChildMethod() = false; + eq OptChildMethod.isOptChildMethod() = true; + /** Tests if AnalysedMethod is a ListChildMethod. * @return 'true' if this is a ListChildMethod, otherwise 'false' */ @@ -123,6 +129,13 @@ aspect Navigation { eq AnalysedMethod.asSingleChildMethod() = null; eq SingleChildMethod.asSingleChildMethod() = this; + /** casts a AnalysedMethod into a OptChildMethod if possible. + * @return 'this' cast to a OptChildMethod or 'null' + */ + syn OptChildMethod AnalysedMethod.asOptChildMethod(); + eq AnalysedMethod.asOptChildMethod() = null; + eq OptChildMethod.asOptChildMethod() = this; + /** casts a AnalysedMethod into a ListChildMethod if possible. * @return 'this' cast to a ListChildMethod or 'null' */ diff --git a/dumpAst/src/main/jastadd/Imports.jadd b/dumpAst.base/src/main/jastadd/Imports.jadd similarity index 100% rename from dumpAst/src/main/jastadd/Imports.jadd rename to dumpAst.base/src/main/jastadd/Imports.jadd diff --git a/dumpAst/src/main/jastadd/GenerationMustache.jrag b/dumpAst.base/src/main/jastadd/Mustache.jrag similarity index 98% rename from dumpAst/src/main/jastadd/GenerationMustache.jrag rename to dumpAst.base/src/main/jastadd/Mustache.jrag index cf9f53455aab8a2cef109e9e8d53a27e8fac4951..40be7d934f14157fc247ec1b267eaf62defd1ca4 100644 --- a/dumpAst/src/main/jastadd/GenerationMustache.jrag +++ b/dumpAst.base/src/main/jastadd/Mustache.jrag @@ -1,4 +1,4 @@ -aspect GenerationMustache { +aspect Mustache { syn String DumpAst.toPlantUml() { StringBuilder sb = new StringBuilder(); com.github.mustachejava.reflect.ReflectionObjectHandler roh = new com.github.mustachejava.reflect.ReflectionObjectHandler() { diff --git a/dumpAst/src/main/jastadd/Navigation.jrag b/dumpAst.base/src/main/jastadd/Navigation.jrag similarity index 100% rename from dumpAst/src/main/jastadd/Navigation.jrag rename to dumpAst.base/src/main/jastadd/Navigation.jrag diff --git a/dumpAst/src/main/jastadd/Printing.jrag b/dumpAst.base/src/main/jastadd/Printing.jrag similarity index 93% rename from dumpAst/src/main/jastadd/Printing.jrag rename to dumpAst.base/src/main/jastadd/Printing.jrag index 6ae0af30b8273ed64d20e486035ef03b912f4844..f42e6fabd2035376057f4655ce36674261d27376 100644 --- a/dumpAst/src/main/jastadd/Printing.jrag +++ b/dumpAst.base/src/main/jastadd/Printing.jrag @@ -43,16 +43,16 @@ aspect Printing { aspect Debugging { syn String ClassAnalysisResult.prettyPrint() { StringBuilder sb = new StringBuilder(); - sb.append("ContainmentMethods:"); + sb.append("- ContainmentMethods: "); for (AnalysedMethod method : getContainmentMethodList()) { - sb.append(method.prettyPrint()).append(","); + sb.append("\n - ").append(method.prettyPrint()); } if (getNumContainmentMethod() == 0) { sb.append("none. "); } - sb.append("other methods:"); + sb.append("\n- Other methods: "); for (AnalysedMethod method : getOtherMethodList()) { - sb.append(method.prettyPrint()).append(","); + sb.append("\n - ").append(method.prettyPrint()); } if (getNumOtherMethod() == 0) { sb.append("none."); diff --git a/dumpAst.base/src/main/jastadd/TemplateContext.jrag b/dumpAst.base/src/main/jastadd/TemplateContext.jrag new file mode 100644 index 0000000000000000000000000000000000000000..e8d5549ccd5722276c53c6063ee381610e9f57c3 --- /dev/null +++ b/dumpAst.base/src/main/jastadd/TemplateContext.jrag @@ -0,0 +1,113 @@ +aspect TemplateContext { + + // --- debug --- (mustache has printConfig as context) + syn boolean PrintConfig.debug() = buildConfig().getDebug(); + + // --- isNull --- + syn boolean DumpNode.isNull() { + return getObject() == null; + } + + // --- isAstNode --- + syn boolean DumpNode.isAstNode() { + if (getObject() == null) { + return false; + } + Class<?> clazz = getObject().getClass(); + for (java.lang.reflect.Method method : clazz.getMethods()) { + if ("init$Children".equals(method.getName()) && method.getParameterCount() == 0) { + return true; + } + } + return false; + } + + // --- NTA: InvisiblePath --- + syn InvisiblePath DumpNode.getInvisiblePath() { + InvisiblePath result = new InvisiblePath(); + for (DumpNode successor : reachableThroughInvisible()) { + result.addInnerRelationDumpNode(new InnerRelationDumpNode(successor)); + } + return result; + } + + // --- reachableThroughInvisible --- + syn java.util.List<DumpNode> DumpNode.reachableThroughInvisible() { + java.util.List<DumpNode> result = new java.util.ArrayList<>(); + for (DumpChildNode childNode : getDumpChildNodeList()) { + for (DumpNode inner : childNode.innerNodes(false)) { + if (inner != null && inner.getInvisible()) { + result.addAll(inner.reachableThroughInvisible()); + } else if (this.getInvisible()) { + result.add(inner); + } + } + } + return result; + } + + // --- labelAndTextColor --- + syn String DumpNode.labelAndTextColor() { + if (getTextColor().isEmpty()) { + return getLabel(); + } else { + return "<color:" + getTextColor() + ">" + getLabel() + "</color>"; + } + } + + // --- 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<>(); + for (DumpChildNode childNode : getDumpChildNodeList()) { + for (DumpNode inner : childNode.innerNodes(true)) { + result.add(inner); + } + } + return result; + } + + // --- successor --- + syn DumpNode DumpNode.successor() { + if (container() == null) { + // not contained + return null; + } + java.util.List<DumpNode> siblingsAndMe = container().myChildren(); + int indexOfMe = siblingsAndMe.indexOf(this); + if (indexOfMe == siblingsAndMe.size() - 1) { + // last child + return null; + } + return siblingsAndMe.get(indexOfMe + 1); + } + + // --- hasSuccessor --- + syn boolean DumpNode.hasSuccessor() = successor() != null; + + syn String DumpAst.computedColor() = getBuildConfig().getStyleInformation().getComputedColor(); + +} diff --git a/dumpAst/src/main/jastadd/GenerationToYaml.jrag b/dumpAst.base/src/main/jastadd/ToYaml.jrag similarity index 97% rename from dumpAst/src/main/jastadd/GenerationToYaml.jrag rename to dumpAst.base/src/main/jastadd/ToYaml.jrag index 5f3d3b26dac7c41a48564599cdf5bd80d158a0f4..0df35a8701bd1a8b4d5b93ab04d47a327ce21436 100644 --- a/dumpAst/src/main/jastadd/GenerationToYaml.jrag +++ b/dumpAst.base/src/main/jastadd/ToYaml.jrag @@ -1,4 +1,4 @@ -aspect GenerationToYaml { +aspect ToYaml { syn String DumpAst.printYaml(boolean prependCreationComment) { Document doc = new Document(); doc.setRootElement(this.toYaml(false)); @@ -240,7 +240,9 @@ aspect GenerationToYaml { if (value.isEmpty()) { return StringElement.of(value); } - return refined(value); + return containsAny(value, ",#[{\"\n") ? + StringElement.of(value.replace("\n", "\\n").replace("\"", "\\\"")) : + ValueElement.of(value); } } diff --git a/dumpAst/src/main/jastadd/GenerationBackend.jadd b/dumpAst.base/src/main/jastadd/Transform.jadd similarity index 50% rename from dumpAst/src/main/jastadd/GenerationBackend.jadd rename to dumpAst.base/src/main/jastadd/Transform.jadd index bf3ccf366e4c433d45963bf294cb3a31d9668171..747a59b1a71a04a008a36c8f5a5b8b054b8a8e65 100644 --- a/dumpAst/src/main/jastadd/GenerationBackend.jadd +++ b/dumpAst.base/src/main/jastadd/Transform.jadd @@ -1,4 +1,4 @@ -aspect GenerationBackend { +aspect Transform { class DumpAst { enum Source { ROOT, NORMAL, RELATION @@ -11,7 +11,7 @@ aspect GenerationBackend { public boolean computed; public TransformationOptions asRelation() { - return fromSource(Source.RELATION, false).allowNullObjectsOnce(); + return fromSource(Source.RELATION, false).computed(false).allowNullObjectsOnce(); } public TransformationOptions asRoot() { @@ -123,9 +123,19 @@ aspect GenerationBackend { System.out.println("for node " + obj + ", analysis was:\n" + car.prettyPrint()); } for (AnalysedMethod containmentMethod : car.getContainmentMethodList()) { - if (containmentMethod.isSingleChildMethod()) { - // -- singleChild -- - Object target = containmentMethod.getMethod().invoke(obj); + if (containmentMethod.isSingleChildMethod() || containmentMethod.isOptChildMethod()) { + // -- singleChild or optChild -- + Object target; + if (containmentMethod.isOptChildMethod() && !((boolean) containmentMethod.asOptChildMethod().getCheckMethod().invoke(obj))) { + if (getBuildConfig().getExcludeNullNodes()) { + continue; + //target = containmentMethod.getMethod().invoke(obj); + } else { + target = null; + } + } else { + target = containmentMethod.getMethod().invoke(obj); + } String childName = containmentMethod.getName(); if (!getBuildConfig().getIncludeChildMethod().shouldInclude(obj, target, childName)) { continue; @@ -306,167 +316,6 @@ aspect GenerationBackend { node.setManualStereotypes(getBuildConfig().getStyleInformation().getStereotypeMethod().get(obj)); } - syn nta ClassAnalysisResult DumpAst.analyzeClass(java.lang.Class<?> clazz) { - ClassAnalysisResult result = new ClassAnalysisResult(); - String clazzName = clazz.getSimpleName(); - java.util.List<String> targetOrder = targetOrder(clazz); - methodLoop: 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": - contextNameToAdd = invokeName(annotation); - NormalSingleChildMethod singleChildMethod = new NormalSingleChildMethod(); - singleChildMethod.setMethod(method); - singleChildMethod.setName(contextNameToAdd); - containmentMethodToAdd = singleChildMethod; - break; - case "OptChild": - contextNameToAdd = invokeName(annotation); - try { - // the annotated method is "get???Opt", but we want "get???" - java.lang.reflect.Method realGetter = clazz.getMethod("get" + contextNameToAdd); - NormalSingleChildMethod normalSingleChildMethod = new NormalSingleChildMethod(); - normalSingleChildMethod.setMethod(realGetter); - normalSingleChildMethod.setName(contextNameToAdd); - containmentMethodToAdd = normalSingleChildMethod; - } catch (NoSuchMethodException e) { - 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); - containmentMethodToAdd = normalListChildMethod; - break; - case "Token": - // heuristic for relations - String tokenName = invokeName(annotation); - if (tokenName.startsWith("_impl_")) { - String relationName = titleCase(tokenName.substring(6)); - try { - java.lang.reflect.Method relationMethod = clazz.getMethod("get" + relationName); - // normal get + token-name -> singleRelation - SingleRelationMethod singleRelationMethod = new SingleRelationMethod(); - singleRelationMethod.setMethod(relationMethod); - singleRelationMethod.setName(relationName); - result.addOtherMethod(singleRelationMethod); - 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 - ListRelationMethod listRelationMethod = new ListRelationMethod(); - listRelationMethod.setMethod(relationMethod); - listRelationMethod.setName(relationName); - result.addOtherMethod(listRelationMethod); - continue; - } catch (NoSuchMethodException e) { - // ignore, but we know this is probably not a relation at all - } - } - IntrinsicTokenMethod tokenMethod = new IntrinsicTokenMethod(); - tokenMethod.setMethod(method); - tokenMethod.setName(tokenName); - result.addOtherMethod(tokenMethod); - break; - case "Attribute": - if (method.getParameterCount() > 0) { - // ignore parametrized attributes - continue; - } - String attributeName = method.getName(); - boolean isNTA = (boolean) invokeMethod("isNTA", annotation); - if (isNTA) { - // remove leading "get" - if (attributeName.startsWith("get")) { - attributeName = attributeName.substring(3); - } - // remove trailing "List" - if (attributeName.endsWith("List")) { - attributeName = attributeName.substring(0, attributeName.length() - 4); - } - if (Iterable.class.isAssignableFrom(method.getReturnType())) { - NTAListChildMethod ntaListChildMethod = new NTAListChildMethod(); - ntaListChildMethod.setMethod(method); - ntaListChildMethod.setName(attributeName); - result.addOtherMethod(ntaListChildMethod); - } else { - NTASingleChildMethod ntaSingleChildMethod = new NTASingleChildMethod(); - ntaSingleChildMethod.setMethod(method); - ntaSingleChildMethod.setName(attributeName); - result.addOtherMethod(ntaSingleChildMethod); - } - } else { - // normal attribute - AttributeMethod attributeMethod = new AttributeMethod(); - attributeMethod.setMethod(method); - attributeMethod.setName(attributeName); - result.addOtherMethod(attributeMethod); - } - break; - } - if (containmentMethodToAdd != null) { - int indexOfContextInTarget = targetOrder.indexOf(contextNameToAdd); - if (indexOfContextInTarget == 0) { - result.getContainmentMethodList().insertChild(containmentMethodToAdd, 0); - continue methodLoop; - } - if (indexOfContextInTarget == targetOrder.size() - 1) { - result.addContainmentMethod(containmentMethodToAdd); - continue methodLoop; - } - - 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); - continue methodLoop; - } - } - 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; - } - return Character.toUpperCase(s.charAt(0)) + s.substring(1); - } - // TODO: add new attributes for: {token,child,relation,attribute,nta}Enabled(String parentType, String name). 1) just move implementation into this attribute. 2) add include/exclude on type-level to it. // --- isTypeEnabled --- @@ -474,24 +323,6 @@ aspect GenerationBackend { return !matches(getBuildConfig().typeIgnorePattern(), typeName); } - // --- match{In,Ex}cludePatternCollection --- - syn PatternCollection BuildConfig.matchIncludePatternCollection(String typeName) { - for (TypePatternCollectionMapping mapping : getIncludeTypePatternList()) { - if (matches(mapping.typePattern(), typeName)) { - return mapping.getPatternCollection(); - } - } - return null; - } - syn PatternCollection BuildConfig.matchExcludePatternCollection(String typeName) { - for (TypePatternCollectionMapping mapping : getExcludeTypePatternList()) { - if (matches(mapping.typePattern(), typeName)) { - return mapping.getPatternCollection(); - } - } - return null; - } - // --- {typeIgnore,child,token,relation,attribute,nta}Pattern --- syn java.util.regex.Pattern BuildConfig.typeIgnorePattern() = java.util.regex.Pattern.compile(getTypeIgnorePattern()); syn java.util.regex.Pattern PatternCollection.childPattern() = java.util.regex.Pattern.compile(getChildPattern()); @@ -506,175 +337,9 @@ aspect GenerationBackend { return p.matcher(input).matches(); } - // --- 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); - } - private static Object DumpAst.invokeMethod(String name, java.lang.annotation.Annotation annotation) { - try { - return annotation.annotationType().getMethod(name).invoke(annotation); - } catch (java.lang.reflect.InvocationTargetException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - // --- isNull --- - syn boolean DumpNode.isNull() { - return getObject() == null; - } - - // --- isAstNode --- - syn boolean DumpNode.isAstNode() { - if (getObject() == null) { - return false; - } - Class<?> clazz = getObject().getClass(); - for (java.lang.reflect.Method method : clazz.getMethods()) { - if ("init$Children".equals(method.getName()) && method.getParameterCount() == 0) { - return true; - } - } - return false; - } - - // --- astNodeAnnotationPrefix --- - syn String DumpAst.astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation"; - inh String DumpNode.astNodeAnnotationPrefix(); - eq DumpAst.getDumpNode().astNodeAnnotationPrefix() = astNodeAnnotationPrefix(); - - // --- NTA: InvisiblePath --- - syn InvisiblePath DumpNode.getInvisiblePath() { - InvisiblePath result = new InvisiblePath(); - for (DumpNode successor : reachableThroughInvisible()) { - result.addInnerRelationDumpNode(new InnerRelationDumpNode(successor)); - } - return result; - } - - // --- reachableThroughInvisible --- - syn java.util.List<DumpNode> DumpNode.reachableThroughInvisible() { - java.util.List<DumpNode> result = new java.util.ArrayList<>(); - for (DumpChildNode childNode : getDumpChildNodeList()) { - for (DumpNode inner : childNode.innerNodes(false)) { - if (inner != null && inner.getInvisible()) { - result.addAll(inner.reachableThroughInvisible()); - } else if (this.getInvisible()) { - result.add(inner); - } - } - } - return result; - } - - // --- labelAndTextColor --- - syn String DumpNode.labelAndTextColor() { - if (getTextColor().isEmpty()) { - return getLabel(); - } else { - return "<color:" + getTextColor() + ">" + getLabel() + "</color>"; - } - } - - // --- 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<>(); - for (DumpChildNode childNode : getDumpChildNodeList()) { - for (DumpNode inner : childNode.innerNodes(true)) { - result.add(inner); - } - } - return result; - } - - // --- successor --- - syn DumpNode DumpNode.successor() { - if (container() == null) { - // not contained - return null; - } - java.util.List<DumpNode> siblingsAndMe = container().myChildren(); - int indexOfMe = siblingsAndMe.indexOf(this); - if (indexOfMe == siblingsAndMe.size() - 1) { - // last child - return null; - } - return siblingsAndMe.get(indexOfMe + 1); - } - - // --- hasSuccessor --- - syn boolean DumpNode.hasSuccessor() = successor() != null; - 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; } - - - 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); - } - - @FunctionalInterface - public interface IncludeRelationMethod<ASTNODE> { - boolean shouldInclude(ASTNODE sourceNode, ASTNODE targetNode, String roleName); - } - - @FunctionalInterface - public interface IncludeChildMethod<ASTNODE> { - boolean shouldInclude(ASTNODE parentNode, ASTNODE childNode, String contextName); - } - - @FunctionalInterface - public interface IncludeAttributeMethod<ASTNODE> { - boolean shouldInclude(ASTNODE node, String attributeName, boolean isNTA, java.util.function.Supplier<Object> value); - } - - @FunctionalInterface - public interface IncludeTokenMethod<ASTNODE> { - boolean shouldInclude(ASTNODE node, String tokenName, Object value); - } } diff --git a/dumpAst/src/main/jastadd/GenerationCommon.jrag b/dumpAst.base/src/main/jastadd/Util.jrag similarity index 78% rename from dumpAst/src/main/jastadd/GenerationCommon.jrag rename to dumpAst.base/src/main/jastadd/Util.jrag index a05412d3eba8dbf7732e1f364c3664304db7d23a..32c0ab008028cd8fc2b9b3aa132b94a942067f21 100644 --- a/dumpAst/src/main/jastadd/GenerationCommon.jrag +++ b/dumpAst.base/src/main/jastadd/Util.jrag @@ -1,4 +1,4 @@ -aspect GenerationCommon { +aspect Util { // --- find{In,Ex}cludePatternCollection --- syn PatternCollection BuildConfig.findIncludePatternCollection(String typeRegex) { for (TypePatternCollectionMapping mapping : getIncludeTypePatternList()) { @@ -8,6 +8,7 @@ aspect GenerationCommon { } return null; } + syn PatternCollection BuildConfig.findExcludePatternCollection(String typeRegex) { for (TypePatternCollectionMapping mapping : getExcludeTypePatternList()) { if (mapping.getTypeRegex().equals(typeRegex)) { @@ -16,4 +17,11 @@ aspect GenerationCommon { } return null; } + + private String DumpAst.titleCase(String s) { + if (s.isEmpty()) { + return s; + } + return Character.toUpperCase(s.charAt(0)) + s.substring(1); + } } diff --git a/dumpAst/src/main/jastadd/mustache b/dumpAst.base/src/main/jastadd/mustache similarity index 100% rename from dumpAst/src/main/jastadd/mustache rename to dumpAst.base/src/main/jastadd/mustache diff --git a/dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java similarity index 99% rename from dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java rename to dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java index 18bd97671bdcf3c61793f4619c3fed393a81659a..251055a5f7a014c9225f39ba16721826622cbd9e 100644 --- a/dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java +++ b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/DumpBuilder.java @@ -56,7 +56,6 @@ public class DumpBuilder { this.target = target; buildConfig = new BuildConfig(); buildConfig.setIncludeChildMethod((parentNode, childNode, contextName) -> { - System.out.printf("child: %s, %s, %s%n", parentNode, childNode, contextName); // level 4: excluded for type? -> return no PatternCollection excludeOnType = buildConfig.matchExcludePatternCollection(parentNode.getClass().getSimpleName()); if (excludeOnType != null && matches(excludeOnType.childPattern(), contextName)) { @@ -580,7 +579,7 @@ public class DumpBuilder { } /** - * Set the method defining, what name a node has (default: n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode())). + * Set the method defining, what name a node has (default: {@code n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode())}). * * <p>Example:<br> * {@code builder.<ASTNode<?>>setNameMethod(n -> n.isA() ? "A" : "Not A")} @@ -594,7 +593,7 @@ public class DumpBuilder { } /** - * Set the method defining, what background color a node has (default: n -> ""). + * Set the method defining, what background color a node has (default: {@code n -> ""}). * * <p>Example:<br> * {@code builder.<ASTNode<?>>setBackgroundColorMethod(n -> n.isA() ? "red" : "blue")} @@ -608,7 +607,7 @@ public class DumpBuilder { } /** - * Set the method defining, what text color a node has (default: n -> ""). + * Set the method defining, what text color a node has (default: {@code n -> ""}). * * <p>Example:<br> * {@code builder.<ASTNode<?>>setTextColorMethod(n -> n.isA() ? "black" : "white")} @@ -622,7 +621,7 @@ public class DumpBuilder { } /** - * Set the method defining, what stereotype a node has (default: n -> ""). + * Set the method defining, what stereotype a node has (default: {@code n -> ""}). * * <p>Example:<br> * {@code builder.<ASTNode<?>>setStereotypeMethod(n -> n.isA() ? "MyStereoType" : "")} diff --git a/dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/Dumper.java b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/Dumper.java similarity index 100% rename from dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/Dumper.java rename to dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/Dumper.java diff --git a/dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamBooleanSetting.java b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamBooleanSetting.java similarity index 100% rename from dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamBooleanSetting.java rename to dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamBooleanSetting.java diff --git a/dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamStringSetting.java b/dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamStringSetting.java similarity index 100% rename from dumpAst/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamStringSetting.java rename to dumpAst.base/src/main/java/de/tudresden/inf/st/jastadd/dumpAst/ast/SkinParamStringSetting.java diff --git a/dumpAst/src/main/resources/dumpAst.mustache b/dumpAst.base/src/main/resources/dumpAst.mustache similarity index 100% rename from dumpAst/src/main/resources/dumpAst.mustache rename to dumpAst.base/src/main/resources/dumpAst.mustache diff --git a/dumpAst.base/src/main/resources/dumpAstVersion.properties b/dumpAst.base/src/main/resources/dumpAstVersion.properties new file mode 100644 index 0000000000000000000000000000000000000000..dd0adf1695b118450b79cf06a51d33c090308347 --- /dev/null +++ b/dumpAst.base/src/main/resources/dumpAstVersion.properties @@ -0,0 +1,2 @@ +#Tue Sep 06 14:11:59 CEST 2022 +version=1.2.2 diff --git a/featureTest/.gitignore b/dumpAst.prototyping/.gitignore similarity index 100% rename from featureTest/.gitignore rename to dumpAst.prototyping/.gitignore diff --git a/featureTest/build.gradle b/dumpAst.prototyping/build.gradle similarity index 80% rename from featureTest/build.gradle rename to dumpAst.prototyping/build.gradle index 21ca23ab47a643426503e7d188a03ac2add312b9..acbb60c1fdd421b6ccb378a41147a73727320001 100644 --- a/featureTest/build.gradle +++ b/dumpAst.prototyping/build.gradle @@ -31,9 +31,11 @@ configurations { } dependencies { - implementation project(":dumpAst") + implementation project(":dumpAst.base") jastadd2 group: 'org.jastadd', name: 'jastadd2', version: '2.3.5-dresden' relast group: 'org.jastadd', name: 'relast', version: "${relast_version}" + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.3' + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.13.3' implementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' } @@ -73,13 +75,13 @@ jastadd { //noinspection GroovyAssignabilityCheck module("featureTest") { jastadd { - basedir ".." - include "featureTest/src/main/jastadd/**/*.ast" - include "featureTest/src/main/jastadd/**/*.jadd" - include "featureTest/src/main/jastadd/**/*.jrag" - include "featureTest/src/gen/jastadd/**/*.ast" - include "featureTest/src/gen/jastadd/**/*.jadd" - include "featureTest/src/gen/jastadd/**/*.jrag" + basedir "." + include "src/main/jastadd/**/*.ast" + include "src/main/jastadd/**/*.jadd" + include "src/main/jastadd/**/*.jrag" + include "src/gen/jastadd/**/*.ast" + include "src/gen/jastadd/**/*.jadd" + include "src/gen/jastadd/**/*.jrag" } } } diff --git a/featureTest/src/main/jastadd/featureTest.jrag b/dumpAst.prototyping/src/main/jastadd/featureTest.jrag similarity index 75% rename from featureTest/src/main/jastadd/featureTest.jrag rename to dumpAst.prototyping/src/main/jastadd/featureTest.jrag index 9a158c1b6d03df5db880aa7ab63b373bc798e6a4..a12910b9685279dc1c8da1342d4c82be5615f107 100644 --- a/featureTest/src/main/jastadd/featureTest.jrag +++ b/dumpAst.prototyping/src/main/jastadd/featureTest.jrag @@ -1,4 +1,8 @@ aspect GrammarGlobal { + + refine @com.fasterxml.jackson.annotation.JsonGetter("id") public String Nameable.getName() { + return refined(); + } syn A C.getCalculated() { A result = new A(); result.setName("Calculated-" + getName()); @@ -34,6 +38,8 @@ aspect GrammarGlobal { syn int Root.simpleAttr() = 42; syn A Root.referenceAttr() = getA(); + syn String Nameable.fancyName() = getName() + ", but fancy!"; + syn boolean ASTNode.isA() = false; eq A.isA() = true; @@ -41,6 +47,17 @@ aspect GrammarGlobal { B contributes this to Root.collectBs(); C contributes nta getAlsoCalculatedList() to Root.collectBs(); C contributes nta getAlsoCalculatedListNewSyntax() to Root.collectBs(); + + inh Root A.root(); + eq Root.getChild().root() = this; + + syn nta B A.AAA() { + B result = new B(); + result.setMaybeC(root().getC()); + return result; + } + + public static int ASTNode.counter; } aspect GrammarTypeLevel { @@ -51,3 +68,7 @@ aspect GrammarTypeLevel { return result; } } + +aspect Refining { + refine GrammarGlobal eq Nameable.fancyName() = refined() + " and more!"; +} diff --git a/featureTest/src/main/jastadd/featureTest.relast b/dumpAst.prototyping/src/main/jastadd/featureTest.relast similarity index 95% rename from featureTest/src/main/jastadd/featureTest.relast rename to dumpAst.prototyping/src/main/jastadd/featureTest.relast index fa1c50ee8d1848f9aaa64306bc75ef70c89f8587..7e108fe9f1949e8bdffd152e20c379b3635f14cb 100644 --- a/featureTest/src/main/jastadd/featureTest.relast +++ b/dumpAst.prototyping/src/main/jastadd/featureTest.relast @@ -1,5 +1,5 @@ // testcases with global inclusion/exclusion -Nameable ::= <Name> ; +abstract Nameable ::= <Name> ; Root : Nameable ::= A B* [C]; A : Nameable ::= B [MyC:C] [D]; B : Nameable ::= <OtherValue> ; diff --git a/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java b/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java similarity index 72% rename from featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java rename to dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java index cd6436ba24f777b8c1b213983286d06018dcbc97..bc1d3729b387006b105e9b23a1670c4c818706e9 100644 --- a/featureTest/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java +++ b/dumpAst.prototyping/src/main/java/de/tudresden/inf/st/jastadd/featureTest/FeatureTestMain.java @@ -2,10 +2,7 @@ package de.tudresden.inf.st.jastadd.featureTest; import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper; import de.tudresden.inf.st.jastadd.dumpAst.ast.SkinParamBooleanSetting; -import org.jastadd.featureTest.ast.A; -import org.jastadd.featureTest.ast.B; -import org.jastadd.featureTest.ast.C; -import org.jastadd.featureTest.ast.Root; +import org.jastadd.featureTest.ast.*; import java.io.IOException; import java.nio.file.Path; @@ -23,29 +20,29 @@ public class FeatureTestMain { root.setName("Root1"); A a = new A().setName("A2"); a.setB(new B().setName("B2.1")); - a.setMyC(new C().setName("C2.1")); - B b1 = new B().setName("B3"); - C c = new C().setName("C4"); - c.setA(new A().setName("A4.1").setB(new B().setName("B4.1.1"))); - c.setRawReference(a); - b1.setOneA(a); - B b2 = new B().setName("B5"); - C myC = new C().setName("C6"); - c.setA(new A().setName("A6.1").setB(new B().setName("B6.1.1"))); - a.setMyC(myC); +// a.setMyC(new C().setName("C2.1")); +// B b1 = new B().setName("B3").setOtherValue("some long text"); +// C c = new C().setName("C4"); +// c.setA(new A().setName("A4.1").setB(new B().setName("B4.1.1"))); +// c.setRawReference(a); +// b1.setOneA(a); +// B b2 = new B().setName("B5").setOtherValue("#ff00ff"); +// C myC = new C().setName("C6"); +// c.setA(new A().setName("A6.1").setB(new B().setName("B6.1.1"))); +// a.setMyC(myC); root.setA(a); - root.addB(b1); - root.addB(b2); - root.setC(c); +// root.addB(b1); +// root.addB(b2); +// root.setC(c); Path pathToYaml = Paths.get("featureTest.yml"); Path pathToPng = Paths.get("featureTest.png"); Path pathToSvg = Paths.get("featureTest.svg"); - Path pathToPdf = Paths.get("featureTest.pdf"); Dumper // .read(null) .read(root) // .customPreamble("hide empty members") + .enableDebug() .customPreamble("title My fancy title") .includeChildWhen((parentNode, childNode, contextName) -> { if (parentNode instanceof A && ((A) parentNode).getName().equals("A2")) { @@ -61,17 +58,19 @@ public class FeatureTestMain { case "collectBs": case "Calculated": case "AlsoCalculatedListNewSyntax": + case "AAA": + case "fancyName": return true; default: return false; } }) .skinParam(SkinParamBooleanSetting.Shadowing, false) + .setNameMethod(node -> node.getClass().getSimpleName() + ASTNode.counter++) // .enableRelationWithRank() .dumpAsYaml(pathToYaml, true) .dumpAsPNG(pathToPng) .dumpAsSVG(pathToSvg) - .dumpAsPDF(pathToPdf) .dumpAsSource(Paths.get("featureTest.puml")) ; } diff --git a/testDumper/.gitignore b/dumpAst.tests/.gitignore similarity index 100% rename from testDumper/.gitignore rename to dumpAst.tests/.gitignore diff --git a/testDumper/build.gradle b/dumpAst.tests/build.gradle similarity index 80% rename from testDumper/build.gradle rename to dumpAst.tests/build.gradle index 1c589314ae9434afb054c922504521320a64174e..8ddde1f3bc7be2488788ac8afec2829c8c6441f6 100644 --- a/testDumper/build.gradle +++ b/dumpAst.tests/build.gradle @@ -30,8 +30,9 @@ configurations { } dependencies { - implementation project(':dumpAst') + implementation project(':dumpAst.base') relast group: 'org.jastadd', name: 'relast', version: "${relast_version}" + jastadd2 "org.jastadd:jastadd2:2.3.5-dresden-6" implementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' @@ -75,21 +76,14 @@ jastadd { modules { //noinspection GroovyAssignabilityCheck module("testDumper") { - - java { - basedir ".." - include "testDumper/src/main/**/*.java" - include "testDumper/src/gen/**/*.java" - } - jastadd { - basedir ".." - include "testDumper/src/main/jastadd/**/*.ast" - include "testDumper/src/main/jastadd/**/*.jadd" - include "testDumper/src/main/jastadd/**/*.jrag" - include "testDumper/src/gen/jastadd/**/*.ast" - include "testDumper/src/gen/jastadd/**/*.jadd" - include "testDumper/src/gen/jastadd/**/*.jrag" + basedir "." + include "src/main/jastadd/**/*.ast" + include "src/main/jastadd/**/*.jadd" + include "src/main/jastadd/**/*.jrag" + include "src/gen/jastadd/**/*.ast" + include "src/gen/jastadd/**/*.jadd" + include "src/gen/jastadd/**/*.jrag" } } } @@ -109,7 +103,7 @@ jastadd { astPackage = 'org.jastadd.testDumper.ast' genDir = 'src/gen/java' buildInfoDir = 'src/gen-res' - jastaddOptions = ["--lineColumnNumbers", "--List=JastAddList", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"] + jastaddOptions = ["--lineColumnNumbers", "--List=JastAddList", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all", "--incremental=param", "--tracing=cache,flush"] } // --- Tests --- diff --git a/testDumper/src/main/jastadd/testDumper.jrag b/dumpAst.tests/src/main/jastadd/testDumper.jrag similarity index 100% rename from testDumper/src/main/jastadd/testDumper.jrag rename to dumpAst.tests/src/main/jastadd/testDumper.jrag diff --git a/testDumper/src/main/jastadd/testDumper.relast b/dumpAst.tests/src/main/jastadd/testDumper.relast similarity index 100% rename from testDumper/src/main/jastadd/testDumper.relast rename to dumpAst.tests/src/main/jastadd/testDumper.relast diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestComplex.java diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestIncluded.java diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java similarity index 96% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java index 8a10b40c290454c154ea0c1ab9d978d279e96952..752e6ce02448417115b276d81152217514769ea8 100644 --- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java +++ b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestSimple.java @@ -143,6 +143,19 @@ public class TestSimple { assertFalse(actualC.hasSuccessor()); } + @Test + public void testNoOptChild() { + Root root = new Root().setName(ROOT_NAME); + + List<DumpNode> nodes = TestUtils.dumpModel(root); + assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME); + DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME); + assertEquals(1, actualRoot.getNumDumpToken()); + assertEquals(0, actualRoot.getNumDumpChildNode()); + assertEquals(0, actualRoot.getNumDumpRelation()); + assertThatMapOf(normalChildren(actualRoot)).isEmpty(); + } + @Test public void testOneOptChild() { Root root = createRoot(null, createC(C_NAME)); diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel3.java diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestTypeLevel4.java diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java b/dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java similarity index 100% rename from testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java rename to dumpAst.tests/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java diff --git a/dumpAst/src/main/resources/dumpAstVersion.properties b/dumpAst/src/main/resources/dumpAstVersion.properties deleted file mode 100644 index 25bac2189f8190c21fcbba00fca7f517f0f99f4f..0000000000000000000000000000000000000000 --- a/dumpAst/src/main/resources/dumpAstVersion.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Tue Jul 05 15:14:22 CEST 2022 -version=1.2.0 diff --git a/pages/docs/adding.md b/pages/docs/adding.md index 6b5c91c5f7cb6a63f35157df466500b4adf4e9c3..2e2f9a84375a501e95467de1af6bd37e7f53d265 100644 --- a/pages/docs/adding.md +++ b/pages/docs/adding.md @@ -1,6 +1,6 @@ # Add DumpAst to your project -Check the [package overview page](https://git-st.inf.tu-dresden.de/jastadd/relast2uml/-/packages) to find the latest versions of the individual packages. +Check the [package overview page](https://git-st.inf.tu-dresden.de/jastadd/dumpAst/-/packages) to find the latest versions of the individual packages. To use `dumpAst`, adjust your `build.gradle` as follows. @@ -25,20 +25,20 @@ dependencies { ## Build from source (not recommended) -If you want to build the tools of `DumpAst` from source, first build the jar from the [repository](https://git-st.inf.tu-dresden.de/jastadd/relast2uml). +If you want to build the tools of `DumpAst` from source, first build the jar from the [repository](https://git-st.inf.tu-dresden.de/jastadd/dumpAst). The normal jar does not suffice, as it lacks the information on needed dependencies. ```bash -git clone https://git-st.inf.tu-dresden.de/jastadd/relast2uml.git -cd relast2uml +git clone https://git-st.inf.tu-dresden.de/jastadd/dumpAst.git +cd dumpAst ./gradlew fatJar -ls dumpAst/build/libs/ +ls dumpAst.base/build/libs/ ``` This jar can then be copied to your project. ```bash -cp dumpAst/build/libs/dumpAst-<version>.jar ../your-project/libs/dumpAst.jar +cp dumpAst.base/build/libs/dumpAst.base-fatJar-<version>.jar ../your-project/libs/dumpAst.jar cd ../your-project/ ``` diff --git a/pages/docs/index.md b/pages/docs/index.md index e8f11ced151c84d6105f804427ae7f40cd6901ac..0910060203c01660960cf1904dcb8fe0a5ee3537 100644 --- a/pages/docs/index.md +++ b/pages/docs/index.md @@ -1,6 +1,6 @@ # DumpAst -The tool called `DumpAst` ([see in repo](https://git-st.inf.tu-dresden.de/jastadd/relast2uml)) is used to create a snapshot of an AST and visualize it. +The tool called `DumpAst` ([see in repo](https://git-st.inf.tu-dresden.de/jastadd/dumpAst)) is used to create a snapshot of an AST and visualize it.  diff --git a/pages/mkdocs.yml b/pages/mkdocs.yml index ae9514a5623852167e6414dc757c2f8ae28fba5e..ac59250d32152419ed9a44f44d83207f2d954397 100644 --- a/pages/mkdocs.yml +++ b/pages/mkdocs.yml @@ -1,5 +1,5 @@ site_name: DumpAst -repo_url: https://git-st.inf.tu-dresden.de/jastadd/relast2uml +repo_url: https://git-st.inf.tu-dresden.de/jastadd/dumpAst site_dir: ../public nav: diff --git a/settings.gradle b/settings.gradle index b5b5e2aba025ed461a508cd5fb5846993f43d7f7..7fd9b64b29629f9b5e2fc5fd0b275433da5cb4f5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,8 +4,8 @@ pluginManagement { } } -rootProject.name = 'relast2uml' +rootProject.name = 'dumpAst' -include 'dumpAst' -include 'testDumper' -include 'featureTest' +include 'dumpAst.base' +include 'dumpAst.tests' +include 'dumpAst.prototyping'