From 07b4048828d9ef8126282c4626dd3f0729213d91 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 1 Jun 2024 18:37:20 +0200 Subject: feat: partial references References marked as partial are not concretized during model generation. The should be managed by the user manually using propagation rules instead. --- .../java/tools/refinery/language/Problem.xtext | 2 +- .../tools/refinery/language/utils/ProblemUtil.java | 14 ++++----- .../language/validation/ProblemValidator.java | 5 +++ .../tests/validation/OppositeValidationTest.java | 36 ++++++++++++++++++++-- 4 files changed, 46 insertions(+), 11 deletions(-) (limited to 'subprojects/language') diff --git a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext index ebb5bf71..10e994a0 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext @@ -45,7 +45,7 @@ AggregatorDeclaration: "extern" "aggregator" name=Identifier "."; enum ReferenceKind: - REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; + REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container" | PARTIAL="partial"; ReferenceDeclaration: (referenceType=[Relation|NonContainmentQualifiedName] | diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java index 9daa8f61..e1820261 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java @@ -42,13 +42,11 @@ public final class ProblemUtil { } public static boolean isImplicit(EObject eObject) { - if (eObject instanceof Node node) { - return isImplicitNode(node); - } else if (eObject instanceof Variable variable) { - return isImplicitVariable(variable); - } else { - return false; - } + return switch (eObject) { + case Node node -> isImplicitNode(node); + case Variable variable -> isImplicitVariable(variable); + default -> false; + }; } public static boolean isError(EObject eObject) { @@ -119,7 +117,7 @@ public final class ProblemUtil { return false; } return switch (kind) { - case CONTAINMENT -> false; + case CONTAINMENT, PARTIAL -> false; case CONTAINER -> true; case DEFAULT, REFERENCE -> { var opposite = referenceDeclaration.getOpposite(); diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index 9f5fdeae..754572d1 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java @@ -318,6 +318,11 @@ public class ProblemValidator extends AbstractProblemValidator { referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, INVALID_OPPOSITE_ISSUE); } + } else if (kind == ReferenceKind.PARTIAL && opposite != null && opposite.getKind() != ReferenceKind.PARTIAL) { + acceptError("Opposite '%s' of partial reference '%s' is not a partial reference." + .formatted(opposite.getName(), referenceDeclaration.getName()), + referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, + INVALID_OPPOSITE_ISSUE); } } diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java index 57602377..d73ef8e7 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java @@ -57,6 +57,18 @@ class OppositeValidationTest { class Foo { Foo foo[] opposite foo } + """, """ + class Foo { + partial Bar bar opposite foo + } + + class Bar { + partial Foo foo opposite bar + } + """, """ + class Foo { + partial Foo foo[] opposite foo + } """}) void validOppositeTest(String text) { var problem = parseHelper.parse(text); @@ -188,7 +200,7 @@ class OppositeValidationTest { } @ParameterizedTest - @ValueSource(strings = {"Foo foo", "container Foo foo"}) + @ValueSource(strings = {"Foo foo", "container Foo foo", "partial Foo foo"}) void containerInvalidOppositeTest(String reference) { var problem = parseHelper.parse(""" class Foo { @@ -203,7 +215,27 @@ class OppositeValidationTest { assertThat(issues, hasItem(allOf( hasProperty("severity", is(Diagnostic.ERROR)), hasProperty("issueCode", is(ProblemValidator.INVALID_OPPOSITE_ISSUE)), - hasProperty("message", stringContainsInOrder("foo", "bar")) + hasProperty("message", stringContainsInOrder("foo", "container", "bar")) + ))); + } + + @ParameterizedTest + @ValueSource(strings = {"Foo foo", "contains Foo foo", "container Foo foo"}) + void partialWithConcreteOppositeTest(String reference) { + var problem = parseHelper.parse(""" + class Foo { + partial Bar bar opposite foo + } + + class Bar { + %s opposite bar + } + """.formatted(reference)); + var issues = problem.validate(); + assertThat(issues, hasItem(allOf( + hasProperty("severity", is(Diagnostic.ERROR)), + hasProperty("issueCode", is(ProblemValidator.INVALID_OPPOSITE_ISSUE)), + hasProperty("message", stringContainsInOrder("foo", "partial", "bar")) ))); } } -- cgit v1.2.3-54-g00ecf