aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language/src/main/java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-19 14:33:58 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-19 14:41:17 +0100
commitadd263cb783ba164c6353482690b53ec8743a648 (patch)
tree0a842960e27ad25d458c18f7bd9f8b4bf5b89b6c /subprojects/language/src/main/java
parentfeat(language): arity validation (diff)
downloadrefinery-add263cb783ba164c6353482690b53ec8743a648.tar.gz
refinery-add263cb783ba164c6353482690b53ec8743a648.tar.zst
refinery-add263cb783ba164c6353482690b53ec8743a648.zip
feat(langauge): validate exists and equals
Diffstat (limited to 'subprojects/language/src/main/java')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java114
1 files changed, 106 insertions, 8 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 00ae4531..8bda4b95 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
@@ -14,7 +14,9 @@ import org.eclipse.emf.ecore.EObject;
14import org.eclipse.emf.ecore.EReference; 14import org.eclipse.emf.ecore.EReference;
15import org.eclipse.xtext.EcoreUtil2; 15import org.eclipse.xtext.EcoreUtil2;
16import org.eclipse.xtext.validation.Check; 16import org.eclipse.xtext.validation.Check;
17import org.jetbrains.annotations.Nullable;
17import tools.refinery.language.model.problem.*; 18import tools.refinery.language.model.problem.*;
19import tools.refinery.language.utils.ProblemDesugarer;
18import tools.refinery.language.utils.ProblemUtil; 20import tools.refinery.language.utils.ProblemUtil;
19 21
20import java.util.ArrayList; 22import java.util.ArrayList;
@@ -53,9 +55,16 @@ public class ProblemValidator extends AbstractProblemValidator {
53 55
54 public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE"; 56 public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE";
55 57
58 public static final String INVALID_VALUE_ISSUE = ISSUE_PREFIX + "INVALID_VALUE";
59
60 public static final String UNSUPPORTED_ASSERTION_ISSUE = ISSUE_PREFIX + "UNSUPPORTED_ASSERTION";
61
56 @Inject 62 @Inject
57 private ReferenceCounter referenceCounter; 63 private ReferenceCounter referenceCounter;
58 64
65 @Inject
66 private ProblemDesugarer desugarer;
67
59 @Check 68 @Check
60 public void checkSingletonVariable(VariableOrNodeExpr expr) { 69 public void checkSingletonVariable(VariableOrNodeExpr expr) {
61 var variableOrNode = expr.getVariableOrNode(); 70 var variableOrNode = expr.getVariableOrNode();
@@ -203,7 +212,7 @@ public class ProblemValidator extends AbstractProblemValidator {
203 } 212 }
204 213
205 @Check 214 @Check
206 void checkContainerOpposite(ReferenceDeclaration referenceDeclaration) { 215 public void checkContainerOpposite(ReferenceDeclaration referenceDeclaration) {
207 var kind = referenceDeclaration.getKind(); 216 var kind = referenceDeclaration.getKind();
208 var opposite = referenceDeclaration.getOpposite(); 217 var opposite = referenceDeclaration.getOpposite();
209 if (opposite != null && opposite.eIsProxy()) { 218 if (opposite != null && opposite.eIsProxy()) {
@@ -231,7 +240,7 @@ public class ProblemValidator extends AbstractProblemValidator {
231 } 240 }
232 241
233 @Check 242 @Check
234 void checkSupertypes(ClassDeclaration classDeclaration) { 243 public void checkSupertypes(ClassDeclaration classDeclaration) {
235 var supertypes = classDeclaration.getSuperTypes(); 244 var supertypes = classDeclaration.getSuperTypes();
236 int supertypeCount = supertypes.size(); 245 int supertypeCount = supertypes.size();
237 for (int i = 0; i < supertypeCount; i++) { 246 for (int i = 0; i < supertypeCount; i++) {
@@ -246,7 +255,7 @@ public class ProblemValidator extends AbstractProblemValidator {
246 } 255 }
247 256
248 @Check 257 @Check
249 void checkReferenceType(ReferenceDeclaration referenceDeclaration) { 258 public void checkReferenceType(ReferenceDeclaration referenceDeclaration) {
250 if (referenceDeclaration.getKind() == ReferenceKind.REFERENCE && 259 if (referenceDeclaration.getKind() == ReferenceKind.REFERENCE &&
251 !ProblemUtil.isContainerReference(referenceDeclaration)) { 260 !ProblemUtil.isContainerReference(referenceDeclaration)) {
252 checkArity(referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__REFERENCE_TYPE, 1); 261 checkArity(referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__REFERENCE_TYPE, 1);
@@ -264,12 +273,12 @@ public class ProblemValidator extends AbstractProblemValidator {
264 } 273 }
265 274
266 @Check 275 @Check
267 void checkParameterType(Parameter parameter) { 276 public void checkParameterType(Parameter parameter) {
268 checkArity(parameter, ProblemPackage.Literals.PARAMETER__PARAMETER_TYPE, 1); 277 checkArity(parameter, ProblemPackage.Literals.PARAMETER__PARAMETER_TYPE, 1);
269 } 278 }
270 279
271 @Check 280 @Check
272 void checkAtom(Atom atom) { 281 public void checkAtom(Atom atom) {
273 int argumentCount = atom.getArguments().size(); 282 int argumentCount = atom.getArguments().size();
274 checkArity(atom, ProblemPackage.Literals.ATOM__RELATION, argumentCount); 283 checkArity(atom, ProblemPackage.Literals.ATOM__RELATION, argumentCount);
275 if (atom.isTransitiveClosure() && argumentCount != 2) { 284 if (atom.isTransitiveClosure() && argumentCount != 2) {
@@ -281,17 +290,21 @@ public class ProblemValidator extends AbstractProblemValidator {
281 } 290 }
282 291
283 @Check 292 @Check
284 void checkAssertion(Assertion assertion) { 293 public void checkAssertion(Assertion assertion) {
285 int argumentCount = assertion.getArguments().size(); 294 int argumentCount = assertion.getArguments().size();
295 if (!(assertion.getValue() instanceof LogicConstant)) {
296 var message = "Assertion value must be one of 'true', 'false', 'unknown', or 'error'.";
297 acceptError(message, assertion, ProblemPackage.Literals.ASSERTION__VALUE, 0, INVALID_VALUE_ISSUE);
298 }
286 checkArity(assertion, ProblemPackage.Literals.ASSERTION__RELATION, argumentCount); 299 checkArity(assertion, ProblemPackage.Literals.ASSERTION__RELATION, argumentCount);
287 } 300 }
288 301
289 @Check 302 @Check
290 void checkTypeScope(TypeScope typeScope) { 303 public void checkTypeScope(TypeScope typeScope) {
291 checkArity(typeScope, ProblemPackage.Literals.TYPE_SCOPE__TARGET_TYPE, 1); 304 checkArity(typeScope, ProblemPackage.Literals.TYPE_SCOPE__TARGET_TYPE, 1);
292 } 305 }
293 306
294 void checkArity(EObject eObject, EReference reference, int expectedArity) { 307 private void checkArity(EObject eObject, EReference reference, int expectedArity) {
295 var value = eObject.eGet(reference); 308 var value = eObject.eGet(reference);
296 if (!(value instanceof Relation relation) || relation.eIsProxy()) { 309 if (!(value instanceof Relation relation) || relation.eIsProxy()) {
297 // Feature does not point to a {@link Relation}, we are probably already emitting another error. 310 // Feature does not point to a {@link Relation}, we are probably already emitting another error.
@@ -305,4 +318,89 @@ public class ProblemValidator extends AbstractProblemValidator {
305 .formatted(relation.getName(), expectedArity, arity); 318 .formatted(relation.getName(), expectedArity, arity);
306 acceptError(message, eObject, reference, 0, INVALID_ARITY_ISSUE); 319 acceptError(message, eObject, reference, 0, INVALID_ARITY_ISSUE);
307 } 320 }
321
322 @Check
323 public void checkMultiObjectAssertion(Assertion assertion) {
324 var builtinSymbolsOption = desugarer.getBuiltinSymbols(assertion);
325 if (builtinSymbolsOption.isEmpty()) {
326 return;
327 }
328 var builtinSymbols = builtinSymbolsOption.get();
329 var relation = assertion.getRelation();
330 boolean isExists = builtinSymbols.exists().equals(relation);
331 boolean isEquals = builtinSymbols.equals().equals(relation);
332 if ((!isExists && !isEquals) || !(assertion.getValue() instanceof LogicConstant logicConstant)) {
333 return;
334 }
335 var value = logicConstant.getLogicValue();
336 if (assertion.isDefault()) {
337 acceptError("Default assertions for 'exists' and 'equals' are not supported.", assertion,
338 ProblemPackage.Literals.ASSERTION__DEFAULT, 0, UNSUPPORTED_ASSERTION_ISSUE);
339 return;
340 }
341 if (value == LogicValue.ERROR) {
342 acceptError("Error assertions for 'exists' and 'equals' are not supported.", assertion,
343 ProblemPackage.Literals.ASSERTION__DEFAULT, 0, UNSUPPORTED_ASSERTION_ISSUE);
344 return;
345 }
346 if (isExists) {
347 checkExistsAssertion(assertion, value);
348 return;
349 }
350 checkEqualsAssertion(assertion, value);
351 }
352
353 private void checkExistsAssertion(Assertion assertion, LogicValue value) {
354 if (value == LogicValue.TRUE || value == LogicValue.UNKNOWN) {
355 // {@code true} is always a valid value for {@code exists}, while {@code unknown} values may always be
356 // refined to {@code true} if necessary (e.g., for individual nodes).
357 return;
358 }
359 var arguments = assertion.getArguments();
360 if (arguments.isEmpty()) {
361 // We already report an error on invalid arity.
362 return;
363 }
364 var node = getNodeArgumentForMultiObjectAssertion(arguments.get(0));
365 if (node != null && !node.eIsProxy() && ProblemUtil.isIndividualNode(node)) {
366 acceptError("Individual nodes must exist.", assertion, null, 0, UNSUPPORTED_ASSERTION_ISSUE);
367 }
368 }
369
370 private void checkEqualsAssertion(Assertion assertion, LogicValue value) {
371 var arguments = assertion.getArguments();
372 if (arguments.size() < 2) {
373 // We already report an error on invalid arity.
374 return;
375 }
376 var left = getNodeArgumentForMultiObjectAssertion(arguments.get(0));
377 var right = getNodeArgumentForMultiObjectAssertion(arguments.get(1));
378 if (left == null || left.eIsProxy() || right == null || right.eIsProxy()) {
379 return;
380 }
381 if (left.equals(right)) {
382 if (value == LogicValue.FALSE || value == LogicValue.ERROR) {
383 acceptError("A node cannot be necessarily unequal to itself.", assertion, null, 0,
384 UNSUPPORTED_ASSERTION_ISSUE);
385 }
386 } else {
387 if (value != LogicValue.FALSE) {
388 acceptError("Equalities between distinct nodes are not supported.", assertion, null, 0,
389 UNSUPPORTED_ASSERTION_ISSUE);
390 }
391 }
392 }
393
394 @Nullable
395 private Node getNodeArgumentForMultiObjectAssertion(AssertionArgument argument) {
396 if (argument instanceof WildcardAssertionArgument) {
397 acceptError("Wildcard arguments for 'exists' are not supported.", argument, null, 0,
398 UNSUPPORTED_ASSERTION_ISSUE);
399 return null;
400 }
401 if (argument instanceof NodeAssertionArgument nodeAssertionArgument) {
402 return nodeAssertionArgument.getNode();
403 }
404 throw new IllegalArgumentException("Unknown assertion argument: " + argument);
405 }
308} 406}