From a49083f31679c47e1685e0cedbc9a40cc8f48fd8 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 26 Aug 2023 21:44:58 +0200 Subject: refactor(frontent): improve graph drawing --- .../language/semantics/metadata/BuiltInDetail.java | 10 ++ .../language/semantics/metadata/ClassDetail.java | 16 ++ .../language/semantics/metadata/Metadata.java | 2 +- .../semantics/metadata/MetadataCreator.java | 181 +++++++++++++++++++++ .../language/semantics/metadata/NodeKind.java | 2 +- .../language/semantics/metadata/NodeMetadata.java | 2 +- .../metadata/OppositeReferenceDetail.java | 9 + .../semantics/metadata/PredicateDetail.java | 16 ++ .../semantics/metadata/ReferenceDetail.java | 16 ++ .../semantics/metadata/RelationDetail.java | 10 ++ .../language/semantics/metadata/RelationKind.java | 18 -- .../semantics/metadata/RelationMetadata.java | 3 +- .../language/semantics/model/ModelInitializer.java | 10 +- 13 files changed, 271 insertions(+), 24 deletions(-) create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/BuiltInDetail.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ClassDetail.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/MetadataCreator.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/OppositeReferenceDetail.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/PredicateDetail.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ReferenceDetail.java create mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationDetail.java delete mode 100644 subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationKind.java (limited to 'subprojects/language-semantics/src/main/java/tools') 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 new file mode 100644 index 00000000..6f706069 --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/BuiltInDetail.java @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public record BuiltInDetail() implements RelationDetail { + public static final BuiltInDetail INSTANCE = new BuiltInDetail(); +} 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 new file mode 100644 index 00000000..1d3190f5 --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ClassDetail.java @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public record ClassDetail(boolean abstractClass) implements RelationDetail { + public static final ClassDetail CONCRETE_CLASS = new ClassDetail(false); + + public static final ClassDetail ABSTRACT_CLASS = new ClassDetail(true); + + public static ClassDetail ofAbstractClass(boolean abstractClass) { + return abstractClass ? ABSTRACT_CLASS : CONCRETE_CLASS; + } +} 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 index 811ac2c0..d2dcb43a 100644 --- 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 @@ -6,7 +6,7 @@ package tools.refinery.language.semantics.metadata; public sealed interface Metadata permits NodeMetadata, RelationMetadata { - String fullyQualifiedName(); + String name(); String simpleName(); } 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.naming.IQualifiedNameConverter; +import org.eclipse.xtext.naming.IQualifiedNameProvider; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.IScopeProvider; +import tools.refinery.language.model.problem.*; +import tools.refinery.language.semantics.model.ModelInitializer; +import tools.refinery.language.semantics.model.TracedException; +import tools.refinery.language.utils.ProblemUtil; +import tools.refinery.store.reasoning.representation.PartialRelation; + +import java.util.*; + +public class MetadataCreator { + @Inject + private IScopeProvider scopeProvider; + + @Inject + private IQualifiedNameProvider qualifiedNameProvider; + + @Inject + private IQualifiedNameConverter qualifiedNameConverter; + + private ModelInitializer initializer; + + private IScope nodeScope; + + private IScope relationScope; + + public void setInitializer(ModelInitializer initializer) { + if (initializer == null) { + throw new IllegalArgumentException("Initializer was already set"); + } + this.initializer = initializer; + var problem = initializer.getProblem(); + nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE); + relationScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION); + } + + public List getNodesMetadata() { + var nodes = new NodeMetadata[initializer.getNodeCount()]; + for (var entry : initializer.getNodeTrace().keyValuesView()) { + var node = entry.getOne(); + var id = entry.getTwo(); + nodes[id] = getNodeMetadata(node); + } + return List.of(nodes); + } + + private NodeMetadata getNodeMetadata(Node node) { + var qualifiedName = getQualifiedName(node); + var simpleName = getSimpleName(node, qualifiedName, nodeScope); + return new NodeMetadata(qualifiedNameConverter.toString(qualifiedName), + qualifiedNameConverter.toString(simpleName), getNodeKind(node)); + } + + private NodeKind getNodeKind(Node node) { + if (ProblemUtil.isImplicitNode(node)) { + return NodeKind.IMPLICIT; + } else if (ProblemUtil.isIndividualNode(node)) { + return NodeKind.INDIVIDUAL; + } else if (ProblemUtil.isNewNode(node)) { + return NodeKind.NEW; + } else { + throw new TracedException(node, "Unknown node type"); + } + } + + public List getRelationsMetadata() { + var relationTrace = initializer.getRelationTrace(); + var relations = new ArrayList(relationTrace.size()); + for (var entry : relationTrace.entrySet()) { + var relation = entry.getKey(); + var partialRelation = entry.getValue(); + var metadata = getRelationMetadata(relation, partialRelation); + relations.add(metadata); + } + return Collections.unmodifiableList(relations); + } + + private RelationMetadata getRelationMetadata(Relation relation, PartialRelation partialRelation) { + var qualifiedName = getQualifiedName(relation); + var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName); + var simpleName = getSimpleName(relation, qualifiedName, relationScope); + var simpleNameString = qualifiedNameConverter.toString(simpleName); + var arity = partialRelation.arity(); + var detail = getRelationDetail(relation, partialRelation); + return new RelationMetadata(qualifiedNameString, simpleNameString, arity, detail); + } + + private RelationDetail getRelationDetail(Relation relation, PartialRelation partialRelation) { + if (ProblemUtil.isBuiltIn(relation) && !ProblemUtil.isError(relation)) { + return getBuiltInDetail(); + } + if (relation instanceof ClassDeclaration classDeclaration) { + return getClassDetail(classDeclaration); + } else if (relation instanceof ReferenceDeclaration) { + return getReferenceDetail(partialRelation); + } else if (relation instanceof EnumDeclaration) { + return getEnumDetail(); + } else if (relation instanceof PredicateDefinition predicateDefinition) { + return getPredicateDetail(predicateDefinition); + } else { + throw new TracedException(relation, "Unknown relation"); + } + } + + private RelationDetail getBuiltInDetail() { + return BuiltInDetail.INSTANCE; + } + + private RelationDetail getClassDetail(ClassDeclaration classDeclaration) { + return ClassDetail.ofAbstractClass(classDeclaration.isAbstract()); + } + + private RelationDetail getReferenceDetail(PartialRelation partialRelation) { + var metamodel = initializer.getMetamodel(); + var opposite = metamodel.oppositeReferences().get(partialRelation); + if (opposite == null) { + boolean isContainment = metamodel.containmentHierarchy().containsKey(partialRelation); + return ReferenceDetail.ofContainment(isContainment); + } else { + boolean isContainer = metamodel.containmentHierarchy().containsKey(opposite); + return new OppositeReferenceDetail(isContainer, opposite.name()); + } + } + + private RelationDetail getEnumDetail() { + return ClassDetail.CONCRETE_CLASS; + } + + private RelationDetail getPredicateDetail(PredicateDefinition predicate) { + return PredicateDetail.ofError(predicate.isError()); + } + + private QualifiedName getQualifiedName(EObject eObject) { + var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject); + if (qualifiedName == null) { + throw new TracedException(eObject, "Unknown qualified name"); + } + return qualifiedName; + } + + private QualifiedName getSimpleName(EObject eObject, QualifiedName qualifiedName, IScope scope) { + var descriptions = scope.getElements(eObject); + var names = new HashSet(); + for (var description : descriptions) { + // {@code getQualifiedName()} will refer to the full name for objects that are loaded from the global + // scope, but {@code getName()} returns the qualified name that we set in + // {@code ProblemResourceDescriptionStrategy}. + names.add(description.getName()); + } + var iterator = names.stream().sorted(Comparator.comparingInt(QualifiedName::getSegmentCount)).iterator(); + while (iterator.hasNext()) { + var simpleName = iterator.next(); + if (names.contains(simpleName) && isUnique(scope, simpleName)) { + return simpleName; + } + } + throw new TracedException(eObject, "Ambiguous qualified name: " + + qualifiedNameConverter.toString(qualifiedName)); + } + + private boolean isUnique(IScope scope, QualifiedName name) { + var iterator = scope.getElements(name).iterator(); + if (!iterator.hasNext()) { + return false; + } + iterator.next(); + return !iterator.hasNext(); + } +} 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 index 27a86cb3..01f0cd09 100644 --- 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 @@ -8,5 +8,5 @@ package tools.refinery.language.semantics.metadata; public enum NodeKind { IMPLICIT, INDIVIDUAL, - ENUM_LITERAL + NEW } 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 index 8d91273c..812952c0 100644 --- 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 @@ -5,5 +5,5 @@ */ package tools.refinery.language.semantics.metadata; -public record NodeMetadata(String fullyQualifiedName, String simpleName, NodeKind kind) implements Metadata { +public record NodeMetadata(String name, String simpleName, NodeKind kind) implements Metadata { } 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 new file mode 100644 index 00000000..26d7461c --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/OppositeReferenceDetail.java @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public record OppositeReferenceDetail(boolean container, String opposite) implements RelationDetail { +} 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 new file mode 100644 index 00000000..ca397eca --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/PredicateDetail.java @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public record PredicateDetail(boolean error) implements RelationDetail { + public static final PredicateDetail PREDICATE = new PredicateDetail(false); + + public static final PredicateDetail ERROR_PREDICATE = new PredicateDetail(true); + + public static PredicateDetail ofError(boolean error) { + return error ? ERROR_PREDICATE : PREDICATE; + } +} 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 new file mode 100644 index 00000000..36771566 --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/ReferenceDetail.java @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public record ReferenceDetail(boolean containment) implements RelationDetail { + public static final ReferenceDetail CROSS_REFERENCE = new ReferenceDetail(false); + + public static final ReferenceDetail CONTAINMENT_REFERENCE = new ReferenceDetail(true); + + public static ReferenceDetail ofContainment(boolean containment) { + return containment ? CONTAINMENT_REFERENCE : CROSS_REFERENCE; + } +} 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 new file mode 100644 index 00000000..105179fd --- /dev/null +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationDetail.java @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.semantics.metadata; + +public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail, + BuiltInDetail { +} diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationKind.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationKind.java deleted file mode 100644 index 28a3c565..00000000 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/metadata/RelationKind.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.semantics.metadata; - -public enum RelationKind { - BUILTIN, - CLASS, - ENUM, - REFERENCE, - OPPOSITE, - CONTAINMENT, - CONTAINER, - PREDICATE, - ERROR -} 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 index 62de6031..5abcc253 100644 --- 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 @@ -5,6 +5,5 @@ */ package tools.refinery.language.semantics.metadata; -public record RelationMetadata(String fullyQualifiedName, String simpleName, int arity, RelationKind kind, - String opposite) implements Metadata { +public record RelationMetadata(String name, String simpleName, int arity, RelationDetail detail) implements Metadata { } 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/model/ModelInitializer.java index 82746aee..aaef3326 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/model/ModelInitializer.java @@ -64,7 +64,7 @@ public class ModelInitializer { private final Map partialRelationInfoMap = new HashMap<>(); - private Map inverseTrace = new HashMap<>(); + private final Map inverseTrace = new HashMap<>(); private Map relationTrace; @@ -74,6 +74,10 @@ public class ModelInitializer { private ModelSeed modelSeed; + public Problem getProblem() { + return problem; + } + public int getNodeCount() { return nodeTrace.size(); } @@ -90,6 +94,10 @@ public class ModelInitializer { return inverseTrace.get(partialRelation); } + public Metamodel getMetamodel() { + return metamodel; + } + public ModelSeed createModel(Problem problem, ModelStoreBuilder storeBuilder) { this.problem = problem; this.storeBuilder = storeBuilder; -- cgit v1.2.3-54-g00ecf