diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-06-01 18:37:20 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-06-01 20:17:47 +0200 |
commit | 07b4048828d9ef8126282c4626dd3f0729213d91 (patch) | |
tree | 4523d01e7802585ae3a3c7ec622d1b0a1e3dfa91 /subprojects/language/src | |
parent | fix(reasoning): candidate count literal rewriting (diff) | |
download | refinery-07b4048828d9ef8126282c4626dd3f0729213d91.tar.gz refinery-07b4048828d9ef8126282c4626dd3f0729213d91.tar.zst refinery-07b4048828d9ef8126282c4626dd3f0729213d91.zip |
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.
Diffstat (limited to 'subprojects/language/src')
4 files changed, 46 insertions, 11 deletions
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: | |||
45 | "extern" "aggregator" name=Identifier "."; | 45 | "extern" "aggregator" name=Identifier "."; |
46 | 46 | ||
47 | enum ReferenceKind: | 47 | enum ReferenceKind: |
48 | REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; | 48 | REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container" | PARTIAL="partial"; |
49 | 49 | ||
50 | ReferenceDeclaration: | 50 | ReferenceDeclaration: |
51 | (referenceType=[Relation|NonContainmentQualifiedName] | | 51 | (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 { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | public static boolean isImplicit(EObject eObject) { | 44 | public static boolean isImplicit(EObject eObject) { |
45 | if (eObject instanceof Node node) { | 45 | return switch (eObject) { |
46 | return isImplicitNode(node); | 46 | case Node node -> isImplicitNode(node); |
47 | } else if (eObject instanceof Variable variable) { | 47 | case Variable variable -> isImplicitVariable(variable); |
48 | return isImplicitVariable(variable); | 48 | default -> false; |
49 | } else { | 49 | }; |
50 | return false; | ||
51 | } | ||
52 | } | 50 | } |
53 | 51 | ||
54 | public static boolean isError(EObject eObject) { | 52 | public static boolean isError(EObject eObject) { |
@@ -119,7 +117,7 @@ public final class ProblemUtil { | |||
119 | return false; | 117 | return false; |
120 | } | 118 | } |
121 | return switch (kind) { | 119 | return switch (kind) { |
122 | case CONTAINMENT -> false; | 120 | case CONTAINMENT, PARTIAL -> false; |
123 | case CONTAINER -> true; | 121 | case CONTAINER -> true; |
124 | case DEFAULT, REFERENCE -> { | 122 | case DEFAULT, REFERENCE -> { |
125 | var opposite = referenceDeclaration.getOpposite(); | 123 | 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 { | |||
318 | referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, | 318 | referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, |
319 | INVALID_OPPOSITE_ISSUE); | 319 | INVALID_OPPOSITE_ISSUE); |
320 | } | 320 | } |
321 | } else if (kind == ReferenceKind.PARTIAL && opposite != null && opposite.getKind() != ReferenceKind.PARTIAL) { | ||
322 | acceptError("Opposite '%s' of partial reference '%s' is not a partial reference." | ||
323 | .formatted(opposite.getName(), referenceDeclaration.getName()), | ||
324 | referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, | ||
325 | INVALID_OPPOSITE_ISSUE); | ||
321 | } | 326 | } |
322 | } | 327 | } |
323 | 328 | ||
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 { | |||
57 | class Foo { | 57 | class Foo { |
58 | Foo foo[] opposite foo | 58 | Foo foo[] opposite foo |
59 | } | 59 | } |
60 | """, """ | ||
61 | class Foo { | ||
62 | partial Bar bar opposite foo | ||
63 | } | ||
64 | |||
65 | class Bar { | ||
66 | partial Foo foo opposite bar | ||
67 | } | ||
68 | """, """ | ||
69 | class Foo { | ||
70 | partial Foo foo[] opposite foo | ||
71 | } | ||
60 | """}) | 72 | """}) |
61 | void validOppositeTest(String text) { | 73 | void validOppositeTest(String text) { |
62 | var problem = parseHelper.parse(text); | 74 | var problem = parseHelper.parse(text); |
@@ -188,7 +200,7 @@ class OppositeValidationTest { | |||
188 | } | 200 | } |
189 | 201 | ||
190 | @ParameterizedTest | 202 | @ParameterizedTest |
191 | @ValueSource(strings = {"Foo foo", "container Foo foo"}) | 203 | @ValueSource(strings = {"Foo foo", "container Foo foo", "partial Foo foo"}) |
192 | void containerInvalidOppositeTest(String reference) { | 204 | void containerInvalidOppositeTest(String reference) { |
193 | var problem = parseHelper.parse(""" | 205 | var problem = parseHelper.parse(""" |
194 | class Foo { | 206 | class Foo { |
@@ -203,7 +215,27 @@ class OppositeValidationTest { | |||
203 | assertThat(issues, hasItem(allOf( | 215 | assertThat(issues, hasItem(allOf( |
204 | hasProperty("severity", is(Diagnostic.ERROR)), | 216 | hasProperty("severity", is(Diagnostic.ERROR)), |
205 | hasProperty("issueCode", is(ProblemValidator.INVALID_OPPOSITE_ISSUE)), | 217 | hasProperty("issueCode", is(ProblemValidator.INVALID_OPPOSITE_ISSUE)), |
206 | hasProperty("message", stringContainsInOrder("foo", "bar")) | 218 | hasProperty("message", stringContainsInOrder("foo", "container", "bar")) |
219 | ))); | ||
220 | } | ||
221 | |||
222 | @ParameterizedTest | ||
223 | @ValueSource(strings = {"Foo foo", "contains Foo foo", "container Foo foo"}) | ||
224 | void partialWithConcreteOppositeTest(String reference) { | ||
225 | var problem = parseHelper.parse(""" | ||
226 | class Foo { | ||
227 | partial Bar bar opposite foo | ||
228 | } | ||
229 | |||
230 | class Bar { | ||
231 | %s opposite bar | ||
232 | } | ||
233 | """.formatted(reference)); | ||
234 | var issues = problem.validate(); | ||
235 | assertThat(issues, hasItem(allOf( | ||
236 | hasProperty("severity", is(Diagnostic.ERROR)), | ||
237 | hasProperty("issueCode", is(ProblemValidator.INVALID_OPPOSITE_ISSUE)), | ||
238 | hasProperty("message", stringContainsInOrder("foo", "partial", "bar")) | ||
207 | ))); | 239 | ))); |
208 | } | 240 | } |
209 | } | 241 | } |