aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-06-28 17:23:50 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-06-28 17:23:50 +0200
commitcad018dc055542f5af82d376a7329869c25ffc3a (patch)
tree1938327c859ac1f3621f20ae3fd02d0b4e550569 /subprojects
parentrefactor(generator): spelling (diff)
downloadrefinery-cad018dc055542f5af82d376a7329869c25ffc3a.tar.gz
refinery-cad018dc055542f5af82d376a7329869c25ffc3a.tar.zst
refinery-cad018dc055542f5af82d376a7329869c25ffc3a.zip
refactor(language): improve propagation rule validation
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java63
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) {