diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-11-03 19:12:08 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-11-03 19:12:19 +0100 |
commit | 32d469d0284d1ab1540423e705a5d3c8e7d99705 (patch) | |
tree | dcff140c1af411612c2ca61a34471134d762843a /subprojects/language-semantics/src/main | |
parent | refactor(langauge-web): use generator facades (diff) | |
download | refinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.tar.gz refinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.tar.zst refinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.zip |
refactor: smenatics and facades
Also moves model metadata into language-web, since we only use it on the
frontent.
Diffstat (limited to 'subprojects/language-semantics/src/main')
24 files changed, 330 insertions, 425 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java index a05e647d..b3c58366 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java | |||
@@ -3,13 +3,11 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model; | 6 | package tools.refinery.language.semantics; |
7 | 7 | ||
8 | import com.google.inject.Inject; | 8 | import com.google.inject.Inject; |
9 | import org.eclipse.collections.api.factory.primitive.ObjectIntMaps; | ||
10 | import org.eclipse.collections.api.map.primitive.MutableObjectIntMap; | ||
11 | import tools.refinery.language.model.problem.*; | 9 | import tools.refinery.language.model.problem.*; |
12 | import tools.refinery.language.semantics.model.internal.MutableSeed; | 10 | import tools.refinery.language.semantics.internal.MutableSeed; |
13 | import tools.refinery.language.utils.BuiltinSymbols; | 11 | import tools.refinery.language.utils.BuiltinSymbols; |
14 | import tools.refinery.language.utils.ProblemDesugarer; | 12 | import tools.refinery.language.utils.ProblemDesugarer; |
15 | import tools.refinery.language.utils.ProblemUtil; | 13 | import tools.refinery.language.utils.ProblemUtil; |
@@ -23,11 +21,11 @@ import tools.refinery.store.query.literal.*; | |||
23 | import tools.refinery.store.query.term.NodeVariable; | 21 | import tools.refinery.store.query.term.NodeVariable; |
24 | import tools.refinery.store.query.term.Variable; | 22 | import tools.refinery.store.query.term.Variable; |
25 | import tools.refinery.store.reasoning.ReasoningAdapter; | 23 | import tools.refinery.store.reasoning.ReasoningAdapter; |
26 | import tools.refinery.store.reasoning.representation.AnyPartialSymbol; | ||
27 | import tools.refinery.store.reasoning.representation.PartialRelation; | 24 | import tools.refinery.store.reasoning.representation.PartialRelation; |
28 | import tools.refinery.store.reasoning.scope.ScopePropagator; | 25 | import tools.refinery.store.reasoning.scope.ScopePropagator; |
29 | import tools.refinery.store.reasoning.seed.ModelSeed; | 26 | import tools.refinery.store.reasoning.seed.ModelSeed; |
30 | import tools.refinery.store.reasoning.seed.Seed; | 27 | import tools.refinery.store.reasoning.seed.Seed; |
28 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
31 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; | 29 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; |
32 | import tools.refinery.store.reasoning.translator.metamodel.Metamodel; | 30 | import tools.refinery.store.reasoning.translator.metamodel.Metamodel; |
33 | import tools.refinery.store.reasoning.translator.metamodel.MetamodelBuilder; | 31 | import tools.refinery.store.reasoning.translator.metamodel.MetamodelBuilder; |
@@ -52,24 +50,19 @@ public class ModelInitializer { | |||
52 | @Inject | 50 | @Inject |
53 | private SemanticsUtils semanticsUtils; | 51 | private SemanticsUtils semanticsUtils; |
54 | 52 | ||
55 | private Problem problem; | 53 | @Inject |
54 | private ProblemTraceImpl problemTrace; | ||
56 | 55 | ||
57 | private ModelStoreBuilder storeBuilder; | 56 | private Problem problem; |
58 | 57 | ||
59 | private BuiltinSymbols builtinSymbols; | 58 | private BuiltinSymbols builtinSymbols; |
60 | 59 | ||
61 | private PartialRelation nodeRelation; | 60 | private PartialRelation nodeRelation; |
62 | 61 | ||
63 | private final MutableObjectIntMap<Node> nodeTrace = ObjectIntMaps.mutable.empty(); | ||
64 | |||
65 | private final Map<Relation, RelationInfo> relationInfoMap = new LinkedHashMap<>(); | 62 | private final Map<Relation, RelationInfo> relationInfoMap = new LinkedHashMap<>(); |
66 | 63 | ||
67 | private final Map<PartialRelation, RelationInfo> partialRelationInfoMap = new HashMap<>(); | 64 | private final Map<PartialRelation, RelationInfo> partialRelationInfoMap = new HashMap<>(); |
68 | 65 | ||
69 | private final Map<AnyPartialSymbol, Relation> inverseTrace = new HashMap<>(); | ||
70 | |||
71 | private final Map<Relation, PartialRelation> relationTrace = new LinkedHashMap<>(); | ||
72 | |||
73 | private final MetamodelBuilder metamodelBuilder = Metamodel.builder(); | 66 | private final MetamodelBuilder metamodelBuilder = Metamodel.builder(); |
74 | 67 | ||
75 | private Metamodel metamodel; | 68 | private Metamodel metamodel; |
@@ -80,81 +73,74 @@ public class ModelInitializer { | |||
80 | 73 | ||
81 | private ModelSeed modelSeed; | 74 | private ModelSeed modelSeed; |
82 | 75 | ||
83 | public Problem getProblem() { | ||
84 | return problem; | ||
85 | } | ||
86 | |||
87 | public int getNodeCount() { | ||
88 | return nodeTrace.size(); | ||
89 | } | ||
90 | |||
91 | public MutableObjectIntMap<Node> getNodeTrace() { | ||
92 | return nodeTrace; | ||
93 | } | ||
94 | |||
95 | public Map<Relation, PartialRelation> getRelationTrace() { | ||
96 | return relationTrace; | ||
97 | } | ||
98 | |||
99 | public Relation getInverseTrace(AnyPartialSymbol partialRelation) { | ||
100 | return inverseTrace.get(partialRelation); | ||
101 | } | ||
102 | |||
103 | public Metamodel getMetamodel() { | ||
104 | return metamodel; | ||
105 | } | ||
106 | |||
107 | public void readProblem(Problem problem) { | 76 | public void readProblem(Problem problem) { |
77 | if (this.problem != null) { | ||
78 | throw new IllegalArgumentException("Problem was already set"); | ||
79 | } | ||
108 | this.problem = problem; | 80 | this.problem = problem; |
109 | builtinSymbols = desugarer.getBuiltinSymbols(problem).orElseThrow(() -> new IllegalArgumentException( | 81 | problemTrace.setProblem(problem); |
110 | "Problem has no builtin library")); | 82 | try { |
111 | var nodeInfo = collectPartialRelation(builtinSymbols.node(), 1, TruthValue.TRUE, TruthValue.TRUE); | 83 | builtinSymbols = desugarer.getBuiltinSymbols(problem).orElseThrow(() -> new IllegalArgumentException( |
112 | nodeRelation = nodeInfo.partialRelation(); | 84 | "Problem has no builtin library")); |
113 | metamodelBuilder.type(nodeRelation); | 85 | var nodeInfo = collectPartialRelation(builtinSymbols.node(), 1, TruthValue.TRUE, TruthValue.TRUE); |
114 | putRelationInfo(builtinSymbols.exists(), new RelationInfo(ReasoningAdapter.EXISTS_SYMBOL, null, | 86 | nodeRelation = nodeInfo.partialRelation(); |
115 | TruthValue.TRUE)); | 87 | metamodelBuilder.type(nodeRelation); |
116 | putRelationInfo(builtinSymbols.equals(), new RelationInfo(ReasoningAdapter.EQUALS_SYMBOL, | 88 | putRelationInfo(builtinSymbols.exists(), new RelationInfo(ReasoningAdapter.EXISTS_SYMBOL, null, |
117 | (TruthValue) null, | 89 | TruthValue.TRUE)); |
118 | null)); | 90 | putRelationInfo(builtinSymbols.equals(), new RelationInfo(ReasoningAdapter.EQUALS_SYMBOL, |
119 | putRelationInfo(builtinSymbols.contained(), new RelationInfo(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, | 91 | (TruthValue) null, |
120 | null, TruthValue.UNKNOWN)); | 92 | null)); |
121 | putRelationInfo(builtinSymbols.contains(), new RelationInfo(ContainmentHierarchyTranslator.CONTAINS_SYMBOL, | 93 | putRelationInfo(builtinSymbols.contained(), |
122 | null, TruthValue.UNKNOWN)); | 94 | new RelationInfo(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, null, TruthValue.UNKNOWN)); |
123 | putRelationInfo(builtinSymbols.invalidContainer(), | 95 | putRelationInfo(builtinSymbols.contains(), new RelationInfo(ContainmentHierarchyTranslator.CONTAINS_SYMBOL, |
124 | new RelationInfo(ContainmentHierarchyTranslator.INVALID_CONTAINER, TruthValue.FALSE, | 96 | null, TruthValue.UNKNOWN)); |
125 | TruthValue.FALSE)); | 97 | putRelationInfo(builtinSymbols.invalidContainer(), |
126 | collectNodes(); | 98 | new RelationInfo(ContainmentHierarchyTranslator.INVALID_CONTAINER, TruthValue.FALSE, |
127 | collectPartialSymbols(); | 99 | TruthValue.FALSE)); |
128 | collectMetamodel(); | 100 | collectNodes(); |
129 | metamodel = metamodelBuilder.build(); | 101 | collectPartialSymbols(); |
130 | collectAssertions(); | 102 | collectMetamodel(); |
131 | int nodeCount = getNodeCount(); | 103 | metamodel = metamodelBuilder.build(); |
132 | var modelSeedBuilder = ModelSeed.builder(nodeCount); | 104 | problemTrace.setMetamodel(metamodel); |
133 | for (var entry : relationInfoMap.entrySet()) { | 105 | collectAssertions(); |
134 | var relation = entry.getKey(); | 106 | int nodeCount = problemTrace.getNodeTrace().size(); |
135 | var info = entry.getValue(); | 107 | var modelSeedBuilder = ModelSeed.builder(nodeCount); |
136 | var partialRelation = info.partialRelation(); | 108 | for (var entry : relationInfoMap.entrySet()) { |
137 | relationTrace.put(relation, partialRelation); | 109 | var info = entry.getValue(); |
138 | modelSeedBuilder.seed(partialRelation, info.toSeed(nodeCount)); | 110 | var partialRelation = info.partialRelation(); |
139 | } | 111 | modelSeedBuilder.seed(partialRelation, info.toSeed(nodeCount)); |
140 | collectScopes(); | 112 | } |
141 | modelSeedBuilder.seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder | 113 | collectScopes(); |
142 | .reducedValue(CardinalityIntervals.SET) | 114 | modelSeedBuilder.seed(MultiObjectTranslator.COUNT_SYMBOL, builder -> builder |
143 | .putAll(countSeed)); | 115 | .reducedValue(CardinalityIntervals.SET) |
144 | modelSeed = modelSeedBuilder.build(); | 116 | .putAll(countSeed)); |
117 | modelSeed = modelSeedBuilder.build(); | ||
118 | } catch (TranslationException e) { | ||
119 | throw problemTrace.wrapException(e); | ||
120 | } | ||
145 | } | 121 | } |
146 | 122 | ||
147 | public void configureStoreBuilder(ModelStoreBuilder storeBuilder) { | 123 | public void configureStoreBuilder(ModelStoreBuilder storeBuilder) { |
148 | this.storeBuilder = storeBuilder; | 124 | checkProblem(); |
149 | storeBuilder.with(new MultiObjectTranslator()); | 125 | try { |
150 | storeBuilder.with(new MetamodelTranslator(metamodel)); | 126 | storeBuilder.with(new MultiObjectTranslator()); |
151 | if (scopePropagator != null) { | 127 | storeBuilder.with(new MetamodelTranslator(metamodel)); |
152 | if (storeBuilder.tryGetAdapter(PropagationBuilder.class).isEmpty()) { | 128 | if (scopePropagator != null) { |
153 | throw new TracedException(problem, "Type scopes require a PropagationBuilder"); | 129 | if (storeBuilder.tryGetAdapter(PropagationBuilder.class).isEmpty()) { |
130 | throw new TracedException(problem, "Type scopes require a PropagationBuilder"); | ||
131 | } | ||
132 | storeBuilder.with(scopePropagator); | ||
154 | } | 133 | } |
155 | storeBuilder.with(scopePropagator); | 134 | collectPredicates(storeBuilder); |
135 | } catch (TranslationException e) { | ||
136 | throw problemTrace.wrapException(e); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | private void checkProblem() { | ||
141 | if (problem == null) { | ||
142 | throw new IllegalStateException("Problem is not set"); | ||
156 | } | 143 | } |
157 | collectPredicates(); | ||
158 | } | 144 | } |
159 | 145 | ||
160 | public ModelSeed createModel(Problem problem, ModelStoreBuilder storeBuilder) { | 146 | public ModelSeed createModel(Problem problem, ModelStoreBuilder storeBuilder) { |
@@ -163,7 +149,13 @@ public class ModelInitializer { | |||
163 | return getModelSeed(); | 149 | return getModelSeed(); |
164 | } | 150 | } |
165 | 151 | ||
152 | public ProblemTrace getProblemTrace() { | ||
153 | checkProblem(); | ||
154 | return problemTrace; | ||
155 | } | ||
156 | |||
166 | public ModelSeed getModelSeed() { | 157 | public ModelSeed getModelSeed() { |
158 | checkProblem(); | ||
167 | return modelSeed; | 159 | return modelSeed; |
168 | } | 160 | } |
169 | 161 | ||
@@ -190,7 +182,7 @@ public class ModelInitializer { | |||
190 | } | 182 | } |
191 | 183 | ||
192 | private void collectNode(Node node) { | 184 | private void collectNode(Node node) { |
193 | nodeTrace.getIfAbsentPut(node, this::getNodeCount); | 185 | problemTrace.collectNode(node); |
194 | } | 186 | } |
195 | 187 | ||
196 | private void collectPartialSymbols() { | 188 | private void collectPartialSymbols() { |
@@ -232,7 +224,7 @@ public class ModelInitializer { | |||
232 | private void putRelationInfo(Relation relation, RelationInfo info) { | 224 | private void putRelationInfo(Relation relation, RelationInfo info) { |
233 | relationInfoMap.put(relation, info); | 225 | relationInfoMap.put(relation, info); |
234 | partialRelationInfoMap.put(info.partialRelation(), info); | 226 | partialRelationInfoMap.put(info.partialRelation(), info); |
235 | inverseTrace.put(info.partialRelation(), relation); | 227 | problemTrace.putRelation(relation, info.partialRelation()); |
236 | } | 228 | } |
237 | 229 | ||
238 | private RelationInfo collectPartialRelation(Relation relation, int arity, TruthValue value, | 230 | private RelationInfo collectPartialRelation(Relation relation, int arity, TruthValue value, |
@@ -241,7 +233,7 @@ public class ModelInitializer { | |||
241 | var name = getName(relation); | 233 | var name = getName(relation); |
242 | var info = new RelationInfo(name, arity, value, defaultValue); | 234 | var info = new RelationInfo(name, arity, value, defaultValue); |
243 | partialRelationInfoMap.put(info.partialRelation(), info); | 235 | partialRelationInfoMap.put(info.partialRelation(), info); |
244 | inverseTrace.put(info.partialRelation(), relation); | 236 | problemTrace.putRelation(relation, info.partialRelation()); |
245 | return info; | 237 | return info; |
246 | }); | 238 | }); |
247 | } | 239 | } |
@@ -421,7 +413,7 @@ public class ModelInitializer { | |||
421 | } | 413 | } |
422 | 414 | ||
423 | private int getNodeId(Node node) { | 415 | private int getNodeId(Node node) { |
424 | return nodeTrace.getOrThrow(node); | 416 | return problemTrace.getNodeId(node); |
425 | } | 417 | } |
426 | 418 | ||
427 | private Tuple getTuple(Assertion assertion) { | 419 | private Tuple getTuple(Assertion assertion) { |
@@ -453,17 +445,18 @@ public class ModelInitializer { | |||
453 | }; | 445 | }; |
454 | } | 446 | } |
455 | 447 | ||
456 | private void collectPredicates() { | 448 | private void collectPredicates(ModelStoreBuilder storeBuilder) { |
457 | for (var statement : problem.getStatements()) { | 449 | for (var statement : problem.getStatements()) { |
458 | if (statement instanceof PredicateDefinition predicateDefinition) { | 450 | if (statement instanceof PredicateDefinition predicateDefinition) { |
459 | collectPredicateDefinitionTraced(predicateDefinition); | 451 | collectPredicateDefinitionTraced(predicateDefinition, storeBuilder); |
460 | } | 452 | } |
461 | } | 453 | } |
462 | } | 454 | } |
463 | 455 | ||
464 | private void collectPredicateDefinitionTraced(PredicateDefinition predicateDefinition) { | 456 | private void collectPredicateDefinitionTraced(PredicateDefinition predicateDefinition, |
457 | ModelStoreBuilder storeBuilder) { | ||
465 | try { | 458 | try { |
466 | collectPredicateDefinition(predicateDefinition); | 459 | collectPredicateDefinition(predicateDefinition, storeBuilder); |
467 | } catch (InvalidClauseException e) { | 460 | } catch (InvalidClauseException e) { |
468 | int clauseIndex = e.getClauseIndex(); | 461 | int clauseIndex = e.getClauseIndex(); |
469 | var bodies = predicateDefinition.getBodies(); | 462 | var bodies = predicateDefinition.getBodies(); |
@@ -477,7 +470,7 @@ public class ModelInitializer { | |||
477 | } | 470 | } |
478 | } | 471 | } |
479 | 472 | ||
480 | private void collectPredicateDefinition(PredicateDefinition predicateDefinition) { | 473 | private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) { |
481 | var partialRelation = getPartialRelation(predicateDefinition); | 474 | var partialRelation = getPartialRelation(predicateDefinition); |
482 | var query = toQuery(partialRelation.name(), predicateDefinition); | 475 | var query = toQuery(partialRelation.name(), predicateDefinition); |
483 | boolean mutable; | 476 | boolean mutable; |
@@ -488,7 +481,7 @@ public class ModelInitializer { | |||
488 | } else { | 481 | } else { |
489 | var seed = modelSeed.getSeed(partialRelation); | 482 | var seed = modelSeed.getSeed(partialRelation); |
490 | defaultValue = seed.reducedValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; | 483 | defaultValue = seed.reducedValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; |
491 | var cursor = seed.getCursor(defaultValue, getNodeCount()); | 484 | var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size()); |
492 | // The symbol should be mutable if there is at least one non-default entry in the seed. | 485 | // The symbol should be mutable if there is at least one non-default entry in the seed. |
493 | mutable = cursor.move(); | 486 | mutable = cursor.move(); |
494 | } | 487 | } |
@@ -652,8 +645,8 @@ public class ModelInitializer { | |||
652 | if (newNode == null) { | 645 | if (newNode == null) { |
653 | throw new TracedException(typeScope, "Target of incremental type scope must be concrete class"); | 646 | throw new TracedException(typeScope, "Target of incremental type scope must be concrete class"); |
654 | } | 647 | } |
655 | int newNodeId = nodeTrace.get(newNode); | 648 | int newNodeId = getNodeId(newNode); |
656 | var type = relationTrace.get(classDeclaration); | 649 | var type = problemTrace.getPartialRelation(classDeclaration); |
657 | var typeInfo = metamodel.typeHierarchy().getAnalysisResult(type); | 650 | var typeInfo = metamodel.typeHierarchy().getAnalysisResult(type); |
658 | if (!typeInfo.getDirectSubtypes().isEmpty()) { | 651 | if (!typeInfo.getDirectSubtypes().isEmpty()) { |
659 | throw new TracedException(typeScope, "Target of incremental type scope cannot have any subclasses"); | 652 | throw new TracedException(typeScope, "Target of incremental type scope cannot have any subclasses"); |
@@ -664,10 +657,7 @@ public class ModelInitializer { | |||
664 | } | 657 | } |
665 | 658 | ||
666 | private void collectTypeScope(TypeScope typeScope) { | 659 | private void collectTypeScope(TypeScope typeScope) { |
667 | var type = relationTrace.get(typeScope.getTargetType()); | 660 | var type = problemTrace.getPartialRelation(typeScope.getTargetType()); |
668 | if (type == null) { | ||
669 | throw new TracedException(typeScope, "Unknown target type"); | ||
670 | } | ||
671 | var interval = getCardinalityInterval(typeScope.getMultiplicity()); | 661 | var interval = getCardinalityInterval(typeScope.getMultiplicity()); |
672 | if (scopePropagator == null) { | 662 | if (scopePropagator == null) { |
673 | scopePropagator = new ScopePropagator(); | 663 | scopePropagator = new ScopePropagator(); |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTrace.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTrace.java new file mode 100644 index 00000000..b8d0b804 --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTrace.java | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics; | ||
7 | |||
8 | import org.eclipse.collections.api.map.primitive.ObjectIntMap; | ||
9 | import org.eclipse.xtext.naming.QualifiedName; | ||
10 | import tools.refinery.language.model.problem.Node; | ||
11 | import tools.refinery.language.model.problem.Problem; | ||
12 | import tools.refinery.language.model.problem.Relation; | ||
13 | import tools.refinery.store.reasoning.representation.AnyPartialSymbol; | ||
14 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
15 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
16 | import tools.refinery.store.reasoning.translator.metamodel.Metamodel; | ||
17 | |||
18 | import java.util.Map; | ||
19 | |||
20 | public interface ProblemTrace { | ||
21 | Problem getProblem(); | ||
22 | |||
23 | Metamodel getMetamodel(); | ||
24 | |||
25 | ObjectIntMap<Node> getNodeTrace(); | ||
26 | |||
27 | int getNodeId(Node node); | ||
28 | |||
29 | int getNodeId(QualifiedName qualifiedName); | ||
30 | |||
31 | int getNodeId(String qualifiedName); | ||
32 | |||
33 | Map<Relation, PartialRelation> getRelationTrace(); | ||
34 | |||
35 | Map<AnyPartialSymbol, Relation> getInverseRelationTrace(); | ||
36 | |||
37 | Relation getRelation(AnyPartialSymbol partialSymbol); | ||
38 | |||
39 | RuntimeException wrapException(TranslationException translationException); | ||
40 | |||
41 | PartialRelation getPartialRelation(Relation relation); | ||
42 | |||
43 | PartialRelation getPartialRelation(QualifiedName qualifiedName); | ||
44 | |||
45 | PartialRelation getPartialRelation(String qualifiedName); | ||
46 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java new file mode 100644 index 00000000..cc634949 --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics; | ||
7 | |||
8 | import com.google.inject.Inject; | ||
9 | import org.eclipse.collections.api.factory.primitive.ObjectIntMaps; | ||
10 | import org.eclipse.collections.api.map.primitive.MutableObjectIntMap; | ||
11 | import org.eclipse.collections.api.map.primitive.ObjectIntMap; | ||
12 | import org.eclipse.emf.ecore.util.EcoreUtil; | ||
13 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
14 | import org.eclipse.xtext.naming.QualifiedName; | ||
15 | import org.eclipse.xtext.scoping.IScope; | ||
16 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
17 | import tools.refinery.language.model.problem.Node; | ||
18 | import tools.refinery.language.model.problem.Problem; | ||
19 | import tools.refinery.language.model.problem.ProblemPackage; | ||
20 | import tools.refinery.language.model.problem.Relation; | ||
21 | import tools.refinery.store.reasoning.representation.AnyPartialSymbol; | ||
22 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
23 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
24 | import tools.refinery.store.reasoning.translator.metamodel.Metamodel; | ||
25 | |||
26 | import java.util.Collections; | ||
27 | import java.util.HashMap; | ||
28 | import java.util.LinkedHashMap; | ||
29 | import java.util.Map; | ||
30 | |||
31 | public class ProblemTraceImpl implements ProblemTrace { | ||
32 | @Inject | ||
33 | private IQualifiedNameConverter qualifiedNameConverter; | ||
34 | |||
35 | @Inject | ||
36 | private SemanticsUtils semanticsUtils; | ||
37 | |||
38 | @Inject | ||
39 | private IScopeProvider scopeProvider; | ||
40 | |||
41 | private Problem problem; | ||
42 | private Metamodel metamodel; | ||
43 | private final MutableObjectIntMap<Node> mutableNodeTrace = ObjectIntMaps.mutable.empty(); | ||
44 | private final ObjectIntMap<Node> nodeTrace = mutableNodeTrace.asUnmodifiable(); | ||
45 | private final Map<Relation, PartialRelation> mutableRelationTrace = new LinkedHashMap<>(); | ||
46 | private final Map<Relation, PartialRelation> relationTrace = | ||
47 | Collections.unmodifiableMap(mutableRelationTrace); | ||
48 | private final Map<AnyPartialSymbol, Relation> mutableInverseTrace = new HashMap<>(); | ||
49 | private final Map<AnyPartialSymbol, Relation> inverseTrace = Collections.unmodifiableMap(mutableInverseTrace); | ||
50 | |||
51 | @Override | ||
52 | public Problem getProblem() { | ||
53 | return problem; | ||
54 | } | ||
55 | |||
56 | void setProblem(Problem problem) { | ||
57 | this.problem = problem; | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public Metamodel getMetamodel() { | ||
62 | return metamodel; | ||
63 | } | ||
64 | |||
65 | void setMetamodel(Metamodel metamodel) { | ||
66 | this.metamodel = metamodel; | ||
67 | } | ||
68 | |||
69 | @Override | ||
70 | public ObjectIntMap<Node> getNodeTrace() { | ||
71 | return nodeTrace; | ||
72 | } | ||
73 | |||
74 | void collectNode(Node node) { | ||
75 | mutableNodeTrace.getIfAbsentPut(node, mutableNodeTrace.size()); | ||
76 | } | ||
77 | |||
78 | @Override | ||
79 | public int getNodeId(Node node) { | ||
80 | try { | ||
81 | return nodeTrace.getOrThrow(node); | ||
82 | } catch (IllegalStateException e) { | ||
83 | var qualifiedName = semanticsUtils.getName(node); | ||
84 | throw new TracedException(node, "No node ID for " + qualifiedName, e); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | @Override | ||
89 | public int getNodeId(QualifiedName qualifiedName) { | ||
90 | var nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE); | ||
91 | return getNodeId(getElement(nodeScope, qualifiedName, Node.class)); | ||
92 | } | ||
93 | |||
94 | @Override | ||
95 | public int getNodeId(String qualifiedName) { | ||
96 | var convertedName = qualifiedNameConverter.toQualifiedName(qualifiedName); | ||
97 | return getNodeId(convertedName); | ||
98 | } | ||
99 | |||
100 | @Override | ||
101 | public Map<Relation, PartialRelation> getRelationTrace() { | ||
102 | return relationTrace; | ||
103 | } | ||
104 | |||
105 | void putRelation(Relation relation, PartialRelation partialRelation) { | ||
106 | var oldPartialRelation = mutableRelationTrace.put(relation, partialRelation); | ||
107 | if (oldPartialRelation != null) { | ||
108 | throw new TracedException(relation, "Relation already mapped to partial relation: " + oldPartialRelation); | ||
109 | } | ||
110 | var oldRelation = mutableInverseTrace.put(partialRelation, relation); | ||
111 | if (oldRelation != null) { | ||
112 | throw new TracedException(oldRelation, "Partial relation %s was already mapped to relation" | ||
113 | .formatted(partialRelation)); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | @Override | ||
118 | public Map<AnyPartialSymbol, Relation> getInverseRelationTrace() { | ||
119 | return inverseTrace; | ||
120 | } | ||
121 | |||
122 | @Override | ||
123 | public Relation getRelation(AnyPartialSymbol partialSymbol) { | ||
124 | var relation = mutableInverseTrace.get(partialSymbol); | ||
125 | if (relation == null) { | ||
126 | throw new IllegalArgumentException("No relation for partial symbol: " + partialSymbol); | ||
127 | } | ||
128 | return relation; | ||
129 | } | ||
130 | |||
131 | @Override | ||
132 | public RuntimeException wrapException(TranslationException translationException) { | ||
133 | var partialSymbol = translationException.getPartialSymbol(); | ||
134 | if (partialSymbol == null) { | ||
135 | return translationException; | ||
136 | } | ||
137 | var relation = mutableInverseTrace.get(partialSymbol); | ||
138 | if (relation == null) { | ||
139 | return translationException; | ||
140 | } | ||
141 | return new TracedException(relation, translationException); | ||
142 | } | ||
143 | |||
144 | @Override | ||
145 | public PartialRelation getPartialRelation(Relation relation) { | ||
146 | var partialRelation = mutableRelationTrace.get(relation); | ||
147 | if (partialRelation == null) { | ||
148 | var qualifiedName = semanticsUtils.getName(relation); | ||
149 | throw new TracedException(relation, "No partial relation for " + qualifiedName); | ||
150 | } | ||
151 | return partialRelation; | ||
152 | } | ||
153 | |||
154 | @Override | ||
155 | public PartialRelation getPartialRelation(QualifiedName qualifiedName) { | ||
156 | var relationScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION); | ||
157 | return getPartialRelation(getElement(relationScope, qualifiedName, Relation.class)); | ||
158 | } | ||
159 | |||
160 | @Override | ||
161 | public PartialRelation getPartialRelation(String qualifiedName) { | ||
162 | var convertedName = qualifiedNameConverter.toQualifiedName(qualifiedName); | ||
163 | return getPartialRelation(convertedName); | ||
164 | } | ||
165 | |||
166 | private <T> T getElement(IScope scope, QualifiedName qualifiedName, Class<T> type) { | ||
167 | var iterator = scope.getElements(qualifiedName).iterator(); | ||
168 | if (!iterator.hasNext()) { | ||
169 | var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName); | ||
170 | throw new IllegalArgumentException("No such %s: %s" | ||
171 | .formatted(type.getName(), qualifiedNameString)); | ||
172 | } | ||
173 | var eObjectDescription = iterator.next(); | ||
174 | if (iterator.hasNext()) { | ||
175 | var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName); | ||
176 | throw new IllegalArgumentException("Ambiguous %s: %s" | ||
177 | .formatted(type.getName(), qualifiedNameString)); | ||
178 | } | ||
179 | var eObject = EcoreUtil.resolve(eObjectDescription.getEObjectOrProxy(), getProblem()); | ||
180 | if (!type.isInstance(eObject)) { | ||
181 | var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName); | ||
182 | throw new IllegalArgumentException("Not a %s: %s" | ||
183 | .formatted(type.getName(), qualifiedNameString)); | ||
184 | } | ||
185 | return type.cast(eObject); | ||
186 | } | ||
187 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/SemanticsUtils.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SemanticsUtils.java index 47c89e9b..b195a8e7 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/SemanticsUtils.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SemanticsUtils.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model; | 6 | package tools.refinery.language.semantics; |
7 | 7 | ||
8 | import com.google.inject.Inject; | 8 | import com.google.inject.Inject; |
9 | import com.google.inject.Singleton; | 9 | import com.google.inject.Singleton; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/TracedException.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/TracedException.java index 38fd8a67..8636bdab 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/TracedException.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/TracedException.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model; | 6 | package tools.refinery.language.semantics; |
7 | 7 | ||
8 | import org.eclipse.emf.ecore.EObject; | 8 | import org.eclipse.emf.ecore.EObject; |
9 | 9 | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTree.java index 32112e61..c732f784 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTree.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | 8 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; |
9 | import tools.refinery.store.map.Cursor; | 9 | import tools.refinery.store.map.Cursor; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeCursor.java index a9fc644a..71b54cbd 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeCursor.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import tools.refinery.store.map.Cursor; | 8 | import tools.refinery.store.map.Cursor; |
9 | import tools.refinery.store.representation.TruthValue; | 9 | import tools.refinery.store.representation.TruthValue; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeNode.java index 3c54e3c5..ebca2634 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeNode.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.api.LazyIntIterable; | 8 | import org.eclipse.collections.api.LazyIntIterable; |
9 | import tools.refinery.store.tuple.Tuple; | 9 | import tools.refinery.store.tuple.Tuple; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeValue.java index 915ae2bf..5053e7ac 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/DecisionTreeValue.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import tools.refinery.store.representation.TruthValue; | 8 | import tools.refinery.store.representation.TruthValue; |
9 | 9 | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java index e6f01d48..0e2f5d18 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.api.LazyIntIterable; | 8 | import org.eclipse.collections.api.LazyIntIterable; |
9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | 9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/MutableSeed.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/MutableSeed.java index 99019e2a..693b9e1f 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/MutableSeed.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/MutableSeed.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import tools.refinery.store.reasoning.seed.Seed; | 8 | import tools.refinery.store.reasoning.seed.Seed; |
9 | import tools.refinery.store.representation.TruthValue; | 9 | import tools.refinery.store.representation.TruthValue; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/NullaryMutableSeed.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/NullaryMutableSeed.java index 80644b1f..7a72c656 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/NullaryMutableSeed.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/NullaryMutableSeed.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import tools.refinery.store.map.Cursor; | 8 | import tools.refinery.store.map.Cursor; |
9 | import tools.refinery.store.map.Cursors; | 9 | import tools.refinery.store.map.Cursors; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/TerminalNode.java index ce49aa62..d3dd757c 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/TerminalNode.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.semantics.model.internal; | 6 | package tools.refinery.language.semantics.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.api.LazyIntIterable; | 8 | import org.eclipse.collections.api.LazyIntIterable; |
9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | 9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/BuiltInDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/BuiltInDetail.java deleted file mode 100644 index 6f706069..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/BuiltInDetail.java +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record BuiltInDetail() implements RelationDetail { | ||
9 | public static final BuiltInDetail INSTANCE = new BuiltInDetail(); | ||
10 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ClassDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ClassDetail.java deleted file mode 100644 index 1d3190f5..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ClassDetail.java +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record ClassDetail(boolean abstractClass) implements RelationDetail { | ||
9 | public static final ClassDetail CONCRETE_CLASS = new ClassDetail(false); | ||
10 | |||
11 | public static final ClassDetail ABSTRACT_CLASS = new ClassDetail(true); | ||
12 | |||
13 | public static ClassDetail ofAbstractClass(boolean abstractClass) { | ||
14 | return abstractClass ? ABSTRACT_CLASS : CONCRETE_CLASS; | ||
15 | } | ||
16 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/Metadata.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/Metadata.java deleted file mode 100644 index d2dcb43a..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/Metadata.java +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public sealed interface Metadata permits NodeMetadata, RelationMetadata { | ||
9 | String name(); | ||
10 | |||
11 | String simpleName(); | ||
12 | } | ||
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 deleted file mode 100644 index 3694f5f4..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | import com.google.inject.Inject; | ||
9 | import org.eclipse.emf.ecore.EObject; | ||
10 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
11 | import org.eclipse.xtext.naming.IQualifiedNameProvider; | ||
12 | import org.eclipse.xtext.naming.QualifiedName; | ||
13 | import org.eclipse.xtext.scoping.IScope; | ||
14 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
15 | import tools.refinery.language.model.problem.*; | ||
16 | import tools.refinery.language.semantics.model.ModelInitializer; | ||
17 | import tools.refinery.language.semantics.model.TracedException; | ||
18 | import tools.refinery.language.utils.ProblemUtil; | ||
19 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
20 | |||
21 | import java.util.*; | ||
22 | |||
23 | public 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 static String unnamedNode(int nodeId) { | ||
50 | return "::" + nodeId; | ||
51 | } | ||
52 | |||
53 | public List<NodeMetadata> getNodesMetadata() { | ||
54 | return getNodesMetadata(initializer.getNodeCount(), true); | ||
55 | } | ||
56 | |||
57 | public List<NodeMetadata> getNodesMetadata(int nodeCount, boolean preserveNewNodes) { | ||
58 | var nodes = new NodeMetadata[Math.max(initializer.getNodeCount(), nodeCount)]; | ||
59 | for (var entry : initializer.getNodeTrace().keyValuesView()) { | ||
60 | var node = entry.getOne(); | ||
61 | var id = entry.getTwo(); | ||
62 | nodes[id] = getNodeMetadata(id, node, preserveNewNodes); | ||
63 | } | ||
64 | for (int i = 0; i < nodes.length; i++) { | ||
65 | if (nodes[i] == null) { | ||
66 | var nodeName = unnamedNode(i); | ||
67 | nodes[i] = new NodeMetadata(nodeName, nodeName, NodeKind.IMPLICIT); | ||
68 | } | ||
69 | } | ||
70 | return List.of(nodes); | ||
71 | } | ||
72 | |||
73 | private NodeMetadata getNodeMetadata(int nodeId, Node node, boolean preserveNewNodes) { | ||
74 | var kind = getNodeKind(node); | ||
75 | if (!preserveNewNodes && kind == NodeKind.NEW) { | ||
76 | var nodeName = unnamedNode(nodeId); | ||
77 | return new NodeMetadata(nodeName, nodeName, NodeKind.IMPLICIT); | ||
78 | } | ||
79 | var qualifiedName = getQualifiedName(node); | ||
80 | var simpleName = getSimpleName(node, qualifiedName, nodeScope); | ||
81 | return new NodeMetadata(qualifiedNameConverter.toString(qualifiedName), | ||
82 | qualifiedNameConverter.toString(simpleName), getNodeKind(node)); | ||
83 | } | ||
84 | |||
85 | private NodeKind getNodeKind(Node node) { | ||
86 | if (ProblemUtil.isImplicitNode(node)) { | ||
87 | return NodeKind.IMPLICIT; | ||
88 | } else if (ProblemUtil.isIndividualNode(node)) { | ||
89 | return NodeKind.INDIVIDUAL; | ||
90 | } else if (ProblemUtil.isNewNode(node)) { | ||
91 | return NodeKind.NEW; | ||
92 | } else { | ||
93 | throw new TracedException(node, "Unknown node type"); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | public List<RelationMetadata> getRelationsMetadata() { | ||
98 | var relationTrace = initializer.getRelationTrace(); | ||
99 | var relations = new ArrayList<RelationMetadata>(relationTrace.size()); | ||
100 | for (var entry : relationTrace.entrySet()) { | ||
101 | var relation = entry.getKey(); | ||
102 | var partialRelation = entry.getValue(); | ||
103 | var metadata = getRelationMetadata(relation, partialRelation); | ||
104 | relations.add(metadata); | ||
105 | } | ||
106 | return Collections.unmodifiableList(relations); | ||
107 | } | ||
108 | |||
109 | private RelationMetadata getRelationMetadata(Relation relation, PartialRelation partialRelation) { | ||
110 | var qualifiedName = getQualifiedName(relation); | ||
111 | var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName); | ||
112 | var simpleName = getSimpleName(relation, qualifiedName, relationScope); | ||
113 | var simpleNameString = qualifiedNameConverter.toString(simpleName); | ||
114 | var arity = partialRelation.arity(); | ||
115 | var detail = getRelationDetail(relation, partialRelation); | ||
116 | return new RelationMetadata(qualifiedNameString, simpleNameString, arity, detail); | ||
117 | } | ||
118 | |||
119 | private RelationDetail getRelationDetail(Relation relation, PartialRelation partialRelation) { | ||
120 | if (ProblemUtil.isBuiltIn(relation) && !ProblemUtil.isError(relation)) { | ||
121 | return getBuiltInDetail(); | ||
122 | } | ||
123 | if (relation instanceof ClassDeclaration classDeclaration) { | ||
124 | return getClassDetail(classDeclaration); | ||
125 | } else if (relation instanceof ReferenceDeclaration) { | ||
126 | return getReferenceDetail(partialRelation); | ||
127 | } else if (relation instanceof EnumDeclaration) { | ||
128 | return getEnumDetail(); | ||
129 | } else if (relation instanceof PredicateDefinition predicateDefinition) { | ||
130 | return getPredicateDetail(predicateDefinition); | ||
131 | } else { | ||
132 | throw new TracedException(relation, "Unknown relation"); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | private RelationDetail getBuiltInDetail() { | ||
137 | return BuiltInDetail.INSTANCE; | ||
138 | } | ||
139 | |||
140 | private RelationDetail getClassDetail(ClassDeclaration classDeclaration) { | ||
141 | return ClassDetail.ofAbstractClass(classDeclaration.isAbstract()); | ||
142 | } | ||
143 | |||
144 | private RelationDetail getReferenceDetail(PartialRelation partialRelation) { | ||
145 | var metamodel = initializer.getMetamodel(); | ||
146 | var opposite = metamodel.oppositeReferences().get(partialRelation); | ||
147 | if (opposite == null) { | ||
148 | boolean isContainment = metamodel.containmentHierarchy().containsKey(partialRelation); | ||
149 | return ReferenceDetail.ofContainment(isContainment); | ||
150 | } else { | ||
151 | boolean isContainer = metamodel.containmentHierarchy().containsKey(opposite); | ||
152 | return new OppositeReferenceDetail(isContainer, opposite.name()); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | private RelationDetail getEnumDetail() { | ||
157 | return ClassDetail.CONCRETE_CLASS; | ||
158 | } | ||
159 | |||
160 | private RelationDetail getPredicateDetail(PredicateDefinition predicate) { | ||
161 | return PredicateDetail.ofError(predicate.isError()); | ||
162 | } | ||
163 | |||
164 | private QualifiedName getQualifiedName(EObject eObject) { | ||
165 | var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject); | ||
166 | if (qualifiedName == null) { | ||
167 | throw new TracedException(eObject, "Unknown qualified name"); | ||
168 | } | ||
169 | return qualifiedName; | ||
170 | } | ||
171 | |||
172 | private QualifiedName getSimpleName(EObject eObject, QualifiedName qualifiedName, IScope scope) { | ||
173 | var descriptions = scope.getElements(eObject); | ||
174 | var names = new ArrayList<QualifiedName>(); | ||
175 | for (var description : descriptions) { | ||
176 | // {@code getQualifiedName()} will refer to the full name for objects that are loaded from the global | ||
177 | // scope, but {@code getName()} returns the qualified name that we set in | ||
178 | // {@code ProblemResourceDescriptionStrategy}. | ||
179 | names.add(description.getName()); | ||
180 | } | ||
181 | names.sort(Comparator.comparingInt(QualifiedName::getSegmentCount)); | ||
182 | for (var simpleName : names) { | ||
183 | if (names.contains(simpleName) && isUnique(scope, simpleName)) { | ||
184 | return simpleName; | ||
185 | } | ||
186 | } | ||
187 | throw new TracedException(eObject, "Ambiguous qualified name: " + | ||
188 | qualifiedNameConverter.toString(qualifiedName)); | ||
189 | } | ||
190 | |||
191 | private boolean isUnique(IScope scope, QualifiedName name) { | ||
192 | var iterator = scope.getElements(name).iterator(); | ||
193 | if (!iterator.hasNext()) { | ||
194 | return false; | ||
195 | } | ||
196 | iterator.next(); | ||
197 | return !iterator.hasNext(); | ||
198 | } | ||
199 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeKind.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeKind.java deleted file mode 100644 index 01f0cd09..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeKind.java +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public enum NodeKind { | ||
9 | IMPLICIT, | ||
10 | INDIVIDUAL, | ||
11 | NEW | ||
12 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeMetadata.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeMetadata.java deleted file mode 100644 index 812952c0..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/NodeMetadata.java +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record NodeMetadata(String name, String simpleName, NodeKind kind) implements Metadata { | ||
9 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/OppositeReferenceDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/OppositeReferenceDetail.java deleted file mode 100644 index 26d7461c..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/OppositeReferenceDetail.java +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record OppositeReferenceDetail(boolean container, String opposite) implements RelationDetail { | ||
9 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/PredicateDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/PredicateDetail.java deleted file mode 100644 index ca397eca..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/PredicateDetail.java +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record PredicateDetail(boolean error) implements RelationDetail { | ||
9 | public static final PredicateDetail PREDICATE = new PredicateDetail(false); | ||
10 | |||
11 | public static final PredicateDetail ERROR_PREDICATE = new PredicateDetail(true); | ||
12 | |||
13 | public static PredicateDetail ofError(boolean error) { | ||
14 | return error ? ERROR_PREDICATE : PREDICATE; | ||
15 | } | ||
16 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ReferenceDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ReferenceDetail.java deleted file mode 100644 index 36771566..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ReferenceDetail.java +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record ReferenceDetail(boolean containment) implements RelationDetail { | ||
9 | public static final ReferenceDetail CROSS_REFERENCE = new ReferenceDetail(false); | ||
10 | |||
11 | public static final ReferenceDetail CONTAINMENT_REFERENCE = new ReferenceDetail(true); | ||
12 | |||
13 | public static ReferenceDetail ofContainment(boolean containment) { | ||
14 | return containment ? CONTAINMENT_REFERENCE : CROSS_REFERENCE; | ||
15 | } | ||
16 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationDetail.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationDetail.java deleted file mode 100644 index 105179fd..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationDetail.java +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail, | ||
9 | BuiltInDetail { | ||
10 | } | ||
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationMetadata.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationMetadata.java deleted file mode 100644 index 5abcc253..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationMetadata.java +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.language.semantics.metadata; | ||
7 | |||
8 | public record RelationMetadata(String name, String simpleName, int arity, RelationDetail detail) implements Metadata { | ||
9 | } | ||