diff options
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 |
14 | Require-Bundle: org.eclipse.emf.ecore;visibility:=reexport, | 14 | Require-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 |
16 | Bundle-ActivationPolicy: lazy | 17 | Bundle-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 | |||
3 | Workflow { | 3 | Workflow { |
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 @@ | |||
1 | package tools.refinery.language.tests.serializer; | ||
2 | |||
3 | import static org.hamcrest.MatcherAssert.assertThat; | ||
4 | import static org.hamcrest.Matchers.equalTo; | ||
5 | |||
6 | import java.io.ByteArrayOutputStream; | ||
7 | import java.io.IOException; | ||
8 | import java.util.Map; | ||
9 | |||
10 | import org.eclipse.emf.common.util.URI; | ||
11 | import org.eclipse.emf.ecore.resource.Resource; | ||
12 | import org.eclipse.emf.ecore.resource.ResourceSet; | ||
13 | import org.eclipse.xtext.testing.InjectWith; | ||
14 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
15 | import org.junit.jupiter.api.BeforeEach; | ||
16 | import org.junit.jupiter.api.Test; | ||
17 | import org.junit.jupiter.api.extension.ExtendWith; | ||
18 | |||
19 | import com.google.inject.Inject; | ||
20 | |||
21 | import tools.refinery.language.model.ProblemUtil; | ||
22 | import tools.refinery.language.model.problem.Atom; | ||
23 | import tools.refinery.language.model.problem.LogicValue; | ||
24 | import tools.refinery.language.model.problem.Node; | ||
25 | import tools.refinery.language.model.problem.PredicateDefinition; | ||
26 | import tools.refinery.language.model.problem.Problem; | ||
27 | import tools.refinery.language.model.problem.ProblemFactory; | ||
28 | import tools.refinery.language.model.problem.Relation; | ||
29 | import tools.refinery.language.model.problem.VariableOrNode; | ||
30 | import tools.refinery.language.model.tests.ProblemTestUtil; | ||
31 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
32 | |||
33 | @ExtendWith(InjectionExtension.class) | ||
34 | @InjectWith(ProblemInjectorProvider.class) | ||
35 | public 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 | } | ||