diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-06-28 17:23:50 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-06-28 17:23:50 +0200 |
commit | cad018dc055542f5af82d376a7329869c25ffc3a (patch) | |
tree | 1938327c859ac1f3621f20ae3fd02d0b4e550569 /subprojects/language | |
parent | refactor(generator): spelling (diff) | |
download | refinery-cad018dc055542f5af82d376a7329869c25ffc3a.tar.gz refinery-cad018dc055542f5af82d376a7329869c25ffc3a.tar.zst refinery-cad018dc055542f5af82d376a7329869c25ffc3a.zip |
refactor(language): improve propagation rule validation
Diffstat (limited to 'subprojects/language')
-rw-r--r-- | subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | 63 |
1 files changed, 61 insertions, 2 deletions
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 84218f17..63c8631c 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 | |||
@@ -55,6 +55,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
55 | public static final String TYPE_ERROR = ISSUE_PREFIX + "TYPE_ERROR"; | 55 | public static final String TYPE_ERROR = ISSUE_PREFIX + "TYPE_ERROR"; |
56 | public static final String VARIABLE_WITHOUT_EXISTS = ISSUE_PREFIX + "VARIABLE_WITHOUT_EXISTS"; | 56 | public static final String VARIABLE_WITHOUT_EXISTS = ISSUE_PREFIX + "VARIABLE_WITHOUT_EXISTS"; |
57 | public static final String UNUSED_PARTIAL_RELATION = ISSUE_PREFIX + "UNUSED_PARTIAL_RELATION"; | 57 | public static final String UNUSED_PARTIAL_RELATION = ISSUE_PREFIX + "UNUSED_PARTIAL_RELATION"; |
58 | public static final String UNUSED_PARAMETER = ISSUE_PREFIX + "UNUSED_PARAMETER"; | ||
58 | 59 | ||
59 | @Inject | 60 | @Inject |
60 | private ReferenceCounter referenceCounter; | 61 | private ReferenceCounter referenceCounter; |
@@ -344,7 +345,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
344 | if (referenceDeclaration.getKind() == ReferenceKind.PARTIAL && | 345 | if (referenceDeclaration.getKind() == ReferenceKind.PARTIAL && |
345 | !actionTargetCollector.isActionTarget(referenceDeclaration)) { | 346 | !actionTargetCollector.isActionTarget(referenceDeclaration)) { |
346 | var message = "Add decision or propagation rules to refine partial relation '%s'." | 347 | var message = "Add decision or propagation rules to refine partial relation '%s'." |
347 | .formatted(referenceDeclaration.getName()); | 348 | .formatted(referenceDeclaration.getName()); |
348 | acceptWarning(message, referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__KIND, 0, | 349 | acceptWarning(message, referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__KIND, 0, |
349 | UNUSED_PARTIAL_RELATION); | 350 | UNUSED_PARTIAL_RELATION); |
350 | } | 351 | } |
@@ -445,7 +446,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
445 | String message; | 446 | String message; |
446 | if (ProblemUtil.isSingletonVariable(variable)) { | 447 | if (ProblemUtil.isSingletonVariable(variable)) { |
447 | message = ("Remove the singleton variable marker '_' and clarify the quantification of variable " + | 448 | message = ("Remove the singleton variable marker '_' and clarify the quantification of variable " + |
448 | "'%s'.").formatted(name); | 449 | "'%s'.").formatted(name); |
449 | } else { | 450 | } else { |
450 | message = ("Add a 'must exists(%s)', 'may exists(%s)', or 'may !exists(%s)' constraint to " + | 451 | message = ("Add a 'must exists(%s)', 'may exists(%s)', or 'may !exists(%s)' constraint to " + |
451 | "clarify the quantification of variable '%s'.").formatted(name, name, name, name); | 452 | "clarify the quantification of variable '%s'.").formatted(name, name, name, name); |
@@ -457,6 +458,64 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
457 | } | 458 | } |
458 | 459 | ||
459 | @Check | 460 | @Check |
461 | public void checkRuleParameters(RuleDefinition ruleDefinition) { | ||
462 | var useCounts = new LinkedHashMap<Parameter, Integer>(); | ||
463 | for (var parameter : ruleDefinition.getParameters()) { | ||
464 | useCounts.put(parameter, 0); | ||
465 | } | ||
466 | var consequents = ruleDefinition.getConsequents(); | ||
467 | for (var consequent : consequents) { | ||
468 | countRuleParameterUsages(consequent, useCounts); | ||
469 | } | ||
470 | var isError = ruleDefinition.getKind() == RuleKind.PROPAGATION; | ||
471 | int consequentCount = consequents.size(); | ||
472 | for (var entry : useCounts.entrySet()) { | ||
473 | if (entry.getValue() < consequentCount) { | ||
474 | var parameter = entry.getKey(); | ||
475 | var message = "Unused rule parameter '%s'.".formatted(parameter.getName()); | ||
476 | if (isError) { | ||
477 | acceptError(message, parameter, ProblemPackage.Literals.NAMED_ELEMENT__NAME, 0, UNUSED_PARAMETER); | ||
478 | } else { | ||
479 | acceptWarning(message, parameter, ProblemPackage.Literals.NAMED_ELEMENT__NAME, 0, | ||
480 | UNUSED_PARAMETER); | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | @Check | ||
487 | public void checkPropagationRuleConsequent(Consequent consequent) { | ||
488 | var rule = EcoreUtil2.getContainerOfType(consequent, RuleDefinition.class); | ||
489 | if (rule == null || rule.getKind() != RuleKind.PROPAGATION) { | ||
490 | return; | ||
491 | } | ||
492 | if (consequent.getActions().size() > 1) { | ||
493 | acceptError("Propagation rules must have exactly one action.", consequent, null, 0, INVALID_RULE_ISSUE); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | private static void countRuleParameterUsages(Consequent consequent, Map<Parameter, Integer> useCounts) { | ||
498 | var usedParameters = new HashSet<Parameter>(); | ||
499 | for (var action : consequent.getActions()) { | ||
500 | if (action instanceof AssertionAction assertionAction) { | ||
501 | collectUsedParameters(assertionAction, usedParameters); | ||
502 | } | ||
503 | } | ||
504 | for (var usedParameter : usedParameters) { | ||
505 | useCounts.compute(usedParameter, (ignored, value) -> value == null ? 0 : value + 1); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | private static void collectUsedParameters(AssertionAction assertionAction, HashSet<Parameter> usedParameters) { | ||
510 | for (var argument : assertionAction.getArguments()) { | ||
511 | if (argument instanceof NodeAssertionArgument nodeAssertionArgument && | ||
512 | nodeAssertionArgument.getNode() instanceof Parameter usedParameter) { | ||
513 | usedParameters.add(usedParameter); | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | |||
518 | @Check | ||
460 | public void checkAssertion(AbstractAssertion assertion) { | 519 | public void checkAssertion(AbstractAssertion assertion) { |
461 | var relation = assertion.getRelation(); | 520 | var relation = assertion.getRelation(); |
462 | if (relation instanceof DatatypeDeclaration) { | 521 | if (relation instanceof DatatypeDeclaration) { |