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

Merge branch 'json-pointer' into 'master'

Json pointer

See merge request johannes.mey/relast!5
parents 6a3f2671 fd6946d8
Pipeline #4718 passed with stage
in 2 minutes and 23 seconds
# RelAST Preprocessor Version 0.2.3 # RelAST Preprocessor Version 0.2.4
![RelAST process](relast-process.png) ![RelAST process](relast-process.png)
......
...@@ -246,6 +246,95 @@ task compileSerializerDefaultNamesTest(type: RelastTest) { ...@@ -246,6 +246,95 @@ task compileSerializerDefaultNamesTest(type: RelastTest) {
moreInputFiles 'src/test/jastadd/Utils.jadd' 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'
}
clean {
delete 'src/test/jastadd/serializer-names/Serializer.ast'
delete 'src/test/jastadd/serializer-names/Serializer.jadd'
delete 'src/test/jastadd/serializer-names/SerializerSerializer.jadd'
delete 'src/test/jastadd/serializer-names/SerializerResolverStubs.jrag'
delete 'src/test/jastadd/serializer-names/SerializerRefResolver.jadd'
delete 'src/test/jastadd/serializer-manual/Serializer.ast'
delete 'src/test/jastadd/serializer-manual/Serializer.jadd'
delete 'src/test/jastadd/serializer-manual/SerializerSerializer.jadd'
delete 'src/test/jastadd/serializer-manual/SerializerResolverStubs.jrag'
delete 'src/test/jastadd/serializer-manual/SerializerRefResolver.jadd'
delete 'src/test/jastadd/resolver2/Resolver.jadd'
delete 'src/test/jastadd/resolver2/Resolver.ast'
delete 'src/test/jastadd/resolver2/ResolverRefResolver.jadd'
delete 'src/test/jastadd/resolver2/ResolverResolverStubs.jrag'
delete 'src/test/jastadd/serializer-manual-relative/Serializer.ast'
delete 'src/test/jastadd/serializer-manual-relative/Serializer.jadd'
delete 'src/test/jastadd/serializer-manual-relative/SerializerSerializer.jadd'
delete 'src/test/jastadd/serializer-manual-relative/SerializerResolverStubs.jrag'
delete 'src/test/jastadd/serializer-manual-relative/SerializerRefResolver.jadd'
delete 'src/test/jastadd/serializer-pointer/Serializer.ast'
delete 'src/test/jastadd/serializer-pointer/Serializer.jadd'
delete 'src/test/jastadd/serializer-pointer/SerializerSerializer.jadd'
delete 'src/test/jastadd/serializer-pointer/SerializerResolverStubs.jrag'
delete 'src/test/jastadd/serializer-pointer/SerializerRefResolver.jadd'
delete 'src/test/jastadd/lowerbounds/LowerBounds.jadd'
delete 'src/test/jastadd/lowerbounds/LowerBounds.ast'
delete 'src/test/jastadd/resolver/Resolver.jadd'
delete 'src/test/jastadd/resolver/Resolver.ast'
delete 'src/test/jastadd/resolver/Resolver2.jadd'
delete 'src/test/jastadd/resolver/Resolver2.ast'
delete 'src/test/jastadd/resolver/Resolver2ResolverStubs.jrag'
delete 'src/test/jastadd/resolver/ResolverRefResolver.jadd'
delete 'src/test/jastadd/resolver/ResolverResolverStubs.jrag'
delete 'src/test/jastadd/resolver/Resolver2RefResolver.jadd'
delete 'src/test/jastadd/errors/Errors.out'
delete 'src/test/jastadd/errors/Inheritance.out'
delete 'src/test/jastadd/errors/Multiple.out'
delete 'src/test/jastadd/errors/InheritanceLeft.out'
delete 'src/test/jastadd/errors/ErrorsLeft.out'
delete 'src/test/jastadd/errors/MultipleLeft.out'
delete 'src/test/jastadd/serializer/Serializer.ast'
delete 'src/test/jastadd/serializer/Serializer.jadd'
delete 'src/test/jastadd/serializer/SerializerSerializer.jadd'
delete 'src/test/jastadd/serializer/SerializerResolverStubs.jrag'
delete 'src/test/jastadd/serializer/SerializerRefResolver.jadd'
delete 'src/test/jastadd/listnames/ListNames.jadd'
delete 'src/test/jastadd/listnames/ListNames.ast'
delete 'src/test/jastadd/relations/Relations2.jadd'
delete 'src/test/jastadd/relations/Relations3.ast'
delete 'src/test/jastadd/relations/Relations2.ast'
delete 'src/test/jastadd/relations/Relations.ast'
delete 'src/test/jastadd/relations/Relations.jadd'
delete 'src/test/jastadd/relations/Relations3.jadd'
delete 'src/test/jastadd/multiple/Multiple.jadd'
delete 'src/test/jastadd/multiple/Multiple.ast'
}
test { test {
outputs.upToDateWhen { false } outputs.upToDateWhen { false }
useJUnitPlatform() useJUnitPlatform()
......
...@@ -5,6 +5,8 @@ aspect BackendAbstractGrammar { ...@@ -5,6 +5,8 @@ aspect BackendAbstractGrammar {
public static boolean ASTNode.resolverHelper = false; public static boolean ASTNode.resolverHelper = false;
public static boolean ASTNode.serializer = 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 static boolean ASTNode.useJastAddNames = false;
public String Program.generateAbstractGrammar() { public String Program.generateAbstractGrammar() {
...@@ -823,13 +825,73 @@ aspect NameResolutionHelper { ...@@ -823,13 +825,73 @@ aspect NameResolutionHelper {
r.generateContextDependentNameResolution(sb); r.generateContextDependentNameResolution(sb);
} }
if (resolverHelper) { if (resolverHelper || ASTNode.jsonPointer || ASTNode.manualReferences) {
for (TypeDecl decl : getTypeDeclList()) { for (TypeDecl decl : getTypeDeclList()) {
decl.generateContextIndependentNameResolution(sb); decl.generateContextIndependentNameResolution(sb);
sb.append("\n"); sb.append("\n");
} }
} }
sb.append("}\n\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 " + getTypeUse().decl() + ".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) { public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) {
...@@ -894,8 +956,12 @@ aspect NameResolutionHelper { ...@@ -894,8 +956,12 @@ aspect NameResolutionHelper {
sb.append(ind(1) + "// context-independent name resolution\n"); 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) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n");
sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n"); sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n");
if (serializer) { if (serializer && !manualReferences) {
if (jsonPointer) {
sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n");
} else {
sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n"); sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n");
}
} else { } else {
sb.append(ind(2) + "// perform context independent name resolution here using the id\n"); 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"); sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n");
...@@ -1002,11 +1068,18 @@ aspect Serializer { ...@@ -1002,11 +1068,18 @@ aspect Serializer {
protected static String ASTNode.jsonTypeKey = "type"; protected static String ASTNode.jsonTypeKey = "type";
protected static String ASTNode.jsonNodeType = "com.fasterxml.jackson.databind.JsonNode"; protected static String ASTNode.jsonNodeType = "com.fasterxml.jackson.databind.JsonNode";
protected static String ASTNode.jsonNodeTypeAccessor = ".get(\"" + jsonTypeKey + "\").asText()"; protected static String ASTNode.jsonNodeTypeAccessor = ".get(\"" + jsonTypeKey + "\").asText()";
public String Program.generateSerializer() { public String Program.generateJacksonSerializer() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
generateFromJson(sb); generateFromJson(sb);
generateToJson(sb); generateToJson(sb);
if (jsonPointer) {
writeJsonPointer(sb);
} else if (manualReferences) {
// TODO
} else {
writeUID(sb); writeUID(sb);
}
return sb.toString(); return sb.toString();
} }
...@@ -1083,9 +1156,11 @@ aspect Serializer { ...@@ -1083,9 +1156,11 @@ aspect Serializer {
sb.append(ind(3) + "} else {\n"); sb.append(ind(3) + "} else {\n");
sb.append(ind(4) + "g.writeObjectFieldStart(fieldName);\n"); sb.append(ind(4) + "g.writeObjectFieldStart(fieldName);\n");
sb.append(ind(3) + "}\n"); sb.append(ind(3) + "}\n");
if (!jsonPointer && !manualReferences) {
sb.append(ind(3) + "g.writeStringField(\"" + jsonTypeKey + "\", \"" + getID() + "\");\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) + "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"); sb.append(ind(3) + "g.writeStringField(\"id\", unique$Id());\n");
}
if (componentsTransitive().size() > 0) { if (componentsTransitive().size() > 0) {
sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n"); sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n");
for (Component child : componentsTransitive()) { for (Component child : componentsTransitive()) {
...@@ -1196,19 +1271,43 @@ aspect Serializer { ...@@ -1196,19 +1271,43 @@ aspect Serializer {
public void OneRelationComponent.serialize(StringBuilder sb, int indent) { public void OneRelationComponent.serialize(StringBuilder sb, int indent) {
if (useJastAddNames){ 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 {
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 { } else {
sb.append(ind(indent) + "g.writeStringField(\""+getID()+"\", " + getID() + "().unique$Id());\n"); sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n");
}
} }
} }
public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) { public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) {
sb.append(ind(indent) + "if (has" + nameCapitalized() + "()) {\n"); sb.append(ind(indent) + "if (has" + nameCapitalized() + "()) {\n");
if (useJastAddNames){ if (useJastAddNames){
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"); sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n");
}
} else {
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 { } else {
sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n");
} }
}
sb.append(ind(indent) + "}\n"); sb.append(ind(indent) + "}\n");
} }
...@@ -1219,7 +1318,14 @@ aspect Serializer { ...@@ -1219,7 +1318,14 @@ aspect Serializer {
} else { } else {
sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : " + getID() + "()) {\n"); sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : " + getID() + "()) {\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 + 1) + "g.writeString(child.unique$Id());\n");
}
sb.append(ind(indent) + "}\n"); sb.append(ind(indent) + "}\n");
sb.append(ind(indent) + "g.writeEndArray();\n"); sb.append(ind(indent) + "g.writeEndArray();\n");
} }
...@@ -1256,10 +1362,12 @@ aspect Serializer { ...@@ -1256,10 +1362,12 @@ aspect Serializer {
sb.append(ind(2) + "element = new " + getID() + "();\n"); sb.append(ind(2) + "element = new " + getID() + "();\n");
} }
if (!jsonPointer && !manualReferences) {
// deserialize id // deserialize id
sb.append(ind(2) + "if (node.has(\"id\")) {\n"); sb.append(ind(2) + "if (node.has(\"id\")) {\n");
sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n");
sb.append(ind(2) + "}\n"); sb.append(ind(2) + "}\n");
}
// deserialize containment children // deserialize containment children
if (componentsTransitive().size() > 0) { if (componentsTransitive().size() > 0) {
...@@ -1361,6 +1469,140 @@ aspect Serializer { ...@@ -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) { public void Program.writeUID(StringBuilder sb) {
sb.append("aspect UID {\n"); sb.append("aspect UID {\n");
sb.append(ind(1) + "class UIDProvider {\n"); sb.append(ind(1) + "class UIDProvider {\n");
......
...@@ -14,7 +14,7 @@ import java.util.List; ...@@ -14,7 +14,7 @@ import java.util.List;
public class Compiler { public class Compiler {
private static final String VERSION = "0.2.3"; private static final String VERSION = "0.2.4";
private ArrayList<Option<?>> options; private ArrayList<Option<?>> options;
private FlagOption optionWriteToFile; private FlagOption optionWriteToFile;
...@@ -89,8 +89,17 @@ public class Compiler { ...@@ -89,8 +89,17 @@ public class Compiler {
ASTNode.serializer = true; ASTNode.serializer = true;
switch (optionSerializer.getValue()) { switch (optionSerializer.getValue()) {
case "jackson": case "jackson":
writeToFile(grammarName + "Serializer.jadd", p.generateSerializer()); writeToFile(grammarName + "Serializer.jadd", p.generateJacksonSerializer());
break; 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 { ...@@ -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")); 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)")); 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.")); 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")); optionQuiet = addOption(new FlagOption("quiet", "do not output anything on stdout"));
} }
......
aspect MyRewrites { aspect MyRewrites {
// context-independent name resolution // context-independent name resolution
refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) { refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) = root().findNamedElement(id);
System.out.println("resolving " + id + " to " + root().findNamedElement(id)); refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) = root().findA(id);
return root().findNamedElement(id); refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) = root().findB(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);
}
} }
aspect Utils { aspect Utils {
inh Root ASTNode.root(); inh Root ASTNode.root();
eq Root.getA(int i).root() = this; eq Root.getChild().root() = this;
eq Root.getB(int i).root() = this;
syn NamedElement Root.findNamedElement(String name) { syn NamedElement Root.findNamedElement(String name) {
for (A a : getAList()) { for (A a : getAList()) {
......
aspect Utils { aspect Utils {
inh Root ASTNode.root(); inh Root ASTNode.root();
eq Root.getA(int i).root() = this; eq Root.getChild().root() = this;
eq Root.getB(int i).root() = this;
syn NamedElement Root.findNamedElement(String name) { syn NamedElement Root.findNamedElement(String name) {
for (A a : getAList()) { for (A a : getAList()) {
......