diff options
6 files changed, 417 insertions, 221 deletions
diff --git a/language/build.gradle b/language/build.gradle index 5b0ab20f..7e079f27 100644 --- a/language/build.gradle +++ b/language/build.gradle | |||
@@ -7,6 +7,7 @@ configurations { | |||
7 | dependencies { | 7 | dependencies { |
8 | testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}" | 8 | testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}" |
9 | testRuntime "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" | 9 | testRuntime "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" |
10 | testCompile "org.junit.jupiter:junit-jupiter-params:${junitVersion}" | ||
10 | testCompile "org.eclipse.xtext:org.eclipse.xtext.testing:${xtextVersion}" | 11 | testCompile "org.eclipse.xtext:org.eclipse.xtext.testing:${xtextVersion}" |
11 | testCompile "org.eclipse.xtext:org.eclipse.xtext.xbase.testing:${xtextVersion}" | 12 | testCompile "org.eclipse.xtext:org.eclipse.xtext.xbase.testing:${xtextVersion}" |
12 | testCompile "org.hamcrest:hamcrest:${hamcrestVersion}" | 13 | testCompile "org.hamcrest:hamcrest:${hamcrestVersion}" |
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/NodeNameCollector.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/NodeNameCollector.java new file mode 100644 index 00000000..4dee5434 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/NodeNameCollector.java | |||
@@ -0,0 +1,140 @@ | |||
1 | package org.eclipse.viatra.solver.language.resource; | ||
2 | |||
3 | import java.util.HashSet; | ||
4 | import java.util.List; | ||
5 | import java.util.Set; | ||
6 | import java.util.function.Predicate; | ||
7 | |||
8 | import org.eclipse.emf.ecore.EObject; | ||
9 | import org.eclipse.emf.ecore.EStructuralFeature; | ||
10 | import org.eclipse.viatra.solver.language.model.problem.Argument; | ||
11 | import org.eclipse.viatra.solver.language.model.problem.Assertion; | ||
12 | import org.eclipse.viatra.solver.language.model.problem.AssertionArgument; | ||
13 | import org.eclipse.viatra.solver.language.model.problem.Atom; | ||
14 | import org.eclipse.viatra.solver.language.model.problem.Conjunction; | ||
15 | import org.eclipse.viatra.solver.language.model.problem.EnumDeclaration; | ||
16 | import org.eclipse.viatra.solver.language.model.problem.Literal; | ||
17 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral; | ||
18 | import org.eclipse.viatra.solver.language.model.problem.Node; | ||
19 | import org.eclipse.viatra.solver.language.model.problem.NodeAssertionArgument; | ||
20 | import org.eclipse.viatra.solver.language.model.problem.NodeValueAssertion; | ||
21 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; | ||
22 | import org.eclipse.viatra.solver.language.model.problem.Problem; | ||
23 | import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; | ||
24 | import org.eclipse.viatra.solver.language.model.problem.Statement; | ||
25 | import org.eclipse.viatra.solver.language.model.problem.VariableOrNodeArgument; | ||
26 | import org.eclipse.xtext.linking.impl.LinkingHelper; | ||
27 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
28 | import org.eclipse.xtext.naming.QualifiedName; | ||
29 | import org.eclipse.xtext.nodemodel.INode; | ||
30 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils; | ||
31 | import org.eclipse.xtext.scoping.IScope; | ||
32 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
33 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | ||
34 | |||
35 | import com.google.inject.Inject; | ||
36 | import com.google.inject.name.Named; | ||
37 | |||
38 | public class NodeNameCollector { | ||
39 | @Inject | ||
40 | private LinkingHelper linkingHelper; | ||
41 | |||
42 | @Inject | ||
43 | private IQualifiedNameConverter qualifiedNameConverter; | ||
44 | |||
45 | @Inject | ||
46 | @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE) | ||
47 | private IScopeProvider scopeProvider; | ||
48 | |||
49 | private final Set<String> nodeNames = new HashSet<>(); | ||
50 | private final Set<String> existingNodeNames = new HashSet<>(); | ||
51 | |||
52 | private IScope nodeScope; | ||
53 | |||
54 | public Set<String> getNodeNames() { | ||
55 | return nodeNames; | ||
56 | } | ||
57 | |||
58 | public void collectNodeNames(Problem problem) { | ||
59 | nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__ARGUMENTS); | ||
60 | collectEnumLiteralNames(problem); | ||
61 | for (Statement statement : problem.getStatements()) { | ||
62 | collectStatementNodeNames(statement); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | protected void collectEnumLiteralNames(Problem problem) { | ||
67 | for (Statement statement : problem.getStatements()) { | ||
68 | if (statement instanceof EnumDeclaration) { | ||
69 | EnumDeclaration enumDeclaration = (EnumDeclaration) statement; | ||
70 | for (Node literal : enumDeclaration.getLiterals()) { | ||
71 | String name = literal.getName(); | ||
72 | if (ProblemDerivedStateComputer.validId(name)) { | ||
73 | existingNodeNames.add(name); | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | protected void collectStatementNodeNames(Statement statement) { | ||
81 | if (statement instanceof Assertion) { | ||
82 | collectAssertionNodeNames((Assertion) statement); | ||
83 | } else if (statement instanceof NodeValueAssertion) { | ||
84 | collectNodeValueAssertionNodeNames((NodeValueAssertion) statement); | ||
85 | } else if (statement instanceof PredicateDefinition) { | ||
86 | collectPredicateDefinitionNodeNames((PredicateDefinition) statement); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | protected void collectAssertionNodeNames(Assertion assertion) { | ||
91 | for (AssertionArgument argument : assertion.getArguments()) { | ||
92 | if (argument instanceof NodeAssertionArgument) { | ||
93 | addNodeNames(argument, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE, | ||
94 | ProblemDerivedStateComputer::validNodeName); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | protected void collectNodeValueAssertionNodeNames(NodeValueAssertion nodeValueAssertion) { | ||
100 | addNodeNames(nodeValueAssertion, ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE, | ||
101 | ProblemDerivedStateComputer::validNodeName); | ||
102 | } | ||
103 | |||
104 | protected void collectPredicateDefinitionNodeNames(PredicateDefinition predicateDefinition) { | ||
105 | for (Conjunction body : predicateDefinition.getBodies()) { | ||
106 | for (Literal literal : body.getLiterals()) { | ||
107 | Atom atom = null; | ||
108 | if (literal instanceof Atom) { | ||
109 | atom = (Atom) literal; | ||
110 | } else if (literal instanceof NegativeLiteral) { | ||
111 | NegativeLiteral negativeLiteral = (NegativeLiteral) literal; | ||
112 | atom = negativeLiteral.getAtom(); | ||
113 | } | ||
114 | if (atom == null) { | ||
115 | continue; | ||
116 | } | ||
117 | for (Argument argument : atom.getArguments()) { | ||
118 | if (argument instanceof VariableOrNodeArgument) { | ||
119 | addNodeNames(argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, | ||
120 | ProblemDerivedStateComputer::validQuotedId); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | private void addNodeNames(EObject eObject, EStructuralFeature feature, Predicate<String> condition) { | ||
128 | List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject, feature); | ||
129 | for (INode node : nodes) { | ||
130 | String nodeName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
131 | if (!condition.test(nodeName)) { | ||
132 | continue; | ||
133 | } | ||
134 | QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(nodeName); | ||
135 | if (!existingNodeNames.contains(nodeName) && nodeScope.getSingleElement(qualifiedName) == null) { | ||
136 | nodeNames.add(nodeName); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } \ No newline at end of file | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java index 42e53534..81236afd 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java | |||
@@ -5,18 +5,14 @@ import java.util.HashSet; | |||
5 | import java.util.List; | 5 | import java.util.List; |
6 | import java.util.Map; | 6 | import java.util.Map; |
7 | import java.util.Set; | 7 | import java.util.Set; |
8 | import java.util.function.Predicate; | ||
9 | import java.util.regex.Pattern; | 8 | import java.util.regex.Pattern; |
10 | 9 | ||
11 | import org.eclipse.emf.common.notify.impl.AdapterImpl; | 10 | import org.eclipse.emf.common.notify.impl.AdapterImpl; |
12 | import org.eclipse.emf.ecore.EObject; | 11 | import org.eclipse.emf.ecore.EObject; |
13 | import org.eclipse.emf.ecore.EStructuralFeature; | ||
14 | import org.eclipse.emf.ecore.resource.Resource; | 12 | import org.eclipse.emf.ecore.resource.Resource; |
15 | import org.eclipse.emf.ecore.util.EcoreUtil; | 13 | import org.eclipse.emf.ecore.util.EcoreUtil; |
16 | import org.eclipse.viatra.solver.language.ProblemUtil; | 14 | import org.eclipse.viatra.solver.language.ProblemUtil; |
17 | import org.eclipse.viatra.solver.language.model.problem.Argument; | 15 | import org.eclipse.viatra.solver.language.model.problem.Argument; |
18 | import org.eclipse.viatra.solver.language.model.problem.Assertion; | ||
19 | import org.eclipse.viatra.solver.language.model.problem.AssertionArgument; | ||
20 | import org.eclipse.viatra.solver.language.model.problem.Atom; | 16 | import org.eclipse.viatra.solver.language.model.problem.Atom; |
21 | import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; | 17 | import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; |
22 | import org.eclipse.viatra.solver.language.model.problem.Conjunction; | 18 | import org.eclipse.viatra.solver.language.model.problem.Conjunction; |
@@ -25,8 +21,6 @@ import org.eclipse.viatra.solver.language.model.problem.ImplicitVariable; | |||
25 | import org.eclipse.viatra.solver.language.model.problem.Literal; | 21 | import org.eclipse.viatra.solver.language.model.problem.Literal; |
26 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral; | 22 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral; |
27 | import org.eclipse.viatra.solver.language.model.problem.Node; | 23 | import org.eclipse.viatra.solver.language.model.problem.Node; |
28 | import org.eclipse.viatra.solver.language.model.problem.NodeAssertionArgument; | ||
29 | import org.eclipse.viatra.solver.language.model.problem.NodeValueAssertion; | ||
30 | import org.eclipse.viatra.solver.language.model.problem.Parameter; | 24 | import org.eclipse.viatra.solver.language.model.problem.Parameter; |
31 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; | 25 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; |
32 | import org.eclipse.viatra.solver.language.model.problem.Problem; | 26 | import org.eclipse.viatra.solver.language.model.problem.Problem; |
@@ -48,6 +42,7 @@ import org.eclipse.xtext.scoping.IScopeProvider; | |||
48 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | 42 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; |
49 | 43 | ||
50 | import com.google.inject.Inject; | 44 | import com.google.inject.Inject; |
45 | import com.google.inject.Provider; | ||
51 | import com.google.inject.Singleton; | 46 | import com.google.inject.Singleton; |
52 | import com.google.inject.name.Named; | 47 | import com.google.inject.name.Named; |
53 | 48 | ||
@@ -73,6 +68,9 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { | |||
73 | @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE) | 68 | @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE) |
74 | private IScopeProvider scopeProvider; | 69 | private IScopeProvider scopeProvider; |
75 | 70 | ||
71 | @Inject | ||
72 | private Provider<NodeNameCollector> nodeNameCollectorProvider; | ||
73 | |||
76 | @Override | 74 | @Override |
77 | public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) { | 75 | public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) { |
78 | Problem problem = getProblem(resource); | 76 | Problem problem = getProblem(resource); |
@@ -121,46 +119,9 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { | |||
121 | } | 119 | } |
122 | 120 | ||
123 | protected Set<String> installDerivedNodes(Problem problem) { | 121 | protected Set<String> installDerivedNodes(Problem problem) { |
124 | IScope nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__ARGUMENTS); | 122 | NodeNameCollector collector = nodeNameCollectorProvider.get(); |
125 | Set<String> nodeNames = new HashSet<>(); | 123 | collector.collectNodeNames(problem); |
126 | for (Statement statement : problem.getStatements()) { | 124 | Set<String> nodeNames = collector.getNodeNames(); |
127 | if (statement instanceof Assertion) { | ||
128 | Assertion assertion = (Assertion) statement; | ||
129 | for (AssertionArgument argument : assertion.getArguments()) { | ||
130 | if (argument instanceof NodeAssertionArgument) { | ||
131 | addNodeNames(nodeNames, nodeScope, argument, | ||
132 | ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE, | ||
133 | ProblemDerivedStateComputer::validNodeName); | ||
134 | } | ||
135 | } | ||
136 | } else if (statement instanceof NodeValueAssertion) { | ||
137 | addNodeNames(nodeNames, nodeScope, statement, ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE, | ||
138 | ProblemDerivedStateComputer::validNodeName); | ||
139 | } else if (statement instanceof PredicateDefinition) { | ||
140 | PredicateDefinition predicateDefinition = (PredicateDefinition) statement; | ||
141 | for (Conjunction body : predicateDefinition.getBodies()) { | ||
142 | for (Literal literal : body.getLiterals()) { | ||
143 | Atom atom = null; | ||
144 | if (literal instanceof Atom) { | ||
145 | atom = (Atom) literal; | ||
146 | } else if (literal instanceof NegativeLiteral) { | ||
147 | NegativeLiteral negativeLiteral = (NegativeLiteral) literal; | ||
148 | atom = negativeLiteral.getAtom(); | ||
149 | } | ||
150 | if (atom == null) { | ||
151 | continue; | ||
152 | } | ||
153 | for (Argument argument : atom.getArguments()) { | ||
154 | if (argument instanceof VariableOrNodeArgument) { | ||
155 | addNodeNames(nodeNames, nodeScope, argument, | ||
156 | ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, | ||
157 | ProblemDerivedStateComputer::validQuotedId); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | List<Node> grapNodes = problem.getNodes(); | 125 | List<Node> grapNodes = problem.getNodes(); |
165 | for (String nodeName : nodeNames) { | 126 | for (String nodeName : nodeNames) { |
166 | Node graphNode = createNode(nodeName); | 127 | Node graphNode = createNode(nodeName); |
@@ -169,21 +130,6 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { | |||
169 | return nodeNames; | 130 | return nodeNames; |
170 | } | 131 | } |
171 | 132 | ||
172 | private void addNodeNames(Set<String> nodeNames, IScope nodeScope, EObject eObject, EStructuralFeature feature, | ||
173 | Predicate<String> condition) { | ||
174 | List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject, feature); | ||
175 | for (INode node : nodes) { | ||
176 | String nodeName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
177 | if (!condition.test(nodeName)) { | ||
178 | continue; | ||
179 | } | ||
180 | QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(nodeName); | ||
181 | if (!nodeNames.contains(nodeName) && nodeScope.getSingleElement(qualifiedName) == null) { | ||
182 | nodeNames.add(nodeName); | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | protected Node createNode(String name) { | 133 | protected Node createNode(String name) { |
188 | Node node = ProblemFactory.eINSTANCE.createNode(); | 134 | Node node = ProblemFactory.eINSTANCE.createNode(); |
189 | node.setName(name); | 135 | node.setName(name); |
@@ -347,7 +293,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { | |||
347 | return validId(name) || validQuotedId(name); | 293 | return validId(name) || validQuotedId(name); |
348 | } | 294 | } |
349 | 295 | ||
350 | public Adapter getOrInstallAdapter(Resource resource) { | 296 | protected Adapter getOrInstallAdapter(Resource resource) { |
351 | if (!(resource instanceof XtextResource)) { | 297 | if (!(resource instanceof XtextResource)) { |
352 | return new Adapter(); | 298 | return new Adapter(); |
353 | } | 299 | } |
@@ -363,7 +309,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { | |||
363 | return adapter; | 309 | return adapter; |
364 | } | 310 | } |
365 | 311 | ||
366 | private static class Adapter extends AdapterImpl { | 312 | protected static class Adapter extends AdapterImpl { |
367 | public Map<ClassDeclaration, Node> newNodes = new HashMap<>(); | 313 | public Map<ClassDeclaration, Node> newNodes = new HashMap<>(); |
368 | 314 | ||
369 | @Override | 315 | @Override |
diff --git a/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemScopingTest.xtend b/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemScopingTest.xtend deleted file mode 100644 index 7fc1c44d..00000000 --- a/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemScopingTest.xtend +++ /dev/null | |||
@@ -1,158 +0,0 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language.tests | ||
5 | |||
6 | import com.google.inject.Inject | ||
7 | import org.eclipse.viatra.solver.language.model.problem.Problem | ||
8 | import org.eclipse.xtext.testing.InjectWith | ||
9 | import org.eclipse.xtext.testing.extensions.InjectionExtension | ||
10 | import org.eclipse.xtext.testing.util.ParseHelper | ||
11 | import org.junit.jupiter.api.Test | ||
12 | import org.junit.jupiter.api.^extension.ExtendWith | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat | ||
15 | import static org.hamcrest.Matchers.* | ||
16 | |||
17 | @ExtendWith(InjectionExtension) | ||
18 | @InjectWith(ProblemInjectorProvider) | ||
19 | class ProblemScopingTest { | ||
20 | @Inject | ||
21 | ParseHelper<Problem> parseHelper | ||
22 | |||
23 | @Inject | ||
24 | extension ProblemTestUtil | ||
25 | |||
26 | @Test | ||
27 | def void builtInArgumentTypeTest() { | ||
28 | val it = parseHelper.parse(''' | ||
29 | pred predicate(node a, data b, int c). | ||
30 | ''') | ||
31 | assertThat(errors, empty) | ||
32 | assertThat(pred('predicate').param(0).parameterType, equalTo(builtin.findClass('node'))) | ||
33 | assertThat(pred('predicate').param(1).parameterType, equalTo(builtin.findClass('data'))) | ||
34 | assertThat(pred('predicate').param(2).parameterType, equalTo(builtin.findClass('int'))) | ||
35 | } | ||
36 | |||
37 | @Test | ||
38 | def void builtiQualifiedArgumentTypeTest() { | ||
39 | val it = parseHelper.parse(''' | ||
40 | pred predicate(builtin::node a, builtin::data b, builtin::int c). | ||
41 | ''') | ||
42 | assertThat(errors, empty) | ||
43 | assertThat(pred('predicate').param(0).parameterType, equalTo(builtin.findClass('node'))) | ||
44 | assertThat(pred('predicate').param(1).parameterType, equalTo(builtin.findClass('data'))) | ||
45 | assertThat(pred('predicate').param(2).parameterType, equalTo(builtin.findClass('int'))) | ||
46 | } | ||
47 | |||
48 | @Test | ||
49 | def void implicitNodeInAssertionTest() { | ||
50 | val it = parseHelper.parse(''' | ||
51 | pred predicate(node a, node b). | ||
52 | predicate(a, a). | ||
53 | ?predicate(a, b). | ||
54 | ''') | ||
55 | assertThat(errors, empty) | ||
56 | assertThat(nodeNames, hasItems('a', 'b')) | ||
57 | assertThat(assertion(0).arg(0).node, equalTo(node('a'))) | ||
58 | assertThat(assertion(0).arg(1).node, equalTo(node('a'))) | ||
59 | assertThat(assertion(1).arg(0).node, equalTo(node('a'))) | ||
60 | assertThat(assertion(1).arg(1).node, equalTo(node('b'))) | ||
61 | } | ||
62 | |||
63 | @Test | ||
64 | def void quotedNodeInAssertionTest() { | ||
65 | val it = parseHelper.parse(''' | ||
66 | pred predicate(node a, node b). | ||
67 | predicate('a', 'a'). | ||
68 | ?predicate('a', 'b'). | ||
69 | ''') | ||
70 | assertThat(errors, empty) | ||
71 | assertThat(nodeNames, hasItems("'a'", "'b'")) | ||
72 | assertThat(assertion(0).arg(0).node, equalTo(node("'a'"))) | ||
73 | assertThat(assertion(0).arg(1).node, equalTo(node("'a'"))) | ||
74 | assertThat(assertion(1).arg(0).node, equalTo(node("'a'"))) | ||
75 | assertThat(assertion(1).arg(1).node, equalTo(node("'b'"))) | ||
76 | } | ||
77 | |||
78 | @Test | ||
79 | def void builtInNodeInAssertionTest() { | ||
80 | val it = parseHelper.parse(''' | ||
81 | pred predicate(node a). | ||
82 | predicate(int::new). | ||
83 | ''') | ||
84 | assertThat(errors, empty) | ||
85 | assertThat(nodes, empty) | ||
86 | assertThat(assertion(0).arg(0).node, equalTo(builtin.findClass('int').newNode)) | ||
87 | } | ||
88 | |||
89 | @Test | ||
90 | def void qualifiedBuiltInNodeInAssertionTest() { | ||
91 | val it = parseHelper.parse(''' | ||
92 | pred predicate(node a). | ||
93 | predicate(builtin::int::new). | ||
94 | ''') | ||
95 | assertThat(errors, empty) | ||
96 | assertThat(nodes, empty) | ||
97 | assertThat(assertion(0).arg(0).node, equalTo(builtin.findClass('int').newNode)) | ||
98 | } | ||
99 | |||
100 | @Test | ||
101 | def void classNewNodeTest() { | ||
102 | val it = parseHelper.parse(''' | ||
103 | class Foo. | ||
104 | pred predicate(node a). | ||
105 | predicate(Foo::new). | ||
106 | ''') | ||
107 | assertThat(errors, empty) | ||
108 | assertThat(nodes, empty) | ||
109 | assertThat(assertion(0).arg(0).node, equalTo(findClass('Foo').newNode)) | ||
110 | } | ||
111 | |||
112 | @Test | ||
113 | def void qualifiedClassNewNodeTest() { | ||
114 | val it = parseHelper.parse(''' | ||
115 | problem test. | ||
116 | class Foo. | ||
117 | pred predicate(node a). | ||
118 | predicate(test::Foo::new). | ||
119 | ''') | ||
120 | assertThat(errors, empty) | ||
121 | assertThat(nodes, empty) | ||
122 | assertThat(assertion(0).arg(0).node, equalTo(findClass('Foo').newNode)) | ||
123 | } | ||
124 | |||
125 | @Test | ||
126 | def void newNodeIsNotSpecial() { | ||
127 | val it = parseHelper.parse(''' | ||
128 | class Foo. | ||
129 | pred predicate(node a). | ||
130 | predicate(new). | ||
131 | ''') | ||
132 | assertThat(errors, empty) | ||
133 | assertThat(nodeNames, hasItem('new')) | ||
134 | assertThat(assertion(0).arg(0).node, not(equalTo(findClass('Foo').newNode))) | ||
135 | } | ||
136 | |||
137 | @Test | ||
138 | def void implicitNodeInPredicateTest() { | ||
139 | val it = parseHelper.parse(''' | ||
140 | pred predicate(node a) :- node(b). | ||
141 | predicate(b). | ||
142 | ''') | ||
143 | assertThat(errors, empty) | ||
144 | assertThat(nodeNames, hasItem("b")) | ||
145 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(node("b"))) | ||
146 | assertThat(assertion(0).arg(0).node, equalTo(node("b"))) | ||
147 | } | ||
148 | |||
149 | @Test | ||
150 | def void quotedNodeInPredicateTest() { | ||
151 | val it = parseHelper.parse(''' | ||
152 | pred predicate(node a) :- node('b'). | ||
153 | ''') | ||
154 | assertThat(errors, empty) | ||
155 | assertThat(nodeNames, hasItem("'b'")) | ||
156 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(node("'b'"))) | ||
157 | } | ||
158 | } | ||
diff --git a/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemTestUtil.xtend b/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemTestUtil.xtend index b16de2b5..f2aedfd5 100644 --- a/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemTestUtil.xtend +++ b/language/src/test/java/org/eclipse/viatra/solver/language/tests/ProblemTestUtil.xtend | |||
@@ -12,6 +12,7 @@ import org.eclipse.viatra.solver.language.model.problem.Literal | |||
12 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral | 12 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral |
13 | import org.eclipse.viatra.solver.language.model.problem.Node | 13 | import org.eclipse.viatra.solver.language.model.problem.Node |
14 | import org.eclipse.viatra.solver.language.model.problem.NodeAssertionArgument | 14 | import org.eclipse.viatra.solver.language.model.problem.NodeAssertionArgument |
15 | import org.eclipse.viatra.solver.language.model.problem.NodeValueAssertion | ||
15 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition | 16 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition |
16 | import org.eclipse.viatra.solver.language.model.problem.Problem | 17 | import org.eclipse.viatra.solver.language.model.problem.Problem |
17 | import org.eclipse.viatra.solver.language.model.problem.Variable | 18 | import org.eclipse.viatra.solver.language.model.problem.Variable |
@@ -74,6 +75,10 @@ class ProblemTestUtil { | |||
74 | statements.filter(Assertion).get(i) | 75 | statements.filter(Assertion).get(i) |
75 | } | 76 | } |
76 | 77 | ||
78 | def nodeValueAssertion(Problem it, int i) { | ||
79 | statements.filter(NodeValueAssertion).get(i) | ||
80 | } | ||
81 | |||
77 | def arg(Assertion it, int i) { | 82 | def arg(Assertion it, int i) { |
78 | arguments.get(i) | 83 | arguments.get(i) |
79 | } | 84 | } |
diff --git a/language/src/test/java/org/eclipse/viatra/solver/language/tests/scoping/NodeScopingTest.xtend b/language/src/test/java/org/eclipse/viatra/solver/language/tests/scoping/NodeScopingTest.xtend new file mode 100644 index 00000000..c92ad4c2 --- /dev/null +++ b/language/src/test/java/org/eclipse/viatra/solver/language/tests/scoping/NodeScopingTest.xtend | |||
@@ -0,0 +1,262 @@ | |||
1 | package org.eclipse.viatra.solver.language.tests.scoping | ||
2 | |||
3 | import com.google.inject.Inject | ||
4 | import java.util.stream.Stream | ||
5 | import org.eclipse.viatra.solver.language.model.problem.Problem | ||
6 | import org.eclipse.viatra.solver.language.tests.ProblemInjectorProvider | ||
7 | import org.eclipse.viatra.solver.language.tests.ProblemTestUtil | ||
8 | import org.eclipse.xtext.testing.InjectWith | ||
9 | import org.eclipse.xtext.testing.extensions.InjectionExtension | ||
10 | import org.eclipse.xtext.testing.util.ParseHelper | ||
11 | import org.junit.jupiter.api.Test | ||
12 | import org.junit.jupiter.api.^extension.ExtendWith | ||
13 | import org.junit.jupiter.params.ParameterizedTest | ||
14 | import org.junit.jupiter.params.provider.Arguments | ||
15 | import org.junit.jupiter.params.provider.MethodSource | ||
16 | import org.junit.jupiter.params.provider.ValueSource | ||
17 | |||
18 | import static org.hamcrest.MatcherAssert.assertThat | ||
19 | import static org.hamcrest.Matchers.* | ||
20 | |||
21 | @ExtendWith(InjectionExtension) | ||
22 | @InjectWith(ProblemInjectorProvider) | ||
23 | class NodeScopingTest { | ||
24 | @Inject | ||
25 | ParseHelper<Problem> parseHelper | ||
26 | |||
27 | @Inject | ||
28 | extension ProblemTestUtil | ||
29 | |||
30 | @ParameterizedTest | ||
31 | @ValueSource(strings=#["", "builtin::"]) | ||
32 | def void builtInArgumentTypeTest(String prefix) { | ||
33 | val it = parseHelper.parse(''' | ||
34 | pred predicate(«prefix»node a, «prefix»data b, «prefix»int c). | ||
35 | ''') | ||
36 | assertThat(errors, empty) | ||
37 | assertThat(pred('predicate').param(0).parameterType, equalTo(builtin.findClass('node'))) | ||
38 | assertThat(pred('predicate').param(1).parameterType, equalTo(builtin.findClass('data'))) | ||
39 | assertThat(pred('predicate').param(2).parameterType, equalTo(builtin.findClass('int'))) | ||
40 | } | ||
41 | |||
42 | @Test | ||
43 | def void implicitNodeInAssertionTest() { | ||
44 | val it = parseHelper.parse(''' | ||
45 | pred predicate(node x, node y) :- node(x). | ||
46 | predicate(a, a). | ||
47 | ?predicate(a, b). | ||
48 | ''') | ||
49 | assertThat(errors, empty) | ||
50 | assertThat(nodeNames, hasItems('a', 'b')) | ||
51 | assertThat(assertion(0).arg(0).node, equalTo(node('a'))) | ||
52 | assertThat(assertion(0).arg(1).node, equalTo(node('a'))) | ||
53 | assertThat(assertion(1).arg(0).node, equalTo(node('a'))) | ||
54 | assertThat(assertion(1).arg(1).node, equalTo(node('b'))) | ||
55 | } | ||
56 | |||
57 | @Test | ||
58 | def void implicitNodeInNodeValueAssertionTest() { | ||
59 | val it = parseHelper.parse(''' | ||
60 | a: 16. | ||
61 | ''') | ||
62 | assertThat(errors, empty) | ||
63 | assertThat(nodeNames, hasItems('a')) | ||
64 | assertThat(nodeValueAssertion(0).node, equalTo(node('a'))) | ||
65 | } | ||
66 | |||
67 | def void implicitNodeInPredicateTest() { | ||
68 | val it = parseHelper.parse(''' | ||
69 | pred predicate(node a) :- node(b). | ||
70 | predicate(b). | ||
71 | ''') | ||
72 | assertThat(errors, empty) | ||
73 | assertThat(nodeNames, hasItem("b")) | ||
74 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(node("b"))) | ||
75 | assertThat(assertion(0).arg(0).node, equalTo(node("b"))) | ||
76 | } | ||
77 | |||
78 | @Test | ||
79 | def void quotedNodeInAssertionTest() { | ||
80 | val it = parseHelper.parse(''' | ||
81 | pred predicate(node x, node y) :- node(x). | ||
82 | predicate('a', 'a'). | ||
83 | ?predicate('a', 'b'). | ||
84 | ''') | ||
85 | assertThat(errors, empty) | ||
86 | assertThat(nodeNames, hasItems("'a'", "'b'")) | ||
87 | assertThat(assertion(0).arg(0).node, equalTo(node("'a'"))) | ||
88 | assertThat(assertion(0).arg(1).node, equalTo(node("'a'"))) | ||
89 | assertThat(assertion(1).arg(0).node, equalTo(node("'a'"))) | ||
90 | assertThat(assertion(1).arg(1).node, equalTo(node("'b'"))) | ||
91 | } | ||
92 | |||
93 | @Test | ||
94 | def void quotedNodeInNodeValueAssertionTest() { | ||
95 | val it = parseHelper.parse(''' | ||
96 | 'a': 16. | ||
97 | ''') | ||
98 | assertThat(errors, empty) | ||
99 | assertThat(nodeNames, hasItems("'a'")) | ||
100 | assertThat(nodeValueAssertion(0).node, equalTo(node("'a'"))) | ||
101 | } | ||
102 | |||
103 | @Test | ||
104 | def void quotedNodeInPredicateTest() { | ||
105 | val it = parseHelper.parse(''' | ||
106 | pred predicate(node a) :- node('b'). | ||
107 | ''') | ||
108 | assertThat(errors, empty) | ||
109 | assertThat(nodeNames, hasItem("'b'")) | ||
110 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(node("'b'"))) | ||
111 | } | ||
112 | |||
113 | @ParameterizedTest | ||
114 | @MethodSource("builtInNodeReferencesSource") | ||
115 | def void builtInNodeTest(String qualifiedName) { | ||
116 | val it = parseHelper.parse(''' | ||
117 | pred predicate(node x) :- node(x). | ||
118 | predicate(«qualifiedName»). | ||
119 | ''') | ||
120 | assertThat(errors, empty) | ||
121 | assertThat(nodes, empty) | ||
122 | assertThat(assertion(0).arg(0).node, equalTo(builtin.findClass('int').newNode)) | ||
123 | } | ||
124 | |||
125 | @ParameterizedTest | ||
126 | @MethodSource("builtInNodeReferencesSource") | ||
127 | def void builtInNodeInNodeValueAssertionTest(String qualifiedName) { | ||
128 | val it = parseHelper.parse(''' | ||
129 | «qualifiedName»: 16. | ||
130 | ''') | ||
131 | assertThat(errors, empty) | ||
132 | assertThat(nodes, empty) | ||
133 | assertThat(nodeValueAssertion(0).node, equalTo(builtin.findClass('int').newNode)) | ||
134 | } | ||
135 | |||
136 | @ParameterizedTest | ||
137 | @MethodSource("builtInNodeReferencesSource") | ||
138 | def void builtInNodeInPredicateTest(String qualifiedName) { | ||
139 | val it = parseHelper.parse(''' | ||
140 | pred predicate(node x) :- node(«qualifiedName»). | ||
141 | ''') | ||
142 | assertThat(errors, empty) | ||
143 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(builtin.findClass('int').newNode)) | ||
144 | } | ||
145 | |||
146 | static def builtInNodeReferencesSource() { | ||
147 | Stream.of( | ||
148 | Arguments.of("int::new"), | ||
149 | Arguments.of("builtin::int::new") | ||
150 | ) | ||
151 | } | ||
152 | |||
153 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
154 | @MethodSource("classNewNodeReferencesSource") | ||
155 | def void classNewNodeTest(String qualifiedName, boolean namedProblem) { | ||
156 | val it = parseHelper.parse(''' | ||
157 | «IF namedProblem»problem test.«ENDIF» | ||
158 | class Foo. | ||
159 | pred predicate(node x) :- node(x). | ||
160 | predicate(«qualifiedName»). | ||
161 | ''') | ||
162 | assertThat(errors, empty) | ||
163 | assertThat(nodes, empty) | ||
164 | assertThat(assertion(0).arg(0).node, equalTo(findClass('Foo').newNode)) | ||
165 | } | ||
166 | |||
167 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
168 | @MethodSource("classNewNodeReferencesSource") | ||
169 | def void classNewNodeInNodeValueAssertionTest(String qualifiedName, boolean namedProblem) { | ||
170 | val it = parseHelper.parse(''' | ||
171 | «IF namedProblem»problem test.«ENDIF» | ||
172 | class Foo. | ||
173 | «qualifiedName»: 16. | ||
174 | ''') | ||
175 | assertThat(errors, empty) | ||
176 | assertThat(nodes, empty) | ||
177 | assertThat(nodeValueAssertion(0).node, equalTo(findClass('Foo').newNode)) | ||
178 | } | ||
179 | |||
180 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
181 | @MethodSource("classNewNodeReferencesSource") | ||
182 | def void classNewNodeInPredicateTest(String qualifiedName, boolean namedProblem) { | ||
183 | val it = parseHelper.parse(''' | ||
184 | «IF namedProblem»problem test.«ENDIF» | ||
185 | class Foo. | ||
186 | pred predicate(node x) :- node(«qualifiedName»). | ||
187 | ''') | ||
188 | assertThat(errors, empty) | ||
189 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(findClass('Foo').newNode)) | ||
190 | } | ||
191 | |||
192 | static def classNewNodeReferencesSource() { | ||
193 | Stream.of( | ||
194 | Arguments.of("Foo::new", false), | ||
195 | Arguments.of("Foo::new", true), | ||
196 | Arguments.of("test::Foo::new", true) | ||
197 | ) | ||
198 | } | ||
199 | |||
200 | @Test | ||
201 | def void newNodeIsNotSpecial() { | ||
202 | val it = parseHelper.parse(''' | ||
203 | class Foo. | ||
204 | pred predicate(node x) :- node(x). | ||
205 | predicate(new). | ||
206 | ''') | ||
207 | assertThat(errors, empty) | ||
208 | assertThat(nodeNames, hasItem('new')) | ||
209 | assertThat(assertion(0).arg(0).node, not(equalTo(findClass('Foo').newNode))) | ||
210 | } | ||
211 | |||
212 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
213 | @MethodSource("enumLiteralReferencesSource") | ||
214 | def void enumLiteralTest(String qualifiedName, boolean namedProblem) { | ||
215 | val it = parseHelper.parse(''' | ||
216 | «IF namedProblem»problem test.«ENDIF» | ||
217 | enum Foo { alpha, beta } | ||
218 | pred predicate(Foo a) :- node(a). | ||
219 | predicate(«qualifiedName»). | ||
220 | ''') | ||
221 | assertThat(errors, empty) | ||
222 | assertThat(nodeNames, empty) | ||
223 | assertThat(assertion(0).arg(0).node, equalTo(findEnum("Foo").literal("alpha"))) | ||
224 | } | ||
225 | |||
226 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
227 | @MethodSource("enumLiteralReferencesSource") | ||
228 | def void enumLiteralInNodeValueAssertionTest(String qualifiedName, boolean namedProblem) { | ||
229 | val it = parseHelper.parse(''' | ||
230 | «IF namedProblem»problem test.«ENDIF» | ||
231 | enum Foo { alpha, beta } | ||
232 | «qualifiedName»: 16. | ||
233 | ''') | ||
234 | assertThat(errors, empty) | ||
235 | assertThat(nodeNames, empty) | ||
236 | assertThat(nodeValueAssertion(0).node, equalTo(findEnum("Foo").literal("alpha"))) | ||
237 | } | ||
238 | |||
239 | @ParameterizedTest(name="{0}, namedProblem={1}") | ||
240 | @MethodSource("enumLiteralReferencesSource") | ||
241 | def void enumLiteralInPredicateTest(String qualifiedName, boolean namedProblem) { | ||
242 | val it = parseHelper.parse(''' | ||
243 | «IF namedProblem»problem test.«ENDIF» | ||
244 | enum Foo { alpha, beta } | ||
245 | pred predicate(Foo a) :- node(«qualifiedName»). | ||
246 | ''') | ||
247 | assertThat(errors, empty) | ||
248 | assertThat(nodeNames, empty) | ||
249 | assertThat(pred("predicate").conj(0).lit(0).arg(0).node, equalTo(findEnum("Foo").literal("alpha"))) | ||
250 | } | ||
251 | |||
252 | static def enumLiteralReferencesSource() { | ||
253 | Stream.of( | ||
254 | Arguments.of("alpha", false), | ||
255 | Arguments.of("alpha", true), | ||
256 | Arguments.of("Foo::alpha", false), | ||
257 | Arguments.of("Foo::alpha", true), | ||
258 | Arguments.of("test::alpha", true), | ||
259 | Arguments.of("test::Foo::alpha", true) | ||
260 | ) | ||
261 | } | ||
262 | } | ||