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

1.0.3

- include null-nodes for single-relation targets
- resolve iterables of ASTNodes in tokens and attributes
parent d0e9a741
Pipeline #13860 passed with stages
in 2 minutes and 12 seconds
......@@ -4,8 +4,11 @@ rel DumpAst.RootNode? -> DumpNode ;
DumpNode ::= DumpChildNode* DumpToken* DumpRelation*
<Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> <Computed:boolean> <ManualStereotypes>
/InvisiblePath/ ;
InnerDumpNode ;
rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ;
InnerRelationDumpNode;
rel InnerRelationDumpNode.DumpNode -> DumpNode ; // .ContainerOfInner*
abstract DumpChildNode ::= <Name> <Computed:boolean> ;
DumpNormalChildNode : DumpChildNode ;
......@@ -15,15 +18,16 @@ DumpListChildNode : DumpChildNode ::= InnerDumpNode* ;
abstract DumpToken ::= <Name> <Computed:boolean> ;
DumpReferenceToken : DumpToken ;
rel DumpReferenceToken.Value -> DumpNode ;
DumpReferenceListToken : DumpToken ::= InnerRelationDumpNode* ;
DumpValueToken : DumpToken ::= <Value:Object> ;
abstract DumpRelation ::= <Name> <Bidirectional:boolean> ;
DumpNormalRelation : DumpRelation ;
rel DumpNormalRelation.DumpNode -> DumpNode ;
DumpListRelation : DumpRelation ::= InnerDumpNode* ;
DumpListRelation : DumpRelation ::= InnerRelationDumpNode* ;
// type of NTA
InvisiblePath ::= InnerDumpNode* ;
InvisiblePath ::= InnerRelationDumpNode* ;
ClassAnalysisResult ::= ContainmentMethod:AnalysedMethod* OtherMethod:AnalysedMethod* ;
abstract AnalysedMethod ::= <Method:java.lang.reflect.Method> <Name> ;
......
......@@ -11,7 +11,7 @@ aspect GenerationBackend {
public boolean computed;
public TransformationOptions asRelation() {
return fromSource(Source.RELATION, false);
return fromSource(Source.RELATION, false).allowNullObjectsOnce();
}
public TransformationOptions asRoot() {
......@@ -192,7 +192,7 @@ aspect GenerationBackend {
// -- singleRelation --
Object target = otherMethod.getMethod().invoke(obj);
DumpNode targetNode = transform(tti, target, options.asRelation());
if (target != null && targetNode != null) {
if (targetNode != null) {
DumpNormalRelation normalRelation = new DumpNormalRelation();
normalRelation.setName(otherMethod.getName());
normalRelation.setDumpNode(targetNode);
......@@ -206,27 +206,52 @@ aspect GenerationBackend {
for (Object target : targetList) {
DumpNode targetNode = transform(tti, target, options.asRelation());
if (target != null && targetNode != null) {
listRelation.addInnerDumpNode(new InnerDumpNode(targetNode));
listRelation.addInnerRelationDumpNode(new InnerRelationDumpNode(targetNode));
}
}
if (listRelation.getNumInnerDumpNode() > 0) {
if (listRelation.getNumInnerRelationDumpNode() > 0) {
node.addDumpRelation(listRelation);
}
} else if (otherMethod.isTokenMethod()) {
// -- token --
Object target = otherMethod.getMethod().invoke(obj);
// java.util.function.Consumer<DumpToken> handleToken = token -> {
// token.setName(otherMethod.getName());
// token.setComputed(otherMethod.asTokenMethod().isAttributeMethod());
// node.addDumpToken(token);
// };
if (target != null) {
DumpNode targetNode = transform(tti, target, options.asRelation());
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;
boolean atLeastOneASTNode = false;
if (Iterable.class.isAssignableFrom(target.getClass())) {
java.util.List<DumpNode> nodes = new java.util.ArrayList<>();
Iterable iterable = (Iterable) target;
for (Object element : iterable) {
// TODO check if isAstNode for first non-null. if yes, use DumpReferenceListToken, other DumpValueToken
DumpNode nodeForElement = transform(tti, element, options.asRelation());
nodes.add(nodeForElement);
if (nodeForElement != null && nodeForElement.isAstNode()) {
atLeastOneASTNode = true;
}
}
if (atLeastOneASTNode) {
DumpReferenceListToken listToken = new DumpReferenceListToken();
nodes.forEach(element -> {
listToken.addInnerRelationDumpNode(new InnerRelationDumpNode().setDumpNode(element));
});
token = listToken;
}
}
if (!atLeastOneASTNode) {
DumpNode targetNode = transform(tti, target, options.asRelation());
if (targetNode != null && targetNode.isAstNode()) {
token = new DumpReferenceToken().setValue(targetNode);
} else {
if (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty()) {
DumpValueToken valueToken = new DumpValueToken();
valueToken.setValue(target);
token = valueToken;
}
}
}
if (token != null) {
......@@ -584,7 +609,7 @@ aspect GenerationBackend {
syn InvisiblePath DumpNode.getInvisiblePath() {
InvisiblePath result = new InvisiblePath();
for (DumpNode successor : reachableThroughInvisible()) {
result.addInnerDumpNode(new InnerDumpNode(successor));
result.addInnerRelationDumpNode(new InnerRelationDumpNode(successor));
}
return result;
}
......
......@@ -26,14 +26,6 @@ aspect GenerationToYaml {
return result;
}
static void ASTNode.addYamledList(MappingElement base, String key, Iterable<? extends ASTNode<?>> iterable, boolean fromRelation) {
ListElement innerList = new ListElement();
for (ASTNode node : iterable) {
innerList.add(safeToYaml(node, fromRelation));
}
base.put(key, innerList);
}
syn MappingElement PrintConfig.toYaml(boolean fromRelation) {
MappingElement result = new MappingElement();
// children
......@@ -128,6 +120,7 @@ aspect GenerationToYaml {
result.put("name", getName());
result.put("computed", getComputed());
// attributes
result.put("isList", isList());
result.put("label", label());
result.put("isDumpValueToken", isDumpValueToken());
return result;
......@@ -142,12 +135,23 @@ aspect GenerationToYaml {
syn MappingElement DumpReferenceToken.toYaml(boolean fromRelation) {
MappingElement result = super.toYaml(fromRelation);
// tokens
// attributes
result.put("innerNodeName", innerNodeName());
result.put("outerNodeName", outerNodeName());
return result;
}
syn MappingElement DumpReferenceListToken.toYaml(boolean fromRelation) {
MappingElement result = super.toYaml(fromRelation);
// children
addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation);
// attributes
result.put("outerNodeName", outerNodeName());
return result;
}
syn MappingElement DumpRelation.toYaml(boolean fromRelation) {
MappingElement result = new MappingElement();
// tokens
......@@ -171,7 +175,7 @@ aspect GenerationToYaml {
syn MappingElement DumpListRelation.toYaml(boolean fromRelation) {
MappingElement result = super.toYaml(fromRelation);
// children
addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation);
addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation);
return result;
}
......@@ -185,13 +189,31 @@ aspect GenerationToYaml {
return result;
}
syn MappingElement InnerRelationDumpNode.toYaml(boolean fromRelation) {
MappingElement result = new MappingElement();
// attributes
result.put("bothVisible", bothVisible());
result.put("innerNodeName", innerNodeName());
result.put("outerNodeName", outerNodeName());
result.put("label", label());
return result;
}
syn MappingElement InvisiblePath.toYaml(boolean fromRelation) {
MappingElement result = super.toYaml(fromRelation);
// children
addYamledList(result, "InnerDumpNodes", getInnerDumpNodeList(), fromRelation);
addYamledList(result, "InnerRelationDumpNode", getInnerRelationDumpNodeList(), fromRelation);
return result;
}
static void ASTNode.addYamledList(MappingElement base, String key, Iterable<? extends ASTNode<?>> iterable, boolean fromRelation) {
ListElement innerList = new ListElement();
for (ASTNode node : iterable) {
innerList.add(safeToYaml(node, fromRelation));
}
base.put(key, innerList);
}
// extension for mustache
public static ValueElement ValueElement.of(double value) {
return new ValueElement(false, String.valueOf(value));
......
......@@ -4,6 +4,8 @@ aspect Navigation {
eq DumpListChildNode.isList() = true;
syn boolean DumpRelation.isList() = false;
eq DumpListRelation.isList() = true;
syn boolean DumpToken.isList() = false;
eq DumpReferenceListToken.isList() = true;
// --- buildConfig ---
inh BuildConfig DumpNode.buildConfig();
......@@ -16,10 +18,12 @@ aspect Navigation {
// --- containingDumpNode ---
inh DumpNode InnerDumpNode.containingDumpNode();
inh DumpNode InnerRelationDumpNode.containingDumpNode();
inh DumpNode DumpChildNode.containingDumpNode();
inh DumpNode DumpRelation.containingDumpNode();
eq DumpNode.getDumpChildNode().containingDumpNode() = this;
eq DumpNode.getDumpRelation().containingDumpNode() = this;
eq DumpNode.getDumpToken().containingDumpNode() = this;
eq DumpNode.getInvisiblePath().containingDumpNode() = this;
// --- container ---
......@@ -69,7 +73,7 @@ aspect Navigation {
return java.util.Collections.emptyList();
}
java.util.List<DumpNode> result = new java.util.ArrayList<>();
getInnerDumpNodeList().forEach(inner -> {
getInnerRelationDumpNodeList().forEach(inner -> {
if (!onlyVisible || !inner.getDumpNode().getInvisible()) {
result.add(inner.getDumpNode());
}
......
aspect Printing {
// --- outerNodeName ---
inh String InnerDumpNode.outerNodeName();
inh String InnerRelationDumpNode.outerNodeName();
inh String DumpChildNode.outerNodeName();
inh String DumpRelation.outerNodeName();
inh String DumpToken.outerNodeName();
inh String DumpReferenceToken.outerNodeName();
eq DumpNode.getChild().outerNodeName() = name();
// --- innerNodeName ---
syn String InnerDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null;
syn String InnerRelationDumpNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null;
syn String DumpNormalChildNode.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null;
syn String DumpNormalRelation.innerNodeName() = getDumpNode() != null ? getDumpNode().name() : null;
syn String DumpReferenceToken.innerNodeName() = getValue().name();
......@@ -21,15 +24,18 @@ aspect Printing {
syn String DumpToken.label() = getName() + (getComputed() ? "()" : "");
syn String DumpNode.label() = getLabel();
inh String InnerDumpNode.label();
inh String InnerRelationDumpNode.label();
eq DumpListChildNode.getInnerDumpNode(int index).label() = label() + "[" + index + "]";
eq DumpListRelation.getInnerDumpNode(int index).label() = label() + "[" + index + "]";
eq InvisiblePath.getInnerDumpNode(int index).label() = null;
eq DumpListRelation.getInnerRelationDumpNode(int index).label() = label() + "[" + index + "]";
eq DumpReferenceListToken.getInnerRelationDumpNode(int index).label() = label() + "[" + index + "]";
eq InvisiblePath.getInnerRelationDumpNode(int index).label() = null;
// --- bothVisible ---
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 InnerRelationDumpNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode());
syn boolean DumpNormalChildNode.bothVisible() = bothVisible(containingDumpNode(), getDumpNode());
syn boolean DumpNormalRelation.bothVisible() = bothVisible(containingDumpNode(), getDumpNode());
}
......
......@@ -37,9 +37,18 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{{stereotypeList}}} {{#backgroun
{{#DumpNodes}}
{{#DumpTokens}}
{{^invisible}}
{{^isDumpValueToken}}
{{#isList}}
{{#InnerRelationDumpNode}}
{{#bothVisible}}
{{{outerNodeName}}} .{{#computed}}[#{{{computedColor}}}]{{/computed}}.> {{{innerNodeName}}} : {{{label}}}
{{/isDumpValueToken}}
{{/bothVisible}}
{{/InnerRelationDumpNode}}
{{/isList}}
{{^isList}}
{{^isDumpValueToken}}
{{{outerNodeName}}} .{{#computed}}[#{{{computedColor}}}]{{/computed}}.> {{{innerNodeName}}} : {{{label}}}
{{/isDumpValueToken}}
{{/isList}}
{{/invisible}}
{{/DumpTokens}}
{{#DumpChildNodes}}
......@@ -58,11 +67,11 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{{stereotypeList}}} {{#backgroun
{{/DumpChildNodes}}
{{#DumpRelations}}
{{#isList}}
{{#InnerDumpNodes}}
{{#InnerRelationDumpNode}}
{{#bothVisible}}
{{{outerNodeName}}} {{#bidirectional}}<{{/bidirectional}}--> {{{innerNodeName}}} : {{{label}}}
{{/bothVisible}}
{{/InnerDumpNodes}}
{{/InnerRelationDumpNode}}
{{/isList}}
{{^isList}}
{{#bothVisible}}
......@@ -72,9 +81,9 @@ object "{{{labelAndTextColor}}}" as {{{name}}} {{{stereotypeList}}} {{#backgroun
{{/DumpRelations}}
{{^invisible}}
{{#InvisiblePath}}
{{#InnerDumpNodes}}
{{#InnerRelationDumpNode}}
{{{outerNodeName}}} o.. {{{innerNodeName}}}
{{/InnerDumpNodes}}
{{/InnerRelationDumpNode}}
{{/InvisiblePath}}
{{/invisible}}
{{#PrintConfig}}{{#orderChildren}}
......
#Mon May 16 18:32:38 CEST 2022
version=1.0.2
#Mon Jun 13 18:33:49 CEST 2022
version=1.0.3
......@@ -32,6 +32,7 @@ configurations {
dependencies {
implementation project(":dumpAst")
jastadd2 group: 'org.jastadd', name: 'jastadd2', version: '2.3.5-dresden'
relast group: 'org.jastadd', name: 'relast', version: "${relast_version}"
implementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
......
......@@ -2,6 +2,7 @@ aspect GrammarGlobal {
syn A C.getCalculated() {
A result = new A();
result.setName("Calculated-" + getName());
result.setB(new B().setName("B" + getName()));
D innerD = new D();
result.setD(innerD);
return result;
......@@ -18,6 +19,7 @@ aspect GrammarGlobal {
syn nta A C.getCalculatedNewSyntax() {
A result = new A();
result.setName("Calculated-" + getName());
result.setB(new B().setName("B" + getName()));
return result;
}
......@@ -34,6 +36,11 @@ aspect GrammarGlobal {
syn boolean ASTNode.isA() = false;
eq A.isA() = true;
coll java.util.Set<B> Root.collectBs() [new java.util.HashSet<>()] root Root ;
B contributes this to Root.collectBs();
C contributes nta getAlsoCalculatedList() to Root.collectBs();
C contributes nta getAlsoCalculatedListNewSyntax() to Root.collectBs();
}
aspect GrammarTypeLevel {
......
// testcases with global inclusion/exclusion
Nameable ::= <Name> ;
Root : Nameable ::= A B* [C];
A : Nameable ::= B MyC:C D;
A : Nameable ::= B [MyC:C] [D];
B : Nameable ::= <OtherValue> ;
C : Nameable ::= [A] <Unwanted:int> <RawReference:A> /Calculated:A/ /AlsoCalculated:B*/ ;
SubC : C ::= <RawReference:A> <Unwanted:int> [A] /Calculated:A/ /AlsoCalculated:B*/ ;
......
......@@ -8,6 +8,8 @@ import org.jastadd.featureTest.ast.*;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Main class of feature test.
......@@ -19,18 +21,17 @@ public class FeatureTestMain {
public static void main(String[] args) throws IOException {
Root root = new Root();
root.setName("Root1");
A a = new A();
a.setName("A2");
B b1 = new B();
b1.setName("B3");
C c = new C();
c.setName("C4");
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();
b2.setName("B5");
C myC = new C();
myC.setName("C6");
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);
root.setA(a);
root.addB(b1);
......@@ -45,7 +46,9 @@ public class FeatureTestMain {
.read(root)
// .customPreamble("hide empty members")
.skinParam(SkinParamBooleanSetting.Shadowing, false)
.includeAttributes("referenceAttr")
.includeAttributes("referenceAttr"
, "collectBs"
)
.includeNonterminalAttributes("Calculated")
.includeNonterminalAttributes("AlsoCalculatedListNewSyntax")
.dumpAsYaml(pathToYaml, true)
......
......@@ -32,6 +32,12 @@ aspect GrammarGlobal {
syn boolean ASTNode.isA() = false;
eq A.isA() = true;
syn Object Root.setOfBs() {
java.util.Set<B> result = new java.util.HashSet<>();
getBList().forEach(result::add);
return result;
}
}
aspect GrammarTypeLevel {
......
......@@ -31,6 +31,18 @@ public class TestIncluded {
assertThat(valueTokens(actualRoot)).containsOnly(entry("Name", ROOT_NAME), entry("simpleAttr", 42));
}
@Test
public void testReferenceListAttributeIncluded() {
Root root = createRoot(null, null, createB(B1_NAME), createB(B2_NAME), createB(B3_NAME));
List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.includeAttributes("setOfBs"));
assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactly(ROOT_NAME, B1_NAME, B2_NAME, B3_NAME);
DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME);
assertThatMapOf(referenceListTokens(actualRoot), "setOfBs").containsOnly(
B1_NAME, B2_NAME, B3_NAME);
}
@Test
public void testReferenceAttributeDefault() {
Root root = createRoot(createA(A_NAME), null);
......
......@@ -74,14 +74,24 @@ public class TestSimple {
List<DumpNode> nodes = TestUtils.dumpModel(root, DumpBuilder::includeNullNodes);
assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(
ROOT_NAME, A_NAME, null, null, null, null);
ROOT_NAME, A_NAME,
null, // C in Root
null, // B in A
null, // MyC in A
null, // D in A
null, // BiC2 in A
null, // BiC1 in A
null // BiC3 in A
);
DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME);
assertEquals(1, actualRoot.getNumDumpToken());
assertEquals(2, actualRoot.getNumDumpChildNode());
assertEquals(0, actualRoot.getNumDumpRelation());
DumpNode actualA = TestUtils.findByName(nodes, A_NAME);
assertEquals(1, actualA.getNumDumpToken());
assertEquals(3, actualA.getNumDumpChildNode());
assertEquals(3, actualA.getNumDumpRelation());
}
@Test
......
......@@ -229,7 +229,7 @@ public class TestUtils {
for (DumpRelation dumpRelation : node.getDumpRelationList()) {
if (dumpRelation.isList()) {
// then it is a DumpListRelation
((DumpListRelation) dumpRelation).getInnerDumpNodeList().forEach(inner -> {
((DumpListRelation) dumpRelation).getInnerRelationDumpNodeList().forEach(inner -> {
if (!inner.getDumpNode().getInvisible()) {
result.computeIfAbsent(dumpRelation.getName(), key -> new ArrayList<>()).add(inner.getDumpNode());
}
......@@ -242,7 +242,7 @@ public class TestUtils {
public static Map<String, DumpNode> referenceTokens(DumpNode node) {
Map<String, DumpNode> result = new HashMap<>();
for (DumpToken dumpToken : node.getDumpTokenList()) {
if (!dumpToken.isDumpValueToken()) {
if (!dumpToken.isDumpValueToken() && !dumpToken.isList()) {
// then it is a DumpReferenceToken
DumpNode target = ((DumpReferenceToken) dumpToken).getValue();
if (!target.getInvisible()) {
......@@ -253,6 +253,21 @@ public class TestUtils {
return result;
}
public static Map<String, List<DumpNode>> referenceListTokens(DumpNode node) {
Map<String, List<DumpNode>> result = new HashMap<>();
for (DumpToken dumpToken : node.getDumpTokenList()) {
if (!dumpToken.isDumpValueToken() && dumpToken.isList()) {
// then it is a DumpReferenceListToken
((DumpReferenceListToken) dumpToken).getInnerRelationDumpNodeList().forEach(inner -> {
if (!inner.getDumpNode().getInvisible()) {
result.computeIfAbsent(dumpToken.getName(), key -> new ArrayList<>()).add(inner.getDumpNode());
}
});
}
}
return result;
}
public static Map<String, Object> valueTokens(DumpNode node) {
Map<String, Object> result = new HashMap<>();
for (DumpToken dumpToken : node.getDumpTokenList()) {
......@@ -267,7 +282,7 @@ public class TestUtils {
public static List<DumpNode> invisiblePath(DumpNode node) {
List<DumpNode> result = new ArrayList<>();
for (InnerDumpNode inner : node.getInvisiblePath().getInnerDumpNodeList()) {
for (InnerRelationDumpNode inner : node.getInvisiblePath().getInnerRelationDumpNodeList()) {
DumpNode target = inner.getDumpNode();
assertFalse(target.getInvisible());
result.add(target);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment