aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-11-06 16:02:37 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-11-06 16:34:01 +0100
commit68e8c8ea4091482c43d810fdaa2fd6ddd6316d07 (patch)
tree00208f2337327d975e073a752133e30edabaede1
parentMerge pull request #11 from kris7t/unique-to-individual (diff)
downloadrefinery-68e8c8ea4091482c43d810fdaa2fd6ddd6316d07.tar.gz
refinery-68e8c8ea4091482c43d810fdaa2fd6ddd6316d07.tar.zst
refinery-68e8c8ea4091482c43d810fdaa2fd6ddd6316d07.zip
fix(lang): mark transient references
Xtext fails to serialize non-transient references that have no corresponding assignment in the grammar. Therefore, we mark * Problem.nodes * ClassDeclaration.newNode * ExistentialQualifier.implicitVariables * VariableOrNodeArgument.singletonVariable as transient. This will allow serializing Problem instances using the textual concrete syntax for display.
-rw-r--r--language-model/META-INF/MANIFEST.MF1
-rw-r--r--language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe26
-rw-r--r--language-model/src/main/resources/model/problem.ecore8
-rw-r--r--language-model/src/main/resources/model/problem.genmodel2
-rw-r--r--language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java199
5 files changed, 208 insertions, 8 deletions
diff --git a/language-model/META-INF/MANIFEST.MF b/language-model/META-INF/MANIFEST.MF
index 88725730..96617f85 100644
--- a/language-model/META-INF/MANIFEST.MF
+++ b/language-model/META-INF/MANIFEST.MF
@@ -12,5 +12,6 @@ Export-Package: tools.refinery.language.model.problem,
12 tools.refinery.language.model.problem.impl, 12 tools.refinery.language.model.problem.impl,
13 tools.refinery.language.model.problem.util 13 tools.refinery.language.model.problem.util
14Require-Bundle: org.eclipse.emf.ecore;visibility:=reexport, 14Require-Bundle: org.eclipse.emf.ecore;visibility:=reexport,
15 org.eclipse.emf.ecore.xmi;visibility:=reexport,
15 org.eclipse.core.runtime 16 org.eclipse.core.runtime
16Bundle-ActivationPolicy: lazy 17Bundle-ActivationPolicy: lazy
diff --git a/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 b/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
index 7f998448..c1518b4d 100644
--- a/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
+++ b/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
@@ -3,7 +3,7 @@ module tools.refinery.language.model.GenerateProblemModel
3Workflow { 3Workflow {
4 bean = org.eclipse.emf.mwe.utils.StandaloneSetup { 4 bean = org.eclipse.emf.mwe.utils.StandaloneSetup {
5 projectMapping = { 5 projectMapping = {
6 projectName = "language-model" 6 projectName = "refinery-language-model"
7 path = "." 7 path = "."
8 } 8 }
9 } 9 }
@@ -14,7 +14,7 @@ Workflow {
14 14
15 component = org.eclipse.emf.mwe2.ecore.EcoreGenerator { 15 component = org.eclipse.emf.mwe2.ecore.EcoreGenerator {
16 generateCustomClasses = false 16 generateCustomClasses = false
17 genModel = "platform:/resource/language-model/src/main/resources/model/problem.genmodel" 17 genModel = "platform:/resource/refinery-language-model/src/main/resources/model/problem.genmodel"
18 srcPath = "platform:/resource/language-model/src/main/emf-gen" 18 srcPath = "platform:/resource/refinery-language-model/src/main/emf-gen"
19 } 19 }
20} 20}
diff --git a/language-model/src/main/resources/model/problem.ecore b/language-model/src/main/resources/model/problem.ecore
index 77211b66..582f67c8 100644
--- a/language-model/src/main/resources/model/problem.ecore
+++ b/language-model/src/main/resources/model/problem.ecore
@@ -3,7 +3,7 @@
3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="problem" nsURI="https://refinery.tools/emf/2021/Problem" nsPrefix="problem"> 3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="problem" nsURI="https://refinery.tools/emf/2021/Problem" nsPrefix="problem">
4 <eClassifiers xsi:type="ecore:EClass" name="Problem" eSuperTypes="#//NamedElement"> 4 <eClassifiers xsi:type="ecore:EClass" name="Problem" eSuperTypes="#//NamedElement">
5 <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1" 5 <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
6 eType="#//Node" containment="true"/> 6 eType="#//Node" transient="true" containment="true"/>
7 <eStructuralFeatures xsi:type="ecore:EReference" name="statements" upperBound="-1" 7 <eStructuralFeatures xsi:type="ecore:EReference" name="statements" upperBound="-1"
8 eType="#//Statement" containment="true"/> 8 eType="#//Statement" containment="true"/>
9 </eClassifiers> 9 </eClassifiers>
@@ -15,7 +15,7 @@
15 <eStructuralFeatures xsi:type="ecore:EReference" name="referenceDeclarations" 15 <eStructuralFeatures xsi:type="ecore:EReference" name="referenceDeclarations"
16 upperBound="-1" eType="#//ReferenceDeclaration" containment="true"/> 16 upperBound="-1" eType="#//ReferenceDeclaration" containment="true"/>
17 <eStructuralFeatures xsi:type="ecore:EReference" name="newNode" eType="#//Node" 17 <eStructuralFeatures xsi:type="ecore:EReference" name="newNode" eType="#//Node"
18 containment="true"/> 18 transient="true" containment="true"/>
19 </eClassifiers> 19 </eClassifiers>
20 <eClassifiers xsi:type="ecore:EClass" name="ReferenceDeclaration" eSuperTypes="#//Relation"> 20 <eClassifiers xsi:type="ecore:EClass" name="ReferenceDeclaration" eSuperTypes="#//Relation">
21 <eStructuralFeatures xsi:type="ecore:EReference" name="referenceType" eType="#//Relation"/> 21 <eStructuralFeatures xsi:type="ecore:EReference" name="referenceType" eType="#//Relation"/>
@@ -52,7 +52,7 @@
52 <eClassifiers xsi:type="ecore:EClass" name="ExistentialQuantifier" abstract="true" 52 <eClassifiers xsi:type="ecore:EClass" name="ExistentialQuantifier" abstract="true"
53 interface="true"> 53 interface="true">
54 <eStructuralFeatures xsi:type="ecore:EReference" name="implicitVariables" upperBound="-1" 54 <eStructuralFeatures xsi:type="ecore:EReference" name="implicitVariables" upperBound="-1"
55 eType="#//ImplicitVariable" containment="true"/> 55 eType="#//ImplicitVariable" transient="true" containment="true"/>
56 </eClassifiers> 56 </eClassifiers>
57 <eClassifiers xsi:type="ecore:EClass" name="Assertion" eSuperTypes="#//Statement"> 57 <eClassifiers xsi:type="ecore:EClass" name="Assertion" eSuperTypes="#//Statement">
58 <eStructuralFeatures xsi:type="ecore:EReference" name="relation" eType="#//Relation"/> 58 <eStructuralFeatures xsi:type="ecore:EReference" name="relation" eType="#//Relation"/>
@@ -95,7 +95,7 @@
95 <eClassifiers xsi:type="ecore:EClass" name="VariableOrNodeArgument" eSuperTypes="#//Argument"> 95 <eClassifiers xsi:type="ecore:EClass" name="VariableOrNodeArgument" eSuperTypes="#//Argument">
96 <eStructuralFeatures xsi:type="ecore:EReference" name="variableOrNode" eType="#//VariableOrNode"/> 96 <eStructuralFeatures xsi:type="ecore:EReference" name="variableOrNode" eType="#//VariableOrNode"/>
97 <eStructuralFeatures xsi:type="ecore:EReference" name="singletonVariable" eType="#//ImplicitVariable" 97 <eStructuralFeatures xsi:type="ecore:EReference" name="singletonVariable" eType="#//ImplicitVariable"
98 containment="true"/> 98 transient="true" containment="true"/>
99 </eClassifiers> 99 </eClassifiers>
100 <eClassifiers xsi:type="ecore:EClass" name="EnumDeclaration" eSuperTypes="#//Relation #//Statement"> 100 <eClassifiers xsi:type="ecore:EClass" name="EnumDeclaration" eSuperTypes="#//Relation #//Statement">
101 <eStructuralFeatures xsi:type="ecore:EReference" name="literals" upperBound="-1" 101 <eStructuralFeatures xsi:type="ecore:EReference" name="literals" upperBound="-1"
diff --git a/language-model/src/main/resources/model/problem.genmodel b/language-model/src/main/resources/model/problem.genmodel
index 094533e7..3e0ee35e 100644
--- a/language-model/src/main/resources/model/problem.genmodel
+++ b/language-model/src/main/resources/model/problem.genmodel
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" 3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel"
4 modelDirectory="/language-model/src/main/emf-gen" creationIcons="false" 4 modelDirectory="/refinery-language-model/src/main/emf-gen" creationIcons="false"
5 editDirectory="/language-edit/src/main/emf-gen" editorDirectory="/org.eclipse.viatra.solver.language.model.editor/src-gen" 5 editDirectory="/language-edit/src/main/emf-gen" editorDirectory="/org.eclipse.viatra.solver.language.model.editor/src-gen"
6 modelPluginID="language-model" modelName="Problem" rootExtendsClass="org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container" 6 modelPluginID="language-model" modelName="Problem" rootExtendsClass="org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container"
7 codeFormatting="true" importerID="org.eclipse.emf.importer.ecore" complianceLevel="5.0" 7 codeFormatting="true" importerID="org.eclipse.emf.importer.ecore" complianceLevel="5.0"
diff --git a/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
new file mode 100644
index 00000000..34c1d14b
--- /dev/null
+++ b/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
@@ -0,0 +1,199 @@
1package tools.refinery.language.tests.serializer;
2
3import static org.hamcrest.MatcherAssert.assertThat;
4import static org.hamcrest.Matchers.equalTo;
5
6import java.io.ByteArrayOutputStream;
7import java.io.IOException;
8import java.util.Map;
9
10import org.eclipse.emf.common.util.URI;
11import org.eclipse.emf.ecore.resource.Resource;
12import org.eclipse.emf.ecore.resource.ResourceSet;
13import org.eclipse.xtext.testing.InjectWith;
14import org.eclipse.xtext.testing.extensions.InjectionExtension;
15import org.junit.jupiter.api.BeforeEach;
16import org.junit.jupiter.api.Test;
17import org.junit.jupiter.api.extension.ExtendWith;
18
19import com.google.inject.Inject;
20
21import tools.refinery.language.model.ProblemUtil;
22import tools.refinery.language.model.problem.Atom;
23import tools.refinery.language.model.problem.LogicValue;
24import tools.refinery.language.model.problem.Node;
25import tools.refinery.language.model.problem.PredicateDefinition;
26import tools.refinery.language.model.problem.Problem;
27import tools.refinery.language.model.problem.ProblemFactory;
28import tools.refinery.language.model.problem.Relation;
29import tools.refinery.language.model.problem.VariableOrNode;
30import tools.refinery.language.model.tests.ProblemTestUtil;
31import tools.refinery.language.tests.ProblemInjectorProvider;
32
33@ExtendWith(InjectionExtension.class)
34@InjectWith(ProblemInjectorProvider.class)
35public class ProblemSerializerTest {
36 @Inject
37 ResourceSet resourceSet;
38
39 @Inject
40 ProblemTestUtil testUtil;
41
42 Resource resource;
43
44 Problem problem;
45
46 Problem builtin;
47
48 @BeforeEach
49 void beforeEach() {
50 problem = ProblemFactory.eINSTANCE.createProblem();
51 resource = resourceSet.createResource(URI.createFileURI("test.problem"));
52 resource.getContents().add(problem);
53 builtin = ProblemUtil.getBuiltInLibrary(problem).get();
54 }
55
56 @Test
57 void implicitNodeTest() {
58 var pred = createPred();
59 var node = ProblemFactory.eINSTANCE.createNode();
60 node.setName("a");
61 problem.getNodes().add(node);
62 createAssertion(pred, node);
63
64 assertSerializedResult("pred foo ( node p ) . foo ( a ) : true .");
65 }
66
67 @Test
68 void individualNodeTest() {
69 var pred = createPred();
70 var node = ProblemFactory.eINSTANCE.createNode();
71 node.setName("a");
72 var individualDeclaration = ProblemFactory.eINSTANCE.createIndividualDeclaration();
73 individualDeclaration.getNodes().add(node);
74 problem.getStatements().add(individualDeclaration);
75 createAssertion(pred, node);
76
77 assertSerializedResult("pred foo ( node p ) . individual a . foo ( a ) : true .");
78 }
79
80 private PredicateDefinition createPred() {
81 var pred = ProblemFactory.eINSTANCE.createPredicateDefinition();
82 pred.setName("foo");
83 var parameter = ProblemFactory.eINSTANCE.createParameter();
84 var nodeType = testUtil.findClass(builtin, "node");
85 parameter.setParameterType(nodeType);
86 parameter.setName("p");
87 pred.getParameters().add(parameter);
88 problem.getStatements().add(pred);
89 return pred;
90 }
91
92 @Test
93 void newNodeTest() {
94 var classDeclaration = ProblemFactory.eINSTANCE.createClassDeclaration();
95 classDeclaration.setName("Foo");
96 var newNode = ProblemFactory.eINSTANCE.createNode();
97 newNode.setName("new");
98 classDeclaration.setNewNode(newNode);
99 problem.getStatements().add(classDeclaration);
100 createAssertion(classDeclaration, newNode);
101
102 assertSerializedResult("class Foo . Foo ( Foo::new ) : true .");
103 }
104
105 private void createAssertion(Relation relation, Node node) {
106 var assertion = ProblemFactory.eINSTANCE.createAssertion();
107 assertion.setRelation(relation);
108 var argument = ProblemFactory.eINSTANCE.createNodeAssertionArgument();
109 argument.setNode(node);
110 assertion.getArguments().add(argument);
111 assertion.setValue(LogicValue.TRUE);
112 problem.getStatements().add(assertion);
113 }
114
115 @Test
116 void implicitVariableTest() {
117 var pred = ProblemFactory.eINSTANCE.createPredicateDefinition();
118 pred.setName("foo");
119 var nodeType = testUtil.findClass(builtin, "node");
120 var parameter1 = ProblemFactory.eINSTANCE.createParameter();
121 parameter1.setParameterType(nodeType);
122 parameter1.setName("p1");
123 pred.getParameters().add(parameter1);
124 var parameter2 = ProblemFactory.eINSTANCE.createParameter();
125 parameter2.setParameterType(nodeType);
126 parameter2.setName("p2");
127 pred.getParameters().add(parameter2);
128 var conjunction = ProblemFactory.eINSTANCE.createConjunction();
129 var variable = ProblemFactory.eINSTANCE.createImplicitVariable();
130 variable.setName("q");
131 conjunction.getImplicitVariables().add(variable);
132 var equals = testUtil.reference(nodeType, "equals");
133 conjunction.getLiterals().add(createAtom(equals, parameter1, variable));
134 conjunction.getLiterals().add(createAtom(equals, variable, parameter2));
135 pred.getBodies().add(conjunction);
136 problem.getStatements().add(pred);
137
138 assertSerializedResult("pred foo ( node p1 , node p2 ) <-> equals ( p1 , q ) , equals ( q , p2 ) .");
139 }
140
141 private Atom createAtom(Relation relation, VariableOrNode variable1, VariableOrNode variable2) {
142 var atom = ProblemFactory.eINSTANCE.createAtom();
143 atom.setRelation(relation);
144 var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument();
145 arg1.setVariableOrNode(variable1);
146 atom.getArguments().add(arg1);
147 var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument();
148 arg2.setVariableOrNode(variable2);
149 atom.getArguments().add(arg2);
150 return atom;
151 }
152
153 @Test
154 void singletonVariableTest() {
155 var pred = ProblemFactory.eINSTANCE.createPredicateDefinition();
156 pred.setName("foo");
157 var nodeType = testUtil.findClass(builtin, "node");
158 var parameter = ProblemFactory.eINSTANCE.createParameter();
159 parameter.setParameterType(nodeType);
160 parameter.setName("p");
161 pred.getParameters().add(parameter);
162 var conjunction = ProblemFactory.eINSTANCE.createConjunction();
163 var atom = ProblemFactory.eINSTANCE.createAtom();
164 var equals = testUtil.reference(nodeType, "equals");
165 atom.setRelation(equals);
166 var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument();
167 arg1.setVariableOrNode(parameter);
168 atom.getArguments().add(arg1);
169 var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument();
170 var variable = ProblemFactory.eINSTANCE.createImplicitVariable();
171 variable.setName("_q");
172 arg2.setSingletonVariable(variable);
173 arg2.setVariableOrNode(variable);
174 atom.getArguments().add(arg2);
175 conjunction.getLiterals().add(atom);
176 pred.getBodies().add(conjunction);
177 problem.getStatements().add(pred);
178
179 assertSerializedResult("pred foo ( node p ) <-> equals ( p , _q ) .");
180 }
181
182 private void assertSerializedResult(String expected) {
183 var outputStream = new ByteArrayOutputStream();
184 try {
185 resource.save(outputStream, Map.of());
186 } catch (IOException e) {
187 throw new AssertionError("Failed to serialize problem", e);
188 } finally {
189 try {
190 outputStream.close();
191 } catch (IOException e) {
192 // Nothing to handle in a test.
193 }
194 }
195 var problemString = outputStream.toString();
196
197 assertThat(problemString, equalTo(expected));
198 }
199}