diff options
Diffstat (limited to 'subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java')
-rw-r--r-- | subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java new file mode 100644 index 00000000..f0baf35f --- /dev/null +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.resource.state; | ||
7 | |||
8 | import com.google.inject.Inject; | ||
9 | import com.google.inject.Singleton; | ||
10 | import com.google.inject.name.Named; | ||
11 | import org.eclipse.xtext.linking.impl.LinkingHelper; | ||
12 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
13 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
14 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | ||
15 | import tools.refinery.language.model.problem.*; | ||
16 | |||
17 | import java.util.*; | ||
18 | |||
19 | @Singleton | ||
20 | public class DerivedVariableComputer { | ||
21 | @Inject | ||
22 | private LinkingHelper linkingHelper; | ||
23 | |||
24 | @Inject | ||
25 | private IQualifiedNameConverter qualifiedNameConverter; | ||
26 | |||
27 | @Inject | ||
28 | @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE) | ||
29 | private IScopeProvider scopeProvider; | ||
30 | |||
31 | public void installDerivedVariables(Problem problem, Set<String> nodeNames) { | ||
32 | for (Statement statement : problem.getStatements()) { | ||
33 | if (statement instanceof ParametricDefinition definition) { | ||
34 | installDerivedParametricDefinitionState(definition, nodeNames); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | protected void installDerivedParametricDefinitionState(ParametricDefinition definition, Set<String> nodeNames) { | ||
40 | Set<String> knownVariables = new HashSet<>(nodeNames); | ||
41 | for (Parameter parameter : definition.getParameters()) { | ||
42 | String name = parameter.getName(); | ||
43 | if (name != null) { | ||
44 | knownVariables.add(name); | ||
45 | } | ||
46 | } | ||
47 | if (definition instanceof PredicateDefinition predicateDefinition) { | ||
48 | installDerivedPredicateDefinitionState(predicateDefinition, knownVariables); | ||
49 | } else if (definition instanceof FunctionDefinition functionDefinition) { | ||
50 | installDerivedFunctionDefinitionState(functionDefinition, knownVariables); | ||
51 | } else if (definition instanceof RuleDefinition ruleDefinition) { | ||
52 | installDerivedRuleDefinitionState(ruleDefinition, knownVariables); | ||
53 | } else { | ||
54 | throw new IllegalArgumentException("Unknown ParametricDefinition: " + definition); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | protected void installDerivedPredicateDefinitionState(PredicateDefinition definition, Set<String> knownVariables) { | ||
59 | for (Conjunction body : definition.getBodies()) { | ||
60 | createVariablesForScope(new ImplicitVariableScope(body, knownVariables)); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | protected void installDerivedFunctionDefinitionState(FunctionDefinition definition, Set<String> knownVariables) { | ||
65 | for (Case body : definition.getCases()) { | ||
66 | if (body instanceof Conjunction conjunction) { | ||
67 | createVariablesForScope(new ImplicitVariableScope(conjunction, knownVariables)); | ||
68 | } else if (body instanceof Match match) { | ||
69 | var condition = match.getCondition(); | ||
70 | if (condition != null) { | ||
71 | createVariablesForScope(new ImplicitVariableScope(match, match.getCondition(), knownVariables)); | ||
72 | } | ||
73 | } else { | ||
74 | throw new IllegalArgumentException("Unknown Case: " + body); | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | protected void installDerivedRuleDefinitionState(RuleDefinition definition, Set<String> knownVariables) { | ||
80 | for (Conjunction precondition : definition.getPreconditions()) { | ||
81 | createVariablesForScope(new ImplicitVariableScope(precondition, knownVariables)); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | protected void createVariablesForScope(ImplicitVariableScope scope) { | ||
86 | var queue = new ArrayDeque<ImplicitVariableScope>(); | ||
87 | queue.addLast(scope); | ||
88 | while (!queue.isEmpty()) { | ||
89 | var nextScope = queue.removeFirst(); | ||
90 | nextScope.createVariables(scopeProvider, linkingHelper, qualifiedNameConverter, queue); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | public void discardDerivedVariables(Problem problem) { | ||
95 | for (Statement statement : problem.getStatements()) { | ||
96 | if (statement instanceof ParametricDefinition parametricDefinition) { | ||
97 | discardParametricDefinitionState(parametricDefinition); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | protected void discardParametricDefinitionState(ParametricDefinition definition) { | ||
103 | List<ExistentialQuantifier> existentialQuantifiers = new ArrayList<>(); | ||
104 | List<VariableOrNodeExpr> variableOrNodeExprs = new ArrayList<>(); | ||
105 | var treeIterator = definition.eAllContents(); | ||
106 | // We must collect the nodes where we are discarding derived state and only discard them after the iteration, | ||
107 | // because modifying the containment hierarchy during iteration causes the TreeIterator to fail with | ||
108 | // IndexOutOfBoundsException. | ||
109 | while (treeIterator.hasNext()) { | ||
110 | var child = treeIterator.next(); | ||
111 | var containingFeature = child.eContainingFeature(); | ||
112 | if (containingFeature == ProblemPackage.Literals.EXISTENTIAL_QUANTIFIER__IMPLICIT_VARIABLES || | ||
113 | containingFeature == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__SINGLETON_VARIABLE) { | ||
114 | treeIterator.prune(); | ||
115 | } else if (child instanceof ExistentialQuantifier existentialQuantifier && | ||
116 | !existentialQuantifier.getImplicitVariables().isEmpty()) { | ||
117 | existentialQuantifiers.add(existentialQuantifier); | ||
118 | } else if (child instanceof VariableOrNodeExpr variableOrNodeExpr && | ||
119 | variableOrNodeExpr.getSingletonVariable() != null) { | ||
120 | variableOrNodeExprs.add(variableOrNodeExpr); | ||
121 | } | ||
122 | } | ||
123 | for (var existentialQuantifier : existentialQuantifiers) { | ||
124 | existentialQuantifier.getImplicitVariables().clear(); | ||
125 | } | ||
126 | for (var variableOrNodeExpr : variableOrNodeExprs) { | ||
127 | variableOrNodeExpr.setSingletonVariable(null); | ||
128 | } | ||
129 | } | ||
130 | } | ||