From 21f989ad6e3ea0d2babc9a997f7eed657a18eb83 Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Fri, 25 Oct 2019 13:22:55 +0200 Subject: [PATCH] implement json pointer (built-in) and manual pointer treatment with two examples (json pointer and relative json pointer) --- build.gradle | 30 ++ src/main/jastadd/Backend.jadd | 276 ++++++++++++++++-- .../org/jastadd/relast/compiler/Compiler.java | 13 +- src/test/jastadd/resolver/MyRefResolver.jadd | 19 +- src/test/jastadd/resolver/ResolverUtils.jadd | 5 +- src/test/jastadd/resolver2/ResolverUtils.jadd | 5 +- .../JsonPointer.jrag | 204 +++++++++++++ .../Serializer.relast | 23 ++ .../serializer-manual/JsonPointer.jrag | 158 ++++++++++ .../serializer-manual/Serializer.relast | 23 ++ .../serializer-pointer/Serializer.relast | 23 ++ .../relast/tests/SerializerManual.java | 135 +++++++++ .../tests/SerializerManualRelative.java | 135 +++++++++ .../relast/tests/SerializerPointer.java | 137 +++++++++ 14 files changed, 1145 insertions(+), 41 deletions(-) create mode 100644 src/test/jastadd/serializer-manual-relative/JsonPointer.jrag create mode 100644 src/test/jastadd/serializer-manual-relative/Serializer.relast create mode 100644 src/test/jastadd/serializer-manual/JsonPointer.jrag create mode 100644 src/test/jastadd/serializer-manual/Serializer.relast create mode 100644 src/test/jastadd/serializer-pointer/Serializer.relast create mode 100644 src/test/java/org/jastadd/relast/tests/SerializerManual.java create mode 100644 src/test/java/org/jastadd/relast/tests/SerializerManualRelative.java create mode 100644 src/test/java/org/jastadd/relast/tests/SerializerPointer.java diff --git a/build.gradle b/build.gradle index 7598b77..1d96120 100644 --- a/build.gradle +++ b/build.gradle @@ -246,6 +246,36 @@ task compileSerializerDefaultNamesTest(type: RelastTest) { moreInputFiles 'src/test/jastadd/Utils.jadd' } +task compileSerializerPointerTest(type: RelastTest) { + verbose = true + resolverHelper = true + relastFiles 'src/test/jastadd/serializer-pointer/Serializer.relast' + grammarName = 'src/test/jastadd/serializer-pointer/Serializer' + serializer = 'jackson-json-pointer' + packageName = 'pointer.serializer.ast' + moreInputFiles 'src/test/jastadd/Utils.jadd' +} + +task compileSerializerManualTest(type: RelastTest) { + verbose = true + resolverHelper = true + relastFiles 'src/test/jastadd/serializer-manual/Serializer.relast' + grammarName = 'src/test/jastadd/serializer-manual/Serializer' + serializer = 'jackson-manual-references' + packageName = 'manual.serializer.ast' + moreInputFiles 'src/test/jastadd/Utils.jadd', 'src/test/jastadd/serializer-manual/JsonPointer.jrag' +} + +task compileSerializerManualRelativeTest(type: RelastTest) { + verbose = true + resolverHelper = true + relastFiles 'src/test/jastadd/serializer-manual-relative/Serializer.relast' + grammarName = 'src/test/jastadd/serializer-manual-relative/Serializer' + serializer = 'jackson-manual-references' + packageName = 'manual.relative.serializer.ast' + moreInputFiles 'src/test/jastadd/Utils.jadd', 'src/test/jastadd/serializer-manual-relative/JsonPointer.jrag' +} + test { outputs.upToDateWhen { false } useJUnitPlatform() diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd index f5d69d3..2f7490b 100644 --- a/src/main/jastadd/Backend.jadd +++ b/src/main/jastadd/Backend.jadd @@ -5,6 +5,8 @@ aspect BackendAbstractGrammar { public static boolean ASTNode.resolverHelper = false; public static boolean ASTNode.serializer = false; + public static boolean ASTNode.jsonPointer = false; + public static boolean ASTNode.manualReferences = false; public static boolean ASTNode.useJastAddNames = false; public String Program.generateAbstractGrammar() { @@ -823,13 +825,73 @@ aspect NameResolutionHelper { r.generateContextDependentNameResolution(sb); } - if (resolverHelper) { + if (resolverHelper || ASTNode.jsonPointer || ASTNode.manualReferences) { for (TypeDecl decl : getTypeDeclList()) { decl.generateContextIndependentNameResolution(sb); sb.append("\n"); } } sb.append("}\n\n"); + + if (ASTNode.manualReferences) { + sb.append("aspect RefCreatorStubs {\n\n"); + + for (Relation r: getRelations()) { + r.generateContextDependentRefCreation(sb); + } + + generateGenericRefCreation(sb); + sb.append("\n"); + + for (TypeDecl decl : getTypeDeclList()) { + decl.generateContextIndependentRefCreation(sb); + sb.append("\n"); + } + + sb.append("}\n\n"); + } + } + + public void Program.generateGenericRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// generic reference creation\n"); + sb.append(ind(1) + "syn String ASTNode.createReference();\n"); + sb.append(ind(1) + "eq ASTNode.createReference() {\n"); + sb.append(ind(2) + "throw new RuntimeException(\"Generic reference creation not implemented.\");\n"); + sb.append(ind(1) + "}\n"); + } + + public void Relation.generateContextDependentRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// " + prettyPrint() + "\n"); + getDirection().generateContextDependentRefCreation(sb); + sb.append("\n"); + } + + public abstract void Direction.generateContextDependentRefCreation(StringBuilder sb); + public void RightDirection.generateContextDependentRefCreation(StringBuilder sb) { + relation().getLeft().generateContextDependentRefCreation(sb); + } + public void LeftDirection.generateContextDependentRefCreation(StringBuilder sb) { + relation().getRight().generateContextDependentRefCreation(sb); + } + public void Bidirectional.generateContextDependentRefCreation(StringBuilder sb) { + relation().getLeft().generateContextDependentRefCreation(sb); + relation().getRight().generateContextDependentRefCreation(sb); + } + + public void RelationComponent.generateContextDependentRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// context-dependent reference creation\n"); + sb.append(ind(1) + "syn String " + toTypeDecl() + ".createRefTo" + nameCapitalized() + "(" + ofTypeDecl() + " target) {\n"); + sb.append(ind(2) + "// default to context-independent reference creation\n"); + sb.append(ind(2) + "return target.createReference();\n"); + sb.append(ind(1) + "}\n"); + } + + public void TypeDecl.generateContextIndependentRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// context-independent reference creation\n"); + sb.append(ind(1) + "eq " + getID() + ".createReference() {\n"); + sb.append(ind(2) + "// default to generic reference creation\n"); + sb.append(ind(2) + "return super.createReference();\n"); + sb.append(ind(1) + "}\n"); } public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) { @@ -894,8 +956,12 @@ aspect NameResolutionHelper { sb.append(ind(1) + "// context-independent name resolution\n"); sb.append(ind(1) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n"); sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n"); - if (serializer) { - sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n"); + if (serializer && !manualReferences) { + if (jsonPointer) { + sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n"); + } else { + sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n"); + } } else { sb.append(ind(2) + "// perform context independent name resolution here using the id\n"); sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n"); @@ -1002,11 +1068,18 @@ aspect Serializer { protected static String ASTNode.jsonTypeKey = "type"; protected static String ASTNode.jsonNodeType = "com.fasterxml.jackson.databind.JsonNode"; protected static String ASTNode.jsonNodeTypeAccessor = ".get(\"" + jsonTypeKey + "\").asText()"; - public String Program.generateSerializer() { + public String Program.generateJacksonSerializer() { StringBuilder sb = new StringBuilder(); generateFromJson(sb); generateToJson(sb); - writeUID(sb); + if (jsonPointer) { + writeJsonPointer(sb); + } else if (manualReferences) { + // TODO + } else { + writeUID(sb); + } + return sb.toString(); } @@ -1083,9 +1156,11 @@ aspect Serializer { sb.append(ind(3) + "} else {\n"); sb.append(ind(4) + "g.writeObjectFieldStart(fieldName);\n"); sb.append(ind(3) + "}\n"); - sb.append(ind(3) + "g.writeStringField(\"" + jsonTypeKey + "\", \"" + getID() + "\");\n"); - sb.append(ind(3) + "if (unique$Id() == null) throw new SerializationException(\"The unique identifier of " + getID() + " is missing.\");\n"); - sb.append(ind(3) + "g.writeStringField(\"id\", unique$Id());\n"); + if (!jsonPointer && !manualReferences) { + sb.append(ind(3) + "g.writeStringField(\"" + jsonTypeKey + "\", \"" + getID() + "\");\n"); + sb.append(ind(3) + "if (unique$Id() == null) throw new SerializationException(\"The unique identifier of " + getID() + " is missing.\");\n"); + sb.append(ind(3) + "g.writeStringField(\"id\", unique$Id());\n"); + } if (componentsTransitive().size() > 0) { sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n"); for (Component child : componentsTransitive()) { @@ -1196,18 +1271,42 @@ aspect Serializer { public void OneRelationComponent.serialize(StringBuilder sb, int indent) { if (useJastAddNames){ - sb.append(ind(indent) + "g.writeStringField(\""+getID()+"\", get" + getID() + "().unique$Id());\n"); + if (jsonPointer) { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", createRefTo" + getID() + "(" + getID() + "()));\n"); + } else { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n"); + } } else { - sb.append(ind(indent) + "g.writeStringField(\""+getID()+"\", " + getID() + "().unique$Id());\n"); + if (jsonPointer) { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", createRefTo" + getID() + "(" + getID() + "()));\n"); + } else { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); + } } } public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) { sb.append(ind(indent) + "if (has" + nameCapitalized() + "()) {\n"); if (useJastAddNames){ - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n"); + if (jsonPointer) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().createReference());\n"); + } else { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n"); + } } else { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); + if (jsonPointer) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + "createRefTo" + getID() + "(" + getID() + "()));\n"); + } else { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); + } } sb.append(ind(indent) + "}\n"); } @@ -1219,7 +1318,14 @@ aspect Serializer { } else { sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : " + getID() + "()) {\n"); } - sb.append(ind(indent + 1) + "g.writeString(child.unique$Id());\n"); + if (jsonPointer) { + sb.append(ind(indent + 1) + "g.writeString(child.jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent + 1) + "g.writeString(createRefTo" + getID() + "(child));\n"); + }else { + sb.append(ind(indent + 1) + "g.writeString(child.unique$Id());\n"); + } + sb.append(ind(indent) + "}\n"); sb.append(ind(indent) + "g.writeEndArray();\n"); } @@ -1256,10 +1362,12 @@ aspect Serializer { sb.append(ind(2) + "element = new " + getID() + "();\n"); } - // deserialize id - sb.append(ind(2) + "if (node.has(\"id\")) {\n"); - sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); - sb.append(ind(2) + "}\n"); + if (!jsonPointer && !manualReferences) { + // deserialize id + sb.append(ind(2) + "if (node.has(\"id\")) {\n"); + sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); + sb.append(ind(2) + "}\n"); + } // deserialize containment children if (componentsTransitive().size() > 0) { @@ -1361,6 +1469,140 @@ aspect Serializer { } } + public void Component.writeJsonPointer(StringBuilder sb) { + // do nothing for other components + } + + public void NormalComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void ListComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); + sb.append(ind(1) + "}\n"); + } + + public void OptComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAListComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAOptComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void Component.resolveJsonPointer(StringBuilder sb) { + // do nothing for other components + } + + public void NormalComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void ListComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); + } + + public void OptComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void NTAComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void NTAListComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); + } + + public void NTAOptComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void TypeDecl.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + getID() + ".resolveJsonPointer(String[] pointer, int index) {\n"); + sb.append(ind(2) + "if (pointer.length == 0 || pointer.length == index) {\n"); + sb.append(ind(3) + "return this;\n"); + sb.append(ind(2) + "} else if (pointer.length == index + 1) {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"there is only one child called \" + pointer[index]);\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "switch (pointer[index + 1]) {\n"); + + for (Component c: getComponentList()) { + c.resolveJsonPointer(sb); + } + + sb.append(ind(4) + "default:\n"); + sb.append(ind(5) + "return super.resolveJsonPointer(pointer, index);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + public void Program.writeJsonPointer(StringBuilder sb) { + sb.append("aspect JsonPointer {\n"); + + sb.append(ind(1) + "syn String ASTNode.jsonPointer() {\n"); + sb.append(ind(2) + "if (getParent() == null) {\n"); + sb.append(ind(3) + "return \"\";\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "return jsonPointerInh();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "inh String ASTNode.jsonPointerInh();\n"); + + // define json pointer for each component + for (TypeDecl td: getTypeDeclList()) { + for (Component c: td.getComponentList()) { + c.writeJsonPointer(sb); + } + } + + sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String pointer) = root().resolveJsonPointer(pointer.split(\"/\"), 1);\n"); + sb.append(ind(1) + "ASTNode ASTNode.root() {\n"); + sb.append(ind(2) + "if (getParent() == null) return this;\n"); + sb.append(ind(2) + "else return getParent().root();\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String[] pointer, int index) {\n"); + sb.append(ind(2) + "if (index < pointer.length) {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"found wrong child \" + pointer[index + 1] + \" in class \" + this.getClass().getSimpleName());\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"Cannot resolve JSON pointer for class \" + this.getClass().getSimpleName());\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + + // resolve JSON pointers in each nonterminal + for (TypeDecl td: getTypeDeclList()) { + td.resolveJsonPointer(sb); + } + + sb.append("}\n"); + } + public void Program.writeUID(StringBuilder sb) { sb.append("aspect UID {\n"); sb.append(ind(1) + "class UIDProvider {\n"); diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java index 22b6168..80a0db9 100644 --- a/src/main/java/org/jastadd/relast/compiler/Compiler.java +++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java @@ -89,8 +89,17 @@ public class Compiler { ASTNode.serializer = true; switch (optionSerializer.getValue()) { case "jackson": - writeToFile(grammarName + "Serializer.jadd", p.generateSerializer()); + writeToFile(grammarName + "Serializer.jadd", p.generateJacksonSerializer()); break; + case "jackson-json-pointer": + ASTNode.jsonPointer = true; + writeToFile(grammarName + "Serializer.jadd", p.generateJacksonSerializer()); + break; + case "jackson-manual-references": + ASTNode.manualReferences = true; + writeToFile(grammarName + "Serializer.jadd", p.generateJacksonSerializer()); + break; + } } @@ -151,7 +160,7 @@ public class Compiler { optionResolverHelper = addOption(new FlagOption("resolverHelper", "create a subtype for each type containing a string that can be used to resolve the type later")); optionJastAddList = addOption(new StringOption("jastAddList", "set the name of the List type in JastAdd (has to match the option '--List' or its default List)")); optionUseJastaddNames = addOption(new FlagOption("useJastAddNames", "generate names in the form of addX, removeX and setX. If omitted, the default, original naming scheme resulting in addToX, removeFromX and setX will be used.")); - optionSerializer = addOption(new EnumOption("serializer", "generate a (de-)serializer", Arrays.asList("jackson"), "jackson")); + optionSerializer = addOption(new EnumOption("serializer", "generate a (de-)serializer", Arrays.asList("jackson", "jackson-json-pointer", "jackson-manual-references"), "jackson")); optionQuiet = addOption(new FlagOption("quiet", "do not output anything on stdout")); } diff --git a/src/test/jastadd/resolver/MyRefResolver.jadd b/src/test/jastadd/resolver/MyRefResolver.jadd index fa585c9..1a22700 100644 --- a/src/test/jastadd/resolver/MyRefResolver.jadd +++ b/src/test/jastadd/resolver/MyRefResolver.jadd @@ -1,22 +1,9 @@ aspect MyRewrites { // context-independent name resolution - refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) { - System.out.println("resolving " + id + " to " + root().findNamedElement(id)); - return root().findNamedElement(id); - } - - // context-independent name resolution - refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) { - System.out.println("resolving " + id + " to " + root().findNamedElement(id)); - return root().findA(id); - } - - // context-independent name resolution - refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) { - System.out.println("resolving " + id + " to " + root().findNamedElement(id)); - return root().findB(id); - } + refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) = root().findNamedElement(id); + refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) = root().findA(id); + refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) = root().findB(id); } diff --git a/src/test/jastadd/resolver/ResolverUtils.jadd b/src/test/jastadd/resolver/ResolverUtils.jadd index a8d5473..105d50e 100644 --- a/src/test/jastadd/resolver/ResolverUtils.jadd +++ b/src/test/jastadd/resolver/ResolverUtils.jadd @@ -1,8 +1,7 @@ aspect Utils { inh Root ASTNode.root(); - eq Root.getA(int i).root() = this; - eq Root.getB(int i).root() = this; + eq Root.getChild().root() = this; syn NamedElement Root.findNamedElement(String name) { for (A a : getAList()) { @@ -35,4 +34,4 @@ aspect Utils { } return null; } -} \ No newline at end of file +} diff --git a/src/test/jastadd/resolver2/ResolverUtils.jadd b/src/test/jastadd/resolver2/ResolverUtils.jadd index a8d5473..105d50e 100644 --- a/src/test/jastadd/resolver2/ResolverUtils.jadd +++ b/src/test/jastadd/resolver2/ResolverUtils.jadd @@ -1,8 +1,7 @@ aspect Utils { inh Root ASTNode.root(); - eq Root.getA(int i).root() = this; - eq Root.getB(int i).root() = this; + eq Root.getChild().root() = this; syn NamedElement Root.findNamedElement(String name) { for (A a : getAList()) { @@ -35,4 +34,4 @@ aspect Utils { } return null; } -} \ No newline at end of file +} diff --git a/src/test/jastadd/serializer-manual-relative/JsonPointer.jrag b/src/test/jastadd/serializer-manual-relative/JsonPointer.jrag new file mode 100644 index 0000000..6a32e35 --- /dev/null +++ b/src/test/jastadd/serializer-manual-relative/JsonPointer.jrag @@ -0,0 +1,204 @@ +aspect JsonPointer { + + refine RefCreatorStubs eq A.createRefToDi1(B target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToDi2(B target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToDi3(B target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi1(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi1(A target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi2(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi2(A target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi3(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi3(A target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi5(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi5(A target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi6(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi6(A target) = createReferenceTo(target); + refine RefCreatorStubs eq A.createRefToBi9(B target) = createReferenceTo(target); + refine RefCreatorStubs eq B.createRefToBi9(A target) = createReferenceTo(target); + refine RefCreatorStubs eq Root.createRefToD(D target) = createReferenceTo(target); + refine RefCreatorStubs eq D.createRefToRoot(Root target) = createReferenceTo(target); + + syn String ASTNode.createReferenceTo(ASTNode target) { + // find common subtree + java.util.List<ASTNode> myParents = parents(); + java.util.List<ASTNode> targetParents = target.parents(); + int minSize = Math.min(myParents.size(), targetParents.size()); + if (minSize > 0) { + int commonDepth = 0; + while (commonDepth < minSize && myParents.get(commonDepth) == targetParents.get(commonDepth)) { + commonDepth ++; + } + + int stepsUp = 0; + for (int i = commonDepth; i < myParents.size(); i++) { + stepsUp += (myParents.get(i).inList()) ? 3 : 2; + } + + return stepsUp + "#" + target.jsonPointerFrom(myParents.get(commonDepth-1)); + } else { + return (myParents.size() == 0) ? target.jsonPointerFrom(this) : myParents.size() + "#"; + } + } + + syn boolean ASTNode.inList() = (getParent() == null) ? false : inListInh(); + + inh boolean ASTNode.inListInh(); + eq Root.getA().inListInh() = true; + eq Root.getB().inListInh() = true; + eq Root.getC().inListInh() = false; + eq C.getD1().inListInh() = false; + eq C.getD2().inListInh() = false; + eq C.getD3().inListInh() = true; + + + syn ASTNode ASTNode.goUp(int steps) = steps > 0 ? goUpInh(steps) : this; + + inh ASTNode ASTNode.goUpInh(int steps); + eq Root.getA().goUpInh(int steps) = goUp(steps-3); + eq Root.getB().goUpInh(int steps) = goUp(steps-3); + eq Root.getC().goUpInh(int steps) = goUp(steps-2); + eq C.getD1().goUpInh(int steps) = goUp(steps-2); + eq C.getD2().goUpInh(int steps) = goUp(steps-2); + eq C.getD3().goUpInh(int steps) = goUp(steps-3); + + /** + * return the parent from root to the current node + */ + syn java.util.List<ASTNode> ASTNode.parents() { + java.util.List<ASTNode> result = new java.util.ArrayList<>(); + if (getParent() != null) { + result.addAll(getParent().parents()); + if (!(this instanceof List) && !(this instanceof Opt)) result.add(this); + } else { + // add the root + result.add(this); + } + return result; + } + + syn String ASTNode.jsonPointerFrom(ASTNode p) = (getParent() == null || this == p) ? "" : jsonPointerInh(p); + + inh String ASTNode.jsonPointerInh(ASTNode p); + eq Root.A(int index).jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/A/" + index; + eq Root.B(int index).jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/B/" + index; + eq Root.C().jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/C"; + eq C.D1().jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/D1"; + eq C.D2().jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/D2"; + eq C.D3(int index).jsonPointerInh(ASTNode p) = this.jsonPointerFrom(p) + "/children/D3/" + index; + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveRootByToken(String id) = (Root) resolveJsonPointer(id); + refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) = (A) resolveJsonPointer(id); + refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) = (B) resolveJsonPointer(id); + refine RefResolverStubs eq ASTNode.globallyResolveCByToken(String id) = (C) resolveJsonPointer(id); + refine RefResolverStubs eq ASTNode.globallyResolveDByToken(String id) = (D) resolveJsonPointer(id); + refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) = (NamedElement) resolveJsonPointer(id); + + syn ASTNode ASTNode.resolveJsonPointer(String pointer) { + if (pointer.isEmpty() || pointer.startsWith("/")) { + return root().resolveJsonPointer(pointer.split("/"),1); + } else { + // a lot of assumptions here... + int depth = Integer.valueOf(pointer.split("#")[0]); + ASTNode result = goUp(depth); + return result.resolveJsonPointer(pointer.split("/"),1); + } + } + + ASTNode ASTNode.root() { + if (getParent() == null) return this; + else return getParent().root(); + } + + syn ASTNode ASTNode.resolveJsonPointer(String[] pointer, int index) { + if (index < pointer.length) { + throw new RuntimeException("found wrong child " + pointer[index + 1] + " in class " + this.getClass().getSimpleName()); + } else { + throw new RuntimeException("Cannot resolve JSON pointer for class " + this.getClass().getSimpleName()); + } + } + eq Root.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + case "A": + return getA(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + case "B": + return getB(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + case "C": + return getC().resolveJsonPointer(pointer, index + 2); + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq A.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq B.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq C.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + case "D1": + return getD1().resolveJsonPointer(pointer, index + 2); + case "D2": + return getD2().resolveJsonPointer(pointer, index + 2); + case "D3": + return getD3(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq D.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq NamedElement.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } +} diff --git a/src/test/jastadd/serializer-manual-relative/Serializer.relast b/src/test/jastadd/serializer-manual-relative/Serializer.relast new file mode 100644 index 0000000..0e850a7 --- /dev/null +++ b/src/test/jastadd/serializer-manual-relative/Serializer.relast @@ -0,0 +1,23 @@ + +Root ::= A* B* C; +A:NamedElement; +B:NamedElement; +C:NamedElement ::= D1:D [D2:D] D3:D*; +D:NamedElement; + +abstract NamedElement ::= <Name>; + +rel A.Di1 -> B; +rel A.Di2? -> B; +rel A.Di3* -> B; + +rel A.Bi1 <-> B.Bi1; +rel A.Bi2 <-> B.Bi2?; +rel A.Bi3 <-> B.Bi3*; + +rel A.Bi5? <-> B.Bi5?; +rel A.Bi6? <-> B.Bi6*; + +rel A.Bi9* <-> B.Bi9*; + +rel Root.D <-> D.Root?; diff --git a/src/test/jastadd/serializer-manual/JsonPointer.jrag b/src/test/jastadd/serializer-manual/JsonPointer.jrag new file mode 100644 index 0000000..db94ab9 --- /dev/null +++ b/src/test/jastadd/serializer-manual/JsonPointer.jrag @@ -0,0 +1,158 @@ +aspect JsonPointer { + + refine RefCreatorStubs eq ASTNode.createReference() = jsonPointer(); + + syn String ASTNode.jsonPointer() { + if (getParent() == null) { + return ""; + } else { + return jsonPointerInh(); + } + } + inh String ASTNode.jsonPointerInh(); + eq Root.A(int index).jsonPointerInh() { + return this.jsonPointer() + "/children/A/" + index; + } + eq Root.B(int index).jsonPointerInh() { + return this.jsonPointer() + "/children/B/" + index; + } + eq Root.C().jsonPointerInh() { + return this.jsonPointer() + "/children/C"; + } + eq C.D1().jsonPointerInh() { + return this.jsonPointer() + "/children/D1"; + } + eq C.D2().jsonPointerInh() { + return this.jsonPointer() + "/children/D2"; + } + eq C.D3(int index).jsonPointerInh() { + return this.jsonPointer() + "/children/D3/" + index; + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveRootByToken(String id) { + return (Root) resolveJsonPointer(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) { + return (A) resolveJsonPointer(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) { + return (B) resolveJsonPointer(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveCByToken(String id) { + return (C) resolveJsonPointer(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveDByToken(String id) { + return (D) resolveJsonPointer(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) { + return (NamedElement) resolveJsonPointer(id); + } + + syn ASTNode ASTNode.resolveJsonPointer(String pointer) = root().resolveJsonPointer(pointer.split("/"), 1); + ASTNode ASTNode.root() { + if (getParent() == null) return this; + else return getParent().root(); + } + syn ASTNode ASTNode.resolveJsonPointer(String[] pointer, int index) { + if (index < pointer.length) { + throw new RuntimeException("found wrong child " + pointer[index + 1] + " in class " + this.getClass().getSimpleName()); + } else { + throw new RuntimeException("Cannot resolve JSON pointer for class " + this.getClass().getSimpleName()); + } + } + eq Root.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + case "A": + return getA(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + case "B": + return getB(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + case "C": + return getC().resolveJsonPointer(pointer, index + 2); + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq A.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq B.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq C.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + case "D1": + return getD1().resolveJsonPointer(pointer, index + 2); + case "D2": + return getD2().resolveJsonPointer(pointer, index + 2); + case "D3": + return getD3(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3); + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq D.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } + eq NamedElement.resolveJsonPointer(String[] pointer, int index) { + if (pointer.length == 0 || pointer.length == index) { + return this; + } else if (pointer.length == index + 1) { + throw new RuntimeException("there is only one child called " + pointer[index]); + } else { + switch (pointer[index + 1]) { + default: + return super.resolveJsonPointer(pointer, index); + } + } + } +} diff --git a/src/test/jastadd/serializer-manual/Serializer.relast b/src/test/jastadd/serializer-manual/Serializer.relast new file mode 100644 index 0000000..0e850a7 --- /dev/null +++ b/src/test/jastadd/serializer-manual/Serializer.relast @@ -0,0 +1,23 @@ + +Root ::= A* B* C; +A:NamedElement; +B:NamedElement; +C:NamedElement ::= D1:D [D2:D] D3:D*; +D:NamedElement; + +abstract NamedElement ::= <Name>; + +rel A.Di1 -> B; +rel A.Di2? -> B; +rel A.Di3* -> B; + +rel A.Bi1 <-> B.Bi1; +rel A.Bi2 <-> B.Bi2?; +rel A.Bi3 <-> B.Bi3*; + +rel A.Bi5? <-> B.Bi5?; +rel A.Bi6? <-> B.Bi6*; + +rel A.Bi9* <-> B.Bi9*; + +rel Root.D <-> D.Root?; diff --git a/src/test/jastadd/serializer-pointer/Serializer.relast b/src/test/jastadd/serializer-pointer/Serializer.relast new file mode 100644 index 0000000..0e850a7 --- /dev/null +++ b/src/test/jastadd/serializer-pointer/Serializer.relast @@ -0,0 +1,23 @@ + +Root ::= A* B* C; +A:NamedElement; +B:NamedElement; +C:NamedElement ::= D1:D [D2:D] D3:D*; +D:NamedElement; + +abstract NamedElement ::= <Name>; + +rel A.Di1 -> B; +rel A.Di2? -> B; +rel A.Di3* -> B; + +rel A.Bi1 <-> B.Bi1; +rel A.Bi2 <-> B.Bi2?; +rel A.Bi3 <-> B.Bi3*; + +rel A.Bi5? <-> B.Bi5?; +rel A.Bi6? <-> B.Bi6*; + +rel A.Bi9* <-> B.Bi9*; + +rel Root.D <-> D.Root?; diff --git a/src/test/java/org/jastadd/relast/tests/SerializerManual.java b/src/test/java/org/jastadd/relast/tests/SerializerManual.java new file mode 100644 index 0000000..a870f56 --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/SerializerManual.java @@ -0,0 +1,135 @@ +package org.jastadd.relast.tests; + +import org.junit.jupiter.api.Test; +import manual.serializer.ast.*; + +import java.io.File; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + + +class SerializerManual { + + + @Test + void testDi1() throws SerializationException, DeserializationException, IOException { + + Root r = new Root(); + A a1 = new A("a1"); + A a2 = new A("a2"); + A a3 = new A("a3"); + B b1 = new B("b1"); + B b2 = new B("b2"); + B b3 = new B("b3"); + C c = new C(); + c.setName("c"); + + // non-terminals + + D d1 = new D("d1"); + + c.setD1(d1); + c.setD2(new D("d2")); + c.addD3(new D("D3-1")); + c.addD3(new D("D3-2")); + c.addD3(new D("D3-3")); + + r.setC(c); + + // non-containment relations + r.addA(a1); + r.addA(a2); + r.addA(a3); + r.addB(b1); + r.addB(b2); + r.addB(b3); + + // Di1 + a1.setDi1(b2); + a2.setDi1(b1); + a3.setDi1(b3); + + // Di2 + a1.setDi2(b2); + a3.setDi2(b1); + + // Di3 + a1.addToDi3(b1); + a1.addToDi3(b2); + a1.addToDi3(b3); + a2.addToDi3(b2); + + // Bi1 + a1.setBi1(b3); + a2.setBi1(b2); + a3.setBi1(b1); + + // Bi2 + a1.setBi2(b1); + a2.setBi2(b2); + a3.setBi2(b3); + + // Bi3 + a1.setBi3(b2); + a2.setBi3(b2); + a3.setBi3(b2); + + // Bi5 + a1.setBi5(b1); + a2.setBi5(b3); + + // Bi6 + a2.setBi6(b3); + a3.setBi6(b3); + + // Bi9 + a1.addToBi9(b1); + a1.addToBi9(b3); + a2.addToBi9(b3); + + // D + r.setD(d1); + + File f1a = File.createTempFile("original", ".json"); + System.out.println(f1a.getAbsoluteFile()); + r.serialize(f1a); + + com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory(); + com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(System.out, com.fasterxml.jackson.core.JsonEncoding.UTF8); + generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter()); + r.serialize(generator); + generator.close(); + + Root copy = Root.deserialize(f1a); + File f1b = File.createTempFile("copy", ".json"); + copy.serialize(f1b); + + assertThat(f1b).hasSameContentAs(f1a); + + // remove a2 + a1.setDi1(b3); + a1.setDi2(b3); + a1.removeFromDi3(b2); + a1.removeFromDi3(b2); + a1.setBi3(b1); + a3.setBi3(b1); + b3.clearBi5(); + b3.removeFromBi6(a2); + b3.removeFromBi9(a2); + r.getAList().removeChild(r.getAList().getIndexOfChild(a2)); + r.getBList().removeChild(r.getBList().getIndexOfChild(b2)); + + File f2a = File.createTempFile("original", ".json"); + System.out.println(f2a.getAbsoluteFile()); + r.serialize(f2a); + + copy = Root.deserialize(f2a); + File f2b = File.createTempFile("copy", ".json"); + copy.serialize(f2b); + + assertThat(f2b).hasSameContentAs(f2a); + + } + +} diff --git a/src/test/java/org/jastadd/relast/tests/SerializerManualRelative.java b/src/test/java/org/jastadd/relast/tests/SerializerManualRelative.java new file mode 100644 index 0000000..6d3ccc2 --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/SerializerManualRelative.java @@ -0,0 +1,135 @@ +package org.jastadd.relast.tests; + +import manual.relative.serializer.ast.*; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + + +class SerializerManualRelative { + + + @Test + void testDi1() throws SerializationException, DeserializationException, IOException { + + Root r = new Root(); + A a1 = new A("a1"); + A a2 = new A("a2"); + A a3 = new A("a3"); + B b1 = new B("b1"); + B b2 = new B("b2"); + B b3 = new B("b3"); + C c = new C(); + c.setName("c"); + + // non-terminals + + D d1 = new D("d1"); + + c.setD1(d1); + c.setD2(new D("d2")); + c.addD3(new D("D3-1")); + c.addD3(new D("D3-2")); + c.addD3(new D("D3-3")); + + r.setC(c); + + // non-containment relations + r.addA(a1); + r.addA(a2); + r.addA(a3); + r.addB(b1); + r.addB(b2); + r.addB(b3); + + // Di1 + a1.setDi1(b2); + a2.setDi1(b1); + a3.setDi1(b3); + + // Di2 + a1.setDi2(b2); + a3.setDi2(b1); + + // Di3 + a1.addToDi3(b1); + a1.addToDi3(b2); + a1.addToDi3(b3); + a2.addToDi3(b2); + + // Bi1 + a1.setBi1(b3); + a2.setBi1(b2); + a3.setBi1(b1); + + // Bi2 + a1.setBi2(b1); + a2.setBi2(b2); + a3.setBi2(b3); + + // Bi3 + a1.setBi3(b2); + a2.setBi3(b2); + a3.setBi3(b2); + + // Bi5 + a1.setBi5(b1); + a2.setBi5(b3); + + // Bi6 + a2.setBi6(b3); + a3.setBi6(b3); + + // Bi9 + a1.addToBi9(b1); + a1.addToBi9(b3); + a2.addToBi9(b3); + + // D + r.setD(d1); + + File f1a = File.createTempFile("original", ".json"); + System.out.println(f1a.getAbsoluteFile()); + r.serialize(f1a); + + com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory(); + com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(System.out, com.fasterxml.jackson.core.JsonEncoding.UTF8); + generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter()); + r.serialize(generator); + generator.close(); + + Root copy = Root.deserialize(f1a); + File f1b = File.createTempFile("copy", ".json"); + copy.serialize(f1b); + + assertThat(f1b).hasSameContentAs(f1a); + + // remove a2 + a1.setDi1(b3); + a1.setDi2(b3); + a1.removeFromDi3(b2); + a1.removeFromDi3(b2); + a1.setBi3(b1); + a3.setBi3(b1); + b3.clearBi5(); + b3.removeFromBi6(a2); + b3.removeFromBi9(a2); + r.getAList().removeChild(r.getAList().getIndexOfChild(a2)); + r.getBList().removeChild(r.getBList().getIndexOfChild(b2)); + + File f2a = File.createTempFile("original", ".json"); + System.out.println(f2a.getAbsoluteFile()); + r.serialize(f2a); + + copy = Root.deserialize(f2a); + File f2b = File.createTempFile("copy", ".json"); + copy.serialize(f2b); + + assertThat(f2b).hasSameContentAs(f2a); + + } + +} diff --git a/src/test/java/org/jastadd/relast/tests/SerializerPointer.java b/src/test/java/org/jastadd/relast/tests/SerializerPointer.java new file mode 100644 index 0000000..2f1d141 --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/SerializerPointer.java @@ -0,0 +1,137 @@ +package org.jastadd.relast.tests; + +import org.junit.jupiter.api.Test; +import pointer.serializer.ast.*; + +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.time.Period; + +import static org.assertj.core.api.Assertions.assertThat; + + +class SerializerPointer { + + + @Test + void testDi1() throws SerializationException, DeserializationException, IOException { + + Root r = new Root(); + A a1 = new A("a1"); + A a2 = new A("a2"); + A a3 = new A("a3"); + B b1 = new B("b1"); + B b2 = new B("b2"); + B b3 = new B("b3"); + C c = new C(); + c.setName("c"); + + // non-terminals + + D d1 = new D("d1"); + + c.setD1(d1); + c.setD2(new D("d2")); + c.addD3(new D("D3-1")); + c.addD3(new D("D3-2")); + c.addD3(new D("D3-3")); + + r.setC(c); + + // non-containment relations + r.addA(a1); + r.addA(a2); + r.addA(a3); + r.addB(b1); + r.addB(b2); + r.addB(b3); + + // Di1 + a1.setDi1(b2); + a2.setDi1(b1); + a3.setDi1(b3); + + // Di2 + a1.setDi2(b2); + a3.setDi2(b1); + + // Di3 + a1.addToDi3(b1); + a1.addToDi3(b2); + a1.addToDi3(b3); + a2.addToDi3(b2); + + // Bi1 + a1.setBi1(b3); + a2.setBi1(b2); + a3.setBi1(b1); + + // Bi2 + a1.setBi2(b1); + a2.setBi2(b2); + a3.setBi2(b3); + + // Bi3 + a1.setBi3(b2); + a2.setBi3(b2); + a3.setBi3(b2); + + // Bi5 + a1.setBi5(b1); + a2.setBi5(b3); + + // Bi6 + a2.setBi6(b3); + a3.setBi6(b3); + + // Bi9 + a1.addToBi9(b1); + a1.addToBi9(b3); + a2.addToBi9(b3); + + // D + r.setD(d1); + + File f1a = File.createTempFile("original", ".json"); + System.out.println(f1a.getAbsoluteFile()); + r.serialize(f1a); + + com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory(); + com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(System.out, com.fasterxml.jackson.core.JsonEncoding.UTF8); + generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter()); + r.serialize(generator); + generator.close(); + + Root copy = Root.deserialize(f1a); + File f1b = File.createTempFile("copy", ".json"); + copy.serialize(f1b); + + assertThat(f1b).hasSameContentAs(f1a); + + // remove a2 + a1.setDi1(b3); + a1.setDi2(b3); + a1.removeFromDi3(b2); + a1.removeFromDi3(b2); + a1.setBi3(b1); + a3.setBi3(b1); + b3.clearBi5(); + b3.removeFromBi6(a2); + b3.removeFromBi9(a2); + r.getAList().removeChild(r.getAList().getIndexOfChild(a2)); + r.getBList().removeChild(r.getBList().getIndexOfChild(b2)); + + File f2a = File.createTempFile("original", ".json"); + System.out.println(f2a.getAbsoluteFile()); + r.serialize(f2a); + + copy = Root.deserialize(f2a); + File f2b = File.createTempFile("copy", ".json"); + copy.serialize(f2b); + + assertThat(f2b).hasSameContentAs(f2a); + + } + +} -- GitLab