aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language/src/main/java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-18 19:43:09 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-19 14:41:17 +0100
commit392242099439fd3f21abb87d55ce94050e71ccb5 (patch)
tree2be45d93ae8ebbd3dd0cc051c3db26f0318cb7d2 /subprojects/language/src/main/java
parentfix: upper and lower scopes (diff)
downloadrefinery-392242099439fd3f21abb87d55ce94050e71ccb5.tar.gz
refinery-392242099439fd3f21abb87d55ce94050e71ccb5.tar.zst
refinery-392242099439fd3f21abb87d55ce94050e71ccb5.zip
feat(language): arity validation
Diffstat (limited to 'subprojects/language/src/main/java')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java122
1 files changed, 104 insertions, 18 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 21b175ee..00ae4531 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
@@ -10,6 +10,8 @@
10package tools.refinery.language.validation; 10package tools.refinery.language.validation;
11 11
12import com.google.inject.Inject; 12import com.google.inject.Inject;
13import org.eclipse.emf.ecore.EObject;
14import org.eclipse.emf.ecore.EReference;
13import org.eclipse.xtext.EcoreUtil2; 15import org.eclipse.xtext.EcoreUtil2;
14import org.eclipse.xtext.validation.Check; 16import org.eclipse.xtext.validation.Check;
15import tools.refinery.language.model.problem.*; 17import tools.refinery.language.model.problem.*;
@@ -43,6 +45,14 @@ public class ProblemValidator extends AbstractProblemValidator {
43 45
44 public static final String INVALID_OPPOSITE_ISSUE = ISSUE_PREFIX + "INVALID_OPPOSITE"; 46 public static final String INVALID_OPPOSITE_ISSUE = ISSUE_PREFIX + "INVALID_OPPOSITE";
45 47
48 public static final String INVALID_SUPERTYPE_ISSUE = ISSUE_PREFIX + "INVALID_SUPERTYPE";
49
50 public static final String INVALID_REFERENCE_TYPE_ISSUE = ISSUE_PREFIX + "INVALID_REFERENCE_TYPE";
51
52 public static final String INVALID_ARITY_ISSUE = ISSUE_PREFIX + "INVALID_ARITY";
53
54 public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE";
55
46 @Inject 56 @Inject
47 private ReferenceCounter referenceCounter; 57 private ReferenceCounter referenceCounter;
48 58
@@ -173,24 +183,24 @@ public class ProblemValidator extends AbstractProblemValidator {
173 } 183 }
174 return; 184 return;
175 } 185 }
176 if (!referenceDeclaration.equals(oppositeOfOpposite)) { 186 if (!referenceDeclaration.equals(oppositeOfOpposite)) {
177 var messageBuilder = new StringBuilder() 187 var messageBuilder = new StringBuilder()
178 .append("Expected reference '") 188 .append("Expected reference '")
179 .append(opposite.getName()) 189 .append(opposite.getName())
180 .append("' to have opposite '") 190 .append("' to have opposite '")
181 .append(referenceDeclaration.getName()) 191 .append(referenceDeclaration.getName())
182 .append("'"); 192 .append("'");
183 var oppositeOfOppositeName = oppositeOfOpposite.getName(); 193 var oppositeOfOppositeName = oppositeOfOpposite.getName();
184 if (oppositeOfOppositeName != null) { 194 if (oppositeOfOppositeName != null) {
185 messageBuilder.append(", got '") 195 messageBuilder.append(", got '")
186 .append(oppositeOfOppositeName) 196 .append(oppositeOfOppositeName)
187 .append("' instead"); 197 .append("' instead");
188 } 198 }
189 messageBuilder.append("."); 199 messageBuilder.append(".");
190 acceptError(messageBuilder.toString(), referenceDeclaration, 200 acceptError(messageBuilder.toString(), referenceDeclaration,
191 ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, INVALID_OPPOSITE_ISSUE); 201 ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE, 0, INVALID_OPPOSITE_ISSUE);
192 } 202 }
193 } 203 }
194 204
195 @Check 205 @Check
196 void checkContainerOpposite(ReferenceDeclaration referenceDeclaration) { 206 void checkContainerOpposite(ReferenceDeclaration referenceDeclaration) {
@@ -219,4 +229,80 @@ public class ProblemValidator extends AbstractProblemValidator {
219 } 229 }
220 } 230 }
221 } 231 }
232
233 @Check
234 void checkSupertypes(ClassDeclaration classDeclaration) {
235 var supertypes = classDeclaration.getSuperTypes();
236 int supertypeCount = supertypes.size();
237 for (int i = 0; i < supertypeCount; i++) {
238 var supertype = supertypes.get(i);
239 if (!supertype.eIsProxy() && !(supertype instanceof ClassDeclaration)) {
240 var message = "Supertype '%s' of '%s' is not a class."
241 .formatted(supertype.getName(), classDeclaration.getName());
242 acceptError(message, classDeclaration, ProblemPackage.Literals.CLASS_DECLARATION__SUPER_TYPES, i,
243 INVALID_SUPERTYPE_ISSUE);
244 }
245 }
246 }
247
248 @Check
249 void checkReferenceType(ReferenceDeclaration referenceDeclaration) {
250 if (referenceDeclaration.getKind() == ReferenceKind.REFERENCE &&
251 !ProblemUtil.isContainerReference(referenceDeclaration)) {
252 checkArity(referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__REFERENCE_TYPE, 1);
253 return;
254 }
255 var referenceType = referenceDeclaration.getReferenceType();
256 if (referenceType == null || referenceType.eIsProxy() || referenceType instanceof ClassDeclaration) {
257 // Either correct, or a missing reference type where we are probably already emitting another error.
258 return;
259 }
260 var message = "Reference type '%s' of the containment or container reference '%s' is not a class."
261 .formatted(referenceType.getName(), referenceDeclaration.getName());
262 acceptError(message, referenceDeclaration, ProblemPackage.Literals.REFERENCE_DECLARATION__REFERENCE_TYPE, 0,
263 INVALID_REFERENCE_TYPE_ISSUE);
264 }
265
266 @Check
267 void checkParameterType(Parameter parameter) {
268 checkArity(parameter, ProblemPackage.Literals.PARAMETER__PARAMETER_TYPE, 1);
269 }
270
271 @Check
272 void checkAtom(Atom atom) {
273 int argumentCount = atom.getArguments().size();
274 checkArity(atom, ProblemPackage.Literals.ATOM__RELATION, argumentCount);
275 if (atom.isTransitiveClosure() && argumentCount != 2) {
276 var message = "Transitive closure needs exactly 2 arguments, got %d arguments instead."
277 .formatted(argumentCount);
278 acceptError(message, atom, ProblemPackage.Literals.ATOM__TRANSITIVE_CLOSURE, 0,
279 INVALID_TRANSITIVE_CLOSURE_ISSUE);
280 }
281 }
282
283 @Check
284 void checkAssertion(Assertion assertion) {
285 int argumentCount = assertion.getArguments().size();
286 checkArity(assertion, ProblemPackage.Literals.ASSERTION__RELATION, argumentCount);
287 }
288
289 @Check
290 void checkTypeScope(TypeScope typeScope) {
291 checkArity(typeScope, ProblemPackage.Literals.TYPE_SCOPE__TARGET_TYPE, 1);
292 }
293
294 void checkArity(EObject eObject, EReference reference, int expectedArity) {
295 var value = eObject.eGet(reference);
296 if (!(value instanceof Relation relation) || relation.eIsProxy()) {
297 // Feature does not point to a {@link Relation}, we are probably already emitting another error.
298 return;
299 }
300 int arity = ProblemUtil.getArity(relation);
301 if (arity == expectedArity) {
302 return;
303 }
304 var message = "Expected symbol '%s' to have arity %d, got arity %d instead."
305 .formatted(relation.getName(), expectedArity, arity);
306 acceptError(message, eObject, reference, 0, INVALID_ARITY_ISSUE);
307 }
222} 308}