From a4c49252681b7b1a0953d0c13fc2d4cbf0a98e3e Mon Sep 17 00:00:00 2001 From: Niklas Fors <niklas.fors@cs.lth.se> Date: Wed, 4 Jul 2018 17:25:15 +0200 Subject: [PATCH] Add part implementation of bidirectional and add test case --- .gitignore | 4 +- spec/jastadd/Analysis.jrag | 11 +- spec/jastadd/Backend.jadd | 94 ++++++++++++-- spec/jastadd/Errors.jrag | 10 +- test/.gitignore | 3 + test/AllBi.relast | 15 +++ test/Makefile | 8 ++ test/Test.java | 248 +++++++++++++++++++++++++++++++++++++ test/Utils.jadd | 9 ++ 9 files changed, 385 insertions(+), 17 deletions(-) create mode 100644 test/.gitignore create mode 100644 test/AllBi.relast create mode 100644 test/Makefile create mode 100644 test/Test.java create mode 100644 test/Utils.jadd diff --git a/.gitignore b/.gitignore index 860c498..c52fdba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ .DS_Store -.class +*.class .vimrc .*.swp -*.relast +/*.relast /.settings /bin/ diff --git a/spec/jastadd/Analysis.jrag b/spec/jastadd/Analysis.jrag index 7943957..f71c225 100644 --- a/spec/jastadd/Analysis.jrag +++ b/spec/jastadd/Analysis.jrag @@ -32,10 +32,13 @@ aspect ComponentAnalysis { inh TypeDecl Component.enclosingTypeDecl(); eq TypeDecl.getChild().enclosingTypeDecl() = this; eq Program.getChild().enclosingTypeDecl() = null; - inh TypeDecl RelationComponent.ofTypeDecl(); - eq Relation.getLeft().ofTypeDecl() = getRight().toTypeDecl(); - eq Relation.getRight().ofTypeDecl() = getLeft().toTypeDecl(); - eq Program.getChild().ofTypeDecl() = null; + + inh RelationComponent RelationComponent.otherSide(); + eq Relation.getLeft().otherSide() = getRight(); + eq Relation.getRight().otherSide() = getLeft(); + eq Program.getChild().otherSide() = null; + + syn TypeDecl RelationComponent.ofTypeDecl() = otherSide().toTypeDecl(); syn boolean Component.isAlreadyDeclared() = !isTargetOfDirectedRelation() diff --git a/spec/jastadd/Backend.jadd b/spec/jastadd/Backend.jadd index 3506e24..2171c5d 100644 --- a/spec/jastadd/Backend.jadd +++ b/spec/jastadd/Backend.jadd @@ -112,13 +112,23 @@ 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); - public void RightDirection.generateAPI(StringBuilder sb) { - relation().getLeft().generateDirectedAPI(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); } - public void Bidirectional.generateAPI(StringBuilder sb) { +} +aspect BackendDirectedAPI { + public void RightDirection.generateAPI(StringBuilder sb) { + relation().getLeft().generateDirectedAPI(sb); } public abstract void RelationComponent.generateDirectedAPI(StringBuilder sb); @@ -180,16 +190,84 @@ aspect BackendAPI { sb.append(ind(2) + "}\n"); sb.append(ind(1) + "}\n"); } +} - inh Relation Direction.relation(); - eq Relation.getChild().relation() = this; - eq Program.getChild().relation() = null; +aspect BackendBidirectionalAPI { + public void Bidirectional.generateAPI(StringBuilder sb) { + RelationComponent l = relation().getLeft(); + RelationComponent r = relation().getRight(); - public String RelationComponent.nameCapitalized() { - return name().substring(0,1).toUpperCase() + name().substring(1); + if (l.multiplicityOne()) { + if (r.multiplicityOne()) { + l.generateBiOne(sb, false); + r.generateBiOne(sb, false); + } else if (r.multiplicityOpt()) { + l.generateBiOne(sb, false); + r.generateBiOne(sb, true); + } else if (r.multiplicityMany()) { + + } + } else if (l.multiplicityOpt()) { + if (r.multiplicityOne()) { + l.generateBiOne(sb, true); + r.generateBiOne(sb, false); + } else if (r.multiplicityOpt()) { + l.generateBiOne(sb, true); + r.generateBiOne(sb, true); + } else if (r.multiplicityMany()) { + + } + } else if (l.multiplicityMany()) { + if (r.multiplicityOne()) { + + } else if (r.multiplicityOpt()) { + + } else if (r.multiplicityMany()) { + + } + } + } + + public void RelationComponent.generateBiOne(StringBuilder sb, boolean isOpt) { + // Get + sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl()); + sb.append("." + name() + "() {\n"); + sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n"); + sb.append(ind(1) + "}\n"); + + // Set + sb.append(ind(1) + "public void " + toTypeDecl()); + sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + if (!isOpt) { + sb.append(ind(2) + "assertNotNull(o);\n"); + } + sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null) {\n"); + sb.append(ind(3) + "get" + getImplAttributeName() + "().set" + otherSide().getImplAttributeName() + "(null);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); + sb.append(ind(3) + "o.get" + otherSide().getImplAttributeName() + "().set" + getImplAttributeName() + "(null);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); + 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(1) + "}\n"); + + if (isOpt) { + // has + sb.append(ind(1) + "public boolean " + toTypeDecl()); + sb.append(".has" + nameCapitalized() + "() {\n"); + sb.append(ind(2) + "return " + name() + "() != null;\n"); + sb.append(ind(1) + "}\n"); + } } } + aspect PrettyPrint { public String Relation.prettyPrint() { return "rel " diff --git a/spec/jastadd/Errors.jrag b/spec/jastadd/Errors.jrag index b97c825..e3f5d60 100644 --- a/spec/jastadd/Errors.jrag +++ b/spec/jastadd/Errors.jrag @@ -32,7 +32,7 @@ aspect Errors { RelationComponent contributes error("The target of a directed relation may only have multiplicity 1") - when isTargetOfDirectedRelation() && !hasMultiplicityOne() + when isTargetOfDirectedRelation() && !multiplicityOne() to Program.errors(); } @@ -44,8 +44,12 @@ aspect HelpAttributes { eq Program.getChild().isToken() = false; eq TokenComponent.getTypeUse().isToken() = true; - syn boolean RelationComponent.hasMultiplicityOne() = false; - eq OneRelationComponent.hasMultiplicityOne() = true; + syn boolean RelationComponent.multiplicityOne() = false; + eq OneRelationComponent.multiplicityOne() = true; + syn boolean RelationComponent.multiplicityOpt() = false; + eq OptionalRelationComponent.multiplicityOpt() = true; + syn boolean RelationComponent.multiplicityMany() = false; + eq ManyRelationComponent.multiplicityMany() = true; } aspect ErrorMessage { diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..c9c2125 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,3 @@ +/AST/* +/AllBiGen.ast +/AllBiGen.jadd diff --git a/test/AllBi.relast b/test/AllBi.relast new file mode 100644 index 0000000..03f9ec1 --- /dev/null +++ b/test/AllBi.relast @@ -0,0 +1,15 @@ +Root ::= A* B*; +A ::= <Name>; +B ::= <Name>; + +rel A.b1 <-> B.a1; +rel A.b2 <-> B.a2?; +rel A.b3 <-> B.a3*; + +rel A.b4? <-> B.a4; +rel A.b5? <-> B.a5?; +rel A.b6? <-> B.a6*; + +rel A.b7* <-> B.a7; +rel A.b8* <-> B.a8?; +rel A.b9* <-> B.a9*; diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..1f34553 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,8 @@ +all: compile run +compile: + (cd .. && ant jar) + java -jar ../compiler.jar AllBi.relast --file + java -jar ../tools/jastadd2.jar --package=AST AllBiGen.ast AllBiGen.jadd Utils.jadd +run: + javac AST/*.java Test.java + java Test \ No newline at end of file diff --git a/test/Test.java b/test/Test.java new file mode 100644 index 0000000..38ae795 --- /dev/null +++ b/test/Test.java @@ -0,0 +1,248 @@ +import AST.*; + +public class Test { + private Root r; + private A a1; + private A a2; + private A a3; + private B b1; + private B b2; + private B b3; + + public static void main(String args[]) { + new Test().test(); + } + + public void test() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + } + + + + /** + * rel A.b1 <-> B.a1; + */ + private void test1() { + test11(); + test12(); + } + private void test11() { + // Init + setup(); + a1.setB1(b1); + a2.setB1(b2); + + // Change + a2.setB1(b1); + + assertNull(a1.b1()); + assertSame(a2.b1(), b1); + assertSame(b1.a1(), a2); + assertNull(b2.a1()); + } + private void test12() { + // Init + setup(); + a1.setB1(b2); + + // Change + a2.setB1(b2); + + assertNull(a1.b1()); + assertSame(a2.b1(), b2); + assertNull(b1.a1()); + assertSame(b2.a1(), a2); + } + + + + /** + * rel A.b2 <-> B.a2?; + */ + private void test2() { + test21(); + test22(); + } + private void test21() { + // Init + setup(); + a1.setB2(b1); + a2.setB2(b2); + + // Change + a2.setB2(b1); + + assertNull(a1.b2()); + assertSame(a2.b2(), b1); + assertSame(b1.a2(), a2); + assertNull(b2.a2()); + } + private void test22() { + // Init + setup(); + a1.setB2(b2); + + // Change + a2.setB2(b2); + + assertNull(a1.b2()); + assertSame(a2.b2(), b2); + assertNull(b1.a2()); + assertSame(b2.a2(), a2); + } + + + + /** + * rel A.b3 <-> B.a3*; + */ + private void test3() { + } + + + + /** + * rel A.b4? <-> B.a4; + */ + private void test4() { + test41(); + test42(); + } + private void test41() { + // Init + setup(); + a1.setB4(b1); + a2.setB4(b2); + + // Change + a2.setB4(b1); + + assertNull(a1.b4()); + assertSame(a2.b4(), b1); + assertSame(b1.a4(), a2); + assertNull(b2.a4()); + } + private void test42() { + // Init + setup(); + a1.setB4(b2); + + // Change + a2.setB4(b2); + + assertNull(a1.b4()); + assertSame(a2.b4(), b2); + assertNull(b1.a4()); + assertSame(b2.a4(), a2); + } + + + + /** + * rel A.b5? <-> B.a5?; + */ + private void test5() { + test51(); + test52(); + } + private void test51() { + // Init + setup(); + a1.setB5(b1); + a2.setB5(b2); + + // Change + a2.setB5(b1); + + assertNull(a1.b5()); + assertSame(a2.b5(), b1); + assertSame(b1.a5(), a2); + assertNull(b2.a5()); + } + private void test52() { + // Init + setup(); + a1.setB5(b2); + + // Change + a2.setB5(b2); + + assertNull(a1.b5()); + assertSame(a2.b5(), b2); + assertNull(b1.a5()); + assertSame(b2.a5(), a2); + } + + + + /** + * rel A.b6? <-> B.a6*; + */ + private void test6() { + } + + + + /** + * rel A.b7* <-> B.a7; + */ + private void test7() { + } + + + + /** + * rel A.b8* <-> B.a8?; + */ + private void test8() { + } + + + + /** + * rel A.b9* <-> B.a9*; + */ + private void test9() { + } + + + + private void setup() { + r = new Root(); + a1 = new A("a1"); + a2 = new A("a2"); + a3 = new A("a3"); + b1 = new B("b1"); + b2 = new B("b2"); + b3 = new B("b3"); + + r.addA(a1); + r.addA(a2); + r.addA(a3); + r.addB(b1); + r.addB(b2); + r.addB(b3); + } + + private void assertNull(Object obj) { + check(obj == null); + } + private void assertSame(Object o1, Object o2) { + check(o1 == o2); + } + + private void check(boolean b) { + if (!b) { + throw new RuntimeException(); + } + + } +} \ No newline at end of file diff --git a/test/Utils.jadd b/test/Utils.jadd new file mode 100644 index 0000000..d7acb1b --- /dev/null +++ b/test/Utils.jadd @@ -0,0 +1,9 @@ +aspect Utils { + public String A.toString() { + return getName(); + } + + public String B.toString() { + return getName(); + } +} \ No newline at end of file -- GitLab