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
Branches
Tags
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