Skip to content
Snippets Groups Projects
Commit 4a507826 authored by Johannes Mey's avatar Johannes Mey
Browse files

serializer and deserializer (reference resolving not working)

parent bf521752
No related branches found
No related tags found
1 merge request!1Mquat2
*.jarsrc/test/java/org/jastadd/relast/tests/Resolver2.java
*.jar
.idea/
.gradle/
build
......@@ -8,6 +8,8 @@ out/
*.class
src/test/jastadd/relations/Relations.ast
src/test/jastadd/relations/Relations.jadd
src/test/jastadd/relations/Relations2.ast
src/test/jastadd/relations/Relations2.jadd
src/test/jastadd/lowerbounds/LowerBounds.ast
src/test/jastadd/lowerbounds/LowerBounds.jadd
src/test/jastadd/multiple/Multiple.ast
......@@ -15,8 +17,14 @@ src/test/jastadd/multiple/Multiple.jadd
src/test/jastadd/resolver/Resolver.ast
src/test/jastadd/resolver/Resolver.jadd
src/test/jastadd/resolver/ResolverRefResolver.jadd
src/test/jastadd/resolver/ResolverResolverStubs.jrag
src/test/jastadd/resolver2/Resolver.ast
src/test/jastadd/resolver2/Resolver.jadd
src/test/jastadd/resolver2/ResolverRefResolver.jadd
src/test/jastadd/resolver2/ResolverResolverStubs.jrag
src/test/jastadd/listnames/ListNames.ast
src/test/jastadd/listnames/ListNames.jadd
\ No newline at end of file
src/test/jastadd/listnames/ListNames.jadd
src/test/jastadd/serializer/Serializer.ast
src/test/jastadd/serializer/Serializer.jadd
src/test/jastadd/serializer/SerializerSerializer.jadd
src/test/jastadd/serializer/SerializerRefResolver.jadd
......@@ -21,6 +21,8 @@ buildscript {
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.0'
compile 'com.fasterxml.jackson.core:jackson-core:2.9.8'
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
runtime 'org.jastadd:jastadd:2.3.2'
compile group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
......@@ -49,6 +51,7 @@ jar {
jastadd {
configureModuleBuild()
modules {
//noinspection GroovyAssignabilityCheck
module("RelAst") {
java {
......@@ -110,6 +113,7 @@ task preprocessRelationTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/relations/Relations.relast', '--file', '--grammarName=src/test/jastadd/relations/Relations'
}
......@@ -121,6 +125,7 @@ task doublePreprocessRelationTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/relations/Relations.ast', '--file', '--grammarName=src/test/jastadd/relations/Relations2'
}
......@@ -132,7 +137,11 @@ task compileRelationTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=relations.ast', 'src/test/jastadd/relations/Relations.ast', 'src/test/jastadd/relations/Relations.jadd', 'src/test/jastadd/Utils.jadd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=relations.ast',
'src/test/jastadd/relations/Relations.ast',
'src/test/jastadd/relations/Relations.jadd',
'src/test/jastadd/Utils.jadd'
}
task preprocessLowerBoundsTest(type: JavaExec, group: 'verification') {
......@@ -143,6 +152,7 @@ task preprocessLowerBoundsTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/lowerbounds/LowerBounds.relast', '--file', '--grammarName=src/test/jastadd/lowerbounds/LowerBounds'
}
......@@ -154,7 +164,11 @@ task compileLowerBoundsTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=lowerbounds.ast', 'src/test/jastadd/lowerbounds/LowerBounds.ast', 'src/test/jastadd/lowerbounds/LowerBounds.jadd', 'src/test/jastadd/Utils.jadd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=lowerbounds.ast',
'src/test/jastadd/lowerbounds/LowerBounds.ast',
'src/test/jastadd/lowerbounds/LowerBounds.jadd',
'src/test/jastadd/Utils.jadd'
}
task preprocessMultipleTest(type: JavaExec, group: 'verification') {
......@@ -165,6 +179,7 @@ task preprocessMultipleTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/multiple/Part1.relast', 'src/test/jastadd/multiple/Part2.relast', 'src/test/jastadd/multiple/Part3.relast', '--file', '--grammarName=src/test/jastadd/multiple/Multiple'
}
......@@ -176,17 +191,22 @@ task compileMultipleTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=multiple.ast', 'src/test/jastadd/multiple/Multiple.ast', 'src/test/jastadd/multiple/Multiple.jadd', 'src/test/jastadd/Utils.jadd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=multiple.ast',
'src/test/jastadd/multiple/Multiple.ast',
'src/test/jastadd/multiple/Multiple.jadd',
'src/test/jastadd/Utils.jadd'
}
task preprocessResolverTest(type: JavaExec, group: 'verification') {
doFirst {
delete 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd'
delete 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd', 'src/test/jastadd/resolver/ResolverResolverStubs.jrag'
}
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/resolver/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper'
}
......@@ -198,7 +218,15 @@ task compileResolverTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=resolver.ast', 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverUtils.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd', 'src/test/jastadd/resolver/MyRefResolver.jadd', 'src/test/jastadd/Utils.jadd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=resolver.ast',
'src/test/jastadd/resolver/Resolver.ast',
'src/test/jastadd/resolver/Resolver.jadd',
'src/test/jastadd/resolver/ResolverUtils.jadd',
'src/test/jastadd/resolver/ResolverRefResolver.jadd',
'src/test/jastadd/resolver/ResolverResolverStubs.jrag',
'src/test/jastadd/resolver/MyRefResolver.jadd',
'src/test/jastadd/Utils.jadd'
}
......@@ -210,6 +238,7 @@ task preprocessResolver2Test(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/resolver2/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver2/Resolver', '--resolverHelper'
}
......@@ -221,7 +250,15 @@ task compileResolver2Test(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=resolver2.ast', 'src/test/jastadd/resolver2/Resolver.ast', 'src/test/jastadd/resolver2/Resolver.jadd', 'src/test/jastadd/resolver2/ResolverUtils.jadd', 'src/test/jastadd/resolver2/ResolverRefResolver.jadd', 'src/test/jastadd/resolver2/MyRefResolver.jadd', 'src/test/jastadd/Utils.jadd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=resolver2.ast',
'src/test/jastadd/resolver2/Resolver.ast',
'src/test/jastadd/resolver2/Resolver.jadd',
'src/test/jastadd/resolver2/ResolverUtils.jadd',
'src/test/jastadd/resolver2/ResolverRefResolver.jadd',
'src/test/jastadd/resolver2/ResolverResolverStubs.jrag',
'src/test/jastadd/resolver2/MyRefResolver.jadd',
'src/test/jastadd/Utils.jadd'
}
task preprocessListNamesTest(type: JavaExec, group: 'verification') {
......@@ -232,6 +269,7 @@ task preprocessListNamesTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/listnames/ListNames.relast', '--file', '--grammarName=src/test/jastadd/listnames/ListNames', '--jastAddList=ListyMcListface'
}
......@@ -243,9 +281,44 @@ task compileListNamesTest(type: JavaExec, group: 'verification') {
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
args '--o=src/test/java-gen/', '--package=listnames.ast', 'src/test/jastadd/listnames/ListNames.ast', 'src/test/jastadd/listnames/ListNames.jadd', 'src/test/jastadd/Utils.jadd', '--List=ListyMcListface'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=listnames.ast', '--List=ListyMcListface',
'src/test/jastadd/listnames/ListNames.ast',
'src/test/jastadd/listnames/ListNames.jadd',
'src/test/jastadd/Utils.jadd'
}
task preprocessSerializerTest(type: JavaExec, group: 'verification') {
doFirst {
delete 'src/test/jastadd/serializer/Serializer.ast',
'src/test/jastadd/serializer/Serializer.jadd',
'src/test/jastadd/serializer/SerializerRefResolver.jadd',
'src/test/jastadd/serializer/SerializerSerializer.jadd'
}
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.relast.compiler.Compiler'
//noinspection GroovyAssignabilityCheck
args 'src/test/jastadd/serializer/Serializer.relast', '--file', '--grammarName=src/test/jastadd/serializer/Serializer', '--serializer=jackson'
}
task compileSerializerTest(type: JavaExec, group: 'verification') {
doFirst {
delete 'src/test/java-gen/serializer'
}
classpath = sourceSets.main.runtimeClasspath
main = 'org.jastadd.JastAdd'
//noinspection GroovyAssignabilityCheck
args '--o=src/test/java-gen/', '--package=serializer.ast',
'src/test/jastadd/serializer/Serializer.ast',
'src/test/jastadd/serializer/Serializer.jadd',
'src/test/jastadd/serializer/SerializerRefResolver.jadd',
'src/test/jastadd/serializer/SerializerSerializer.jadd',
'src/test/jastadd/Utils.jadd'
}
test {
outputs.upToDateWhen { false }
......@@ -270,4 +343,7 @@ test.dependsOn compileResolver2Test
compileResolver2Test.dependsOn preprocessResolver2Test
test.dependsOn compileListNamesTest
compileListNamesTest.dependsOn preprocessListNamesTest
\ No newline at end of file
compileListNamesTest.dependsOn preprocessListNamesTest
test.dependsOn compileSerializerTest
compileSerializerTest.dependsOn preprocessSerializerTest
\ No newline at end of file
......@@ -3,7 +3,8 @@ aspect BackendAbstractGrammar {
public static String ASTNode.listClass = "ArrayList";
public static String ASTNode.jastAddListType = "List";
public static boolean ASTNode.resolverHelper = false;
public static boolean ASTNode.resolverHelper = false;
public static boolean ASTNode.serializer = false;
public String Program.generateAbstractGrammar() {
StringBuilder sb = new StringBuilder();
......@@ -694,7 +695,13 @@ aspect NameResolutionHelper {
return sb.toString();
}
public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) {
public String Program.generateResolverStubs() {
StringBuilder sb = new StringBuilder();
generateResolverStubs(sb);
return sb.toString();
}
public void Program.generateResolverStubs(StringBuilder sb) {
sb.append("aspect RefResolverStubs {\n\n");
for (Relation r: getRelations()) {
......@@ -708,6 +715,9 @@ aspect NameResolutionHelper {
}
}
sb.append("}\n\n");
}
public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) {
sb.append("aspect ReferenceCreation {\n\n");
......@@ -871,6 +881,391 @@ aspect NameResolutionHelper {
}
}
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() {
StringBuilder sb = new StringBuilder();
generateFromJson(sb);
generateToJson(sb);
writeUID(sb);
return sb.toString();
}
public void Program.generateFromJson(StringBuilder sb) {
sb.append("aspect JsonToModel {\n");
sb.append(ind(1) + "public class DeserializationException extends Exception {\n");
sb.append(ind(2) + "public DeserializationException(String message) {\n");
sb.append(ind(3) + "super(message);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(2) + "public DeserializationException(String message, Exception cause) {\n");
sb.append(ind(3) + "super(message, cause);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
sb.append(ind(1) + "public void ASTNode.serialize(com.fasterxml.jackson.core.JsonGenerator g) throws SerializationException {\n");
sb.append(ind(2) + "serialize(g, null);\n");
sb.append(ind(1) + "}\n");
sb.append(ind(1) + "public void ASTNode.serialize(com.fasterxml.jackson.core.JsonGenerator g, String field) throws SerializationException {\n");
sb.append(ind(2) + "throw new SerializationException(\"unable to serialize class \" + this.getClass().getSimpleName());\n");
sb.append(ind(1) + "}\n");
sb.append(ind(1) + "public void ASTNode.serialize(java.io.File file) throws SerializationException {\n");
sb.append(ind(2) + "try {\n");
sb.append(ind(3) + "com.fasterxml.jackson.core.JsonFactory factory = new com.fasterxml.jackson.core.JsonFactory();\n");
sb.append(ind(3) + "com.fasterxml.jackson.core.JsonGenerator generator = factory.createGenerator(file, com.fasterxml.jackson.core.JsonEncoding.UTF8);\n");
sb.append(ind(3) + "generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter());\n");
sb.append(ind(3) + "serialize(generator);\n");
sb.append(ind(3) + "generator.close();\n");
sb.append(ind(2) + "} catch (java.io.IOException e) {\n");
sb.append(ind(3) + "throw new SerializationException(\"Unable to serialize file \" + file.getAbsolutePath(), e);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
for (TypeDecl decl : getTypeDeclList()) {
if (!decl.isUnresolved()) {
decl.deserialize(sb);
}
}
sb.append("}\n");
}
public void Program.generateToJson(StringBuilder sb) {
sb.append("aspect ModelToJson {\n");
sb.append(ind(1) + "public class SerializationException extends Exception {\n");
sb.append(ind(2) + "public SerializationException(String message) {\n");
sb.append(ind(3) + "super(message);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(2) + "public SerializationException(String message, Exception cause) {\n");
sb.append(ind(3) + "super(message, cause);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
for (TypeDecl decl : getTypeDeclList()) {
if (!decl.isUnresolved()) {
decl.serialize(sb);
}
}
sb.append("}\n");
}
public void TypeDecl.serialize(StringBuilder sb) {
sb.append(ind(1) + "public void " + getID() + ".serialize(com.fasterxml.jackson.core.JsonGenerator g, String fieldName) throws SerializationException {\n");
sb.append(ind(2) + "try {\n");
sb.append(ind(3) + "if (fieldName == null) {\n");
sb.append(ind(4) + "g.writeStartObject();\n");
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) + "g.writeStringField(\"id\", __uid());\n");
if (componentsTransitive().size() > 0) {
sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n");
for (Component child : componentsTransitive()) {
child.serialize(sb, 3);
}
sb.append(ind(3) + "g.writeEndObject(); // children\n");
}
if (relationComponents().size() > 0) {
sb.append(ind(3) + "g.writeObjectFieldStart(\"relations\");\n");
for (RelationComponent relation : relationComponents()) {
relation.serialize(sb, 3);
}
sb.append(ind(3) + "g.writeEndObject(); // relations\n");
}
sb.append(ind(3) + "g.writeEndObject();\n");
sb.append(ind(2) + "} catch (java.io.IOException e) {\n");
sb.append(ind(3) + "throw new SerializationException(\"unable to serialize " + getID() + "\", e);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
}
public abstract void Component.serialize(StringBuilder sb, int indent);
public void NormalComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "get" + getID() + "().serialize(g, \"" + getID() + "\");\n");
}
public void OptComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "if (has" + getID() + "()) {\n");
sb.append(ind(indent + 1) + "get" + getID() + "().serialize(g, \"" + getID() + "\");\n");
sb.append(ind(indent) + "}\n");
}
public void TokenComponent.serialize(StringBuilder sb, int indent) {
String type = getTypeUse().getID();
switch (type) {
case "float":
case "Float":
case "double":
case "Double":
case "int":
case "Integer":
case "short":
case "Short":
case "long":
case "Long":
case "byte":
case "Byte":
sb.append(ind(indent) + "g.writeNumberField(\"" + getID() + "\", get" + getID() + "());\n");
break;
case "boolean":
case "Boolean":
sb.append(ind(indent) + "g.writeBooleanField(\"" + getID() + "\", get" + getID() + "());\n");
break;
case "char":
case "Character":
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", Character.toString(get"+ getID() + "()));\n");
break;
case "String":
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "());\n");
break;
case "java.time.Instant":
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "()).toString());\n");
break;
case "java.time.Period":
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "()).toString());\n");
break;
default:
// assume that the type is an enum. there is no way of checking this here
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "()).name());\n");
// sb.append("throw new DeserializationException(\"Unable to deserialize child node of type \"" + getTypeUse() + "\"\")")
}
}
public void NTAComponent.serialize(StringBuilder sb, int indent) {
// do not serialize NTA
}
public void ListComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "if (getNum" + getID() + "() > 0) {\n");
sb.append(ind(indent + 1) + "g.writeArrayFieldStart(\"" + getID() + "\");\n");
sb.append(ind(indent + 1) + "for (" + getTypeUse().decl().getID() + " child : get" + getID() + "List()) {\n");
sb.append(ind(indent + 2) + "child.serialize(g);\n");
sb.append(ind(indent + 1) + "}\n");
sb.append(ind(indent + 1) + "g.writeEndArray();\n");
sb.append(ind(indent) + "}\n");
}
public void OneRelationComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().__uid());\n");
}
public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "if (has" + getID() + "()) {\n");
sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().__uid());\n");
sb.append(ind(indent) + "}\n");
}
public void ManyRelationComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "g.writeArrayFieldStart(\"" + getID() + "\");\n");
sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : get" + getID() + "List()) {\n");
sb.append(ind(indent + 1) + "g.writeString(child.__uid());\n");
sb.append(ind(indent) + "}\n");
sb.append(ind(indent) + "g.writeEndArray();\n");
}
public void TypeDecl.deserialize(StringBuilder sb) {
sb.append(ind(1) + "public static " + getID() + " " + getID() + ".deserialize(java.io.File file) throws DeserializationException {\n");
sb.append(ind(2) + "try {\n");
sb.append(ind(3) + "com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();\n");
sb.append(ind(3) + "com.fasterxml.jackson.core.JsonFactory factory = mapper.getFactory();\n");
sb.append(ind(3) + "com.fasterxml.jackson.core.JsonParser parser = factory.createParser(file);\n");
sb.append(ind(3) + "return deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));\n");
sb.append(ind(2) + "} catch (java.io.IOException e) {\n");
sb.append(ind(3) + "throw new DeserializationException(\"unable to deserialize \" + file.getAbsolutePath(), e);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
sb.append(ind(1) + "public static " + getID() + " " + getID() + ".deserialize(" + jsonNodeType + " node) throws DeserializationException {\n");
sb.append(ind(2) + getID() + " element;\n");
if (getAbstract()) {
// switch case between all implementations of the abstract class
sb.append(ind(2) + "switch (node" + jsonNodeTypeAccessor + ") {\n");
for (TypeDecl subType : subTypeDecls()) {
sb.append(ind(3) + "case \"" + subType.getID() + "\":\n");
sb.append(ind(4) + "element = " + subType.getID() + ".deserialize(node);\n");
sb.append(ind(4) + "break;\n");
}
sb.append(ind(3) + "default:\n");
sb.append(ind(4) + "throw new DeserializationException(\"Unable to deserialize child of unexpected type \" + node" + jsonNodeTypeAccessor + " + \"(" + getID() + " expected)\");\n");
sb.append(ind(2) + "}\n");
} else {
sb.append(ind(2) + "element = new " + getID() + "();\n");
}
// deserialize id
sb.append(ind(2) + "if (node.has(\"id\")) {\n");
sb.append(ind(3) + "element.__uid = node.get(\"id\").asText();\n");
sb.append(ind(2) + "}\n");
// deserialize containment children
if (componentsTransitive().size() > 0) {
sb.append(ind(2) + "if (node.has(\"children\")) {\n");
sb.append(ind(3) + jsonNodeType + " children = node.get(\"children\");\n");
for (Component component : componentsTransitive()) {
sb.append(ind(3) + "if (children.has(\"" + component.getID() + "\")) {\n");
component.deserialize(sb, 4);
sb.append(ind(3) + "}\n");
}
sb.append(ind(2) + "}\n");
}
// deserialize non-containment children
Set<RelationComponent> relationComponents = relationComponents();
if (relationComponents.size() > 0) {
sb.append(ind(2) + "if (node.has(\"relations\")) {\n");
sb.append(ind(3) + jsonNodeType + " relations = node.get(\"relations\");\n");
for (RelationComponent component : relationComponents) {
sb.append(ind(3) + "if (relations.has(\"" + component.getID() + "\")) {\n");
component.deserialize(sb, 4);
sb.append(ind(3) + "}\n");
}
sb.append(ind(2) + "}\n");
}
sb.append(ind(2) + "return element;\n");
sb.append(ind(1) + "}\n");
}
public abstract void Component.deserialize(StringBuilder sb, int indent);
public void NormalComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "element.set" + getID() + "(" + getTypeUse().decl().getID() + ".deserialize(children.get(\"" + getID() + "\")));\n");
sb.append(ind(indent - 1) + "} else {\n");
sb.append(ind(indent) + "throw new DeserializationException(\"deserializer of missing mandatory child " + getID() + "\");\n");
}
public void OptComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent + 1) + "element.set" + getID() + "(" + getTypeUse().decl().getID() + ".deserialize(children.get(\"" + getID() + "\")));\n");
}
public void TokenComponent.deserialize(StringBuilder sb, int indent) {
String type = getTypeUse().getID();
switch (type) {
case "float":
case "Float":
sb.append(ind(indent) + "element.set" + getID() + "(Float.valueOf(children.get(\"" + getID() + "\").asText()));\n");
break;
case "double":
case "Double":
sb.append(ind(indent) + "element.set" + getID() + "(children.get(\"" + getID() + "\").asDouble());\n");
break;
case "int":
case "Integer":
sb.append(ind(indent) + "element.set" + getID() + "(children.get(\"" + getID() + "\").asInt());\n");
break;
case "short":
case "Short":
sb.append(ind(indent) + "element.set" + getID() + "(Short.valueOf(children.get(\"" + getID() + "\").asText()));\n");
break;
case "long":
case "Long":
sb.append(ind(indent) + "element.set" + getID() + "(children.get(\"" + getID() + "\").asLong());\n");
break;
case "byte":
case "Byte":
sb.append(ind(indent) + "element.set" + getID() + "(Byte.valueOf(children.get(\"" + getID() + "\").asText()));\n");
break;
case "boolean":
case "Boolean":
sb.append(ind(indent) + "element.set" + getID() + "(children.get(\"" + getID() + "\").asBoolean());\n");
break;
case "char":
case "Character":
sb.append(ind(indent) + "String chars = children.get(\"" + getID() + "\").asText();\n");
sb.append(ind(indent) + "if (chars.length() == 1) {\n");
sb.append(ind(indent + 2) + "element.set" + getID() + "(chars.charAt(0))\n");
sb.append(ind(indent) + "} else {\n");
sb.append(ind(indent + 2) + "throw new DeserializationException(\"unable to deserialize char '\" + chars + \"'\");\n");
sb.append(ind(indent) + "}\n");
break;
case "String":
sb.append(ind(indent) + "element.set" + getID() + "(children.get(\"" + getID() + "\").asText());\n");
break;
case "java.time.Instant":
sb.append(ind(indent) + "element.set" + getID() + "(java.time.Instant.parse(children.get(\"" + getID() + "\").asText()));\n");
break;
case "java.time.Period":
sb.append(ind(indent) + "element.set" + getID() + "(java.time.Period.parse(children.get(\"" + getID() + "\").asText()));\n");
break;
default:
// assume that the type is an enum. there is no way of checking this here
sb.append(ind(indent) + "element.set" + getID() + "Enum.valueOf(" + type + ".getClass(), children.get(\"" + getID() + "\".asText())));\n");
// sb.append("throw new DeserializationException(\"Unable to deserialize child node of type \"" + getTypeUse() + "\"\")")
}
}
public void Program.writeUID(StringBuilder sb) {
sb.append("aspect UID {\n");
sb.append(ind(1) + "class UIDProvider {\n");
sb.append(ind(2) + "private static long nextUID = 0;\n");
sb.append(ind(2) + "public static String getUID() {\n");
sb.append(ind(3) + "return String.valueOf(nextUID++);\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
sb.append("\n");
sb.append(ind(1) + "protected String ASTNode.__uid = null;\n");
sb.append("\n");
sb.append(ind(1) + "protected String ASTNode.__uid() {\n");
sb.append(ind(2) + "String customUID = serializationID();\n");
sb.append(ind(2) + "if (customUID == null) {\n");
sb.append(ind(3) + "if (__uid == null) {\n");
sb.append(ind(4) + "__uid = UIDProvider.getUID();\n");
sb.append(ind(3) + "}\n");
sb.append(ind(3) + "return __uid;\n");
sb.append(ind(2) + "} else {\n");
sb.append(ind(3) + "return customUID;\n");
sb.append(ind(2) + "}\n");
sb.append(ind(1) + "}\n");
sb.append("\n");
sb.append(ind(1) + "protected String ASTNode.serializationID() {\n");
sb.append(ind(2) + "return null;\n");
sb.append(ind(1) + "}\n");
sb.append("}\n");
}
public void NTAComponent.deserialize(StringBuilder sb, int indent) {
// do not serialize NTA
}
public void ListComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "for (" + jsonNodeType + " child : children.get(\"" + getID() + "\")) {\n");
sb.append(ind(indent + 1) + "element.add" + getID() + "(" + getTypeUse().decl().getID() + ".deserialize(child));\n");
sb.append(ind(indent) + "}\n");
}
public void OneRelationComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "element.set" + getID() + "(" + ofTypeDecl().getID() + ".createRefDirection(relations.get(\"" + getID() + "\").asText()));\n");
sb.append(ind(indent - 1) + "} else {\n");
sb.append(ind(indent) + "throw new DeserializationException(\"deserializer of missing mandatory relation child " + getID() + "\");\n");
}
public void OptionalRelationComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "element.set" + getID() + "(" + ofTypeDecl().getID() + ".createRefDirection(relations.get(\"" + getID() + "\").asText()));\n");
}
public void ManyRelationComponent.deserialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "for (" + jsonNodeType + " child : relations.get(\"" + getID() + "\")) {\n");
sb.append(ind(indent + 1) + "element.add" + getID() + "(" + ofTypeDecl().getID() + ".createRefDirection(child.asText()));\n");
sb.append(ind(indent) + "}\n");
}
}
aspect PrettyPrint {
public String Relation.prettyPrint() {
return "rel "
......
......@@ -2,16 +2,14 @@ package org.jastadd.relast.compiler;
import beaver.Parser;
import org.jastadd.relast.ast.*;
import org.jastadd.relast.compiler.options.CommandLine;
import org.jastadd.relast.compiler.options.*;
import org.jastadd.relast.compiler.options.CommandLine.CommandLineException;
import org.jastadd.relast.compiler.options.FlagOption;
import org.jastadd.relast.compiler.options.Option;
import org.jastadd.relast.compiler.options.StringOption;
import org.jastadd.relast.parser.RelAstParser;
import org.jastadd.relast.scanner.RelAstScanner;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Compiler {
......@@ -21,6 +19,7 @@ public class Compiler {
private StringOption optionListClass;
private StringOption optionJastAddList;
private StringOption optionGrammarName;
private EnumOption optionSerializer;
private FlagOption optionResolverHelper;
private CommandLine commandLine;
......@@ -45,7 +44,7 @@ public class Compiler {
}
if (optionResolverHelper.isSet()) {
if (optionResolverHelper.isSet() || optionSerializer.isSet()) {
// get a list of all (abstract or not) non-terminals
List<TypeDecl> nonTerminals = new ArrayList<>();
for (TypeDecl typeDecl : p.getTypeDecls()) {
......@@ -88,8 +87,21 @@ public class Compiler {
if (optionWriteToFile.isSet()) {
if (optionSerializer.isSet()) {
ASTNode.serializer = true;
switch (optionSerializer.getValue()) {
case "jackson":
writeToFile(grammarName + "Serializer.jadd", p.generateSerializer());
break;
}
}
if (optionResolverHelper.isSet()) {
ASTNode.resolverHelper = true;
writeToFile(grammarName + "ResolverStubs.jrag", p.generateResolverStubs());
}
if (optionSerializer.isSet() || optionResolverHelper.isSet()) {
writeToFile(grammarName + "RefResolver.jadd", p.generateRewriteToSuperTypeStub());
}
......@@ -131,6 +143,7 @@ public class Compiler {
optionGrammarName = addOption(new StringOption("grammarName", "name of the generated grammar and aspect (without file extension)"));
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)"));
optionSerializer = addOption(new EnumOption("serializer", "generate a (de-)serializer", Arrays.asList("jackson"), "jackson"));
}
......
Root ::= A* B*;
A ::= <Name:String> <_impl_Di2:B> <_impl_Bi2:B> <_impl_Bi4:B> <_impl_Bi3:B> <_impl_Bi8:ArrayList<B>> <_impl_Bi9:ArrayList<B>> <_impl_Bi1:B> <_impl_Bi5:B> <_impl_Di3:ArrayList<B>> <_impl_Bi7:ArrayList<B>> <_impl_Bi6:B> <_impl_Di1:B>;
B ::= <Name:String> <_impl_Bi7:A> <_impl_Bi3:ArrayList<A>> <_impl_Bi5:A> <_impl_Bi1:A> <_impl_Bi6:ArrayList<A>> <_impl_Bi9:ArrayList<A>> <_impl_Bi2:A> <_impl_Bi4:A> <_impl_Bi8:A>;
import java.util.ArrayList;
import java.util.Collections;
aspect RelAstAPI {
public boolean ASTNode.violatesLowerBounds() {
return !getLowerBoundsViolations().isEmpty();
}
public java.util.List<Pair<ASTNode, String>> ASTNode.getLowerBoundsViolations() {
ArrayList<Pair<ASTNode, String>> list = new ArrayList<>();
computeLowerBoundsViolations(list);
return list;
}
public void ASTNode.computeLowerBoundsViolations(java.util.List<Pair<ASTNode, String>> list) {
for (int i = 0; i < getNumChildNoTransform(); i++) {
getChildNoTransform(i).computeLowerBoundsViolations(list);
}
}
public class Pair<T1, T2> {
public final T1 _1;
public final T2 _2;
public Pair(T1 _1, T2 _2) {
ASTNode.assertNotNull(_1);
ASTNode.assertNotNull(_2);
this._1 = _1;
this._2 = _2;
}
public boolean equals(Object other) {
if (other instanceof Pair) {
Pair<?,?> p = (Pair<?,?>) other;
return _1.equals(p._1) && _2.equals(p._2);
} else {
return false;
}
}
public int hashCode() {
return 31*_1.hashCode() + _2.hashCode();
}
}
public static void ASTNode.assertNotNull(Object obj) {
if (obj == null) {
throw new NullPointerException();
}
}
}
Root ::= A* B* C;
A:NamedElement;
B:NamedElement;
C:NamedElement ::= D1:D [D2:D] D3:D* <F1:float> <F2:Float>;
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*;
package org.jastadd.relast.tests;
import org.junit.jupiter.api.Test;
import serializer.ast.*;
import java.io.File;
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
class Serializer {
@Test
void testDi1() throws SerializationException, DeserializationException {
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
c.setD1(new D("d1"));
c.setD2(new D("d2"));
c.addD3(new D("D3-1"));
c.addD3(new D("D3-2"));
c.addD3(new D("D3-3"));
// tokens
c.setF1(42f);
c.setF2(42.13f);
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.addDi3(b1);
a1.addDi3(b2);
a1.addDi3(b3);
a2.addDi3(b2);
// Bi1
a1.setBi1(b1);
a2.setBi1(b3);
a3.setBi1(b2);
// 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(b2);
a3.setBi6(b2);
// Bi9
a1.addBi9(b1);
a1.addBi9(b2);
a2.addBi9(b2);
File f = new File("test.json");
r.serialize(f);
Root copy = Root.deserialize(f);
File f2 = new File("copy.json");
copy.serialize(f2);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment