diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-09-13 20:39:27 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-09-14 12:10:43 +0200 |
commit | 748bf89911359bffbfafe354e522f7d656488146 (patch) | |
tree | 555fe86e0a068eda1f84538faaca8d6e76fd3bd8 /subprojects/language/src | |
parent | chore(deps): bump dependencies (diff) | |
download | refinery-748bf89911359bffbfafe354e522f7d656488146.tar.gz refinery-748bf89911359bffbfafe354e522f7d656488146.tar.zst refinery-748bf89911359bffbfafe354e522f7d656488146.zip |
refactor(language): clarify containment hierarchy
Diffstat (limited to 'subprojects/language/src')
3 files changed, 74 insertions, 9 deletions
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 f7b86dca..2a5af628 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext | |||
@@ -26,15 +26,23 @@ EnumDeclaration: | |||
26 | EnumLiteral returns Node: | 26 | EnumLiteral returns Node: |
27 | name=Identifier; | 27 | name=Identifier; |
28 | 28 | ||
29 | enum ReferenceKind: | ||
30 | REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; | ||
31 | |||
29 | ReferenceDeclaration: | 32 | ReferenceDeclaration: |
30 | (containment?="contains" | "refers")? | 33 | ( |
31 | referenceType=[Relation|QualifiedName] | 34 | kind=ReferenceKind referenceType=[Relation|QualifiedName] | |
35 | referenceType=[Relation|NonRelationKindQualifiedName] | ||
36 | ) | ||
32 | ("[" multiplicity=Multiplicity "]")? | 37 | ("[" multiplicity=Multiplicity "]")? |
33 | name=Identifier | 38 | name=Identifier |
34 | ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; | 39 | ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; |
35 | 40 | ||
41 | enum PredicateKind: | ||
42 | ERROR="error" | CONTAINED="contained" | CONTAINMENT="containment"; | ||
43 | |||
36 | PredicateDefinition: | 44 | PredicateDefinition: |
37 | (error?="error" "pred"? | "pred") | 45 | (kind=PredicateKind "pred"? | "pred") |
38 | name=Identifier | 46 | name=Identifier |
39 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" | 47 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" |
40 | ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? | 48 | ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? |
@@ -150,7 +158,7 @@ ScopeDeclaration: | |||
150 | "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* "."; | 158 | "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* "."; |
151 | 159 | ||
152 | TypeScope: | 160 | TypeScope: |
153 | targetType=[ClassDeclaration|QualifiedName] | 161 | targetType=[Relation|QualifiedName] |
154 | (increment?="+=" | "=") | 162 | (increment?="+=" | "=") |
155 | multiplicity=DefiniteMultiplicity; | 163 | multiplicity=DefiniteMultiplicity; |
156 | 164 | ||
@@ -175,12 +183,19 @@ IndividualDeclaration: | |||
175 | UpperBound returns ecore::EInt: | 183 | UpperBound returns ecore::EInt: |
176 | INT | "*"; | 184 | INT | "*"; |
177 | 185 | ||
186 | NonRelationKindQualifiedName hidden(): | ||
187 | NonRelationKindIdentifier ("::" Identifier)*; | ||
188 | |||
178 | QualifiedName hidden(): | 189 | QualifiedName hidden(): |
179 | Identifier ("::" Identifier)*; | 190 | Identifier ("::" Identifier)*; |
180 | 191 | ||
192 | NonRelationKindIdentifier: | ||
193 | ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | | ||
194 | "pred" | "indiv" | "problem" | "new" | "delete" | "rule" | "may" | "must" | "current" | | ||
195 | "count" | "default" | "scope" | "contained" | "containment"; | ||
196 | |||
181 | Identifier: | 197 | Identifier: |
182 | ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | "pred" | | 198 | NonRelationKindIdentifier | "refers" | "contains" | "container"; |
183 | "indiv" | "problem" | "new" | "delete" | "rule" | "may" | "must" | "current" | "count"; | ||
184 | 199 | ||
185 | Integer returns ecore::EInt hidden(): | 200 | Integer returns ecore::EInt hidden(): |
186 | "-"? INT; | 201 | "-"? INT; |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemUtil.java index b1e39176..0be296fd 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/ProblemUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemUtil.java | |||
@@ -27,6 +27,10 @@ public final class ProblemUtil { | |||
27 | 27 | ||
28 | public static final String NODE_CLASS_NAME = "node"; | 28 | public static final String NODE_CLASS_NAME = "node"; |
29 | 29 | ||
30 | public static final String DOMAIN_CLASS_NAME = "domain"; | ||
31 | |||
32 | public static final String DATA_CLASS_NAME = "data"; | ||
33 | |||
30 | private ProblemUtil() { | 34 | private ProblemUtil() { |
31 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | 35 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); |
32 | } | 36 | } |
@@ -80,15 +84,15 @@ public final class ProblemUtil { | |||
80 | return false; | 84 | return false; |
81 | } | 85 | } |
82 | 86 | ||
83 | public static Optional<ClassDeclaration> getNodeClassDeclaration(EObject context) { | 87 | public static Optional<ClassDeclaration> getBuiltinClassDeclaration(EObject context, String name) { |
84 | return getBuiltInLibrary(context).flatMap(problem -> problem.getStatements().stream() | 88 | return getBuiltInLibrary(context).flatMap(problem -> problem.getStatements().stream() |
85 | .filter(ClassDeclaration.class::isInstance).map(ClassDeclaration.class::cast) | 89 | .filter(ClassDeclaration.class::isInstance).map(ClassDeclaration.class::cast) |
86 | .filter(declaration -> NODE_CLASS_NAME.equals(declaration.getName())).findFirst()); | 90 | .filter(declaration -> name.equals(declaration.getName())).findFirst()); |
87 | } | 91 | } |
88 | 92 | ||
89 | public static Collection<ClassDeclaration> getSuperclassesAndSelf(ClassDeclaration classDeclaration) { | 93 | public static Collection<ClassDeclaration> getSuperclassesAndSelf(ClassDeclaration classDeclaration) { |
90 | Set<ClassDeclaration> found = new HashSet<>(); | 94 | Set<ClassDeclaration> found = new HashSet<>(); |
91 | getNodeClassDeclaration(classDeclaration).ifPresent(found::add); | 95 | getBuiltinClassDeclaration(classDeclaration, NODE_CLASS_NAME).ifPresent(found::add); |
92 | Deque<ClassDeclaration> queue = new ArrayDeque<>(); | 96 | Deque<ClassDeclaration> queue = new ArrayDeque<>(); |
93 | queue.addLast(classDeclaration); | 97 | queue.addLast(classDeclaration); |
94 | while (!queue.isEmpty()) { | 98 | while (!queue.isEmpty()) { |
@@ -102,6 +106,11 @@ public final class ProblemUtil { | |||
102 | } | 106 | } |
103 | } | 107 | } |
104 | } | 108 | } |
109 | getBuiltinClassDeclaration(classDeclaration, DATA_CLASS_NAME).ifPresent((dataClassDelcaration) -> { | ||
110 | if (!found.contains(dataClassDelcaration)) { | ||
111 | getBuiltinClassDeclaration(classDeclaration, DOMAIN_CLASS_NAME).ifPresent(found::add); | ||
112 | } | ||
113 | }); | ||
105 | return found; | 114 | return found; |
106 | } | 115 | } |
107 | 116 | ||
@@ -113,6 +122,28 @@ public final class ProblemUtil { | |||
113 | return referenceDeclarations; | 122 | return referenceDeclarations; |
114 | } | 123 | } |
115 | 124 | ||
125 | public static boolean isDataClass(Relation relation) { | ||
126 | if (relation instanceof ClassDeclaration classDeclaration) { | ||
127 | var supertypes = getSuperclassesAndSelf(classDeclaration); | ||
128 | return getBuiltinClassDeclaration(classDeclaration, DATA_CLASS_NAME).map(supertypes::contains) | ||
129 | .orElse(false); | ||
130 | } | ||
131 | return false; | ||
132 | } | ||
133 | |||
134 | public static boolean isContainmentReference(ReferenceDeclaration referenceDeclaration) { | ||
135 | switch (referenceDeclaration.getKind()) { | ||
136 | case REFERENCE, CONTAINER: | ||
137 | return false; | ||
138 | case CONTAINMENT: | ||
139 | return true; | ||
140 | case DEFAULT: | ||
141 | return isDataClass(referenceDeclaration.getReferenceType()); | ||
142 | default: | ||
143 | throw new IllegalArgumentException("Unknown reference kind " + referenceDeclaration.getKind()); | ||
144 | } | ||
145 | } | ||
146 | |||
116 | private static URI getLibraryUri(String libraryName) { | 147 | private static URI getLibraryUri(String libraryName) { |
117 | return URI.createURI(ProblemUtil.class.getClassLoader() | 148 | return URI.createURI(ProblemUtil.class.getClassLoader() |
118 | .getResource("tools/refinery/language/%s.problem".formatted(libraryName)).toString()); | 149 | .getResource("tools/refinery/language/%s.problem".formatted(libraryName)).toString()); |
diff --git a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem index 323e03f1..e39ff1a3 100644 --- a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem +++ b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem | |||
@@ -19,3 +19,22 @@ class real extends data. | |||
19 | class int extends data. | 19 | class int extends data. |
20 | 20 | ||
21 | class string extends data. | 21 | class string extends data. |
22 | |||
23 | pred contained(node node). | ||
24 | |||
25 | pred contains(node container, node contained). | ||
26 | |||
27 | pred root(node node). | ||
28 | |||
29 | % error missingContainer(contained node) <-> | ||
30 | % !contains(node, _), !root(node). | ||
31 | % | ||
32 | % error tooManyContainers(contained node) <-> | ||
33 | % count contains(_, node) > 1 | ||
34 | % ; | ||
35 | % contains(_, node), root(node) | ||
36 | % ; | ||
37 | % contains(_, node), !contained(node). | ||
38 | % | ||
39 | % error containmentCycle(node node) <-> | ||
40 | % contains+(node, node). | ||