aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java
blob: f686e98076962f505d7457ef639f31a0bbe8c083 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package tools.refinery.language.semantics;

import com.google.inject.Inject;
import org.eclipse.collections.api.factory.primitive.ObjectIntMaps;
import org.eclipse.collections.api.map.primitive.MutableObjectIntMap;
import org.eclipse.collections.api.map.primitive.ObjectIntMap;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopeProvider;
import tools.refinery.language.model.problem.Node;
import tools.refinery.language.model.problem.Problem;
import tools.refinery.language.model.problem.ProblemPackage;
import tools.refinery.language.model.problem.Relation;
import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
import tools.refinery.store.reasoning.representation.PartialRelation;
import tools.refinery.store.reasoning.translator.TranslationException;
import tools.refinery.store.reasoning.translator.metamodel.Metamodel;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

class ProblemTraceImpl implements ProblemTrace {
	@Inject
	private IQualifiedNameConverter qualifiedNameConverter;

	@Inject
	private SemanticsUtils semanticsUtils;

	@Inject
	private IScopeProvider scopeProvider;

	private Problem problem;
	private Metamodel metamodel;
	private final MutableObjectIntMap<Node> mutableNodeTrace = ObjectIntMaps.mutable.empty();
	private final ObjectIntMap<Node> nodeTrace = mutableNodeTrace.asUnmodifiable();
	private final Map<Relation, PartialRelation> mutableRelationTrace = new LinkedHashMap<>();
	private final Map<Relation, PartialRelation> relationTrace =
			Collections.unmodifiableMap(mutableRelationTrace);
	private final Map<AnyPartialSymbol, Relation> mutableInverseTrace = new HashMap<>();
	private final Map<AnyPartialSymbol, Relation> inverseTrace = Collections.unmodifiableMap(mutableInverseTrace);

	@Override
	public Problem getProblem() {
		return problem;
	}

	void setProblem(Problem problem) {
		this.problem = problem;
	}

	@Override
	public Metamodel getMetamodel() {
		return metamodel;
	}

	void setMetamodel(Metamodel metamodel) {
		this.metamodel = metamodel;
	}

	@Override
	public ObjectIntMap<Node> getNodeTrace() {
		return nodeTrace;
	}

	void collectNode(Node node) {
		mutableNodeTrace.getIfAbsentPut(node, mutableNodeTrace.size());
	}

	@Override
	public int getNodeId(Node node) {
		try {
			return nodeTrace.getOrThrow(node);
		} catch (IllegalStateException e) {
			var qualifiedName = semanticsUtils.getName(node);
			throw new TracedException(node, "No node ID for " + qualifiedName, e);
		}
	}

	@Override
	public int getNodeId(QualifiedName qualifiedName) {
		var nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE);
		return getNodeId(getElement(nodeScope, qualifiedName, Node.class));
	}

	@Override
	public int getNodeId(String qualifiedName) {
		var convertedName = qualifiedNameConverter.toQualifiedName(qualifiedName);
		return getNodeId(convertedName);
	}

	@Override
	public Map<Relation, PartialRelation> getRelationTrace() {
		return relationTrace;
	}

	void putRelation(Relation relation, PartialRelation partialRelation) {
		var oldPartialRelation = mutableRelationTrace.put(relation, partialRelation);
		if (oldPartialRelation != null) {
			throw new TracedException(relation, "Relation already mapped to partial relation: " + oldPartialRelation);
		}
		var oldRelation = mutableInverseTrace.put(partialRelation, relation);
		if (oldRelation != null) {
			throw new TracedException(oldRelation, "Partial relation %s was already mapped to relation"
					.formatted(partialRelation));
		}
	}

	@Override
	public Map<AnyPartialSymbol, Relation> getInverseRelationTrace() {
		return inverseTrace;
	}

	@Override
	public Relation getRelation(AnyPartialSymbol partialSymbol) {
		var relation = mutableInverseTrace.get(partialSymbol);
		if (relation == null) {
			throw new IllegalArgumentException("No relation for partial symbol: " + partialSymbol);
		}
		return relation;
	}

	@Override
	public RuntimeException wrapException(TranslationException translationException) {
		var partialSymbol = translationException.getPartialSymbol();
		if (partialSymbol == null) {
			return translationException;
		}
		var relation = mutableInverseTrace.get(partialSymbol);
		if (relation == null) {
			return translationException;
		}
		return new TracedException(relation, translationException);
	}

	@Override
	public PartialRelation getPartialRelation(Relation relation) {
		var partialRelation = mutableRelationTrace.get(relation);
		if (partialRelation == null) {
			var qualifiedName = semanticsUtils.getName(relation);
			throw new TracedException(relation, "No partial relation for " + qualifiedName);
		}
		return partialRelation;
	}

	@Override
	public PartialRelation getPartialRelation(QualifiedName qualifiedName) {
		var relationScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION);
		return getPartialRelation(getElement(relationScope, qualifiedName, Relation.class));
	}

	@Override
	public PartialRelation getPartialRelation(String qualifiedName) {
		var convertedName = qualifiedNameConverter.toQualifiedName(qualifiedName);
		return getPartialRelation(convertedName);
	}

	private <T> T getElement(IScope scope, QualifiedName qualifiedName, Class<T> type) {
		return semanticsUtils.getElement(problem, scope, qualifiedName, type);
	}
}