aboutsummaryrefslogtreecommitdiffstats
path: root/language
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2021-11-05 19:54:27 +0100
committerLibravatar GitHub <noreply@github.com>2021-11-05 19:54:27 +0100
commit8350a0634d1caf34826fb3ac41d5a892cf3ff1c9 (patch)
tree6769f681ff339e0796e2ca43525df3e58b6fc6db /language
parentMerge pull request #9 from kris7t/cm6-sonar-fixes (diff)
parentchore(web): implicit completion info in grammar (diff)
downloadrefinery-8350a0634d1caf34826fb3ac41d5a892cf3ff1c9.tar.gz
refinery-8350a0634d1caf34826fb3ac41d5a892cf3ff1c9.tar.zst
refinery-8350a0634d1caf34826fb3ac41d5a892cf3ff1c9.zip
Merge pull request #10 from kris7t/cm6-fixes
More CodeMirrror fixes
Diffstat (limited to 'language')
-rw-r--r--language/src/main/java/tools/refinery/language/Problem.xtext6
-rw-r--r--language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java51
-rw-r--r--language/src/main/java/tools/refinery/language/validation/ProblemValidator.java49
3 files changed, 103 insertions, 3 deletions
diff --git a/language/src/main/java/tools/refinery/language/Problem.xtext b/language/src/main/java/tools/refinery/language/Problem.xtext
index 6f6a8588..0fa47d63 100644
--- a/language/src/main/java/tools/refinery/language/Problem.xtext
+++ b/language/src/main/java/tools/refinery/language/Problem.xtext
@@ -154,7 +154,7 @@ ScopeDeclaration:
154 "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* "."; 154 "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* ".";
155 155
156TypeScope: 156TypeScope:
157 targetType=[ClassDeclaration] 157 targetType=[ClassDeclaration|QualifiedName]
158 (increment?="+=" | "=") 158 (increment?="+=" | "=")
159 multiplicity=DefiniteMultiplicity; 159 multiplicity=DefiniteMultiplicity;
160 160
@@ -183,8 +183,8 @@ QualifiedName hidden():
183 Identifier ("::" Identifier)*; 183 Identifier ("::" Identifier)*;
184 184
185Identifier: 185Identifier:
186 ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | "pred" | "scope" | 186 ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | "pred" |
187 "unique" | "default" | "problem" | "new" | "delete"; 187 "unique" | "problem" | "new" | "delete";
188 188
189Integer returns ecore::EInt hidden(): 189Integer returns ecore::EInt hidden():
190 "-"? INT; 190 "-"? INT;
diff --git a/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java b/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java
new file mode 100644
index 00000000..7525dfc6
--- /dev/null
+++ b/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java
@@ -0,0 +1,51 @@
1package tools.refinery.language.resource;
2
3import java.util.HashMap;
4import java.util.Map;
5
6import org.eclipse.emf.ecore.EObject;
7import org.eclipse.xtext.util.IResourceScopeCache;
8
9import com.google.inject.Inject;
10import com.google.inject.Singleton;
11
12import tools.refinery.language.model.problem.Problem;
13
14@Singleton
15public class ReferenceCounter {
16 @Inject
17 private IResourceScopeCache cache;
18
19 public int countReferences(Problem problem, EObject eObject) {
20 var count = getReferenceCounts(problem).get(eObject);
21 if (count == null) {
22 return 0;
23 }
24 return count;
25 }
26
27 protected Map<EObject, Integer> getReferenceCounts(Problem problem) {
28 var resource = problem.eResource();
29 if (resource == null) {
30 return doGetReferenceCounts(problem);
31 }
32 return cache.get(problem, resource, () -> doGetReferenceCounts(problem));
33 }
34
35 protected Map<EObject, Integer> doGetReferenceCounts(Problem problem) {
36 var map = new HashMap<EObject, Integer>();
37 countCrossReferences(problem, map);
38 var iterator = problem.eAllContents();
39 while (iterator.hasNext()) {
40 var eObject = iterator.next();
41 countCrossReferences(eObject, map);
42 }
43 return map;
44 }
45
46 protected void countCrossReferences(EObject eObject, Map<EObject, Integer> map) {
47 for (var referencedObject : eObject.eCrossReferences()) {
48 map.compute(referencedObject, (key, currentValue) -> currentValue == null ? 1 : currentValue + 1);
49 }
50 }
51}
diff --git a/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
index f2378df6..dfd386f5 100644
--- a/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
+++ b/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
@@ -3,6 +3,19 @@
3 */ 3 */
4package tools.refinery.language.validation; 4package tools.refinery.language.validation;
5 5
6import org.eclipse.xtext.EcoreUtil2;
7import org.eclipse.xtext.validation.Check;
8
9import com.google.inject.Inject;
10
11import tools.refinery.language.model.ProblemUtil;
12import tools.refinery.language.model.problem.Node;
13import tools.refinery.language.model.problem.Problem;
14import tools.refinery.language.model.problem.ProblemPackage;
15import tools.refinery.language.model.problem.Variable;
16import tools.refinery.language.model.problem.VariableOrNodeArgument;
17import tools.refinery.language.resource.ReferenceCounter;
18
6/** 19/**
7 * This class contains custom validation rules. 20 * This class contains custom validation rules.
8 * 21 *
@@ -10,4 +23,40 @@ package tools.refinery.language.validation;
10 * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation 23 * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation
11 */ 24 */
12public class ProblemValidator extends AbstractProblemValidator { 25public class ProblemValidator extends AbstractProblemValidator {
26 private static final String ISSUE_PREFIX = "tools.refinery.language.validation.ProblemValidator.";
27
28 public static final String SINGLETON_VARIABLE_ISSUE = ISSUE_PREFIX + "SINGLETON_VARIABLE";
29
30 public static final String NON_UNIQUE_NODE_ISSUE = ISSUE_PREFIX + "NON_UNIQUE_NODE";
31
32 @Inject
33 private ReferenceCounter referenceCounter;
34
35 @Check
36 public void checkUniqueVariable(VariableOrNodeArgument argument) {
37 var variableOrNode = argument.getVariableOrNode();
38 if (variableOrNode instanceof Variable variable && ProblemUtil.isImplicitVariable(variable)
39 && !ProblemUtil.isSingletonVariable(variable)) {
40 var problem = EcoreUtil2.getContainerOfType(variable, Problem.class);
41 if (problem != null && referenceCounter.countReferences(problem, variable) <= 1) {
42 var name = variable.getName();
43 var message = "Variable '%s' has only a single reference. Add another reference or mark is as a singleton variable: '_%s'"
44 .formatted(name, name);
45 warning(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE,
46 INSIGNIFICANT_INDEX, SINGLETON_VARIABLE_ISSUE);
47 }
48 }
49 }
50
51 @Check
52 public void checkNonUniqueNode(VariableOrNodeArgument argument) {
53 var variableOrNode = argument.getVariableOrNode();
54 if (variableOrNode instanceof Node node && !ProblemUtil.isUniqueNode(node)) {
55 var name = node.getName();
56 var message = "Only unique nodes can be referenced in predicates. Mark '%s' as unique with the declaration 'unique %s.'"
57 .formatted(name, name);
58 error(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE,
59 INSIGNIFICANT_INDEX, NON_UNIQUE_NODE_ISSUE);
60 }
61 }
13} 62}