aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java')
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java181
1 files changed, 181 insertions, 0 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java
new file mode 100644
index 00000000..0c18b1b3
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java
@@ -0,0 +1,181 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.semantics.metadata;
7
8import com.google.inject.Inject;
9import org.eclipse.emf.ecore.EObject;
10import org.eclipse.xtext.naming.IQualifiedNameConverter;
11import org.eclipse.xtext.naming.IQualifiedNameProvider;
12import org.eclipse.xtext.naming.QualifiedName;
13import org.eclipse.xtext.scoping.IScope;
14import org.eclipse.xtext.scoping.IScopeProvider;
15import tools.refinery.language.model.problem.*;
16import tools.refinery.language.semantics.model.ModelInitializer;
17import tools.refinery.language.semantics.model.TracedException;
18import tools.refinery.language.utils.ProblemUtil;
19import tools.refinery.store.reasoning.representation.PartialRelation;
20
21import java.util.*;
22
23public class MetadataCreator {
24 @Inject
25 private IScopeProvider scopeProvider;
26
27 @Inject
28 private IQualifiedNameProvider qualifiedNameProvider;
29
30 @Inject
31 private IQualifiedNameConverter qualifiedNameConverter;
32
33 private ModelInitializer initializer;
34
35 private IScope nodeScope;
36
37 private IScope relationScope;
38
39 public void setInitializer(ModelInitializer initializer) {
40 if (initializer == null) {
41 throw new IllegalArgumentException("Initializer was already set");
42 }
43 this.initializer = initializer;
44 var problem = initializer.getProblem();
45 nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE);
46 relationScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION);
47 }
48
49 public List<NodeMetadata> getNodesMetadata() {
50 var nodes = new NodeMetadata[initializer.getNodeCount()];
51 for (var entry : initializer.getNodeTrace().keyValuesView()) {
52 var node = entry.getOne();
53 var id = entry.getTwo();
54 nodes[id] = getNodeMetadata(node);
55 }
56 return List.of(nodes);
57 }
58
59 private NodeMetadata getNodeMetadata(Node node) {
60 var qualifiedName = getQualifiedName(node);
61 var simpleName = getSimpleName(node, qualifiedName, nodeScope);
62 return new NodeMetadata(qualifiedNameConverter.toString(qualifiedName),
63 qualifiedNameConverter.toString(simpleName), getNodeKind(node));
64 }
65
66 private NodeKind getNodeKind(Node node) {
67 if (ProblemUtil.isImplicitNode(node)) {
68 return NodeKind.IMPLICIT;
69 } else if (ProblemUtil.isIndividualNode(node)) {
70 return NodeKind.INDIVIDUAL;
71 } else if (ProblemUtil.isNewNode(node)) {
72 return NodeKind.NEW;
73 } else {
74 throw new TracedException(node, "Unknown node type");
75 }
76 }
77
78 public List<RelationMetadata> getRelationsMetadata() {
79 var relationTrace = initializer.getRelationTrace();
80 var relations = new ArrayList<RelationMetadata>(relationTrace.size());
81 for (var entry : relationTrace.entrySet()) {
82 var relation = entry.getKey();
83 var partialRelation = entry.getValue();
84 var metadata = getRelationMetadata(relation, partialRelation);
85 relations.add(metadata);
86 }
87 return Collections.unmodifiableList(relations);
88 }
89
90 private RelationMetadata getRelationMetadata(Relation relation, PartialRelation partialRelation) {
91 var qualifiedName = getQualifiedName(relation);
92 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
93 var simpleName = getSimpleName(relation, qualifiedName, relationScope);
94 var simpleNameString = qualifiedNameConverter.toString(simpleName);
95 var arity = partialRelation.arity();
96 var detail = getRelationDetail(relation, partialRelation);
97 return new RelationMetadata(qualifiedNameString, simpleNameString, arity, detail);
98 }
99
100 private RelationDetail getRelationDetail(Relation relation, PartialRelation partialRelation) {
101 if (ProblemUtil.isBuiltIn(relation) && !ProblemUtil.isError(relation)) {
102 return getBuiltInDetail();
103 }
104 if (relation instanceof ClassDeclaration classDeclaration) {
105 return getClassDetail(classDeclaration);
106 } else if (relation instanceof ReferenceDeclaration) {
107 return getReferenceDetail(partialRelation);
108 } else if (relation instanceof EnumDeclaration) {
109 return getEnumDetail();
110 } else if (relation instanceof PredicateDefinition predicateDefinition) {
111 return getPredicateDetail(predicateDefinition);
112 } else {
113 throw new TracedException(relation, "Unknown relation");
114 }
115 }
116
117 private RelationDetail getBuiltInDetail() {
118 return BuiltInDetail.INSTANCE;
119 }
120
121 private RelationDetail getClassDetail(ClassDeclaration classDeclaration) {
122 return ClassDetail.ofAbstractClass(classDeclaration.isAbstract());
123 }
124
125 private RelationDetail getReferenceDetail(PartialRelation partialRelation) {
126 var metamodel = initializer.getMetamodel();
127 var opposite = metamodel.oppositeReferences().get(partialRelation);
128 if (opposite == null) {
129 boolean isContainment = metamodel.containmentHierarchy().containsKey(partialRelation);
130 return ReferenceDetail.ofContainment(isContainment);
131 } else {
132 boolean isContainer = metamodel.containmentHierarchy().containsKey(opposite);
133 return new OppositeReferenceDetail(isContainer, opposite.name());
134 }
135 }
136
137 private RelationDetail getEnumDetail() {
138 return ClassDetail.CONCRETE_CLASS;
139 }
140
141 private RelationDetail getPredicateDetail(PredicateDefinition predicate) {
142 return PredicateDetail.ofError(predicate.isError());
143 }
144
145 private QualifiedName getQualifiedName(EObject eObject) {
146 var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject);
147 if (qualifiedName == null) {
148 throw new TracedException(eObject, "Unknown qualified name");
149 }
150 return qualifiedName;
151 }
152
153 private QualifiedName getSimpleName(EObject eObject, QualifiedName qualifiedName, IScope scope) {
154 var descriptions = scope.getElements(eObject);
155 var names = new HashSet<QualifiedName>();
156 for (var description : descriptions) {
157 // {@code getQualifiedName()} will refer to the full name for objects that are loaded from the global
158 // scope, but {@code getName()} returns the qualified name that we set in
159 // {@code ProblemResourceDescriptionStrategy}.
160 names.add(description.getName());
161 }
162 var iterator = names.stream().sorted(Comparator.comparingInt(QualifiedName::getSegmentCount)).iterator();
163 while (iterator.hasNext()) {
164 var simpleName = iterator.next();
165 if (names.contains(simpleName) && isUnique(scope, simpleName)) {
166 return simpleName;
167 }
168 }
169 throw new TracedException(eObject, "Ambiguous qualified name: " +
170 qualifiedNameConverter.toString(qualifiedName));
171 }
172
173 private boolean isUnique(IScope scope, QualifiedName name) {
174 var iterator = scope.getElements(name).iterator();
175 if (!iterator.hasNext()) {
176 return false;
177 }
178 iterator.next();
179 return !iterator.hasNext();
180 }
181}