diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd deleted file mode 100644 index cab17e15766bc3323d2cc8b6c1b8f5c3c754c396..0000000000000000000000000000000000000000 --- a/src/main/jastadd/Backend.jadd +++ /dev/null @@ -1,1744 +0,0 @@ -aspect BackendAbstractGrammar { - - public static String ASTNode.listClass = "ArrayList"; - public static String ASTNode.jastAddListType = "List"; - - public static boolean ASTNode.resolverHelper = false; - public static boolean ASTNode.serializer = false; - public static boolean ASTNode.jsonPointer = false; - public static boolean ASTNode.manualReferences = false; - public static boolean ASTNode.useJastAddNames = false; - - public String Program.generateAbstractGrammar() { - StringBuilder sb = new StringBuilder(); - generateAbstractGrammar(sb); - return sb.toString(); - } - - public void Program.generateAbstractGrammar(StringBuilder sb) { - for (TypeDecl td: getTypeDecls()) { - td.generateAbstractGrammar(sb); - } - } - - public void TypeDecl.generateUnresolvedClass(StringBuilder sb) { - if (getAbstract()) { - sb.append(ind(1) + "abstract "); - } else { - sb.append(ind(1)); - } - sb.append("class " + "Unresolved$" + getID() + " extends " + getID() + " implements Unresolved$Node {\n"); - - sb.append(ind(2) + "private String unresolved$Token;\n"); - sb.append(ind(2) + "public String getUnresolved$Token() {\n"); - sb.append(ind(3) + "return unresolved$Token;\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "void setUnresolved$Token(String token) {\n"); - sb.append(ind(3) + "this.unresolved$Token = token;\n"); - sb.append(ind(2) + "}\n"); - - sb.append(ind(2) + "private boolean unresolved$ResolveOpposite;\n"); - sb.append(ind(2) + "public boolean getUnresolved$ResolveOpposite() {\n"); - sb.append(ind(3) + "return unresolved$ResolveOpposite;\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "void setUnresolved$ResolveOpposite(boolean resolveOpposite) {\n"); - sb.append(ind(3) + "this.unresolved$ResolveOpposite = resolveOpposite;\n"); - sb.append(ind(2) + "}\n"); - - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "Unresolved$Node " + getID() + ".as$Unresolved() {\n"); - sb.append(ind(2) + "return null;\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "Unresolved$Node Unresolved$" + getID() + ".as$Unresolved() {\n"); - sb.append(ind(2) + "return this;\n"); - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "boolean " + getID() + ".is$Unresolved() {\n"); - sb.append(ind(2) + "return false;\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "boolean Unresolved$" + getID() + ".is$Unresolved() {\n"); - sb.append(ind(2) + "return true;\n"); - sb.append(ind(1) + "}\n"); - } - - public void TypeDecl.generateAbstractGrammar(StringBuilder sb) { - if (getAbstract()) { - sb.append("abstract "); - } - sb.append(getID()); - if (hasSuper()) { - sb.append(" : " + getSuper()); - } - - if (getNumComponent() > 0 || relationComponents().size() > 0) { - sb.append(" ::="); - } - for (Component c: getComponents()) { - sb.append(" "); - sb.append(c.generateAbstractGrammar()); - } - for (RelationComponent c: relationComponents()) { - sb.append(" "); - sb.append(c.generateAbstractGrammar()); - } - - sb.append(";\n"); - } - - public String Component.generateAbstractGrammar() { - if (getID().equals(getTypeUse().toString())) { - return getTypeUse().toString(); - } else { - return getID() + ":" + getTypeUse(); - } - } - public String ListComponent.generateAbstractGrammar() { - return super.generateAbstractGrammar() + "*"; - } - public String OptComponent.generateAbstractGrammar() { - return "[" + super.generateAbstractGrammar() + "]"; - } - public String NTAComponent.generateAbstractGrammar() { - return "/" + super.generateAbstractGrammar() + "/"; - } - public String NTAListComponent.generateAbstractGrammar() { - return "/" + super.generateAbstractGrammar() + "*/"; - } - public String NTAOptComponent.generateAbstractGrammar() { - return "/[" + super.generateAbstractGrammar() + "]/"; - } - public String TokenComponent.generateAbstractGrammar() { - return "<" + getID() + ":" + getTypeUse() + ">"; - } - public String NTATokenComponent.generateAbstractGrammar() { - return "/<" + getID() + ":" + getTypeUse() + ">/"; - } - - public String RelationComponent.generateAbstractGrammar() { - return "<" + getImplAttributeName() + ":" + ofTypeDecl() + ">"; - } - public String ManyRelationComponent.generateAbstractGrammar() { - return "<" + getImplAttributeName() + ":" + ASTNode.listClass + "<" + ofTypeDecl() + ">>"; - } - - public String RelationComponent.getImplAttributeName() { - return "_impl_" + getID(); - } - - public String RelationComponent.getImplAttributeField() { - // tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type())); - return "token" + ofTypeDecl() + "__impl_" + getID(); - } - - public String ManyRelationComponent.getImplAttributeField() { - // tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type())); - return "token" + listClass + "_" + ofTypeDecl() + "___impl_" + getID(); - } -} - -aspect BackendAspect { - public String Program.generateAspect() { - StringBuilder sb = new StringBuilder(); - generateAspect(sb); - return sb.toString(); - } - - public void Program.generateAspect(StringBuilder sb) { - sb.append("import java.util.ArrayList;\n"); - sb.append("import java.util.Collections;\n"); - sb.append("import java.time.Instant;\n"); - sb.append("import java.time.Period;\n"); - sb.append("aspect RelAstAPI {\n"); - - for (TypeDecl td: getTypeDecls()) { - if (td.needsConstructor()) { - td.generateConstructor(sb); - } - } - for (Relation r: getRelations()) { - r.generateAPI(sb); - } - - generateLowerBoundCheck(sb); - - sb.append(ind(1) + "public static void ASTNode.assertNotNull(Object obj) {\n"); - sb.append(ind(2) + "if (obj == null) {\n"); - sb.append(ind(3) + "throw new NullPointerException();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - sb.append("}\n"); - } - - public void TypeDecl.generateConstructor(StringBuilder sb) { - sb.append(ind(1) + "public " + getID() + "." + getID() + "("); - int i = 0; - for (Component c: componentsTransitive()) { - sb.append(c.constructorParameter()); - if (++i < componentsTransitive().size()) { - sb.append(", "); - } - } - sb.append(") {\n"); - for (Component c: componentsTransitive()) { - sb.append(ind(2) + c.constructorSetMethod() + "(" + c.getID() + ");\n"); - } - sb.append(ind(1) + "}\n"); - } - public String Component.constructorParameter() { - return getTypeUse() + " " + getID(); - } - public String ListComponent.constructorParameter() { - return ASTNode.jastAddListType + "<" + getTypeUse() + "> " + getID(); - } - public String OptComponent.constructorParameter() { - return "Opt<" + getTypeUse() + "> " + getID(); - } - public String Component.constructorSetMethod() { - return "set" + getID(); - } - public String ListComponent.constructorSetMethod() { - return "set" + getID() + "List"; - } - public String OptComponent.constructorSetMethod() { - return "set" + getID() + "Opt"; - } -} - -aspect BackendAPI { - public void Relation.generateAPI(StringBuilder sb) { - sb.append(ind(1) + "// " + prettyPrint() + "\n"); - getDirection().generateAPI(sb); - sb.append("\n"); - } - public abstract void Direction.generateAPI(StringBuilder sb); - - - inh Relation Direction.relation(); - eq Relation.getChild().relation() = this; - eq Program.getChild().relation() = null; - - public String RelationComponent.nameCapitalized() { - return name().substring(0,1).toUpperCase() + name().substring(1); - } -} - -aspect BackendDirectedAPI { - public void RightDirection.generateAPI(StringBuilder sb) { - relation().getLeft().generateDirectedAPI(sb); - } - public void LeftDirection.generateAPI(StringBuilder sb) { - relation().getRight().generateDirectedAPI(sb); - } - - public abstract void RelationComponent.generateDirectedAPI(StringBuilder sb); - public void OneRelationComponent.generateDirectedAPI(StringBuilder sb) { - generateDirectedZeroOneAPI(sb, false); - } - public void OptionalRelationComponent.generateDirectedAPI(StringBuilder sb) { - generateDirectedZeroOneAPI(sb, true); - - generateExtraOptAPI(sb); - } - public void RelationComponent.generateDirectedZeroOneAPI(StringBuilder sb, boolean optional) { - // Get - generateGetOne(sb); - - // Set - sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl()); - sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - if (!optional) { - sb.append(ind(2) + "assertNotNull(o);\n"); - } - sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); - sb.append(ind(2) + "return this;\n"); - sb.append(ind(1) + "}\n"); - } - - public void ManyRelationComponent.generateDirectedAPI(StringBuilder sb) { - // Get - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); - if (useJastAddNames) { - // getXs - sb.append("get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); - - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); - } else { - sb.append(name() + "() {\n"); - } - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); - // resolve the entire list - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (l != null) {\n"); - sb.append(ind(3) + "boolean changed = false;\n"); - sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); - sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); - sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); - sb.append(ind(5) + "changed = true;\n"); - sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); - sb.append(ind(5) + "l.set(i, resolvedElement);\n"); - sb.append(ind(4) + "}\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(3) + "if (changed) {\n"); - sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); - sb.append(ind(1) + "}\n"); - - // Add - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(o);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(1) + "}\n"); - - // Insert / add at specific position - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(index, o);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(1) + "}\n"); - - // Remove - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); - if (!useJastAddNames) { - sb.append("From"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); - sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - } - - public void RelationComponent.generateGetOne(StringBuilder sb) { - sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + "."); - if (useJastAddNames) { - sb.append("get" + nameCapitalized()); - } else { - sb.append(name()); - } - sb.append("() {\n"); - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (" + getImplAttributeField() + " != null && " + getImplAttributeField() + ".is$Unresolved()) {\n"); - sb.append(ind(3) + "if (" + getImplAttributeField() + ".as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); - sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n"); - sb.append(ind(3) + "} else {\n"); - sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n"); - sb.append(ind(1) + "}\n"); - } - - public void RelationComponent.generateExtraOptAPI(StringBuilder sb) { - // has - sb.append(ind(1) + "public boolean " + getTypeUse().decl()); - sb.append(".has" + nameCapitalized() + "() {\n"); - sb.append(ind(2) + "return "); - if (useJastAddNames) { - sb.append("get" + nameCapitalized()); - } else { - sb.append(name()); - } - sb.append("() != null;\n"); - sb.append(ind(1) + "}\n"); - - // clear - sb.append(ind(1) + "public void " + getTypeUse().decl()); - sb.append(".clear" + nameCapitalized() + "() {\n"); - sb.append(ind(2) + "set" + nameCapitalized() + "(null);\n"); - sb.append(ind(1) + "}\n"); - } -} - -aspect BackendBidirectionalAPI { - public void Bidirectional.generateAPI(StringBuilder sb) { - RelationComponent l = relation().getLeft(); - RelationComponent r = relation().getRight(); - - if (l.multiplicityOne()) { - if (r.multiplicityOne()) { - l.generateBiOneOne(sb, false); - r.generateBiOneOne(sb, false); - } else if (r.multiplicityOpt()) { - l.generateBiOneOne(sb, false); - r.generateBiOneOne(sb, true); - } else if (r.multiplicityMany()) { - l.generateBiOneMany(sb, false); - r.generateBiManyOne(sb, l); - } - } else if (l.multiplicityOpt()) { - if (r.multiplicityOne()) { - l.generateBiOneOne(sb, true); - r.generateBiOneOne(sb, false); - } else if (r.multiplicityOpt()) { - l.generateBiOneOne(sb, true); - r.generateBiOneOne(sb, true); - } else if (r.multiplicityMany()) { - l.generateBiOneMany(sb, true); - r.generateBiManyOne(sb, l); - } - } else if (l.multiplicityMany()) { - if (r.multiplicityOne()) { - l.generateBiManyOne(sb, r); - r.generateBiOneMany(sb, false); - } else if (r.multiplicityOpt()) { - l.generateBiManyOne(sb, r); - r.generateBiOneMany(sb, true); - } else if (r.multiplicityMany()) { - l.generateBiManyMany(sb, r); - r.generateBiManyMany(sb, l); - } - } - } - - public void RelationComponent.generateBiOneOne(StringBuilder sb, boolean isOpt) { - // Get - generateGetOne(sb); - - // Set - sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl()); - sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - if (!isOpt) { - sb.append(ind(2) + "assertNotNull(o);\n"); - } - // unset the old opposite - sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n"); - sb.append(ind(3) + "" + getImplAttributeField() + ".set" + otherSide().getImplAttributeName() + "(null);\n"); - sb.append(ind(2) + "}\n"); - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (o != null && !o.is$Unresolved() && o." + otherSide().getImplAttributeField() + " != null) {\n"); - } else { - sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); - } - sb.append(ind(3) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(null);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (o == null || !o.is$Unresolved()) {\n"); - if (isOpt) { - sb.append(ind(3) + "if (o != null) {\n"); - sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - sb.append(ind(3) + "}\n"); - } else { - sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - } - sb.append(ind(2) + "}\n"); - } else { - if (isOpt) { - sb.append(ind(2) + "if (o != null) {\n"); - sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - sb.append(ind(2) + "}\n"); - } else { - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - } - } - - sb.append(ind(2) + "return this;\n"); - sb.append(ind(1) + "}\n"); - - if (isOpt) { - generateExtraOptAPI(sb); - } - } - - public void RelationComponent.generateBiManyMany(StringBuilder sb, RelationComponent opposite) { - // Get - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); - if (useJastAddNames) { - // getXs - sb.append("get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); - - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); - } else { - sb.append(name() + "() {\n"); - } - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); - // resolve the entire list - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (l != null) {\n"); - sb.append(ind(3) + "boolean changed = false;\n"); - sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); - sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); - sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); - sb.append(ind(5) + "changed = true;\n"); - sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); - sb.append(ind(5) + "if (resolvedElement != null && element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); - sb.append(ind(6) + ASTNode.listClass + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + opposite.getImplAttributeField() + ";\n"); - sb.append(ind(6) + "if (otherList == null) {\n"); - sb.append(ind(7) + "otherList = new " + listClass + "<>();\n"); - sb.append(ind(6) + "}\n"); - sb.append(ind(6) + "otherList.add(this);\n"); - sb.append(ind(6) + "resolvedElement.set" + opposite.getImplAttributeName() + "(otherList);\n"); - sb.append(ind(5) + "}\n"); - sb.append(ind(5) + "l.set(i, resolvedElement);\n"); - sb.append(ind(4) + "}\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(3) + "if (changed) {\n"); - sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); - sb.append(ind(1) + "}\n"); - - // Add - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list2 == null) {\n"); - sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(o);\n"); - sb.append(ind(2) + "list2.add(this);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); - sb.append(ind(1) + "}\n"); - - // Insert / add at specific position - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." - + otherSide().getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list2 == null) {\n"); - sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(index, o);\n"); - sb.append(ind(2) + "list2.add(this);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); - sb.append(ind(1) + "}\n"); - - // Remove - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); - if (!useJastAddNames) { - sb.append("From"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); - sb.append(ind(3) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." - + otherSide().getImplAttributeField() + ";\n"); - sb.append(ind(3) + "if (list2 != null) list2.remove(this);\n"); - sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - } - - - public void RelationComponent.generateBiManyOne(StringBuilder sb, RelationComponent opposite) { - // Get - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); - if (useJastAddNames) { - // getXs - sb.append("get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); - - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); - } else { - sb.append(name() + "() {\n"); - } - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); - // resolve the entire list - if (resolverHelper | serializer) { - sb.append(ind(2) + "if (l != null) {\n"); - sb.append(ind(3) + "boolean changed = false;\n"); - sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); - sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); - sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); - sb.append(ind(5) + "changed = true;\n"); - sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); - sb.append(ind(5) + "if (element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); - sb.append(ind(6) + getTypeUse().decl() + " oldTarget = resolvedElement." + opposite.getImplAttributeField() + ";\n"); - sb.append(ind(6) + "if (oldTarget != null && oldTarget != this) {\n"); - sb.append(ind(7) + "oldTarget." + getImplAttributeField() + ".remove(resolvedElement);\n"); - sb.append(ind(6) + "}\n"); - sb.append(ind(6) + "if (oldTarget == this) {\n"); - sb.append(ind(7) + "l.remove(i);\n"); - sb.append(ind(7) + "i--;\n"); - sb.append(ind(6) + "} else {\n"); - sb.append(ind(7) + "resolvedElement.set" + opposite.getImplAttributeName() + "(this);\n"); - sb.append(ind(7) + "l.set(i, resolvedElement);\n"); - sb.append(ind(6) + "}\n"); - sb.append(ind(5) + "} else {\n"); - sb.append(ind(6) + "l.set(i, resolvedElement);\n"); - sb.append(ind(5) + "}\n"); - sb.append(ind(4) + "}\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(3) + "if (changed) {\n"); - sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); - sb.append(ind(1) + "}\n"); - - // Add - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); - sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." - + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n"); - sb.append(ind(3) + "if (list2.remove(o))\n"); - sb.append(ind(4) + "o." + otherSide().getImplAttributeField() - + ".set" + getImplAttributeName() + "(list2);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(o);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - sb.append(ind(1) + "}\n"); - - // Insert / add at specific position - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); - if (!useJastAddNames) { - sb.append("To"); - } - sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); - sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n"); - sb.append(ind(3) + "if (list2.remove(o))\n"); - sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(list2);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list == null) {\n"); - sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "list.add(index, o);\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); - sb.append(ind(1) + "}\n"); - - // Remove - sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); - if (!useJastAddNames) { - sb.append("From"); - } - sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); - sb.append(ind(2) + "assertNotNull(o);\n"); - sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); - sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); - sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); - sb.append(ind(3) + "if (o." + otherSide().getImplAttributeField() + " == this) {\n"); - sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(null);\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - } - - public void RelationComponent.generateBiOneMany(StringBuilder sb, boolean isOpt) { - // Get - generateGetOne(sb); - - // Set - sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized() - + "(" + ofTypeDecl() + " o) {\n"); - if (!isOpt) { - sb.append(ind(2) + "assertNotNull(o);\n"); - } - sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n"); - sb.append(ind(3) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list2 = " + getImplAttributeField() - + "." + otherSide().getImplAttributeField() + ";\n"); - sb.append(ind(3) + "list2.remove(this);\n"); - sb.append(ind(3) + getImplAttributeField() + "." + "set" - + otherSide().getImplAttributeName() + "(list2);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); - - int ind = isOpt ? 3 : 2; - if (isOpt) { - sb.append(ind(2) + "if (o != null) {\n"); - } - sb.append(ind(ind) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list = o." - + otherSide().getImplAttributeField() + ";\n"); - sb.append(ind(ind) + "if (list == null) {\n"); - sb.append(ind(ind+1) + "list = new " + ASTNode.listClass + "<>();\n"); - sb.append(ind(ind) + "}\n"); - sb.append(ind(ind) + "list.add(this);\n"); - sb.append(ind(ind) + "o.set" + otherSide().getImplAttributeName() + "(list);\n"); - if (isOpt) { - sb.append(ind(2) + "}\n"); - } - sb.append(ind(2) + "return this;\n"); - sb.append(ind(1) + "}\n"); - - if (isOpt) { - generateExtraOptAPI(sb); - } - } -} - -aspect LowerBoundCheck { - public void Program.generateLowerBoundCheck(StringBuilder sb) { - sb.append(ind(1) + "public boolean ASTNode.violatesLowerBounds() {\n"); - sb.append(ind(2) + "return !getLowerBoundsViolations().isEmpty();\n"); - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "public java.util.List<Pair<ASTNode, String>> " - + "ASTNode.getLowerBoundsViolations() {\n"); - sb.append(ind(2) + "ArrayList<Pair<ASTNode, String>> list = new ArrayList<>();\n"); - sb.append(ind(2) + "computeLowerBoundsViolations(list);\n"); - sb.append(ind(2) + "return list;\n"); - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "public void ASTNode.computeLowerBoundsViolations(" - + "java.util.List<Pair<ASTNode, String>> list) {\n"); - sb.append(ind(2) + "for (int i = 0; i < getNumChildNoTransform(); i++) {\n"); - sb.append(ind(3) + "getChildNoTransform(i).computeLowerBoundsViolations(list);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - - for (TypeDecl td: getTypeDecls()) { - td.generateLowerBoundCheck(sb); - } - - generatePairClass(sb); - } - - public void TypeDecl.generateLowerBoundCheck(StringBuilder sb) { - if (!oneRelationComponents().isEmpty()) { - sb.append(ind(1) + "public void " + getID() + ".computeLowerBoundsViolations(" + - "java.util.List<Pair<ASTNode, String>> list) {\n"); - for (OneRelationComponent o: oneRelationComponents()) { - o.generateLowerBoundCheck(sb); - } - sb.append(ind(2) + "super.computeLowerBoundsViolations(list);\n"); - sb.append(ind(1) + "}\n"); - } - } - - public void OneRelationComponent.generateLowerBoundCheck(StringBuilder sb) { - sb.append(ind(2) + "if ("); - if (useJastAddNames) { - sb.append("get" + nameCapitalized()); - } else { - sb.append(name()); - } - sb.append("() == null) {\n"); - sb.append(ind(3) + "list.add(new Pair<>(this, \"" + name() + "\"));\n"); - sb.append(ind(2) + "}\n"); - } - - - public void Program.generatePairClass(StringBuilder sb) { - sb.append(ind(1) + "public class Pair<T1, T2> {\n"); - sb.append(ind(2) + "public final T1 _1;\n"); - sb.append(ind(2) + "public final T2 _2;\n"); - // Constructor - sb.append(ind(2) + "public Pair(T1 _1, T2 _2) {\n"); - sb.append(ind(3) + "ASTNode.assertNotNull(_1);\n"); - sb.append(ind(3) + "ASTNode.assertNotNull(_2);\n"); - sb.append(ind(3) + "this._1 = _1;\n"); - sb.append(ind(3) + "this._2 = _2;\n"); - sb.append(ind(2) + "}\n"); - // equals - sb.append(ind(2) + "public boolean equals(Object other) {\n"); - sb.append(ind(3) + "if (other instanceof Pair) {\n"); - sb.append(ind(4) + "Pair<?,?> p = (Pair<?,?>) other;\n"); - sb.append(ind(4) + "return _1.equals(p._1) && _2.equals(p._2);\n"); - sb.append(ind(3) + "} else {\n"); - sb.append(ind(4) + "return false;\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - // hashCode - sb.append(ind(2) + "public int hashCode() {\n"); - sb.append(ind(3) + "return 31*_1.hashCode() + _2.hashCode();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - } -} - -aspect NameResolutionHelper { - - public String Program.generateRewriteToSuperTypeStub() { - StringBuilder sb = new StringBuilder(); - generateRewriteToSuperTypeStub(sb); - return sb.toString(); - } - - 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()) { - r.generateContextDependentNameResolution(sb); - } - - if (resolverHelper || ASTNode.jsonPointer || ASTNode.manualReferences) { - for (TypeDecl decl : getTypeDeclList()) { - decl.generateContextIndependentNameResolution(sb); - sb.append("\n"); - } - } - sb.append("}\n\n"); - - if (ASTNode.manualReferences) { - sb.append("aspect RefCreatorStubs {\n\n"); - - for (Relation r: getRelations()) { - r.generateContextDependentRefCreation(sb); - } - - generateGenericRefCreation(sb); - sb.append("\n"); - - for (TypeDecl decl : getTypeDeclList()) { - decl.generateContextIndependentRefCreation(sb); - sb.append("\n"); - } - - sb.append("}\n\n"); - } - } - - public void Program.generateGenericRefCreation(StringBuilder sb) { - sb.append(ind(1) + "// generic reference creation\n"); - sb.append(ind(1) + "syn String ASTNode.createReference();\n"); - sb.append(ind(1) + "eq ASTNode.createReference() {\n"); - sb.append(ind(2) + "throw new RuntimeException(\"Generic reference creation not implemented.\");\n"); - sb.append(ind(1) + "}\n"); - } - - public void Relation.generateContextDependentRefCreation(StringBuilder sb) { - sb.append(ind(1) + "// " + prettyPrint() + "\n"); - getDirection().generateContextDependentRefCreation(sb); - sb.append("\n"); - } - - public abstract void Direction.generateContextDependentRefCreation(StringBuilder sb); - public void RightDirection.generateContextDependentRefCreation(StringBuilder sb) { - relation().getLeft().generateContextDependentRefCreation(sb); - } - public void LeftDirection.generateContextDependentRefCreation(StringBuilder sb) { - relation().getRight().generateContextDependentRefCreation(sb); - } - public void Bidirectional.generateContextDependentRefCreation(StringBuilder sb) { - relation().getLeft().generateContextDependentRefCreation(sb); - relation().getRight().generateContextDependentRefCreation(sb); - } - - public void RelationComponent.generateContextDependentRefCreation(StringBuilder sb) { - sb.append(ind(1) + "// context-dependent reference creation\n"); - sb.append(ind(1) + "syn String " + 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) { - - sb.append("aspect ReferenceCreation {\n\n"); - - for (TypeDecl decl : getTypeDeclList()) { - decl.createReferenceCreator(sb); - } - - sb.append("}\n\n"); - - sb.append("aspect ResolverTrigger {\n\n"); - - resolveAll(sb); - - for (TypeDecl decl : getTypeDeclList()) { - decl.resolveAll(sb); - } - - sb.append("}\n\n"); - - sb.append("aspect RefResolverHelpers {\n\n"); - - sb.append(ind(1) + "interface Unresolved$Node {\n"); - sb.append(ind(2) + "String getUnresolved$Token();\n"); - sb.append(ind(2) + "boolean getUnresolved$ResolveOpposite();\n"); - sb.append(ind(1) + "}\n\n"); - - for (TypeDecl td: getTypeDecls()) { - if (td.needUnresolvedClass()) { - td.generateUnresolvedClass(sb); - } - } - - sb.append("\n}\n"); - } - - public void TypeDecl.createReferenceCreator(StringBuilder sb) { - - TypeDecl instantiableSubType = instantiableSubType(); - if (instantiableSubType == null) { - throw new RuntimeException("unable to find instantiable subtype for " + getID()); - } - - sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRef(String ref) {\n"); - sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n"); - sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n"); - sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(true);\n"); - sb.append(ind(2) + "return unresolvedNode;\n"); - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRefDirection(String ref) {\n"); - sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n"); - sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n"); - sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(false);\n"); - sb.append(ind(2) + "return unresolvedNode;\n"); - sb.append(ind(1) + "}\n"); - } - - public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) { - sb.append(ind(1) + "// context-independent name resolution\n"); - sb.append(ind(1) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n"); - sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n"); - if (serializer && !manualReferences) { - if (jsonPointer) { - sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n"); - } else { - sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n"); - } - } else { - sb.append(ind(2) + "// perform context independent name resolution here using the id\n"); - sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n"); - } - sb.append(ind(1) + "}\n"); - } - - public void Relation.generateContextDependentNameResolution(StringBuilder sb) { - sb.append(ind(1) + "// " + prettyPrint() + "\n"); - getDirection().generateContextDependentNameResolution(sb); - sb.append("\n"); - } - - public abstract void Direction.generateContextDependentNameResolution(StringBuilder sb); - public void RightDirection.generateContextDependentNameResolution(StringBuilder sb) { - relation().getLeft().generateContextDependentNameResolution(sb); - } - public void LeftDirection.generateContextDependentNameResolution(StringBuilder sb) { - relation().getRight().generateContextDependentNameResolution(sb); - } - public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) { - relation().getLeft().generateContextDependentNameResolution(sb); - relation().getRight().generateContextDependentNameResolution(sb); - } - - public abstract void RelationComponent.generateContextDependentNameResolution(StringBuilder sb); - public void OneRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { - generateDirectedContextDependentNameResolution(sb); - } - public void OptionalRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { - // optional relations are resolved in the same way as mandatory relations - // TODO maybe, there should be a check if the id to be solved is empty or null - generateDirectedContextDependentNameResolution(sb); - } - public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { - - if (serializer && !resolverHelper) { - sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n"); - sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n"); - sb.append(ind(1) + "}\n"); - } else { - sb.append(ind(1) + "// context-dependent name resolution\n"); - sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position);\n"); - sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n"); - sb.append(ind(2) + "// default to context-independent name resolution\n"); - sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n"); - sb.append(ind(1) + "}\n"); - } - } - - public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) { - if (serializer && !resolverHelper) { - sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n"); - sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n"); - sb.append(ind(1) + "}\n"); - } else { - sb.append(ind(1) + "// context-dependent name resolution\n"); - sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id);\n"); - sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n"); - sb.append(ind(2) + "// default to context-independent name resolution\n"); - sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n"); - sb.append(ind(1) + "}\n"); - } - } - - public void Program.resolveAll(StringBuilder sb) { - sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n"); - sb.append(ind(1) + "public void ASTNode.resolveAll() {\n"); - sb.append(ind(1) + "}\n\n"); - - sb.append(ind(1) + "// enforce resolving in the entire subtree\n"); - sb.append(ind(1) + "public void ASTNode.treeResolveAll() {\n"); - sb.append(ind(2) + "if (children != null) {\n"); - sb.append(ind(3) + "for (int i = 0; i < numChildren; ++i) {\n"); - sb.append(ind(4) + "ASTNode child = children[i];\n"); - sb.append(ind(4) + "if (child != null) {\n"); - sb.append(ind(5) + "child.treeResolveAll();\n"); - sb.append(ind(4) + "}\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "resolveAll();\n"); - sb.append(ind(1) + "}\n"); - } - - public void TypeDecl.resolveAll(StringBuilder sb) { - sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n"); - sb.append(ind(1) + "public void " + getID() + ".resolveAll() {\n"); - for (RelationComponent relationComponent : relationComponents()) { - sb.append(ind(2)); - if (useJastAddNames) { - sb.append("get" + relationComponent.nameCapitalized()); - } else { - sb.append(relationComponent.name()); - } - sb.append(relationComponent.isMany() && useJastAddNames ? "List" : "").append("();\n"); - } - sb.append(ind(2) + "super.resolveAll();\n"); - sb.append(ind(1) + "}\n"); - } -} - -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.generateJacksonSerializer() { - StringBuilder sb = new StringBuilder(); - generateFromJson(sb); - generateToJson(sb); - if (jsonPointer) { - writeJsonPointer(sb); - } else if (manualReferences) { - // TODO - } else { - 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) + "serialize(file, false);\n"); - sb.append(ind(1) + "}\n"); - - sb.append(ind(1) + "public void ASTNode.serialize(java.io.File file, boolean humanReadable) 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) + "if (humanReadable) {\n"); - sb.append(ind(4) + "generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter());\n"); - sb.append(ind(3) + "}\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()) { - 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()) { - 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"); - if (!jsonPointer && !manualReferences) { - sb.append(ind(3) + "g.writeStringField(\"" + jsonTypeKey + "\", \"" + getID() + "\");\n"); - sb.append(ind(3) + "if (unique$Id() == null) throw new SerializationException(\"The unique identifier of " + getID() + " is missing.\");\n"); - sb.append(ind(3) + "g.writeStringField(\"id\", unique$Id());\n"); - } - if (componentsTransitive().size() > 0) { - sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n"); - for (Component child : componentsTransitive()) { - if (child.isNullable()) { - String componentAccessor = child.getID(); - if (child.isList()) { - componentAccessor += "List"; - } else if (child.isOpt()) { - componentAccessor += "Opt"; - } - sb.append(ind(3) + "if (get" + componentAccessor + "() == null) throw new SerializationException(\"The component " + child.getID() + " of " + getID() + " is missing.\");\n"); - } - child.serialize(sb, 3); - } - sb.append(ind(3) + "g.writeEndObject(); // children\n"); - } - if (relationComponentsTransitive().size() > 0) { - sb.append(ind(3) + "g.writeObjectFieldStart(\"relations\");\n"); - for (RelationComponent relation : relationComponentsTransitive()) { - 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 "Instant": - sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().toString());\n"); - break; - case "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 NTAListComponent.serialize(StringBuilder sb, int indent) { - // do not serialize NTA - } - - public void NTAOptComponent.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) { - if (useJastAddNames){ - 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 { - sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); - } - } - } - - public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) { - sb.append(ind(indent) + "if (has" + nameCapitalized() + "()) {\n"); - if (useJastAddNames){ - if (jsonPointer) { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().jsonPointer());\n"); - } else if (manualReferences) { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().createReference());\n"); - } else { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n"); - } - } else { - if (jsonPointer) { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().jsonPointer());\n"); - } else if (manualReferences) { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + "createRefTo" + getID() + "(" + getID() + "()));\n"); - } else { - sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); - } - } - sb.append(ind(indent) + "}\n"); - } - - public void ManyRelationComponent.serialize(StringBuilder sb, int indent) { - sb.append(ind(indent) + "g.writeArrayFieldStart(\"" + getID() + "\");\n"); - if (useJastAddNames) { - sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : get" + getID() + "List()) {\n"); - } else { - 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) + "}\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) + getID() + " result = deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));\n"); - sb.append(ind(3) + "parser.close();\n"); - sb.append(ind(3) + "return result;\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"); - } - - if (!jsonPointer && !manualReferences) { - // deserialize id - sb.append(ind(2) + "if (node.has(\"id\")) {\n"); - sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); - sb.append(ind(2) + "}\n"); - } - - // deserialize containment children - if (componentsTransitive().size() > 0) { - 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 "Instant": - sb.append(ind(indent) + "element.set" + getID() + "(Instant.parse(children.get(\"" + getID() + "\").asText()));\n"); - break; - case "Period": - sb.append(ind(indent) + "element.set" + getID() + "(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 + ".class, children.get(\"" + getID() + "\").asText()));\n"); - - // sb.append("throw new DeserializationException(\"Unable to deserialize child node of type \"" + getTypeUse() + "\"\")") - } - } - - public void Component.writeJsonPointer(StringBuilder sb) { - // do nothing for other components - } - - public void NormalComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); - sb.append(ind(1) + "}\n"); - } - - public void ListComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); - sb.append(ind(1) + "}\n"); - } - - public void OptComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); - sb.append(ind(1) + "}\n"); - } - - public void NTAComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); - sb.append(ind(1) + "}\n"); - } - - public void NTAListComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); - sb.append(ind(1) + "}\n"); - } - - public void NTAOptComponent.writeJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); - sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); - sb.append(ind(1) + "}\n"); - } - - public void Component.resolveJsonPointer(StringBuilder sb) { - // do nothing for other components - } - - public void NormalComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); - } - - public void ListComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); - } - - public void OptComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); - } - - public void NTAComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); - } - - public void NTAListComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); - } - - public void NTAOptComponent.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(4) + "case \"" + getID() + "\":\n"); - sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); - } - - public void TypeDecl.resolveJsonPointer(StringBuilder sb) { - sb.append(ind(1) + "eq " + getID() + ".resolveJsonPointer(String[] pointer, int index) {\n"); - sb.append(ind(2) + "if (pointer.length == 0 || pointer.length == index) {\n"); - sb.append(ind(3) + "return this;\n"); - sb.append(ind(2) + "} else if (pointer.length == index + 1) {\n"); - sb.append(ind(3) + "throw new RuntimeException(\"there is only one child called \" + pointer[index]);\n"); - sb.append(ind(2) + "} else {\n"); - sb.append(ind(3) + "switch (pointer[index + 1]) {\n"); - - for (Component c: getComponentList()) { - c.resolveJsonPointer(sb); - } - - sb.append(ind(4) + "default:\n"); - sb.append(ind(5) + "return super.resolveJsonPointer(pointer, index);\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - } - - public void Program.writeJsonPointer(StringBuilder sb) { - sb.append("aspect JsonPointer {\n"); - - sb.append(ind(1) + "syn String ASTNode.jsonPointer() {\n"); - sb.append(ind(2) + "if (getParent() == null) {\n"); - sb.append(ind(3) + "return \"\";\n"); - sb.append(ind(2) + "} else {\n"); - sb.append(ind(3) + "return jsonPointerInh();\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "inh String ASTNode.jsonPointerInh();\n"); - - // define json pointer for each component - for (TypeDecl td: getTypeDeclList()) { - for (Component c: td.getComponentList()) { - c.writeJsonPointer(sb); - } - } - - sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String pointer) = root().resolveJsonPointer(pointer.split(\"/\"), 1);\n"); - sb.append(ind(1) + "ASTNode ASTNode.root() {\n"); - sb.append(ind(2) + "if (getParent() == null) return this;\n"); - sb.append(ind(2) + "else return getParent().root();\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String[] pointer, int index) {\n"); - sb.append(ind(2) + "if (index < pointer.length) {\n"); - sb.append(ind(3) + "throw new RuntimeException(\"found wrong child \" + pointer[index + 1] + \" in class \" + this.getClass().getSimpleName());\n"); - sb.append(ind(2) + "} else {\n"); - sb.append(ind(3) + "throw new RuntimeException(\"Cannot resolve JSON pointer for class \" + this.getClass().getSimpleName());\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - - // resolve JSON pointers in each nonterminal - for (TypeDecl td: getTypeDeclList()) { - td.resolveJsonPointer(sb); - } - - sb.append("}\n"); - } - - public void Program.writeUID(StringBuilder sb) { - sb.append("aspect UID {\n"); - sb.append(ind(1) + "class UIDProvider {\n"); - 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.unique$Id = null;\n"); - sb.append("\n"); - sb.append(ind(1) + "protected String ASTNode.unique$Id() {\n"); - sb.append(ind(2) + "String customUID = customID();\n"); - sb.append(ind(2) + "if (customUID == null) {\n"); - sb.append(ind(3) + "if (unique$Id == null) {\n"); - sb.append(ind(4) + "unique$Id = UIDProvider.getUID();\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(3) + "return unique$Id;\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.customID() {\n"); - sb.append(ind(1) + " return null;\n"); - sb.append(ind(1) + "}\n"); - sb.append("\n"); - sb.append(ind(1) + "ASTNode ASTNode.globallyResolveASTNodeByUID(String uid) {\n"); - sb.append(ind(2) + "if (getParent() == null) {\n"); - sb.append(ind(3) + "return uid$Map().get(uid).get();\n"); - sb.append(ind(2) + "} else {\n"); - sb.append(ind(3) + "return getParent().globallyResolveASTNodeByUID(uid);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(1) + "}\n"); - sb.append("\n"); - sb.append(ind(1) + "java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map;\n"); - sb.append("\n"); - sb.append(ind(1) + "java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map() {\n"); - sb.append(ind(2) + "if (uid$Map == null) {\n"); - sb.append(ind(3) + "uid$Map = uid$Map(new java.util.HashMap());\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "return uid$Map;\n"); - sb.append(ind(1) + "}\n"); - sb.append(ind(1) + "protected java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map(java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> map) {\n"); - sb.append(ind(2) + "if (!(this instanceof " + jastAddListType + " || this instanceof Opt)) {\n"); - sb.append(ind(3) + "if (map.keySet().contains(unique$Id())) {\n"); - sb.append(ind(4) + "throw new RuntimeException(new SerializationException(\"UID \" + this.unique$Id() + \" is assigned to both \" + this.getClass().getSimpleName() + \":\" + this.hashCode() + \" and \" + map.get(unique$Id()).getClass().getSimpleName() + \":\" + map.get(unique$Id()).hashCode()));\n"); - sb.append(ind(3) + "} else {\n"); - sb.append(ind(4) + "map.put(this.unique$Id, new java.lang.ref.WeakReference(this));\n"); - sb.append(ind(3) + "}\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "for (ASTNode child : astChildren()) {\n"); - sb.append(ind(3) + "child.uid$Map(map);\n"); - sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "return map;\n"); - sb.append(ind(1) + "}\n"); - sb.append("}\n"); - } - - public void NTAComponent.deserialize(StringBuilder sb, int indent) { - // do not serialize NTA - } - - public void NTAListComponent.deserialize(StringBuilder sb, int indent) { - // do not serialize NTA - } - - public void NTAOptComponent.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" + nameCapitalized() + "(" + 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" + nameCapitalized() + "(" + 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" + (useJastAddNames?"":"To") + nameCapitalized() + "(" + ofTypeDecl().getID() + ".createRefDirection(child.asText()));\n"); - sb.append(ind(indent) + "}\n"); - } -} - -aspect PrettyPrint { - public String Relation.prettyPrint() { - return "rel " - + getLeft().prettyPrint() + " " - + getDirection().prettyPrint() + " " - + getRight().prettyPrint(); - } - public String RelationComponent.prettyPrint() { - if (getID().isEmpty()) { - return getTypeUse().toString(); - } else { - return getTypeUse() + "." + getID(); - } - } - public String OptionalRelationComponent.prettyPrint() { - return super.prettyPrint() + "?"; - } - public String ManyRelationComponent.prettyPrint() { - return super.prettyPrint() + "*"; - } - abstract public String Direction.prettyPrint(); - public String RightDirection.prettyPrint() { - return "->"; - } - public String LeftDirection.prettyPrint() { - return "<-"; - } - public String Bidirectional.prettyPrint() { - return "<->"; - } - -} - -aspect Utils { - public String ASTNode.ind(int n) { - String s = ""; - for (int i = 0; i < n; i++) { - s += " "; - } - return s; - } -} diff --git a/src/main/jastadd/backend/API.jadd b/src/main/jastadd/backend/API.jadd new file mode 100644 index 0000000000000000000000000000000000000000..481bc2dbbea2bb55c7d0fd6f0bf350e739fba416 --- /dev/null +++ b/src/main/jastadd/backend/API.jadd @@ -0,0 +1,17 @@ +aspect BackendAPI { + public void Relation.generateAPI(StringBuilder sb) { + sb.append(ind(1) + "// " + prettyPrint() + "\n"); + getDirection().generateAPI(sb); + sb.append("\n"); + } + public abstract void Direction.generateAPI(StringBuilder sb); + + + inh Relation Direction.relation(); + eq Relation.getChild().relation() = this; + eq Program.getChild().relation() = null; + + public String RelationComponent.nameCapitalized() { + return name().substring(0,1).toUpperCase() + name().substring(1); + } +} diff --git a/src/main/jastadd/backend/AbstractGrammar.jadd b/src/main/jastadd/backend/AbstractGrammar.jadd new file mode 100644 index 0000000000000000000000000000000000000000..a9728d231ef25162218719dc08a47853003abbdb --- /dev/null +++ b/src/main/jastadd/backend/AbstractGrammar.jadd @@ -0,0 +1,138 @@ +aspect BackendAbstractGrammar { + + public static String ASTNode.listClass = "ArrayList"; + public static String ASTNode.jastAddListType = "List"; + + public static boolean ASTNode.resolverHelper = false; + public static boolean ASTNode.serializer = false; + public static boolean ASTNode.jsonPointer = false; + public static boolean ASTNode.manualReferences = false; + public static boolean ASTNode.useJastAddNames = false; + + public String Program.generateAbstractGrammar() { + StringBuilder sb = new StringBuilder(); + generateAbstractGrammar(sb); + return sb.toString(); + } + + public void Program.generateAbstractGrammar(StringBuilder sb) { + for (TypeDecl td: getTypeDecls()) { + td.generateAbstractGrammar(sb); + } + } + + public void TypeDecl.generateUnresolvedClass(StringBuilder sb) { + if (getAbstract()) { + sb.append(ind(1) + "abstract "); + } else { + sb.append(ind(1)); + } + sb.append("class " + "Unresolved$" + getID() + " extends " + getID() + " implements Unresolved$Node {\n"); + + sb.append(ind(2) + "private String unresolved$Token;\n"); + sb.append(ind(2) + "public String getUnresolved$Token() {\n"); + sb.append(ind(3) + "return unresolved$Token;\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "void setUnresolved$Token(String token) {\n"); + sb.append(ind(3) + "this.unresolved$Token = token;\n"); + sb.append(ind(2) + "}\n"); + + sb.append(ind(2) + "private boolean unresolved$ResolveOpposite;\n"); + sb.append(ind(2) + "public boolean getUnresolved$ResolveOpposite() {\n"); + sb.append(ind(3) + "return unresolved$ResolveOpposite;\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "void setUnresolved$ResolveOpposite(boolean resolveOpposite) {\n"); + sb.append(ind(3) + "this.unresolved$ResolveOpposite = resolveOpposite;\n"); + sb.append(ind(2) + "}\n"); + + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "Unresolved$Node " + getID() + ".as$Unresolved() {\n"); + sb.append(ind(2) + "return null;\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "Unresolved$Node Unresolved$" + getID() + ".as$Unresolved() {\n"); + sb.append(ind(2) + "return this;\n"); + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "boolean " + getID() + ".is$Unresolved() {\n"); + sb.append(ind(2) + "return false;\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "boolean Unresolved$" + getID() + ".is$Unresolved() {\n"); + sb.append(ind(2) + "return true;\n"); + sb.append(ind(1) + "}\n"); + } + + public void TypeDecl.generateAbstractGrammar(StringBuilder sb) { + if (getAbstract()) { + sb.append("abstract "); + } + sb.append(getID()); + if (hasSuper()) { + sb.append(" : " + getSuper()); + } + + if (getNumComponent() > 0 || relationComponents().size() > 0) { + sb.append(" ::="); + } + for (Component c: getComponents()) { + sb.append(" "); + sb.append(c.generateAbstractGrammar()); + } + for (RelationComponent c: relationComponents()) { + sb.append(" "); + sb.append(c.generateAbstractGrammar()); + } + + sb.append(";\n"); + } + + public String Component.generateAbstractGrammar() { + if (getID().equals(getTypeUse().toString())) { + return getTypeUse().toString(); + } else { + return getID() + ":" + getTypeUse(); + } + } + public String ListComponent.generateAbstractGrammar() { + return super.generateAbstractGrammar() + "*"; + } + public String OptComponent.generateAbstractGrammar() { + return "[" + super.generateAbstractGrammar() + "]"; + } + public String NTAComponent.generateAbstractGrammar() { + return "/" + super.generateAbstractGrammar() + "/"; + } + public String NTAListComponent.generateAbstractGrammar() { + return "/" + super.generateAbstractGrammar() + "*/"; + } + public String NTAOptComponent.generateAbstractGrammar() { + return "/[" + super.generateAbstractGrammar() + "]/"; + } + public String TokenComponent.generateAbstractGrammar() { + return "<" + getID() + ":" + getTypeUse() + ">"; + } + public String NTATokenComponent.generateAbstractGrammar() { + return "/<" + getID() + ":" + getTypeUse() + ">/"; + } + + public String RelationComponent.generateAbstractGrammar() { + return "<" + getImplAttributeName() + ":" + ofTypeDecl() + ">"; + } + public String ManyRelationComponent.generateAbstractGrammar() { + return "<" + getImplAttributeName() + ":" + ASTNode.listClass + "<" + ofTypeDecl() + ">>"; + } + + public String RelationComponent.getImplAttributeName() { + return "_impl_" + getID(); + } + + public String RelationComponent.getImplAttributeField() { + // tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type())); + return "token" + ofTypeDecl() + "__impl_" + getID(); + } + + public String ManyRelationComponent.getImplAttributeField() { + // tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type())); + return "token" + listClass + "_" + ofTypeDecl() + "___impl_" + getID(); + } +} diff --git a/src/main/jastadd/backend/Backend.jadd b/src/main/jastadd/backend/Backend.jadd new file mode 100644 index 0000000000000000000000000000000000000000..c751488eb18df1a1e59b4a93edebf341bcdea0c0 --- /dev/null +++ b/src/main/jastadd/backend/Backend.jadd @@ -0,0 +1,67 @@ +aspect BackendAspect { + public String Program.generateAspect() { + StringBuilder sb = new StringBuilder(); + generateAspect(sb); + return sb.toString(); + } + + public void Program.generateAspect(StringBuilder sb) { + sb.append("import java.util.ArrayList;\n"); + sb.append("import java.util.Collections;\n"); + sb.append("import java.time.Instant;\n"); + sb.append("import java.time.Period;\n"); + sb.append("aspect RelAstAPI {\n"); + + for (TypeDecl td: getTypeDecls()) { + if (td.needsConstructor()) { + td.generateConstructor(sb); + } + } + for (Relation r: getRelations()) { + r.generateAPI(sb); + } + + generateLowerBoundCheck(sb); + + sb.append(ind(1) + "public static void ASTNode.assertNotNull(Object obj) {\n"); + sb.append(ind(2) + "if (obj == null) {\n"); + sb.append(ind(3) + "throw new NullPointerException();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + sb.append("}\n"); + } + + public void TypeDecl.generateConstructor(StringBuilder sb) { + sb.append(ind(1) + "public " + getID() + "." + getID() + "("); + int i = 0; + for (Component c: componentsTransitive()) { + sb.append(c.constructorParameter()); + if (++i < componentsTransitive().size()) { + sb.append(", "); + } + } + sb.append(") {\n"); + for (Component c: componentsTransitive()) { + sb.append(ind(2) + c.constructorSetMethod() + "(" + c.getID() + ");\n"); + } + sb.append(ind(1) + "}\n"); + } + public String Component.constructorParameter() { + return getTypeUse() + " " + getID(); + } + public String ListComponent.constructorParameter() { + return ASTNode.jastAddListType + "<" + getTypeUse() + "> " + getID(); + } + public String OptComponent.constructorParameter() { + return "Opt<" + getTypeUse() + "> " + getID(); + } + public String Component.constructorSetMethod() { + return "set" + getID(); + } + public String ListComponent.constructorSetMethod() { + return "set" + getID() + "List"; + } + public String OptComponent.constructorSetMethod() { + return "set" + getID() + "Opt"; + } +} diff --git a/src/main/jastadd/backend/BidirectionalAPI.jadd b/src/main/jastadd/backend/BidirectionalAPI.jadd new file mode 100644 index 0000000000000000000000000000000000000000..75f28ab40df71d2690208408e6cb314d9107d886 --- /dev/null +++ b/src/main/jastadd/backend/BidirectionalAPI.jadd @@ -0,0 +1,349 @@ +aspect BackendBidirectionalAPI { + public void Bidirectional.generateAPI(StringBuilder sb) { + RelationComponent l = relation().getLeft(); + RelationComponent r = relation().getRight(); + + if (l.multiplicityOne()) { + if (r.multiplicityOne()) { + l.generateBiOneOne(sb, false); + r.generateBiOneOne(sb, false); + } else if (r.multiplicityOpt()) { + l.generateBiOneOne(sb, false); + r.generateBiOneOne(sb, true); + } else if (r.multiplicityMany()) { + l.generateBiOneMany(sb, false); + r.generateBiManyOne(sb, l); + } + } else if (l.multiplicityOpt()) { + if (r.multiplicityOne()) { + l.generateBiOneOne(sb, true); + r.generateBiOneOne(sb, false); + } else if (r.multiplicityOpt()) { + l.generateBiOneOne(sb, true); + r.generateBiOneOne(sb, true); + } else if (r.multiplicityMany()) { + l.generateBiOneMany(sb, true); + r.generateBiManyOne(sb, l); + } + } else if (l.multiplicityMany()) { + if (r.multiplicityOne()) { + l.generateBiManyOne(sb, r); + r.generateBiOneMany(sb, false); + } else if (r.multiplicityOpt()) { + l.generateBiManyOne(sb, r); + r.generateBiOneMany(sb, true); + } else if (r.multiplicityMany()) { + l.generateBiManyMany(sb, r); + r.generateBiManyMany(sb, l); + } + } + } + + public void RelationComponent.generateBiOneOne(StringBuilder sb, boolean isOpt) { + // Get + generateGetOne(sb); + + // Set + sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl()); + sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + if (!isOpt) { + sb.append(ind(2) + "assertNotNull(o);\n"); + } + // unset the old opposite + sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n"); + sb.append(ind(3) + "" + getImplAttributeField() + ".set" + otherSide().getImplAttributeName() + "(null);\n"); + sb.append(ind(2) + "}\n"); + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (o != null && !o.is$Unresolved() && o." + otherSide().getImplAttributeField() + " != null) {\n"); + } else { + sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); + } + sb.append(ind(3) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(null);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (o == null || !o.is$Unresolved()) {\n"); + if (isOpt) { + sb.append(ind(3) + "if (o != null) {\n"); + sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(3) + "}\n"); + } else { + sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + } + sb.append(ind(2) + "}\n"); + } else { + if (isOpt) { + sb.append(ind(2) + "if (o != null) {\n"); + sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(2) + "}\n"); + } else { + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + } + } + + sb.append(ind(2) + "return this;\n"); + sb.append(ind(1) + "}\n"); + + if (isOpt) { + generateExtraOptAPI(sb); + } + } + + public void RelationComponent.generateBiManyMany(StringBuilder sb, RelationComponent opposite) { + // Get + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); + + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); + // resolve the entire list + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (l != null) {\n"); + sb.append(ind(3) + "boolean changed = false;\n"); + sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); + sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); + sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); + sb.append(ind(5) + "changed = true;\n"); + sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); + sb.append(ind(5) + "if (resolvedElement != null && element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); + sb.append(ind(6) + ASTNode.listClass + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + opposite.getImplAttributeField() + ";\n"); + sb.append(ind(6) + "if (otherList == null) {\n"); + sb.append(ind(7) + "otherList = new " + listClass + "<>();\n"); + sb.append(ind(6) + "}\n"); + sb.append(ind(6) + "otherList.add(this);\n"); + sb.append(ind(6) + "resolvedElement.set" + opposite.getImplAttributeName() + "(otherList);\n"); + sb.append(ind(5) + "}\n"); + sb.append(ind(5) + "l.set(i, resolvedElement);\n"); + sb.append(ind(4) + "}\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(3) + "if (changed) {\n"); + sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + } + sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); + sb.append(ind(1) + "}\n"); + + // Add + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list2 == null) {\n"); + sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(o);\n"); + sb.append(ind(2) + "list2.add(this);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); + sb.append(ind(1) + "}\n"); + + // Insert / add at specific position + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + + otherSide().getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list2 == null) {\n"); + sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(index, o);\n"); + sb.append(ind(2) + "list2.add(this);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); + sb.append(ind(1) + "}\n"); + + // Remove + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); + sb.append(ind(3) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + + otherSide().getImplAttributeField() + ";\n"); + sb.append(ind(3) + "if (list2 != null) list2.remove(this);\n"); + sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + + public void RelationComponent.generateBiManyOne(StringBuilder sb, RelationComponent opposite) { + // Get + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); + + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); + // resolve the entire list + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (l != null) {\n"); + sb.append(ind(3) + "boolean changed = false;\n"); + sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); + sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); + sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); + sb.append(ind(5) + "changed = true;\n"); + sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); + sb.append(ind(5) + "if (element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); + sb.append(ind(6) + getTypeUse().decl() + " oldTarget = resolvedElement." + opposite.getImplAttributeField() + ";\n"); + sb.append(ind(6) + "if (oldTarget != null && oldTarget != this) {\n"); + sb.append(ind(7) + "oldTarget." + getImplAttributeField() + ".remove(resolvedElement);\n"); + sb.append(ind(6) + "}\n"); + sb.append(ind(6) + "if (oldTarget == this) {\n"); + sb.append(ind(7) + "l.remove(i);\n"); + sb.append(ind(7) + "i--;\n"); + sb.append(ind(6) + "} else {\n"); + sb.append(ind(7) + "resolvedElement.set" + opposite.getImplAttributeName() + "(this);\n"); + sb.append(ind(7) + "l.set(i, resolvedElement);\n"); + sb.append(ind(6) + "}\n"); + sb.append(ind(5) + "} else {\n"); + sb.append(ind(6) + "l.set(i, resolvedElement);\n"); + sb.append(ind(5) + "}\n"); + sb.append(ind(4) + "}\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(3) + "if (changed) {\n"); + sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + } + sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); + sb.append(ind(1) + "}\n"); + + // Add + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); + sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n"); + sb.append(ind(3) + "if (list2.remove(o))\n"); + sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + + ".set" + getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(o);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(1) + "}\n"); + + // Insert / add at specific position + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n"); + sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n"); + sb.append(ind(3) + "if (list2.remove(o))\n"); + sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(index, o);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(1) + "}\n"); + + // Remove + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); + sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(3) + "if (o." + otherSide().getImplAttributeField() + " == this) {\n"); + sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(null);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + public void RelationComponent.generateBiOneMany(StringBuilder sb, boolean isOpt) { + // Get + generateGetOne(sb); + + // Set + sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized() + + "(" + ofTypeDecl() + " o) {\n"); + if (!isOpt) { + sb.append(ind(2) + "assertNotNull(o);\n"); + } + sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n"); + sb.append(ind(3) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list2 = " + getImplAttributeField() + + "." + otherSide().getImplAttributeField() + ";\n"); + sb.append(ind(3) + "list2.remove(this);\n"); + sb.append(ind(3) + getImplAttributeField() + "." + "set" + + otherSide().getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); + + int ind = isOpt ? 3 : 2; + if (isOpt) { + sb.append(ind(2) + "if (o != null) {\n"); + } + sb.append(ind(ind) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list = o." + + otherSide().getImplAttributeField() + ";\n"); + sb.append(ind(ind) + "if (list == null) {\n"); + sb.append(ind(ind+1) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(ind) + "}\n"); + sb.append(ind(ind) + "list.add(this);\n"); + sb.append(ind(ind) + "o.set" + otherSide().getImplAttributeName() + "(list);\n"); + if (isOpt) { + sb.append(ind(2) + "}\n"); + } + sb.append(ind(2) + "return this;\n"); + sb.append(ind(1) + "}\n"); + + if (isOpt) { + generateExtraOptAPI(sb); + } + } +} diff --git a/src/main/jastadd/backend/DirectedAPI.jadd b/src/main/jastadd/backend/DirectedAPI.jadd new file mode 100644 index 0000000000000000000000000000000000000000..000c47614ec48abbf110f18090a1d08ec55eb758 --- /dev/null +++ b/src/main/jastadd/backend/DirectedAPI.jadd @@ -0,0 +1,153 @@ +aspect BackendDirectedAPI { + public void RightDirection.generateAPI(StringBuilder sb) { + relation().getLeft().generateDirectedAPI(sb); + } + public void LeftDirection.generateAPI(StringBuilder sb) { + relation().getRight().generateDirectedAPI(sb); + } + + public abstract void RelationComponent.generateDirectedAPI(StringBuilder sb); + public void OneRelationComponent.generateDirectedAPI(StringBuilder sb) { + generateDirectedZeroOneAPI(sb, false); + } + public void OptionalRelationComponent.generateDirectedAPI(StringBuilder sb) { + generateDirectedZeroOneAPI(sb, true); + + generateExtraOptAPI(sb); + } + public void RelationComponent.generateDirectedZeroOneAPI(StringBuilder sb, boolean optional) { + // Get + generateGetOne(sb); + + // Set + sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl()); + sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + if (!optional) { + sb.append(ind(2) + "assertNotNull(o);\n"); + } + sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); + sb.append(ind(2) + "return this;\n"); + sb.append(ind(1) + "}\n"); + } + + public void ManyRelationComponent.generateDirectedAPI(StringBuilder sb) { + // Get + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); + + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); + // resolve the entire list + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (l != null) {\n"); + sb.append(ind(3) + "boolean changed = false;\n"); + sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n"); + sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n"); + sb.append(ind(4) + "if (element.is$Unresolved()) {\n"); + sb.append(ind(5) + "changed = true;\n"); + sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n"); + sb.append(ind(5) + "l.set(i, resolvedElement);\n"); + sb.append(ind(4) + "}\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(3) + "if (changed) {\n"); + sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + } + sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); + sb.append(ind(1) + "}\n"); + + // Add + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(o);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(1) + "}\n"); + + // Insert / add at specific position + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(index, o);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(1) + "}\n"); + + // Remove + sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n"); + sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); + sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + public void RelationComponent.generateGetOne(StringBuilder sb) { + sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + "."); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() {\n"); + if (resolverHelper | serializer) { + sb.append(ind(2) + "if (" + getImplAttributeField() + " != null && " + getImplAttributeField() + ".is$Unresolved()) {\n"); + sb.append(ind(3) + "if (" + getImplAttributeField() + ".as$Unresolved().getUnresolved$ResolveOpposite()) {\n"); + sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n"); + sb.append(ind(3) + "} else {\n"); + sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + } + sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n"); + sb.append(ind(1) + "}\n"); + } + + public void RelationComponent.generateExtraOptAPI(StringBuilder sb) { + // has + sb.append(ind(1) + "public boolean " + getTypeUse().decl()); + sb.append(".has" + nameCapitalized() + "() {\n"); + sb.append(ind(2) + "return "); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() != null;\n"); + sb.append(ind(1) + "}\n"); + + // clear + sb.append(ind(1) + "public void " + getTypeUse().decl()); + sb.append(".clear" + nameCapitalized() + "() {\n"); + sb.append(ind(2) + "set" + nameCapitalized() + "(null);\n"); + sb.append(ind(1) + "}\n"); + } +} diff --git a/src/main/jastadd/backend/LowerBoundCheck.jadd b/src/main/jastadd/backend/LowerBoundCheck.jadd new file mode 100644 index 0000000000000000000000000000000000000000..e7690cacca84527435dc09e7e6a1ff6991089795 --- /dev/null +++ b/src/main/jastadd/backend/LowerBoundCheck.jadd @@ -0,0 +1,79 @@ +aspect LowerBoundCheck { + public void Program.generateLowerBoundCheck(StringBuilder sb) { + sb.append(ind(1) + "public boolean ASTNode.violatesLowerBounds() {\n"); + sb.append(ind(2) + "return !getLowerBoundsViolations().isEmpty();\n"); + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "public java.util.List<Pair<ASTNode, String>> " + + "ASTNode.getLowerBoundsViolations() {\n"); + sb.append(ind(2) + "ArrayList<Pair<ASTNode, String>> list = new ArrayList<>();\n"); + sb.append(ind(2) + "computeLowerBoundsViolations(list);\n"); + sb.append(ind(2) + "return list;\n"); + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "public void ASTNode.computeLowerBoundsViolations(" + + "java.util.List<Pair<ASTNode, String>> list) {\n"); + sb.append(ind(2) + "for (int i = 0; i < getNumChildNoTransform(); i++) {\n"); + sb.append(ind(3) + "getChildNoTransform(i).computeLowerBoundsViolations(list);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + + for (TypeDecl td: getTypeDecls()) { + td.generateLowerBoundCheck(sb); + } + + generatePairClass(sb); + } + + public void TypeDecl.generateLowerBoundCheck(StringBuilder sb) { + if (!oneRelationComponents().isEmpty()) { + sb.append(ind(1) + "public void " + getID() + ".computeLowerBoundsViolations(" + + "java.util.List<Pair<ASTNode, String>> list) {\n"); + for (OneRelationComponent o: oneRelationComponents()) { + o.generateLowerBoundCheck(sb); + } + sb.append(ind(2) + "super.computeLowerBoundsViolations(list);\n"); + sb.append(ind(1) + "}\n"); + } + } + + public void OneRelationComponent.generateLowerBoundCheck(StringBuilder sb) { + sb.append(ind(2) + "if ("); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() == null) {\n"); + sb.append(ind(3) + "list.add(new Pair<>(this, \"" + name() + "\"));\n"); + sb.append(ind(2) + "}\n"); + } + + + public void Program.generatePairClass(StringBuilder sb) { + sb.append(ind(1) + "public class Pair<T1, T2> {\n"); + sb.append(ind(2) + "public final T1 _1;\n"); + sb.append(ind(2) + "public final T2 _2;\n"); + // Constructor + sb.append(ind(2) + "public Pair(T1 _1, T2 _2) {\n"); + sb.append(ind(3) + "ASTNode.assertNotNull(_1);\n"); + sb.append(ind(3) + "ASTNode.assertNotNull(_2);\n"); + sb.append(ind(3) + "this._1 = _1;\n"); + sb.append(ind(3) + "this._2 = _2;\n"); + sb.append(ind(2) + "}\n"); + // equals + sb.append(ind(2) + "public boolean equals(Object other) {\n"); + sb.append(ind(3) + "if (other instanceof Pair) {\n"); + sb.append(ind(4) + "Pair<?,?> p = (Pair<?,?>) other;\n"); + sb.append(ind(4) + "return _1.equals(p._1) && _2.equals(p._2);\n"); + sb.append(ind(3) + "} else {\n"); + sb.append(ind(4) + "return false;\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + // hashCode + sb.append(ind(2) + "public int hashCode() {\n"); + sb.append(ind(3) + "return 31*_1.hashCode() + _2.hashCode();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } +} diff --git a/src/main/jastadd/backend/NameResolution.jadd b/src/main/jastadd/backend/NameResolution.jadd new file mode 100644 index 0000000000000000000000000000000000000000..1d373e9e4b4c224bf5c65227182e0c2493197737 --- /dev/null +++ b/src/main/jastadd/backend/NameResolution.jadd @@ -0,0 +1,258 @@ +aspect NameResolutionHelper { + + public String Program.generateRewriteToSuperTypeStub() { + StringBuilder sb = new StringBuilder(); + generateRewriteToSuperTypeStub(sb); + return sb.toString(); + } + + 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()) { + r.generateContextDependentNameResolution(sb); + } + + if (resolverHelper || ASTNode.jsonPointer || ASTNode.manualReferences) { + for (TypeDecl decl : getTypeDeclList()) { + decl.generateContextIndependentNameResolution(sb); + sb.append("\n"); + } + } + sb.append("}\n\n"); + + if (ASTNode.manualReferences) { + sb.append("aspect RefCreatorStubs {\n\n"); + + for (Relation r: getRelations()) { + r.generateContextDependentRefCreation(sb); + } + + generateGenericRefCreation(sb); + sb.append("\n"); + + for (TypeDecl decl : getTypeDeclList()) { + decl.generateContextIndependentRefCreation(sb); + sb.append("\n"); + } + + sb.append("}\n\n"); + } + } + + public void Program.generateGenericRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// generic reference creation\n"); + sb.append(ind(1) + "syn String ASTNode.createReference();\n"); + sb.append(ind(1) + "eq ASTNode.createReference() {\n"); + sb.append(ind(2) + "throw new RuntimeException(\"Generic reference creation not implemented.\");\n"); + sb.append(ind(1) + "}\n"); + } + + public void Relation.generateContextDependentRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// " + prettyPrint() + "\n"); + getDirection().generateContextDependentRefCreation(sb); + sb.append("\n"); + } + + public abstract void Direction.generateContextDependentRefCreation(StringBuilder sb); + public void RightDirection.generateContextDependentRefCreation(StringBuilder sb) { + relation().getLeft().generateContextDependentRefCreation(sb); + } + public void LeftDirection.generateContextDependentRefCreation(StringBuilder sb) { + relation().getRight().generateContextDependentRefCreation(sb); + } + public void Bidirectional.generateContextDependentRefCreation(StringBuilder sb) { + relation().getLeft().generateContextDependentRefCreation(sb); + relation().getRight().generateContextDependentRefCreation(sb); + } + + public void RelationComponent.generateContextDependentRefCreation(StringBuilder sb) { + sb.append(ind(1) + "// context-dependent reference creation\n"); + sb.append(ind(1) + "syn String " + 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) { + + sb.append("aspect ReferenceCreation {\n\n"); + + for (TypeDecl decl : getTypeDeclList()) { + decl.createReferenceCreator(sb); + } + + sb.append("}\n\n"); + + sb.append("aspect ResolverTrigger {\n\n"); + + resolveAll(sb); + + for (TypeDecl decl : getTypeDeclList()) { + decl.resolveAll(sb); + } + + sb.append("}\n\n"); + + sb.append("aspect RefResolverHelpers {\n\n"); + + sb.append(ind(1) + "interface Unresolved$Node {\n"); + sb.append(ind(2) + "String getUnresolved$Token();\n"); + sb.append(ind(2) + "boolean getUnresolved$ResolveOpposite();\n"); + sb.append(ind(1) + "}\n\n"); + + for (TypeDecl td: getTypeDecls()) { + if (td.needUnresolvedClass()) { + td.generateUnresolvedClass(sb); + } + } + + sb.append("\n}\n"); + } + + public void TypeDecl.createReferenceCreator(StringBuilder sb) { + + TypeDecl instantiableSubType = instantiableSubType(); + if (instantiableSubType == null) { + throw new RuntimeException("unable to find instantiable subtype for " + getID()); + } + + sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRef(String ref) {\n"); + sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n"); + sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n"); + sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(true);\n"); + sb.append(ind(2) + "return unresolvedNode;\n"); + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRefDirection(String ref) {\n"); + sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n"); + sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n"); + sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(false);\n"); + sb.append(ind(2) + "return unresolvedNode;\n"); + sb.append(ind(1) + "}\n"); + } + + public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) { + sb.append(ind(1) + "// context-independent name resolution\n"); + sb.append(ind(1) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n"); + sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n"); + if (serializer && !manualReferences) { + if (jsonPointer) { + sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n"); + } else { + sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n"); + } + } else { + sb.append(ind(2) + "// perform context independent name resolution here using the id\n"); + sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n"); + } + sb.append(ind(1) + "}\n"); + } + + public void Relation.generateContextDependentNameResolution(StringBuilder sb) { + sb.append(ind(1) + "// " + prettyPrint() + "\n"); + getDirection().generateContextDependentNameResolution(sb); + sb.append("\n"); + } + + public abstract void Direction.generateContextDependentNameResolution(StringBuilder sb); + public void RightDirection.generateContextDependentNameResolution(StringBuilder sb) { + relation().getLeft().generateContextDependentNameResolution(sb); + } + public void LeftDirection.generateContextDependentNameResolution(StringBuilder sb) { + relation().getRight().generateContextDependentNameResolution(sb); + } + public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) { + relation().getLeft().generateContextDependentNameResolution(sb); + relation().getRight().generateContextDependentNameResolution(sb); + } + + public abstract void RelationComponent.generateContextDependentNameResolution(StringBuilder sb); + public void OneRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { + generateDirectedContextDependentNameResolution(sb); + } + public void OptionalRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { + // optional relations are resolved in the same way as mandatory relations + // TODO maybe, there should be a check if the id to be solved is empty or null + generateDirectedContextDependentNameResolution(sb); + } + public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { + + if (serializer && !resolverHelper) { + sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n"); + sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n"); + sb.append(ind(1) + "}\n"); + } else { + sb.append(ind(1) + "// context-dependent name resolution\n"); + sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position);\n"); + sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id, int position) {\n"); + sb.append(ind(2) + "// default to context-independent name resolution\n"); + sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n"); + sb.append(ind(1) + "}\n"); + } + } + + public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) { + if (serializer && !resolverHelper) { + sb.append(ind(1) + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n"); + sb.append(ind(2) + "return (" + ofTypeDecl() + ") globallyResolveASTNodeByUID(id);\n"); + sb.append(ind(1) + "}\n"); + } else { + sb.append(ind(1) + "// context-dependent name resolution\n"); + sb.append(ind(1) + "uncache " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id);\n"); + sb.append(ind(1) + "syn " + ofTypeDecl() + " " + getTypeUse().decl() + ".resolve" + nameCapitalized() + "ByToken(String id) {\n"); + sb.append(ind(2) + "// default to context-independent name resolution\n"); + sb.append(ind(2) + "return globallyResolve" + ofTypeDecl() + "ByToken(id);\n"); + sb.append(ind(1) + "}\n"); + } + } + + public void Program.resolveAll(StringBuilder sb) { + sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n"); + sb.append(ind(1) + "public void ASTNode.resolveAll() {\n"); + sb.append(ind(1) + "}\n\n"); + + sb.append(ind(1) + "// enforce resolving in the entire subtree\n"); + sb.append(ind(1) + "public void ASTNode.treeResolveAll() {\n"); + sb.append(ind(2) + "if (children != null) {\n"); + sb.append(ind(3) + "for (int i = 0; i < numChildren; ++i) {\n"); + sb.append(ind(4) + "ASTNode child = children[i];\n"); + sb.append(ind(4) + "if (child != null) {\n"); + sb.append(ind(5) + "child.treeResolveAll();\n"); + sb.append(ind(4) + "}\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "resolveAll();\n"); + sb.append(ind(1) + "}\n"); + } + + public void TypeDecl.resolveAll(StringBuilder sb) { + sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n"); + sb.append(ind(1) + "public void " + getID() + ".resolveAll() {\n"); + for (RelationComponent relationComponent : relationComponents()) { + sb.append(ind(2)); + if (useJastAddNames) { + sb.append("get" + relationComponent.nameCapitalized()); + } else { + sb.append(relationComponent.name()); + } + sb.append(relationComponent.isMany() && useJastAddNames ? "List" : "").append("();\n"); + } + sb.append(ind(2) + "super.resolveAll();\n"); + sb.append(ind(1) + "}\n"); + } +} diff --git a/src/main/jastadd/backend/PrettyPrinting.jadd b/src/main/jastadd/backend/PrettyPrinting.jadd new file mode 100644 index 0000000000000000000000000000000000000000..49d33b9997f4840e54afe7de2f7dd4ba786bb45d --- /dev/null +++ b/src/main/jastadd/backend/PrettyPrinting.jadd @@ -0,0 +1,42 @@ +aspect PrettyPrinting { + public String Relation.prettyPrint() { + return "rel " + + getLeft().prettyPrint() + " " + + getDirection().prettyPrint() + " " + + getRight().prettyPrint(); + } + public String RelationComponent.prettyPrint() { + if (getID().isEmpty()) { + return getTypeUse().toString(); + } else { + return getTypeUse() + "." + getID(); + } + } + public String OptionalRelationComponent.prettyPrint() { + return super.prettyPrint() + "?"; + } + public String ManyRelationComponent.prettyPrint() { + return super.prettyPrint() + "*"; + } + abstract public String Direction.prettyPrint(); + public String RightDirection.prettyPrint() { + return "->"; + } + public String LeftDirection.prettyPrint() { + return "<-"; + } + public String Bidirectional.prettyPrint() { + return "<->"; + } + +} + +aspect Utils { + public String ASTNode.ind(int n) { + String s = ""; + for (int i = 0; i < n; i++) { + s += " "; + } + return s; + } +} diff --git a/src/main/jastadd/backend/Serializer.jadd b/src/main/jastadd/backend/Serializer.jadd new file mode 100644 index 0000000000000000000000000000000000000000..90ba24e30df96ba67eb8d3bec543347648d58879 --- /dev/null +++ b/src/main/jastadd/backend/Serializer.jadd @@ -0,0 +1,633 @@ +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.generateJacksonSerializer() { + StringBuilder sb = new StringBuilder(); + generateFromJson(sb); + generateToJson(sb); + if (jsonPointer) { + writeJsonPointer(sb); + } else if (manualReferences) { + // TODO + } else { + 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) + "serialize(file, false);\n"); + sb.append(ind(1) + "}\n"); + + sb.append(ind(1) + "public void ASTNode.serialize(java.io.File file, boolean humanReadable) 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) + "if (humanReadable) {\n"); + sb.append(ind(4) + "generator.setPrettyPrinter(new com.fasterxml.jackson.core.util.DefaultPrettyPrinter());\n"); + sb.append(ind(3) + "}\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()) { + 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()) { + 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"); + if (!jsonPointer && !manualReferences) { + sb.append(ind(3) + "g.writeStringField(\"" + jsonTypeKey + "\", \"" + getID() + "\");\n"); + sb.append(ind(3) + "if (unique$Id() == null) throw new SerializationException(\"The unique identifier of " + getID() + " is missing.\");\n"); + sb.append(ind(3) + "g.writeStringField(\"id\", unique$Id());\n"); + } + if (componentsTransitive().size() > 0) { + sb.append(ind(3) + "g.writeObjectFieldStart(\"children\");\n"); + for (Component child : componentsTransitive()) { + if (child.isNullable()) { + String componentAccessor = child.getID(); + if (child.isList()) { + componentAccessor += "List"; + } else if (child.isOpt()) { + componentAccessor += "Opt"; + } + sb.append(ind(3) + "if (get" + componentAccessor + "() == null) throw new SerializationException(\"The component " + child.getID() + " of " + getID() + " is missing.\");\n"); + } + child.serialize(sb, 3); + } + sb.append(ind(3) + "g.writeEndObject(); // children\n"); + } + if (relationComponentsTransitive().size() > 0) { + sb.append(ind(3) + "g.writeObjectFieldStart(\"relations\");\n"); + for (RelationComponent relation : relationComponentsTransitive()) { + 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 "Instant": + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().toString());\n"); + break; + case "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 NTAListComponent.serialize(StringBuilder sb, int indent) { + // do not serialize NTA + } + + public void NTAOptComponent.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) { + if (useJastAddNames){ + 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 { + sb.append(ind(indent) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); + } + } + } + + public void OptionalRelationComponent.serialize(StringBuilder sb, int indent) { + sb.append(ind(indent) + "if (has" + nameCapitalized() + "()) {\n"); + if (useJastAddNames){ + if (jsonPointer) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().createReference());\n"); + } else { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", get" + getID() + "().unique$Id());\n"); + } + } else { + if (jsonPointer) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().jsonPointer());\n"); + } else if (manualReferences) { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + "createRefTo" + getID() + "(" + getID() + "()));\n"); + } else { + sb.append(ind(indent + 1) + "g.writeStringField(\"" + getID() + "\", " + getID() + "().unique$Id());\n"); + } + } + sb.append(ind(indent) + "}\n"); + } + + public void ManyRelationComponent.serialize(StringBuilder sb, int indent) { + sb.append(ind(indent) + "g.writeArrayFieldStart(\"" + getID() + "\");\n"); + if (useJastAddNames) { + sb.append(ind(indent) + "for (" + ofTypeDecl().getID() + " child : get" + getID() + "List()) {\n"); + } else { + 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) + "}\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) + getID() + " result = deserialize((com.fasterxml.jackson.databind.JsonNode)mapper.readTree(parser));\n"); + sb.append(ind(3) + "parser.close();\n"); + sb.append(ind(3) + "return result;\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"); + } + + if (!jsonPointer && !manualReferences) { + // deserialize id + sb.append(ind(2) + "if (node.has(\"id\")) {\n"); + sb.append(ind(3) + "element.unique$Id = node.get(\"id\").asText();\n"); + sb.append(ind(2) + "}\n"); + } + + // deserialize containment children + if (componentsTransitive().size() > 0) { + 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 "Instant": + sb.append(ind(indent) + "element.set" + getID() + "(Instant.parse(children.get(\"" + getID() + "\").asText()));\n"); + break; + case "Period": + sb.append(ind(indent) + "element.set" + getID() + "(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 + ".class, children.get(\"" + getID() + "\").asText()));\n"); + + // sb.append("throw new DeserializationException(\"Unable to deserialize child node of type \"" + getTypeUse() + "\"\")") + } + } + + public void Component.writeJsonPointer(StringBuilder sb) { + // do nothing for other components + } + + public void NormalComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void ListComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); + sb.append(ind(1) + "}\n"); + } + + public void OptComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAListComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "(int index).jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "/\" + index;\n"); + sb.append(ind(1) + "}\n"); + } + + public void NTAOptComponent.writeJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + enclosingTypeDecl().getID() + (useJastAddNames?".get":".") + getID() + "().jsonPointerInh() {\n"); + sb.append(ind(2) + "return this.jsonPointer() + \"/children/" + getID() + "\";\n"); + sb.append(ind(1) + "}\n"); + } + + public void Component.resolveJsonPointer(StringBuilder sb) { + // do nothing for other components + } + + public void NormalComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void ListComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); + } + + public void OptComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void NTAComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void NTAListComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "(Integer.valueOf(pointer[index + 2])).resolveJsonPointer(pointer, index + 3);\n"); + } + + public void NTAOptComponent.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(4) + "case \"" + getID() + "\":\n"); + sb.append(ind(5) + "return get" + getID() + "().resolveJsonPointer(pointer, index + 2);\n"); + } + + public void TypeDecl.resolveJsonPointer(StringBuilder sb) { + sb.append(ind(1) + "eq " + getID() + ".resolveJsonPointer(String[] pointer, int index) {\n"); + sb.append(ind(2) + "if (pointer.length == 0 || pointer.length == index) {\n"); + sb.append(ind(3) + "return this;\n"); + sb.append(ind(2) + "} else if (pointer.length == index + 1) {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"there is only one child called \" + pointer[index]);\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "switch (pointer[index + 1]) {\n"); + + for (Component c: getComponentList()) { + c.resolveJsonPointer(sb); + } + + sb.append(ind(4) + "default:\n"); + sb.append(ind(5) + "return super.resolveJsonPointer(pointer, index);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + public void Program.writeJsonPointer(StringBuilder sb) { + sb.append("aspect JsonPointer {\n"); + + sb.append(ind(1) + "syn String ASTNode.jsonPointer() {\n"); + sb.append(ind(2) + "if (getParent() == null) {\n"); + sb.append(ind(3) + "return \"\";\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "return jsonPointerInh();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "inh String ASTNode.jsonPointerInh();\n"); + + // define json pointer for each component + for (TypeDecl td: getTypeDeclList()) { + for (Component c: td.getComponentList()) { + c.writeJsonPointer(sb); + } + } + + sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String pointer) = root().resolveJsonPointer(pointer.split(\"/\"), 1);\n"); + sb.append(ind(1) + "ASTNode ASTNode.root() {\n"); + sb.append(ind(2) + "if (getParent() == null) return this;\n"); + sb.append(ind(2) + "else return getParent().root();\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "syn ASTNode ASTNode.resolveJsonPointer(String[] pointer, int index) {\n"); + sb.append(ind(2) + "if (index < pointer.length) {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"found wrong child \" + pointer[index + 1] + \" in class \" + this.getClass().getSimpleName());\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "throw new RuntimeException(\"Cannot resolve JSON pointer for class \" + this.getClass().getSimpleName());\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + + // resolve JSON pointers in each nonterminal + for (TypeDecl td: getTypeDeclList()) { + td.resolveJsonPointer(sb); + } + + sb.append("}\n"); + } + + public void Program.writeUID(StringBuilder sb) { + sb.append("aspect UID {\n"); + sb.append(ind(1) + "class UIDProvider {\n"); + 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.unique$Id = null;\n"); + sb.append("\n"); + sb.append(ind(1) + "protected String ASTNode.unique$Id() {\n"); + sb.append(ind(2) + "String customUID = customID();\n"); + sb.append(ind(2) + "if (customUID == null) {\n"); + sb.append(ind(3) + "if (unique$Id == null) {\n"); + sb.append(ind(4) + "unique$Id = UIDProvider.getUID();\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(3) + "return unique$Id;\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.customID() {\n"); + sb.append(ind(1) + " return null;\n"); + sb.append(ind(1) + "}\n"); + sb.append("\n"); + sb.append(ind(1) + "ASTNode ASTNode.globallyResolveASTNodeByUID(String uid) {\n"); + sb.append(ind(2) + "if (getParent() == null) {\n"); + sb.append(ind(3) + "return uid$Map().get(uid).get();\n"); + sb.append(ind(2) + "} else {\n"); + sb.append(ind(3) + "return getParent().globallyResolveASTNodeByUID(uid);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + sb.append("\n"); + sb.append(ind(1) + "java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map;\n"); + sb.append("\n"); + sb.append(ind(1) + "java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map() {\n"); + sb.append(ind(2) + "if (uid$Map == null) {\n"); + sb.append(ind(3) + "uid$Map = uid$Map(new java.util.HashMap());\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "return uid$Map;\n"); + sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "protected java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> ASTNode.uid$Map(java.util.Map<String, java.lang.ref.WeakReference<ASTNode>> map) {\n"); + sb.append(ind(2) + "if (!(this instanceof " + jastAddListType + " || this instanceof Opt)) {\n"); + sb.append(ind(3) + "if (map.keySet().contains(unique$Id())) {\n"); + sb.append(ind(4) + "throw new RuntimeException(new SerializationException(\"UID \" + this.unique$Id() + \" is assigned to both \" + this.getClass().getSimpleName() + \":\" + this.hashCode() + \" and \" + map.get(unique$Id()).getClass().getSimpleName() + \":\" + map.get(unique$Id()).hashCode()));\n"); + sb.append(ind(3) + "} else {\n"); + sb.append(ind(4) + "map.put(this.unique$Id, new java.lang.ref.WeakReference(this));\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "for (ASTNode child : astChildren()) {\n"); + sb.append(ind(3) + "child.uid$Map(map);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "return map;\n"); + sb.append(ind(1) + "}\n"); + sb.append("}\n"); + } + + public void NTAComponent.deserialize(StringBuilder sb, int indent) { + // do not serialize NTA + } + + public void NTAListComponent.deserialize(StringBuilder sb, int indent) { + // do not serialize NTA + } + + public void NTAOptComponent.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" + nameCapitalized() + "(" + 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" + nameCapitalized() + "(" + 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" + (useJastAddNames?"":"To") + nameCapitalized() + "(" + ofTypeDecl().getID() + ".createRefDirection(child.asText()));\n"); + sb.append(ind(indent) + "}\n"); + } +}