From c4757c72887d0d83a51099c9f33d3e027f55a4e6 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Tue, 15 Aug 2023 12:35:06 +0200 Subject: refactor(language): invalid multiplicity trace Also simplifies attributes and flags for now, as we don't translate them to abstractions. --- .../java/tools/refinery/language/Problem.xtext | 48 ++-- .../resource/ProblemDerivedStateComputer.java | 96 ++++++-- .../resource/ProblemLocationInFileProvider.java | 1 - .../ProblemResourceDescriptionStrategy.java | 44 ++-- .../refinery/language/utils/BuiltinSymbols.java | 6 +- .../refinery/language/utils/CollectedSymbols.java | 15 -- .../refinery/language/utils/ContainmentRole.java | 22 -- .../tools/refinery/language/utils/NodeInfo.java | 9 - .../refinery/language/utils/ProblemDesugarer.java | 25 +- .../tools/refinery/language/utils/ProblemUtil.java | 38 ++- .../refinery/language/utils/RelationInfo.java | 29 --- .../refinery/language/utils/SymbolCollector.java | 255 --------------------- 12 files changed, 158 insertions(+), 430 deletions(-) delete mode 100644 subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java delete mode 100644 subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java delete mode 100644 subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java delete mode 100644 subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java delete mode 100644 subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java (limited to 'subprojects/language/src/main/java') diff --git a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext index 9e330347..0a91178b 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext @@ -14,7 +14,7 @@ Problem: Statement: Assertion | ClassDeclaration | EnumDeclaration | - PredicateDefinition | FunctionDefinition | /* RuleDefinition | */ + PredicateDefinition | /* FunctionDefinition | RuleDefinition | */ ScopeDeclaration | IndividualDeclaration; ClassDeclaration: @@ -32,7 +32,7 @@ EnumLiteral returns Node: name=Identifier; FeatureDeclaration: - ReferenceDeclaration | AttributeDeclaration | FlagDeclaration; + ReferenceDeclaration /* | AttributeDeclaration | FlagDeclaration */; enum ReferenceKind: REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; @@ -44,23 +44,17 @@ ReferenceDeclaration: name=Identifier ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; -enum PrimitiveType: - INT="int" | REAL="real" | STRING="string"; - -AttributeDeclaration: - attributeType=PrimitiveType name=Identifier; - -FlagDeclaration: - "bool" name=Identifier; - -enum ErrorKind returns PredicateKind: - ERROR="error"; - -enum PredicateKind: - ERROR="error" | CONTAINED="contained" | CONTAINMENT="containment"; +//enum PrimitiveType: +// INT="int" | REAL="real" | STRING="string"; +// +//AttributeDeclaration: +// attributeType=PrimitiveType name=Identifier; +// +//FlagDeclaration: +// "bool" name=Identifier; PredicateDefinition: - (kind=ErrorKind | kind=PredicateKind? "pred") + ("pred" | error?="error" "pred"?) name=Identifier "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? @@ -69,14 +63,14 @@ PredicateDefinition: Conjunction: literals+=Expr ("," literals+=Expr)*; -FunctionDefinition: - "fn" functionType=PrimitiveType name=Identifier - "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" - ("=" cases+=Case (";" cases+=Case)*)? - "."; - -Case: - Conjunction ({Match.condition=current} "->" value=Expr)?; +//FunctionDefinition: +// "fn" functionType=PrimitiveType name=Identifier +// "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" +// ("=" cases+=Case (";" cases+=Case)*)? +// "."; +// +//Case: +// Conjunction ({Match.condition=current} "->" value=Expr)?; //RuleDefinition: // "rule" @@ -87,7 +81,7 @@ Case: // "."; Parameter: - (modality=Modality? parameterType=[Relation|QualifiedName])? name=Identifier; + parameterType=[Relation|QualifiedName]? name=Identifier; //Consequent: // actions+=Action ("," actions+=Action)*; @@ -268,7 +262,7 @@ NonContainmentQualifiedName hidden(): NonContainmentIdentifier ("::" Identifier)*; Identifier: - NonContainmentIdentifier | "contains"; + NonContainmentIdentifier | "contains" | "container"; NonContainmentIdentifier: ID | "contained" | "sum" | "prod" | "min" | "max"; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java index b145ef27..31eb55a6 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java @@ -18,6 +18,7 @@ import org.eclipse.xtext.resource.DerivedStateAwareResource; import org.eclipse.xtext.resource.IDerivedStateComputer; import org.eclipse.xtext.resource.XtextResource; import tools.refinery.language.model.problem.*; +import tools.refinery.language.utils.ProblemUtil; import java.util.*; import java.util.function.Function; @@ -58,7 +59,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { } protected void installDerivedProblemState(Problem problem, Adapter adapter, boolean preLinkingPhase) { - installNewNodes(problem, adapter); + installDerivedClassDeclarationState(problem, adapter); if (preLinkingPhase) { return; } @@ -66,24 +67,67 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { derivedVariableComputer.installDerivedVariables(problem, nodeNames); } - protected void installNewNodes(Problem problem, Adapter adapter) { - for (Statement statement : problem.getStatements()) { - if (statement instanceof ClassDeclaration declaration && !declaration.isAbstract() - && declaration.getNewNode() == null) { + protected void installDerivedClassDeclarationState(Problem problem, Adapter adapter) { + for (var statement : problem.getStatements()) { + if (statement instanceof ClassDeclaration classDeclaration) { + installOrRemoveNewNode(adapter, classDeclaration); + for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) { + if (featureDeclaration instanceof ReferenceDeclaration referenceDeclaration) { + installOrRemoveInvalidMultiplicityPredicate(adapter, classDeclaration, referenceDeclaration); + } + } + } + } + } + + protected void installOrRemoveNewNode(Adapter adapter, ClassDeclaration declaration) { + if (declaration.isAbstract()) { + var newNode = declaration.getNewNode(); + if (newNode != null) { + declaration.setNewNode(null); + adapter.removeNewNode(declaration); + } + } else { + if (declaration.getNewNode() == null) { var newNode = adapter.createNewNodeIfAbsent(declaration, key -> createNode(NEW_NODE)); declaration.setNewNode(newNode); } } } + protected void installOrRemoveInvalidMultiplicityPredicate( + Adapter adapter, ClassDeclaration containingClassDeclaration, ReferenceDeclaration declaration) { + if (ProblemUtil.hasMultiplicityConstraint(declaration)) { + if (declaration.getInvalidMultiplicity() == null) { + var invalidMultiplicity = adapter.createInvalidMultiplicityPredicateIfAbsent(declaration, key -> { + var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition(); + predicate.setError(true); + predicate.setName("invalidMultiplicity"); + var parameter = ProblemFactory.eINSTANCE.createParameter(); + parameter.setParameterType(containingClassDeclaration); + parameter.setName("node"); + predicate.getParameters().add(parameter); + return predicate; + }); + declaration.setInvalidMultiplicity(invalidMultiplicity); + } + } else { + var invalidMultiplicity = declaration.getInvalidMultiplicity(); + if (invalidMultiplicity != null) { + declaration.setInvalidMultiplicity(null); + adapter.removeInvalidMultiplicityPredicate(declaration); + } + } + } + protected Set installDerivedNodes(Problem problem) { var collector = nodeNameCollectorProvider.get(); collector.collectNodeNames(problem); Set nodeNames = collector.getNodeNames(); - List grapNodes = problem.getNodes(); + List graphNodes = problem.getNodes(); for (String nodeName : nodeNames) { var graphNode = createNode(nodeName); - grapNodes.add(graphNode); + graphNodes.add(graphNode); } return nodeNames; } @@ -104,15 +148,24 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { } protected void discardDerivedProblemState(Problem problem, Adapter adapter) { - Set classDeclarations = new HashSet<>(); + var abstractClassDeclarations = new HashSet(); + var referenceDeclarationsWithMultiplicity = new HashSet(); problem.getNodes().clear(); for (var statement : problem.getStatements()) { if (statement instanceof ClassDeclaration classDeclaration) { classDeclaration.setNewNode(null); - classDeclarations.add(classDeclaration); + if (classDeclaration.isAbstract()) { + abstractClassDeclarations.add(classDeclaration); + } + for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) { + if (featureDeclaration instanceof ReferenceDeclaration referenceDeclaration && + ProblemUtil.hasMultiplicityConstraint(referenceDeclaration)) { + referenceDeclarationsWithMultiplicity.add(referenceDeclaration); + } + } } } - adapter.retainAll(classDeclarations); + adapter.retainAll(abstractClassDeclarations, referenceDeclarationsWithMultiplicity); derivedVariableComputer.discardDerivedVariables(problem); } @@ -134,14 +187,31 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { protected static class Adapter extends AdapterImpl { private final Map newNodes = new HashMap<>(); + private final Map invalidMultiplicityPredicates = new HashMap<>(); public Node createNewNodeIfAbsent(ClassDeclaration classDeclaration, - Function createNode) { + Function createNode) { return newNodes.computeIfAbsent(classDeclaration, createNode); } - public void retainAll(Collection classDeclarations) { - newNodes.keySet().retainAll(classDeclarations); + public void removeNewNode(ClassDeclaration classDeclaration) { + newNodes.remove(classDeclaration); + } + + public PredicateDefinition createInvalidMultiplicityPredicateIfAbsent( + ReferenceDeclaration referenceDeclaration, + Function createPredicate) { + return invalidMultiplicityPredicates.computeIfAbsent(referenceDeclaration, createPredicate); + } + + public void removeInvalidMultiplicityPredicate(ReferenceDeclaration referenceDeclaration) { + invalidMultiplicityPredicates.remove(referenceDeclaration); + } + + public void retainAll(Collection abstractClassDeclarations, + Collection referenceDeclarationsWithMultiplicity) { + newNodes.keySet().retainAll(abstractClassDeclarations); + invalidMultiplicityPredicates.keySet().retainAll(referenceDeclarationsWithMultiplicity); } @Override diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java index 1fe2df89..29eaad84 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java @@ -8,7 +8,6 @@ package tools.refinery.language.resource; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.resource.DefaultLocationInFileProvider; import org.eclipse.xtext.util.ITextRegion; - import tools.refinery.language.model.problem.ImplicitVariable; import tools.refinery.language.model.problem.Node; import tools.refinery.language.utils.ProblemUtil; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java index 630be379..a16f77eb 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java @@ -5,6 +5,9 @@ */ package tools.refinery.language.resource; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import com.google.inject.Singleton; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.naming.IQualifiedNameConverter; @@ -13,19 +16,18 @@ import org.eclipse.xtext.resource.EObjectDescription; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionStrategy; import org.eclipse.xtext.util.IAcceptor; - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import tools.refinery.language.model.problem.NamedElement; -import tools.refinery.language.model.problem.Node; -import tools.refinery.language.model.problem.Problem; -import tools.refinery.language.model.problem.Variable; +import tools.refinery.language.model.problem.*; import tools.refinery.language.naming.NamingUtil; import tools.refinery.language.utils.ProblemUtil; +import java.util.Map; + @Singleton public class ProblemResourceDescriptionStrategy extends DefaultResourceDescriptionStrategy { + public static final String ERROR_PREDICATE = "tools.refinery.language.resource" + + ".ProblemResourceDescriptionStrategy.ERROR_PREDICATE"; + public static final String ERROR_PREDICATE_TRUE = "true"; + @Inject private IQualifiedNameConverter qualifiedNameConverter; @@ -40,9 +42,10 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti } var problem = EcoreUtil2.getContainerOfType(eObject, Problem.class); var problemQualifiedName = getNameAsQualifiedName(problem); + var userData = getUserData(eObject); boolean nameExported; if (shouldExportSimpleName(eObject)) { - acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, acceptor); + acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, userData, acceptor); nameExported = true; } else { nameExported = false; @@ -56,7 +59,7 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti } qualifiedName = parentQualifiedName.append(qualifiedName); if (shouldExportSimpleName(parent)) { - acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, acceptor); + acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, userData, acceptor); nameExported = true; } else { nameExported = false; @@ -64,16 +67,15 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti parent = parent.eContainer(); } if (!nameExported) { - acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, acceptor); + acceptEObjectDescription(eObject, problemQualifiedName, qualifiedName, userData, acceptor); } return true; } protected QualifiedName getNameAsQualifiedName(EObject eObject) { - if (!(eObject instanceof NamedElement)) { + if (!(eObject instanceof NamedElement namedElement)) { return null; } - var namedElement = (NamedElement) eObject; var name = namedElement.getName(); if (NamingUtil.isNullOrEmpty(name)) { return null; @@ -93,16 +95,28 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti return true; } + protected Map getUserData(EObject eObject) { + var builder = ImmutableMap.builder(); + if (eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isError()) { + builder.put(ERROR_PREDICATE, ERROR_PREDICATE_TRUE); + } + return builder.build(); + } + protected boolean shouldExportSimpleName(EObject eObject) { if (eObject instanceof Node node) { return !ProblemUtil.isNewNode(node); } + if (eObject instanceof PredicateDefinition predicateDefinition) { + return !ProblemUtil.isInvalidMultiplicityConstraint(predicateDefinition); + } return true; } private void acceptEObjectDescription(EObject eObject, QualifiedName prefix, QualifiedName qualifiedName, - IAcceptor acceptor) { + Map userData, IAcceptor acceptor) { var qualifiedNameWithPrefix = prefix == null ? qualifiedName : prefix.append(qualifiedName); - acceptor.accept(EObjectDescription.create(qualifiedNameWithPrefix, eObject)); + var description = EObjectDescription.create(qualifiedNameWithPrefix, eObject, userData); + acceptor.accept(description); } } diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java index c8c7fd4a..70a86b51 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java @@ -7,7 +7,7 @@ package tools.refinery.language.utils; import tools.refinery.language.model.problem.*; -public record BuiltinSymbols(Problem problem, ClassDeclaration node, ReferenceDeclaration equals, - PredicateDefinition exists, PredicateDefinition contained, PredicateDefinition contains, - PredicateDefinition root) { +public record BuiltinSymbols(Problem problem, ClassDeclaration node, PredicateDefinition equals, + PredicateDefinition exists, ClassDeclaration contained, PredicateDefinition contains, + PredicateDefinition invalidNumberOfContainers) { } diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java deleted file mode 100644 index e4e4d07a..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.utils; - -import java.util.Map; - -import tools.refinery.language.model.problem.Node; -import tools.refinery.language.model.problem.Relation; - -public record CollectedSymbols(Map nodes, Map relations) { - -} diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java deleted file mode 100644 index a43c7dfe..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.utils; - -import tools.refinery.language.model.problem.PredicateKind; - -public enum ContainmentRole { - NONE, - CONTAINED, - CONTAINMENT; - - public static ContainmentRole fromPredicateKind(PredicateKind predicateKind) { - return switch (predicateKind) { - case CONTAINED -> CONTAINED; - case CONTAINMENT -> CONTAINMENT; - default -> NONE; - }; - } -} diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java deleted file mode 100644 index 0fa7a454..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java +++ /dev/null @@ -1,9 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.utils; - -public record NodeInfo(String name, boolean individual) { -} diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java index 738a0896..9f08654c 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java @@ -6,7 +6,6 @@ package tools.refinery.language.utils; import com.google.inject.Inject; -import com.google.inject.Provider; import com.google.inject.Singleton; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; @@ -21,9 +20,6 @@ public class ProblemDesugarer { @Inject private IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE; - @Inject - private Provider symbolCollectorProvider; - public Optional getBuiltinProblem(EObject context) { return Optional.ofNullable(context).map(EObject::eResource).flatMap(resource -> cache.get("builtinProblem", resource, () -> doGetBuiltinProblem(resource))); @@ -43,12 +39,13 @@ public class ProblemDesugarer { private BuiltinSymbols doGetBuiltinSymbols(Problem builtin) { var node = doGetDeclaration(builtin, ClassDeclaration.class, "node"); - var equals = doGetEqualsReference(node); + var equals = doGetDeclaration(builtin, PredicateDefinition.class, "equals"); var exists = doGetDeclaration(builtin, PredicateDefinition.class, "exists"); - var contained = doGetDeclaration(builtin, PredicateDefinition.class, "contained"); + var contained = doGetDeclaration(builtin, ClassDeclaration.class, "contained"); var contains = doGetDeclaration(builtin, PredicateDefinition.class, "contains"); - var root = doGetDeclaration(builtin, PredicateDefinition.class, "root"); - return new BuiltinSymbols(builtin, node, equals, exists, contained, contains, root); + var invalidNumberOfContainers = doGetDeclaration(builtin, PredicateDefinition.class, + "invalidNumberOfContainers"); + return new BuiltinSymbols(builtin, node, equals, exists, contained, contains, invalidNumberOfContainers); } private T doGetDeclaration(Problem builtin, Class type, String name) { @@ -57,13 +54,6 @@ public class ProblemDesugarer { .orElseThrow(() -> new IllegalArgumentException("Built-in declaration " + name + " was not found")); } - private ReferenceDeclaration doGetEqualsReference(ClassDeclaration nodeClassDeclaration) { - return (ReferenceDeclaration) nodeClassDeclaration.getFeatureDeclarations().stream() - .filter(reference -> reference instanceof ReferenceDeclaration && - "equals".equals(reference.getName())).findFirst() - .orElseThrow(() -> new IllegalArgumentException("Reference " + "equals" + " not found")); - } - public Collection getSuperclassesAndSelf(ClassDeclaration classDeclaration) { return cache.get(Tuples.create(classDeclaration, "superclassesAndSelf"), classDeclaration.eResource(), () -> doGetSuperclassesAndSelf(classDeclaration)); @@ -109,9 +99,4 @@ public class ProblemDesugarer { public boolean isContainmentReference(ReferenceDeclaration referenceDeclaration) { return referenceDeclaration.getKind() == ReferenceKind.CONTAINMENT; } - - public CollectedSymbols collectSymbols(Problem problem) { - return cache.get(Tuples.create(problem, "collectedSymbols"), problem.eResource(), - () -> symbolCollectorProvider.get().collectSymbols(problem)); - } } diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java index 9486dc2a..bac274b0 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java @@ -8,32 +8,12 @@ package tools.refinery.language.utils; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; -import tools.refinery.language.model.problem.ImplicitVariable; -import tools.refinery.language.model.problem.Node; -import tools.refinery.language.model.problem.ProblemPackage; -import tools.refinery.language.model.problem.Variable; +import tools.refinery.language.model.problem.*; public final class ProblemUtil { public static final String BUILTIN_LIBRARY_NAME = "builtin"; - public static final URI BUILTIN_LIBRARY_URI = getLibraryUri(BUILTIN_LIBRARY_NAME); - public static final String NODE_CLASS_NAME = "node"; - - public static final String DOMAIN_CLASS_NAME = "domain"; - - public static final String DATA_CLASS_NAME = "data"; - - public static final String INT_CLASS_NAME = "int"; - - public static final String REAL_CLASS_NAME = "real"; - - public static final String STRING_CLASS_NAME = "string"; - - public static final String EQUALS_RELATION_NAME = "equals"; - - public static final String EXISTS_PREDICATE_NAME = "exists"; - private ProblemUtil() { throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); } @@ -80,6 +60,22 @@ public final class ProblemUtil { return node.eContainingFeature() == ProblemPackage.Literals.CLASS_DECLARATION__NEW_NODE; } + public static boolean isInvalidMultiplicityConstraint(PredicateDefinition predicateDefinition) { + return predicateDefinition.eContainingFeature() == + ProblemPackage.Literals.REFERENCE_DECLARATION__INVALID_MULTIPLICITY; + } + + public static boolean hasMultiplicityConstraint(ReferenceDeclaration referenceDeclaration) { + var multiplicity = referenceDeclaration.getMultiplicity(); + if (multiplicity instanceof UnboundedMultiplicity) { + return false; + } + if (multiplicity instanceof RangeMultiplicity rangeMultiplicity) { + return rangeMultiplicity.getLowerBound() > 0 || rangeMultiplicity.getUpperBound() >= 0; + } + return true; + } + private static URI getLibraryUri(String libraryName) { return URI.createURI(ProblemUtil.class.getClassLoader() .getResource("tools/refinery/language/%s.problem".formatted(libraryName)).toString()); diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java deleted file mode 100644 index 1c46fe72..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.utils; - -import tools.refinery.language.model.problem.*; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public record RelationInfo(String name, ContainmentRole containmentRole, List parameters, - Multiplicity multiplicity, Relation opposite, Collection bodies, - Collection assertions, Collection typeScopes) { - public RelationInfo(String name, ContainmentRole containmentRole, List parameters, - Multiplicity multiplicity, Relation opposite, Collection bodies) { - this(name, containmentRole, parameters, multiplicity, opposite, bodies, new ArrayList<>(), new ArrayList<>()); - } - - public boolean hasDefinition() { - return bodies != null && !bodies.isEmpty(); - } - - public int arity() { - return parameters.size(); - } -} diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java deleted file mode 100644 index a4ea1113..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.language.utils; - -import com.google.inject.Inject; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.naming.IQualifiedNameConverter; -import org.eclipse.xtext.naming.IQualifiedNameProvider; -import tools.refinery.language.model.problem.*; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -class SymbolCollector { - @Inject - private IQualifiedNameProvider qualifiedNameProvider; - - @Inject - private IQualifiedNameConverter qualifiedNameConverter; - - @Inject - private ProblemDesugarer desugarer; - - private BuiltinSymbols builtinSymbols; - - private final Map nodes = new LinkedHashMap<>(); - - private final Map relations = new LinkedHashMap<>(); - - public CollectedSymbols collectSymbols(Problem problem) { - builtinSymbols = desugarer.getBuiltinSymbols(problem).orElseThrow(() -> new IllegalArgumentException( - "Problem has no associated built-in library")); - collectOwnSymbols(builtinSymbols.problem()); - collectOwnSymbols(problem); - return new CollectedSymbols(nodes, relations); - } - - public void collectOwnSymbols(Problem problem) { - collectOwnRelations(problem); - collectOwnNodes(problem); - collectOwnAssertions(problem); - } - - private void collectOwnRelations(Problem problem) { - for (var statement : problem.getStatements()) { - if (statement instanceof PredicateDefinition predicateDefinition) { - collectPredicate(predicateDefinition); - } else if (statement instanceof ClassDeclaration classDeclaration) { - collectClass(classDeclaration); - } else if (statement instanceof EnumDeclaration enumDeclaration) { - collectEnum(enumDeclaration); - } else if (statement instanceof RuleDefinition) { - throw new UnsupportedOperationException("Rules are not currently supported"); - } - } - } - - private void collectPredicate(PredicateDefinition predicateDefinition) { - var predicateKind = predicateDefinition.getKind(); - var info = new RelationInfo(getQualifiedNameString(predicateDefinition), - ContainmentRole.fromPredicateKind(predicateKind), predicateDefinition.getParameters(), null, null, - predicateDefinition.getBodies()); - relations.put(predicateDefinition, info); - } - - private void collectClass(ClassDeclaration classDeclaration) { - var contained = classDeclaration != builtinSymbols.node(); - var containmentRole = contained ? ContainmentRole.CONTAINED : ContainmentRole.NONE; - var instanceParameter = ProblemFactory.eINSTANCE.createParameter(); - instanceParameter.setName("instance"); - var classInfo = new RelationInfo(getQualifiedNameString(classDeclaration), containmentRole, - List.of(instanceParameter), null, null, List.of()); - relations.put(classDeclaration, classInfo); - collectFeatures(classDeclaration); - } - - private void collectFeatures(ClassDeclaration classDeclaration) { - for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) { - if (featureDeclaration instanceof ReferenceDeclaration referenceDeclaration) { - collectReference(classDeclaration, referenceDeclaration); - } else if (featureDeclaration instanceof AttributeDeclaration attributeDeclaration) { - collectAttribute(classDeclaration, attributeDeclaration); - } else if (featureDeclaration instanceof FlagDeclaration flagDeclaration) { - collectFlag(classDeclaration, flagDeclaration); - } else { - throw new IllegalArgumentException("Unknown FeatureDeclaration: " + featureDeclaration); - } - } - } - - private void collectReference(ClassDeclaration classDeclaration, ReferenceDeclaration referenceDeclaration) { - var referenceRole = desugarer.isContainmentReference(referenceDeclaration) ? - ContainmentRole.CONTAINMENT : - ContainmentRole.NONE; - var sourceParameter = ProblemFactory.eINSTANCE.createParameter(); - sourceParameter.setName("source"); - sourceParameter.setParameterType(classDeclaration); - var targetParameter = ProblemFactory.eINSTANCE.createParameter(); - targetParameter.setName("target"); - var multiplicity = referenceDeclaration.getMultiplicity(); - if (multiplicity == null) { - var exactMultiplicity = ProblemFactory.eINSTANCE.createExactMultiplicity(); - exactMultiplicity.setExactValue(1); - multiplicity = exactMultiplicity; - } - targetParameter.setParameterType(referenceDeclaration.getReferenceType()); - var referenceInfo = new RelationInfo(getQualifiedNameString(referenceDeclaration), referenceRole, - List.of(sourceParameter, targetParameter), multiplicity, referenceDeclaration.getOpposite(), - List.of()); - this.relations.put(referenceDeclaration, referenceInfo); - } - - private void collectAttribute(ClassDeclaration classDeclaration, AttributeDeclaration attributeDeclaration) { - // TODO Implement attribute handling. - } - - private void collectFlag(ClassDeclaration classDeclaration, FlagDeclaration flagDeclaration) { - var parameter = ProblemFactory.eINSTANCE.createParameter(); - parameter.setName("object"); - parameter.setParameterType(classDeclaration); - var referenceInfo = new RelationInfo(getQualifiedNameString(flagDeclaration), ContainmentRole.NONE, - List.of(parameter), null, null, List.of()); - this.relations.put(flagDeclaration, referenceInfo); - } - - private void collectEnum(EnumDeclaration enumDeclaration) { - var instanceParameter = ProblemFactory.eINSTANCE.createParameter(); - instanceParameter.setName("instance"); - var info = new RelationInfo(getQualifiedNameString(enumDeclaration), ContainmentRole.NONE, - List.of(instanceParameter), null, null, List.of()); - this.relations.put(enumDeclaration, info); - } - - private void collectOwnNodes(Problem problem) { - for (var statement : problem.getStatements()) { - if (statement instanceof IndividualDeclaration individualDeclaration) { - collectIndividuals(individualDeclaration); - } else if (statement instanceof ClassDeclaration classDeclaration) { - collectNewNode(classDeclaration); - } else if (statement instanceof EnumDeclaration enumDeclaration) { - collectEnumLiterals(enumDeclaration); - } - } - for (var node : problem.getNodes()) { - addNode(node, false); - } - } - - private void collectIndividuals(IndividualDeclaration individualDeclaration) { - for (var individual : individualDeclaration.getNodes()) { - addNode(individual, true); - } - } - - private void collectNewNode(ClassDeclaration classDeclaration) { - var newNode = classDeclaration.getNewNode(); - if (newNode != null) { - addNode(newNode, false); - } - } - - private void collectEnumLiterals(EnumDeclaration enumDeclaration) { - for (var literal : enumDeclaration.getLiterals()) { - addNode(literal, true); - } - } - - private void addNode(Node node, boolean individual) { - var info = new NodeInfo(getQualifiedNameString(node), individual); - this.nodes.put(node, info); - } - - private String getQualifiedNameString(EObject eObject) { - var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject); - if (qualifiedName == null) { - return null; - } - return qualifiedNameConverter.toString(qualifiedName); - } - - private void collectOwnAssertions(Problem problem) { - for (var statement : problem.getStatements()) { - if (statement instanceof Assertion assertion) { - collectAssertion(assertion); - } else if (statement instanceof PredicateDefinition predicateDefinition) { - collectPredicateAssertion(predicateDefinition); - } else if (statement instanceof ClassDeclaration classDeclaration) { - collectClassAssertion(classDeclaration); - } else if (statement instanceof EnumDeclaration enumDeclaration) { - collectEnumAssertions(enumDeclaration); - } - } - } - - private void collectAssertion(Assertion assertion) { - var relationInfo = this.relations.get(assertion.getRelation()); - if (relationInfo == null) { - throw new IllegalStateException("Assertion refers to unknown relation"); - } - if (assertion.getArguments().size() != relationInfo.parameters().size()) { - // Silently ignoring assertions of invalid arity helps when SymbolCollector is called on an invalid - // Problem during editing. The errors can still be detected by the Problem validator. - return; - } - relationInfo.assertions().add(assertion); - } - - private void collectPredicateAssertion(PredicateDefinition predicateDefinition) { - if (predicateDefinition.getKind() != PredicateKind.ERROR) { - return; - } - int arity = predicateDefinition.getParameters().size(); - addAssertion(predicateDefinition, LogicValue.FALSE, new Node[arity]); - } - - private void collectClassAssertion(ClassDeclaration classDeclaration) { - var node = classDeclaration.getNewNode(); - if (node == null) { - return; - } - addAssertion(classDeclaration, LogicValue.TRUE, node); - addAssertion(builtinSymbols.exists(), LogicValue.UNKNOWN, node); - addAssertion(builtinSymbols.equals(), LogicValue.UNKNOWN, node, node); - } - - private void collectEnumAssertions(EnumDeclaration enumDeclaration) { - for (var literal : enumDeclaration.getLiterals()) { - addAssertion(enumDeclaration, LogicValue.TRUE, literal); - } - } - - private void addAssertion(Relation relation, LogicValue logicValue, Node... nodes) { - var assertion = ProblemFactory.eINSTANCE.createAssertion(); - assertion.setRelation(relation); - for (var node : nodes) { - AssertionArgument argument; - if (node == null) { - argument = ProblemFactory.eINSTANCE.createWildcardAssertionArgument(); - } else { - var nodeArgument = ProblemFactory.eINSTANCE.createNodeAssertionArgument(); - nodeArgument.setNode(node); - argument = nodeArgument; - } - assertion.getArguments().add(argument); - } - var value = ProblemFactory.eINSTANCE.createLogicConstant(); - value.setLogicValue(logicValue); - assertion.setValue(value); - collectAssertion(assertion); - } -} -- cgit v1.2.3-54-g00ecf