diff options
author | Kristóf Marussy <marussy@mit.bme.hu> | 2021-11-06 16:56:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-06 16:56:11 +0100 |
commit | bf479290c950c004d8f99eda967e3a6c76e0e64b (patch) | |
tree | 2d805f058ab6b4289d4338b8f6beb12c51c31d09 /language | |
parent | Merge pull request #11 from kris7t/unique-to-individual (diff) | |
parent | chore(lang): seralize assertions in short form (diff) | |
download | refinery-bf479290c950c004d8f99eda967e3a6c76e0e64b.tar.gz refinery-bf479290c950c004d8f99eda967e3a6c76e0e64b.tar.zst refinery-bf479290c950c004d8f99eda967e3a6c76e0e64b.zip |
Merge pull request #12 from kris7t/xtext-serialization
Make sure Xtext serialization works
Diffstat (limited to 'language')
5 files changed, 227 insertions, 12 deletions
diff --git a/language/src/main/java/tools/refinery/language/Problem.xtext b/language/src/main/java/tools/refinery/language/Problem.xtext index b7562759..26773047 100644 --- a/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/language/src/main/java/tools/refinery/language/Problem.xtext | |||
@@ -109,12 +109,12 @@ ConstantArgument: | |||
109 | 109 | ||
110 | Assertion: | 110 | Assertion: |
111 | default?="default"? | 111 | default?="default"? |
112 | (relation=[Relation|QualifiedName] | 112 | (value=ShortLogicValue? |
113 | "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")" | ||
114 | ":" value=LogicValue | | ||
115 | value=ShortLogicValue? | ||
116 | relation=[Relation|QualifiedName] | 113 | relation=[Relation|QualifiedName] |
117 | "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")") | 114 | "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")" |
115 | | relation=[Relation|QualifiedName] | ||
116 | "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")" | ||
117 | ":" value=LogicValue) | ||
118 | "."; | 118 | "."; |
119 | 119 | ||
120 | AssertionArgument: | 120 | AssertionArgument: |
@@ -174,7 +174,7 @@ ExactMultiplicity: | |||
174 | exactValue=INT; | 174 | exactValue=INT; |
175 | 175 | ||
176 | IndividualDeclaration: | 176 | IndividualDeclaration: |
177 | "individual" nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; | 177 | "indiv" nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; |
178 | 178 | ||
179 | UpperBound returns ecore::EInt: | 179 | UpperBound returns ecore::EInt: |
180 | INT | "*"; | 180 | INT | "*"; |
@@ -184,7 +184,7 @@ QualifiedName hidden(): | |||
184 | 184 | ||
185 | Identifier: | 185 | Identifier: |
186 | ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | "pred" | | 186 | ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | "pred" | |
187 | "individual" | "problem" | "new" | "delete" | "direct" | "rule"; | 187 | "indiv" | "problem" | "new" | "delete" | "direct" | "rule"; |
188 | 188 | ||
189 | Integer returns ecore::EInt hidden(): | 189 | Integer returns ecore::EInt hidden(): |
190 | "-"? INT; | 190 | "-"? INT; |
diff --git a/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index 3c10d39e..975fdca2 100644 --- a/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | |||
@@ -53,7 +53,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
53 | var variableOrNode = argument.getVariableOrNode(); | 53 | var variableOrNode = argument.getVariableOrNode(); |
54 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { | 54 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { |
55 | var name = node.getName(); | 55 | var name = node.getName(); |
56 | var message = "Only individual nodes can be referenced in predicates. Mark '%s' as individual with the declaration 'individual %s.'" | 56 | var message = "Only individual nodes can be referenced in predicates. Mark '%s' as individual with the declaration 'indiv %s.'" |
57 | .formatted(name, name); | 57 | .formatted(name, name); |
58 | error(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, | 58 | error(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, |
59 | INSIGNIFICANT_INDEX, NON_INDIVIDUAL_NODE_ISSUE); | 59 | INSIGNIFICANT_INDEX, NON_INDIVIDUAL_NODE_ISSUE); |
diff --git a/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.xtend b/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.xtend index 9e357529..53d31a6c 100644 --- a/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.xtend +++ b/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.xtend | |||
@@ -46,7 +46,7 @@ class ProblemParsingTest { | |||
46 | error invalidTaxStatus(Person p) <-> | 46 | error invalidTaxStatus(Person p) <-> |
47 | taxStatus(p, child), children(p, _q). | 47 | taxStatus(p, child), children(p, _q). |
48 | 48 | ||
49 | individual family. | 49 | indiv family. |
50 | Family(family). | 50 | Family(family). |
51 | members(family, anne): true. | 51 | members(family, anne): true. |
52 | members(family, bob). | 52 | members(family, bob). |
diff --git a/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.xtend b/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.xtend index 5f669847..3a046341 100644 --- a/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.xtend +++ b/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.xtend | |||
@@ -81,7 +81,7 @@ class NodeScopingTest { | |||
81 | def void individualNodeInAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { | 81 | def void individualNodeInAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { |
82 | val it = parseHelper.parse(''' | 82 | val it = parseHelper.parse(''' |
83 | «IF namedProblem»problem test.«ENDIF» | 83 | «IF namedProblem»problem test.«ENDIF» |
84 | individual a, b. | 84 | indiv a, b. |
85 | pred predicate(node x, node y) <-> node(x). | 85 | pred predicate(node x, node y) <-> node(x). |
86 | predicate(«qualifiedNamePrefix»a, «qualifiedNamePrefix»a). | 86 | predicate(«qualifiedNamePrefix»a, «qualifiedNamePrefix»a). |
87 | ?predicate(«qualifiedNamePrefix»a, «qualifiedNamePrefix»b). | 87 | ?predicate(«qualifiedNamePrefix»a, «qualifiedNamePrefix»b). |
@@ -99,7 +99,7 @@ class NodeScopingTest { | |||
99 | def void individualNodeInNodeValueAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { | 99 | def void individualNodeInNodeValueAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { |
100 | val it = parseHelper.parse(''' | 100 | val it = parseHelper.parse(''' |
101 | «IF namedProblem»problem test.«ENDIF» | 101 | «IF namedProblem»problem test.«ENDIF» |
102 | individual a. | 102 | indiv a. |
103 | «qualifiedNamePrefix»a: 16. | 103 | «qualifiedNamePrefix»a: 16. |
104 | ''') | 104 | ''') |
105 | assertThat(errors, empty) | 105 | assertThat(errors, empty) |
@@ -112,7 +112,7 @@ class NodeScopingTest { | |||
112 | def void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) { | 112 | def void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) { |
113 | val it = parseHelper.parse(''' | 113 | val it = parseHelper.parse(''' |
114 | «IF namedProblem»problem test.«ENDIF» | 114 | «IF namedProblem»problem test.«ENDIF» |
115 | individual b. | 115 | indiv b. |
116 | pred predicate(node a) <-> node(«qualifiedNamePrefix»b). | 116 | pred predicate(node a) <-> node(«qualifiedNamePrefix»b). |
117 | ''') | 117 | ''') |
118 | assertThat(errors, empty) | 118 | assertThat(errors, empty) |
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..802457cb --- /dev/null +++ b/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java | |||
@@ -0,0 +1,215 @@ | |||
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 | import java.util.stream.Stream; | ||
10 | |||
11 | import org.eclipse.emf.common.util.URI; | ||
12 | import org.eclipse.emf.ecore.resource.Resource; | ||
13 | import org.eclipse.emf.ecore.resource.ResourceSet; | ||
14 | import org.eclipse.xtext.testing.InjectWith; | ||
15 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
16 | import org.junit.jupiter.api.BeforeEach; | ||
17 | import org.junit.jupiter.api.Test; | ||
18 | import org.junit.jupiter.api.extension.ExtendWith; | ||
19 | import org.junit.jupiter.params.ParameterizedTest; | ||
20 | import org.junit.jupiter.params.provider.Arguments; | ||
21 | import org.junit.jupiter.params.provider.MethodSource; | ||
22 | |||
23 | import com.google.inject.Inject; | ||
24 | |||
25 | import tools.refinery.language.model.ProblemUtil; | ||
26 | import tools.refinery.language.model.problem.Atom; | ||
27 | import tools.refinery.language.model.problem.LogicValue; | ||
28 | import tools.refinery.language.model.problem.Node; | ||
29 | import tools.refinery.language.model.problem.PredicateDefinition; | ||
30 | import tools.refinery.language.model.problem.Problem; | ||
31 | import tools.refinery.language.model.problem.ProblemFactory; | ||
32 | import tools.refinery.language.model.problem.Relation; | ||
33 | import tools.refinery.language.model.problem.VariableOrNode; | ||
34 | import tools.refinery.language.model.tests.ProblemTestUtil; | ||
35 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
36 | |||
37 | @ExtendWith(InjectionExtension.class) | ||
38 | @InjectWith(ProblemInjectorProvider.class) | ||
39 | public class ProblemSerializerTest { | ||
40 | @Inject | ||
41 | ResourceSet resourceSet; | ||
42 | |||
43 | @Inject | ||
44 | ProblemTestUtil testUtil; | ||
45 | |||
46 | Resource resource; | ||
47 | |||
48 | Problem problem; | ||
49 | |||
50 | Problem builtin; | ||
51 | |||
52 | @BeforeEach | ||
53 | void beforeEach() { | ||
54 | problem = ProblemFactory.eINSTANCE.createProblem(); | ||
55 | resource = resourceSet.createResource(URI.createFileURI("test.problem")); | ||
56 | resource.getContents().add(problem); | ||
57 | builtin = ProblemUtil.getBuiltInLibrary(problem).get(); | ||
58 | } | ||
59 | |||
60 | @ParameterizedTest | ||
61 | @MethodSource | ||
62 | void assertionTest(LogicValue value, String serializedAssertion) { | ||
63 | var pred = createPred(); | ||
64 | var node = ProblemFactory.eINSTANCE.createNode(); | ||
65 | node.setName("a"); | ||
66 | var individualDeclaration = ProblemFactory.eINSTANCE.createIndividualDeclaration(); | ||
67 | individualDeclaration.getNodes().add(node); | ||
68 | problem.getStatements().add(individualDeclaration); | ||
69 | createAssertion(pred, node, value); | ||
70 | |||
71 | assertSerializedResult("pred foo ( node p ) . indiv a . " + serializedAssertion); | ||
72 | } | ||
73 | |||
74 | static Stream<Arguments> assertionTest() { | ||
75 | return Stream.of(Arguments.of(LogicValue.TRUE, "foo ( a ) ."), | ||
76 | Arguments.of(LogicValue.FALSE, "! foo ( a ) ."), | ||
77 | Arguments.of(LogicValue.UNKNOWN, "? foo ( a ) ."), | ||
78 | Arguments.of(LogicValue.ERROR, "foo ( a ) : error .")); | ||
79 | } | ||
80 | |||
81 | @Test | ||
82 | void implicitNodeTest() { | ||
83 | var pred = createPred(); | ||
84 | var node = ProblemFactory.eINSTANCE.createNode(); | ||
85 | node.setName("a"); | ||
86 | problem.getNodes().add(node); | ||
87 | createAssertion(pred, node); | ||
88 | |||
89 | assertSerializedResult("pred foo ( node p ) . foo ( a ) ."); | ||
90 | } | ||
91 | |||
92 | private PredicateDefinition createPred() { | ||
93 | var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); | ||
94 | pred.setName("foo"); | ||
95 | var parameter = ProblemFactory.eINSTANCE.createParameter(); | ||
96 | var nodeType = testUtil.findClass(builtin, "node"); | ||
97 | parameter.setParameterType(nodeType); | ||
98 | parameter.setName("p"); | ||
99 | pred.getParameters().add(parameter); | ||
100 | problem.getStatements().add(pred); | ||
101 | return pred; | ||
102 | } | ||
103 | |||
104 | @Test | ||
105 | void newNodeTest() { | ||
106 | var classDeclaration = ProblemFactory.eINSTANCE.createClassDeclaration(); | ||
107 | classDeclaration.setName("Foo"); | ||
108 | var newNode = ProblemFactory.eINSTANCE.createNode(); | ||
109 | newNode.setName("new"); | ||
110 | classDeclaration.setNewNode(newNode); | ||
111 | problem.getStatements().add(classDeclaration); | ||
112 | createAssertion(classDeclaration, newNode); | ||
113 | |||
114 | assertSerializedResult("class Foo . Foo ( Foo::new ) ."); | ||
115 | } | ||
116 | |||
117 | private void createAssertion(Relation relation, Node node) { | ||
118 | createAssertion(relation, node, LogicValue.TRUE); | ||
119 | } | ||
120 | |||
121 | private void createAssertion(Relation relation, Node node, LogicValue value) { | ||
122 | var assertion = ProblemFactory.eINSTANCE.createAssertion(); | ||
123 | assertion.setRelation(relation); | ||
124 | var argument = ProblemFactory.eINSTANCE.createNodeAssertionArgument(); | ||
125 | argument.setNode(node); | ||
126 | assertion.getArguments().add(argument); | ||
127 | assertion.setValue(value); | ||
128 | problem.getStatements().add(assertion); | ||
129 | } | ||
130 | |||
131 | @Test | ||
132 | void implicitVariableTest() { | ||
133 | var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); | ||
134 | pred.setName("foo"); | ||
135 | var nodeType = testUtil.findClass(builtin, "node"); | ||
136 | var parameter1 = ProblemFactory.eINSTANCE.createParameter(); | ||
137 | parameter1.setParameterType(nodeType); | ||
138 | parameter1.setName("p1"); | ||
139 | pred.getParameters().add(parameter1); | ||
140 | var parameter2 = ProblemFactory.eINSTANCE.createParameter(); | ||
141 | parameter2.setParameterType(nodeType); | ||
142 | parameter2.setName("p2"); | ||
143 | pred.getParameters().add(parameter2); | ||
144 | var conjunction = ProblemFactory.eINSTANCE.createConjunction(); | ||
145 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | ||
146 | variable.setName("q"); | ||
147 | conjunction.getImplicitVariables().add(variable); | ||
148 | var equals = testUtil.reference(nodeType, "equals"); | ||
149 | conjunction.getLiterals().add(createAtom(equals, parameter1, variable)); | ||
150 | conjunction.getLiterals().add(createAtom(equals, variable, parameter2)); | ||
151 | pred.getBodies().add(conjunction); | ||
152 | problem.getStatements().add(pred); | ||
153 | |||
154 | assertSerializedResult("pred foo ( node p1 , node p2 ) <-> equals ( p1 , q ) , equals ( q , p2 ) ."); | ||
155 | } | ||
156 | |||
157 | private Atom createAtom(Relation relation, VariableOrNode variable1, VariableOrNode variable2) { | ||
158 | var atom = ProblemFactory.eINSTANCE.createAtom(); | ||
159 | atom.setRelation(relation); | ||
160 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | ||
161 | arg1.setVariableOrNode(variable1); | ||
162 | atom.getArguments().add(arg1); | ||
163 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | ||
164 | arg2.setVariableOrNode(variable2); | ||
165 | atom.getArguments().add(arg2); | ||
166 | return atom; | ||
167 | } | ||
168 | |||
169 | @Test | ||
170 | void singletonVariableTest() { | ||
171 | var pred = ProblemFactory.eINSTANCE.createPredicateDefinition(); | ||
172 | pred.setName("foo"); | ||
173 | var nodeType = testUtil.findClass(builtin, "node"); | ||
174 | var parameter = ProblemFactory.eINSTANCE.createParameter(); | ||
175 | parameter.setParameterType(nodeType); | ||
176 | parameter.setName("p"); | ||
177 | pred.getParameters().add(parameter); | ||
178 | var conjunction = ProblemFactory.eINSTANCE.createConjunction(); | ||
179 | var atom = ProblemFactory.eINSTANCE.createAtom(); | ||
180 | var equals = testUtil.reference(nodeType, "equals"); | ||
181 | atom.setRelation(equals); | ||
182 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | ||
183 | arg1.setVariableOrNode(parameter); | ||
184 | atom.getArguments().add(arg1); | ||
185 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | ||
186 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | ||
187 | variable.setName("_q"); | ||
188 | arg2.setSingletonVariable(variable); | ||
189 | arg2.setVariableOrNode(variable); | ||
190 | atom.getArguments().add(arg2); | ||
191 | conjunction.getLiterals().add(atom); | ||
192 | pred.getBodies().add(conjunction); | ||
193 | problem.getStatements().add(pred); | ||
194 | |||
195 | assertSerializedResult("pred foo ( node p ) <-> equals ( p , _q ) ."); | ||
196 | } | ||
197 | |||
198 | private void assertSerializedResult(String expected) { | ||
199 | var outputStream = new ByteArrayOutputStream(); | ||
200 | try { | ||
201 | resource.save(outputStream, Map.of()); | ||
202 | } catch (IOException e) { | ||
203 | throw new AssertionError("Failed to serialize problem", e); | ||
204 | } finally { | ||
205 | try { | ||
206 | outputStream.close(); | ||
207 | } catch (IOException e) { | ||
208 | // Nothing to handle in a test. | ||
209 | } | ||
210 | } | ||
211 | var problemString = outputStream.toString(); | ||
212 | |||
213 | assertThat(problemString, equalTo(expected)); | ||
214 | } | ||
215 | } | ||