diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-01-31 02:00:09 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-01-31 18:45:13 +0100 |
commit | c63126d2f1ce5f571c316b37e00fb43d2da7c7d3 (patch) | |
tree | 16e9dd04624565f7c9ccedd17749a9f264e89cb0 /subprojects/language/src/main/java | |
parent | fix(build): avoid cyclic dependency (diff) | |
download | refinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.tar.gz refinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.tar.zst refinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.zip |
refactor(language): module and node declarations
* New default file extension: .refinery (.problem is also supported).
* Add module keyword for self-contained modules.
* Rename indiv declarations to atom declaration.
* Add node and multi declarations for explicitly declared nodes and
multi-objects, respectively.
Diffstat (limited to 'subprojects/language/src/main/java')
7 files changed, 43 insertions, 28 deletions
diff --git a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 index 59eba8f7..863e55d4 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 +++ b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 | |||
@@ -51,7 +51,7 @@ Workflow { | |||
51 | 51 | ||
52 | language = StandardLanguage { | 52 | language = StandardLanguage { |
53 | name = 'tools.refinery.language.Problem' | 53 | name = 'tools.refinery.language.Problem' |
54 | fileExtensions = 'problem' | 54 | fileExtensions = 'refinery,problem' |
55 | referencedResource = 'platform:/resource/tools.refinery.refinery-language-model/model/problem.genmodel' | 55 | referencedResource = 'platform:/resource/tools.refinery.refinery-language-model/model/problem.genmodel' |
56 | serializer = { | 56 | serializer = { |
57 | generateStub = false | 57 | generateStub = false |
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 0fb96954..c5c42ebe 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext | |||
@@ -9,13 +9,16 @@ import "http://www.eclipse.org/emf/2002/Ecore" as ecore | |||
9 | import "https://refinery.tools/emf/2021/Problem" | 9 | import "https://refinery.tools/emf/2021/Problem" |
10 | 10 | ||
11 | Problem: | 11 | Problem: |
12 | ("problem" name=Identifier ".")? | 12 | (kind=ModuleKind name=QualifiedName? ".")? |
13 | statements+=Statement*; | 13 | statements+=Statement*; |
14 | 14 | ||
15 | enum ModuleKind: | ||
16 | PROBLEM="problem" | MODULE="module"; | ||
17 | |||
15 | Statement: | 18 | Statement: |
16 | Assertion | ClassDeclaration | EnumDeclaration | | 19 | Assertion | ClassDeclaration | EnumDeclaration | |
17 | PredicateDefinition | /* FunctionDefinition | RuleDefinition | */ | 20 | PredicateDefinition | /* FunctionDefinition | RuleDefinition | */ |
18 | ScopeDeclaration | IndividualDeclaration; | 21 | ScopeDeclaration | NodeDeclaration; |
19 | 22 | ||
20 | ClassDeclaration: | 23 | ClassDeclaration: |
21 | abstract?="abstract"? "class" | 24 | abstract?="abstract"? "class" |
@@ -252,8 +255,11 @@ RangeMultiplicity: | |||
252 | ExactMultiplicity: | 255 | ExactMultiplicity: |
253 | exactValue=INT; | 256 | exactValue=INT; |
254 | 257 | ||
255 | IndividualDeclaration: | 258 | NodeDeclaration: |
256 | "indiv" nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; | 259 | kind=NodeKind nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; |
260 | |||
261 | enum NodeKind: | ||
262 | NODE="node" | ATOM="atom" | MULTI="multi"; | ||
257 | 263 | ||
258 | UpperBound returns ecore::EInt: | 264 | UpperBound returns ecore::EInt: |
259 | INT | "*"; | 265 | INT | "*"; |
@@ -268,7 +274,8 @@ Identifier: | |||
268 | NonContainmentIdentifier | "contains" | "container"; | 274 | NonContainmentIdentifier | "contains" | "container"; |
269 | 275 | ||
270 | NonContainmentIdentifier: | 276 | NonContainmentIdentifier: |
271 | ID | "contained" | "sum" | "prod" | "min" | "max"; | 277 | ID | "node" | "atom" | "multi" | "contained" | |
278 | "sum" | "prod" | "min" | "max" | "problem" | "module"; | ||
272 | 279 | ||
273 | Real returns ecore::EDouble: | 280 | Real returns ecore::EDouble: |
274 | EXPONENTIAL | INT "." (INT | EXPONENTIAL); | 281 | EXPONENTIAL | INT "." (INT | EXPONENTIAL); |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java index 0f3bd3ee..0b87e8bb 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java | |||
@@ -23,7 +23,7 @@ public class ProblemFormatter extends AbstractJavaFormatter { | |||
23 | protected void format(Problem problem, IFormattableDocument doc) { | 23 | protected void format(Problem problem, IFormattableDocument doc) { |
24 | doc.prepend(problem, this::noSpace); | 24 | doc.prepend(problem, this::noSpace); |
25 | var region = regionFor(problem); | 25 | var region = regionFor(problem); |
26 | doc.append(region.keyword("problem"), this::oneSpace); | 26 | doc.append(region.feature(ProblemPackage.Literals.PROBLEM__KIND), this::oneSpace); |
27 | doc.prepend(region.keyword("."), this::noSpace); | 27 | doc.prepend(region.keyword("."), this::noSpace); |
28 | appendNewLines(doc, region.keyword("."), this::twoNewLines); | 28 | appendNewLines(doc, region.keyword("."), this::twoNewLines); |
29 | for (var statement : problem.getStatements()) { | 29 | for (var statement : problem.getStatements()) { |
@@ -132,10 +132,10 @@ public class ProblemFormatter extends AbstractJavaFormatter { | |||
132 | } | 132 | } |
133 | } | 133 | } |
134 | 134 | ||
135 | protected void format(IndividualDeclaration individualDeclaration, IFormattableDocument doc) { | 135 | protected void format(NodeDeclaration nodeDeclaration, IFormattableDocument doc) { |
136 | surroundNewLines(doc, individualDeclaration, this::singleNewLine); | 136 | surroundNewLines(doc, nodeDeclaration, this::singleNewLine); |
137 | var region = regionFor(individualDeclaration); | 137 | var region = regionFor(nodeDeclaration); |
138 | doc.append(region.keyword("indiv"), this::oneSpace); | 138 | doc.append(region.feature(ProblemPackage.Literals.NODE_DECLARATION__KIND), this::oneSpace); |
139 | formatList(region, ",", doc); | 139 | formatList(region, ",", doc); |
140 | doc.prepend(region.keyword("."), this::noSpace); | 140 | doc.prepend(region.keyword("."), this::noSpace); |
141 | } | 141 | } |
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 29eaad84..c81431e5 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 | |||
@@ -25,10 +25,10 @@ public class ProblemLocationInFileProvider extends DefaultLocationInFileProvider | |||
25 | } | 25 | } |
26 | 26 | ||
27 | protected ITextRegion getNodeTextRegion(Node node, RegionDescription query) { | 27 | protected ITextRegion getNodeTextRegion(Node node, RegionDescription query) { |
28 | if (ProblemUtil.isIndividualNode(node)) { | 28 | if (ProblemUtil.isDeclaredNode(node)) { |
29 | return super.doGetTextRegion(node, query); | 29 | return super.doGetTextRegion(node, query); |
30 | } | 30 | } |
31 | if (ProblemUtil.isNewNode(node)) { | 31 | if (ProblemUtil.isMultiNode(node)) { |
32 | EObject container = node.eContainer(); | 32 | EObject container = node.eContainer(); |
33 | return doGetTextRegion(container, query); | 33 | return doGetTextRegion(container, query); |
34 | } | 34 | } |
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 c04c7d09..79dad6e7 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 | |||
@@ -91,8 +91,7 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti | |||
91 | return false; | 91 | return false; |
92 | } | 92 | } |
93 | if (eObject instanceof Node node) { | 93 | if (eObject instanceof Node node) { |
94 | // Only enum literals and new nodes are visible across problem files. | 94 | return !ProblemUtil.isImplicitNode(node); |
95 | return ProblemUtil.isIndividualNode(node) || ProblemUtil.isNewNode(node); | ||
96 | } | 95 | } |
97 | return true; | 96 | return true; |
98 | } | 97 | } |
@@ -111,7 +110,7 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti | |||
111 | 110 | ||
112 | protected boolean shouldExportSimpleName(EObject eObject) { | 111 | protected boolean shouldExportSimpleName(EObject eObject) { |
113 | if (eObject instanceof Node node) { | 112 | if (eObject instanceof Node node) { |
114 | return !ProblemUtil.isNewNode(node); | 113 | return !ProblemUtil.isMultiNode(node); |
115 | } | 114 | } |
116 | if (eObject instanceof PredicateDefinition predicateDefinition) { | 115 | if (eObject instanceof PredicateDefinition predicateDefinition) { |
117 | return !ProblemUtil.isInvalidMultiplicityConstraint(predicateDefinition); | 116 | return !ProblemUtil.isInvalidMultiplicityConstraint(predicateDefinition); |
@@ -146,6 +145,5 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti | |||
146 | return false; | 145 | return false; |
147 | } | 146 | } |
148 | return eObject instanceof ClassDeclaration || eObject instanceof EnumDeclaration; | 147 | return eObject instanceof ClassDeclaration || eObject instanceof EnumDeclaration; |
149 | |||
150 | } | 148 | } |
151 | } | 149 | } |
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 7b6407e1..ee0e141d 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 | |||
@@ -54,14 +54,24 @@ public final class ProblemUtil { | |||
54 | return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isError(); | 54 | return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isError(); |
55 | } | 55 | } |
56 | 56 | ||
57 | public static boolean isIndividualNode(Node node) { | 57 | public static boolean isAtomNode(Node node) { |
58 | var containingFeature = node.eContainingFeature(); | 58 | var containingFeature = node.eContainingFeature(); |
59 | return containingFeature == ProblemPackage.Literals.INDIVIDUAL_DECLARATION__NODES | 59 | if (containingFeature == ProblemPackage.Literals.NODE_DECLARATION__NODES) { |
60 | || containingFeature == ProblemPackage.Literals.ENUM_DECLARATION__LITERALS; | 60 | return ((NodeDeclaration) node.eContainer()).getKind() == NodeKind.ATOM; |
61 | } | ||
62 | return containingFeature == ProblemPackage.Literals.ENUM_DECLARATION__LITERALS; | ||
63 | } | ||
64 | |||
65 | public static boolean isMultiNode(Node node) { | ||
66 | var containingFeature = node.eContainingFeature(); | ||
67 | if (containingFeature == ProblemPackage.Literals.NODE_DECLARATION__NODES) { | ||
68 | return ((NodeDeclaration) node.eContainer()).getKind() == NodeKind.MULTI; | ||
69 | } | ||
70 | return containingFeature == ProblemPackage.Literals.CLASS_DECLARATION__NEW_NODE; | ||
61 | } | 71 | } |
62 | 72 | ||
63 | public static boolean isNewNode(Node node) { | 73 | public static boolean isDeclaredNode(Node node) { |
64 | return node.eContainingFeature() == ProblemPackage.Literals.CLASS_DECLARATION__NEW_NODE; | 74 | return node.eContainingFeature() == ProblemPackage.Literals.NODE_DECLARATION__NODES; |
65 | } | 75 | } |
66 | 76 | ||
67 | public static boolean isInvalidMultiplicityConstraint(PredicateDefinition predicateDefinition) { | 77 | public static boolean isInvalidMultiplicityConstraint(PredicateDefinition predicateDefinition) { |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index 8bda4b95..a95e8b3c 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | |||
@@ -84,7 +84,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
84 | @Check | 84 | @Check |
85 | public void checkNodeConstants(VariableOrNodeExpr expr) { | 85 | public void checkNodeConstants(VariableOrNodeExpr expr) { |
86 | var variableOrNode = expr.getVariableOrNode(); | 86 | var variableOrNode = expr.getVariableOrNode(); |
87 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { | 87 | if (variableOrNode instanceof Node node && !ProblemUtil.isAtomNode(node)) { |
88 | var name = node.getName(); | 88 | var name = node.getName(); |
89 | var message = ("Only individuals can be referenced in predicates. " + | 89 | var message = ("Only individuals can be referenced in predicates. " + |
90 | "Mark '%s' as individual with the declaration 'indiv %s.'").formatted(name, name); | 90 | "Mark '%s' as individual with the declaration 'indiv %s.'").formatted(name, name); |
@@ -96,16 +96,16 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
96 | @Check | 96 | @Check |
97 | public void checkUniqueDeclarations(Problem problem) { | 97 | public void checkUniqueDeclarations(Problem problem) { |
98 | var relations = new ArrayList<Relation>(); | 98 | var relations = new ArrayList<Relation>(); |
99 | var individuals = new ArrayList<Node>(); | 99 | var nodes = new ArrayList<Node>(); |
100 | for (var statement : problem.getStatements()) { | 100 | for (var statement : problem.getStatements()) { |
101 | if (statement instanceof Relation relation) { | 101 | if (statement instanceof Relation relation) { |
102 | relations.add(relation); | 102 | relations.add(relation); |
103 | } else if (statement instanceof IndividualDeclaration individualDeclaration) { | 103 | } else if (statement instanceof NodeDeclaration nodeDeclaration) { |
104 | individuals.addAll(individualDeclaration.getNodes()); | 104 | nodes.addAll(nodeDeclaration.getNodes()); |
105 | } | 105 | } |
106 | } | 106 | } |
107 | checkUniqueSimpleNames(relations); | 107 | checkUniqueSimpleNames(relations); |
108 | checkUniqueSimpleNames(individuals); | 108 | checkUniqueSimpleNames(nodes); |
109 | } | 109 | } |
110 | 110 | ||
111 | @Check | 111 | @Check |
@@ -362,7 +362,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
362 | return; | 362 | return; |
363 | } | 363 | } |
364 | var node = getNodeArgumentForMultiObjectAssertion(arguments.get(0)); | 364 | var node = getNodeArgumentForMultiObjectAssertion(arguments.get(0)); |
365 | if (node != null && !node.eIsProxy() && ProblemUtil.isIndividualNode(node)) { | 365 | if (node != null && !node.eIsProxy() && ProblemUtil.isAtomNode(node)) { |
366 | acceptError("Individual nodes must exist.", assertion, null, 0, UNSUPPORTED_ASSERTION_ISSUE); | 366 | acceptError("Individual nodes must exist.", assertion, null, 0, UNSUPPORTED_ASSERTION_ISSUE); |
367 | } | 367 | } |
368 | } | 368 | } |