diff options
author | 2023-11-18 19:43:09 +0100 | |
---|---|---|
committer | 2023-11-19 14:41:17 +0100 | |
commit | 392242099439fd3f21abb87d55ce94050e71ccb5 (patch) | |
tree | 2be45d93ae8ebbd3dd0cc051c3db26f0318cb7d2 /subprojects/language/src/main/java | |
parent | fix: upper and lower scopes (diff) | |
download | refinery-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.java | 122 |
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 @@ | |||
10 | package tools.refinery.language.validation; | 10 | package tools.refinery.language.validation; |
11 | 11 | ||
12 | import com.google.inject.Inject; | 12 | import com.google.inject.Inject; |
13 | import org.eclipse.emf.ecore.EObject; | ||
14 | import org.eclipse.emf.ecore.EReference; | ||
13 | import org.eclipse.xtext.EcoreUtil2; | 15 | import org.eclipse.xtext.EcoreUtil2; |
14 | import org.eclipse.xtext.validation.Check; | 16 | import org.eclipse.xtext.validation.Check; |
15 | import tools.refinery.language.model.problem.*; | 17 | import 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 | } |