aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/language')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/Problem.xtext102
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java21
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java32
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java38
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java67
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java3
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java52
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java12
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java10
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java50
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java134
-rw-r--r--subprojects/language/src/main/resources/tools/refinery/language/builtin.problem28
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java12
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java4
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java14
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java81
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java36
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java73
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java8
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java23
21 files changed, 322 insertions, 483 deletions
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 bc1ee465..8b13a693 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
+++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
@@ -10,14 +10,13 @@ Problem:
10Statement: 10Statement:
11 ClassDeclaration | EnumDeclaration | 11 ClassDeclaration | EnumDeclaration |
12 PredicateDefinition | FunctionDefinition | /* RuleDefinition | */ 12 PredicateDefinition | FunctionDefinition | /* RuleDefinition | */
13 Assertion | NodeValueAssertion | 13 Assertion | ScopeDeclaration | IndividualDeclaration;
14 ScopeDeclaration | IndividualDeclaration;
15 14
16ClassDeclaration: 15ClassDeclaration:
17 abstract?="abstract"? "class" 16 abstract?="abstract"? "class"
18 name=Identifier 17 name=Identifier
19 ("extends" superTypes+=[Relation|QualifiedName] ("," superTypes+=[Relation|QualifiedName])*)? 18 ("extends" superTypes+=[Relation|QualifiedName] ("," superTypes+=[Relation|QualifiedName])*)?
20 ("{" (referenceDeclarations+=ReferenceDeclaration ";"?)* "}" | "."); 19 ("{" (featureDeclarations+=FeatureDeclaration ";"?)* "}" | ".");
21 20
22EnumDeclaration: 21EnumDeclaration:
23 "enum" 22 "enum"
@@ -27,16 +26,27 @@ EnumDeclaration:
27EnumLiteral returns Node: 26EnumLiteral returns Node:
28 name=Identifier; 27 name=Identifier;
29 28
29FeatureDeclaration:
30 ReferenceDeclaration | AttributeDeclaration | FlagDeclaration;
31
30enum ReferenceKind: 32enum ReferenceKind:
31 REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; 33 REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container";
32 34
33ReferenceDeclaration: 35ReferenceDeclaration:
34 (kind=ReferenceKind referenceType=[Relation|QualifiedName] | 36 kind=ReferenceKind referenceType=[Relation|QualifiedName]
35 referenceType=[Relation|NonRelationKindQualifiedName])
36 ("[" multiplicity=Multiplicity "]")? 37 ("[" multiplicity=Multiplicity "]")?
37 name=Identifier 38 name=Identifier
38 ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; 39 ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?;
39 40
41enum PrimitiveType:
42 INT="int" | REAL="real" | STRING="string";
43
44AttributeDeclaration:
45 attributeType=PrimitiveType name=Identifier;
46
47FlagDeclaration:
48 "bool" name=Identifier;
49
40enum ErrorKind returns PredicateKind: 50enum ErrorKind returns PredicateKind:
41 ERROR="error"; 51 ERROR="error";
42 52
@@ -54,7 +64,7 @@ Conjunction:
54 literals+=Expr ("," literals+=Expr)*; 64 literals+=Expr ("," literals+=Expr)*;
55 65
56FunctionDefinition: 66FunctionDefinition:
57 functionType=[Relation|QualifiedName] name=Identifier 67 functionType=PrimitiveType name=Identifier
58 "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" 68 "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")"
59 ("=" cases+=Case (";" cases+=Case)*)? 69 ("=" cases+=Case (";" cases+=Case)*)?
60 "."; 70 ".";
@@ -96,11 +106,21 @@ Expr:
96 ComparisonExpr; 106 ComparisonExpr;
97 107
98enum ComparisonOp: 108enum ComparisonOp:
99 LESS="<" | LESS_EQ="<=" | GREATER=">" | GREATER_EQ=">=" | EQ="==" | NOT_EQ="!="; 109 LESS="<" | LESS_EQ="<=" | GREATER=">" | GREATER_EQ=">=" | EQ="==" | NOT_EQ="!=" | IN="in";
100 110
101ComparisonExpr returns Expr: 111ComparisonExpr returns Expr:
102 AdditiveExpr ({ComparisonExpr.left=current} 112 LatticeExpr ({ComparisonExpr.left=current}
103 op=ComparisonOp right=AdditiveExpr)*; 113 op=ComparisonOp right=LatticeExpr)*;
114
115enum LatticeOp returns BinaryOp:
116 MEET="/\\" | JOIN="\\/";
117
118LatticeExpr returns Expr:
119 RangeExpr ({ArithmeticBinaryExpr.left=current}
120 op=LatticeOp right=RangeExpr)*;
121
122RangeExpr returns Expr:
123 AdditiveExpr ({RangeExpr.left=current} ".." right=AdditiveExpr)*;
104 124
105enum AdditiveOp returns BinaryOp: 125enum AdditiveOp returns BinaryOp:
106 ADD="+" | SUB="-"; 126 ADD="+" | SUB="-";
@@ -125,7 +145,7 @@ ExponentialExpr returns Expr:
125 145
126UnaryExpr returns Expr: 146UnaryExpr returns Expr:
127 ArithmeticUnaryExpr | ModalExpr | NegationExpr | CountExpr | AggregationExpr | 147 ArithmeticUnaryExpr | ModalExpr | NegationExpr | CountExpr | AggregationExpr |
128 Atom | VariableOrNodeExpr | ConstantExpr | "(" Expr ")"; 148 Atom | VariableOrNodeExpr | Constant | "(" Expr ")";
129 149
130enum UnaryOp: 150enum UnaryOp:
131 PLUS="+" | MINUS="-"; 151 PLUS="+" | MINUS="-";
@@ -159,21 +179,33 @@ Atom:
159VariableOrNodeExpr: 179VariableOrNodeExpr:
160 variableOrNode=[VariableOrNode|QualifiedName]; 180 variableOrNode=[VariableOrNode|QualifiedName];
161 181
162ConstantExpr: 182Constant:
163 constant=Constant; 183 RealConstant | IntConstant | InfConstant | StringConstant;
184
185IntConstant:
186 intValue=INT;
187
188RealConstant:
189 realValue=Real;
190
191InfConstant:
192 {InfConstant} "*";
193
194StringConstant:
195 stringValue=STRING;
164 196
165Assertion: 197Assertion:
166 default?="default"? 198 default?="default"?
167 (value=ShortLogicValue? 199 (relation=[Relation|QualifiedName]
168 relation=[Relation|QualifiedName]
169 "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")"
170 | relation=[Relation|QualifiedName]
171 "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")" 200 "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")"
172 ":" value=LogicValue) 201 value=AssertionValue |
202 value=ShortLogicAssertionValue
203 relation=[Relation|QualifiedName]
204 "(" (arguments+=AssertionArgument ("," arguments+=AssertionArgument)*)? ")")
173 "."; 205 ".";
174 206
175AssertionArgument: 207AssertionArgument:
176 NodeAssertionArgument | WildcardAssertionArgument | ConstantAssertionArgument; 208 NodeAssertionArgument | WildcardAssertionArgument;
177 209
178NodeAssertionArgument: 210NodeAssertionArgument:
179 node=[Node|QualifiedName]; 211 node=[Node|QualifiedName];
@@ -181,29 +213,23 @@ NodeAssertionArgument:
181WildcardAssertionArgument: 213WildcardAssertionArgument:
182 {WildcardAssertionArgument} "*"; 214 {WildcardAssertionArgument} "*";
183 215
184ConstantAssertionArgument: 216AssertionValue:
185 negative?="-"? constant=Constant; 217 LogicAssertionValue | ExprAssertionValue;
186 218
187enum LogicValue: 219enum LogicValue:
188 TRUE="true" | FALSE="false" | UNKNOWN="unknown" | ERROR="error"; 220 TRUE="true" | FALSE="false" | UNKNOWN="unknown" | ERROR="error";
189 221
190enum ShortLogicValue returns LogicValue: 222LogicAssertionValue:
191 FALSE="!" | UNKNOWN="?"; 223 ":" logicValue=LogicValue;
192 224
193NodeValueAssertion: 225ExprAssertionValue:
194 node=[Node|QualifiedName] ":" value=Constant "."; 226 (range?="in" | "=") body=Expr;
195
196Constant:
197 RealConstant | IntConstant | StringConstant;
198
199IntConstant:
200 intValue=INT;
201 227
202RealConstant: 228enum ShortLogicValue returns LogicValue:
203 realValue=Real; 229 FALSE="!" | UNKNOWN="?";
204 230
205StringConstant: 231ShortLogicAssertionValue returns LogicAssertionValue:
206 stringValue=STRING; 232 {LogicAssertionValue} logicValue=ShortLogicValue?;
207 233
208ScopeDeclaration: 234ScopeDeclaration:
209 "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* "."; 235 "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* ".";
@@ -234,17 +260,11 @@ IndividualDeclaration:
234UpperBound returns ecore::EInt: 260UpperBound returns ecore::EInt:
235 INT | "*"; 261 INT | "*";
236 262
237NonRelationKindQualifiedName hidden():
238 NonRelationKindIdentifier ("::" Identifier)*;
239
240QualifiedName hidden(): 263QualifiedName hidden():
241 Identifier ("::" Identifier)*; 264 Identifier ("::" Identifier)*;
242 265
243NonRelationKindIdentifier:
244 ID | "true" | "false" | "contained" | "sum" | "prod" | "min" | "max";
245
246Identifier: 266Identifier:
247 NonRelationKindIdentifier | "contains"; 267 ID | "contains" | "contained" | "sum" | "prod" | "min" | "max";
248 268
249Real returns ecore::EDouble: 269Real returns ecore::EDouble:
250 EXPONENTIAL | INT "." (INT | EXPONENTIAL); 270 EXPONENTIAL | INT "." (INT | EXPONENTIAL);
diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
index c0777038..5efcdc81 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
@@ -3,25 +3,18 @@
3 */ 3 */
4package tools.refinery.language; 4package tools.refinery.language;
5 5
6import com.google.inject.Binder;
7import com.google.inject.name.Names;
6import org.eclipse.xtext.conversion.IValueConverterService; 8import org.eclipse.xtext.conversion.IValueConverterService;
7import org.eclipse.xtext.naming.IQualifiedNameConverter; 9import org.eclipse.xtext.naming.IQualifiedNameConverter;
8import org.eclipse.xtext.parser.IParser; 10import org.eclipse.xtext.parser.IParser;
9import org.eclipse.xtext.resource.DerivedStateAwareResource; 11import org.eclipse.xtext.resource.*;
10import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager;
11import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
12import org.eclipse.xtext.resource.IDerivedStateComputer;
13import org.eclipse.xtext.resource.ILocationInFileProvider;
14import org.eclipse.xtext.resource.IResourceDescription;
15import org.eclipse.xtext.resource.XtextResource;
16import org.eclipse.xtext.scoping.IGlobalScopeProvider; 12import org.eclipse.xtext.scoping.IGlobalScopeProvider;
17import org.eclipse.xtext.scoping.IScopeProvider; 13import org.eclipse.xtext.scoping.IScopeProvider;
18import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; 14import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
15import org.eclipse.xtext.serializer.sequencer.ISemanticSequencer;
19import org.eclipse.xtext.validation.IResourceValidator; 16import org.eclipse.xtext.validation.IResourceValidator;
20import org.eclipse.xtext.xbase.annotations.validation.DerivedStateAwareResourceValidator; 17import org.eclipse.xtext.xbase.annotations.validation.DerivedStateAwareResourceValidator;
21
22import com.google.inject.Binder;
23import com.google.inject.name.Names;
24
25import tools.refinery.language.conversion.ProblemValueConverterService; 18import tools.refinery.language.conversion.ProblemValueConverterService;
26import tools.refinery.language.naming.ProblemQualifiedNameConverter; 19import tools.refinery.language.naming.ProblemQualifiedNameConverter;
27import tools.refinery.language.parser.antlr.TokenSourceInjectingProblemParser; 20import tools.refinery.language.parser.antlr.TokenSourceInjectingProblemParser;
@@ -30,6 +23,7 @@ import tools.refinery.language.resource.ProblemLocationInFileProvider;
30import tools.refinery.language.resource.ProblemResourceDescriptionStrategy; 23import tools.refinery.language.resource.ProblemResourceDescriptionStrategy;
31import tools.refinery.language.scoping.ProblemGlobalScopeProvider; 24import tools.refinery.language.scoping.ProblemGlobalScopeProvider;
32import tools.refinery.language.scoping.ProblemLocalScopeProvider; 25import tools.refinery.language.scoping.ProblemLocalScopeProvider;
26import tools.refinery.language.serializer.PreferShortAssertionsProblemSemanticSequencer;
33 27
34/** 28/**
35 * Use this class to register components to be used at runtime / without the 29 * Use this class to register components to be used at runtime / without the
@@ -88,4 +82,9 @@ public class ProblemRuntimeModule extends AbstractProblemRuntimeModule {
88 public Class<? extends ILocationInFileProvider> bindILocationInFileProvider() { 82 public Class<? extends ILocationInFileProvider> bindILocationInFileProvider() {
89 return ProblemLocationInFileProvider.class; 83 return ProblemLocationInFileProvider.class;
90 } 84 }
85
86 @Override
87 public Class<? extends ISemanticSequencer> bindISemanticSequencer() {
88 return PreferShortAssertionsProblemSemanticSequencer.class;
89 }
91} 90}
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 a65e0750..46870edb 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
@@ -3,6 +3,7 @@
3 */ 3 */
4package tools.refinery.language.formatting2; 4package tools.refinery.language.formatting2;
5 5
6import com.google.inject.Inject;
6import org.eclipse.emf.ecore.EObject; 7import org.eclipse.emf.ecore.EObject;
7import org.eclipse.xtext.formatting2.AbstractJavaFormatter; 8import org.eclipse.xtext.formatting2.AbstractJavaFormatter;
8import org.eclipse.xtext.formatting2.IFormattableDocument; 9import org.eclipse.xtext.formatting2.IFormattableDocument;
@@ -12,9 +13,12 @@ import org.eclipse.xtext.formatting2.regionaccess.ISequentialRegion;
12import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; 13import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
13 14
14import tools.refinery.language.model.problem.*; 15import tools.refinery.language.model.problem.*;
16import tools.refinery.language.services.ProblemGrammarAccess;
15 17
16@SuppressWarnings("UnstableApiUsage") 18@SuppressWarnings("UnstableApiUsage")
17public class ProblemFormatter extends AbstractJavaFormatter { 19public class ProblemFormatter extends AbstractJavaFormatter {
20 @Inject
21 private ProblemGrammarAccess problemGrammarAccess;
18 22
19 protected void format(Problem problem, IFormattableDocument doc) { 23 protected void format(Problem problem, IFormattableDocument doc) {
20 doc.prepend(problem, this::noSpace); 24 doc.prepend(problem, this::noSpace);
@@ -31,17 +35,35 @@ public class ProblemFormatter extends AbstractJavaFormatter {
31 surroundNewLines(doc, assertion, this::singleNewLine); 35 surroundNewLines(doc, assertion, this::singleNewLine);
32 var region = regionFor(assertion); 36 var region = regionFor(assertion);
33 doc.append(region.feature(ProblemPackage.Literals.ASSERTION__DEFAULT), this::oneSpace); 37 doc.append(region.feature(ProblemPackage.Literals.ASSERTION__DEFAULT), this::oneSpace);
34 doc.append(region.feature(ProblemPackage.Literals.ASSERTION__VALUE), this::noSpace);
35 doc.append(region.feature(ProblemPackage.Literals.ASSERTION__RELATION), this::noSpace); 38 doc.append(region.feature(ProblemPackage.Literals.ASSERTION__RELATION), this::noSpace);
36 formatParenthesizedList(region, doc); 39 formatParenthesizedList(region, doc);
37 doc.prepend(region.keyword(":"), this::noSpace); 40 var value = assertion.getValue();
38 doc.append(region.keyword(":"), this::oneSpace); 41 if (value != null) {
42 doc.append(value, this::noSpace);
43 doc.format(value);
44 }
39 doc.prepend(region.keyword("."), this::noSpace); 45 doc.prepend(region.keyword("."), this::noSpace);
40 for (var argument : assertion.getArguments()) { 46 for (var argument : assertion.getArguments()) {
41 doc.format(argument); 47 doc.format(argument);
42 } 48 }
43 } 49 }
44 50
51 protected void format(LogicAssertionValue assertionValue, IFormattableDocument doc) {
52 var region = regionFor(assertionValue);
53 doc.prepend(region.keyword(":"), this::noSpace);
54 doc.append(region.keyword(":"), this::oneSpace);
55 }
56
57 protected void format(ExprAssertionValue assertionValue, IFormattableDocument doc) {
58 var region = regionFor(assertionValue);
59 doc.surround(region.keyword("="), this::oneSpace);
60 doc.surround(region.keyword("in"), this::oneSpace);
61 var body = assertionValue.getBody();
62 if (body != null) {
63 doc.format(body);
64 }
65 }
66
45 protected void format(ClassDeclaration classDeclaration, IFormattableDocument doc) { 67 protected void format(ClassDeclaration classDeclaration, IFormattableDocument doc) {
46 surroundNewLines(doc, classDeclaration, this::twoNewLines); 68 surroundNewLines(doc, classDeclaration, this::twoNewLines);
47 var region = regionFor(classDeclaration); 69 var region = regionFor(classDeclaration);
@@ -53,8 +75,8 @@ public class ProblemFormatter extends AbstractJavaFormatter {
53 doc.append(region.keyword("{"), it -> it.setNewLines(1, 1, 2)); 75 doc.append(region.keyword("{"), it -> it.setNewLines(1, 1, 2));
54 doc.prepend(region.keyword("}"), it -> it.setNewLines(1, 1, 2)); 76 doc.prepend(region.keyword("}"), it -> it.setNewLines(1, 1, 2));
55 doc.prepend(region.keyword("."), this::noSpace); 77 doc.prepend(region.keyword("."), this::noSpace);
56 for (var referenceDeclaration : classDeclaration.getReferenceDeclarations()) { 78 for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) {
57 doc.format(referenceDeclaration); 79 doc.format(featureDeclaration);
58 } 80 }
59 } 81 }
60 82
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
index 99bf9b64..419be0d3 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
@@ -1,10 +1,9 @@
1package tools.refinery.language.resource; 1package tools.refinery.language.resource;
2 2
3import java.util.List; 3import com.google.common.collect.ImmutableSet;
4import java.util.Set; 4import com.google.inject.Inject;
5 5import com.google.inject.name.Named;
6import org.eclipse.emf.ecore.EObject; 6import org.eclipse.emf.ecore.EObject;
7import org.eclipse.emf.ecore.EStructuralFeature;
8import org.eclipse.xtext.linking.impl.LinkingHelper; 7import org.eclipse.xtext.linking.impl.LinkingHelper;
9import org.eclipse.xtext.naming.IQualifiedNameConverter; 8import org.eclipse.xtext.naming.IQualifiedNameConverter;
10import org.eclipse.xtext.nodemodel.INode; 9import org.eclipse.xtext.nodemodel.INode;
@@ -12,20 +11,12 @@ import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
12import org.eclipse.xtext.scoping.IScope; 11import org.eclipse.xtext.scoping.IScope;
13import org.eclipse.xtext.scoping.IScopeProvider; 12import org.eclipse.xtext.scoping.IScopeProvider;
14import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; 13import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
15 14import tools.refinery.language.model.problem.*;
16import com.google.common.collect.ImmutableSet;
17import com.google.inject.Inject;
18import com.google.inject.name.Named;
19
20import tools.refinery.language.model.problem.Assertion;
21import tools.refinery.language.model.problem.AssertionArgument;
22import tools.refinery.language.model.problem.NodeAssertionArgument;
23import tools.refinery.language.model.problem.NodeValueAssertion;
24import tools.refinery.language.model.problem.Problem;
25import tools.refinery.language.model.problem.ProblemPackage;
26import tools.refinery.language.model.problem.Statement;
27import tools.refinery.language.naming.NamingUtil; 15import tools.refinery.language.naming.NamingUtil;
28 16
17import java.util.List;
18import java.util.Set;
19
29public class NodeNameCollector { 20public class NodeNameCollector {
30 @Inject 21 @Inject
31 private LinkingHelper linkingHelper; 22 private LinkingHelper linkingHelper;
@@ -55,25 +46,20 @@ public class NodeNameCollector {
55 protected void collectStatementNodeNames(Statement statement) { 46 protected void collectStatementNodeNames(Statement statement) {
56 if (statement instanceof Assertion assertion) { 47 if (statement instanceof Assertion assertion) {
57 collectAssertionNodeNames(assertion); 48 collectAssertionNodeNames(assertion);
58 } else if (statement instanceof NodeValueAssertion nodeValueAssertion) {
59 collectNodeValueAssertionNodeNames(nodeValueAssertion);
60 } 49 }
61 } 50 }
62 51
63 protected void collectAssertionNodeNames(Assertion assertion) { 52 protected void collectAssertionNodeNames(Assertion assertion) {
64 for (AssertionArgument argument : assertion.getArguments()) { 53 for (AssertionArgument argument : assertion.getArguments()) {
65 if (argument instanceof NodeAssertionArgument) { 54 if (argument instanceof NodeAssertionArgument) {
66 collectNodeNames(argument, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE); 55 collectNodeNames(argument);
67 } 56 }
68 } 57 }
69 } 58 }
70 59
71 protected void collectNodeValueAssertionNodeNames(NodeValueAssertion nodeValueAssertion) { 60 private void collectNodeNames(EObject eObject) {
72 collectNodeNames(nodeValueAssertion, ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE); 61 List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject,
73 } 62 ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE);
74
75 private void collectNodeNames(EObject eObject, EStructuralFeature feature) {
76 List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject, feature);
77 for (INode node : nodes) { 63 for (INode node : nodes) {
78 var nodeName = linkingHelper.getCrossRefNodeAsString(node, true); 64 var nodeName = linkingHelper.getCrossRefNodeAsString(node, true);
79 if (!NamingUtil.isValidId(nodeName)) { 65 if (!NamingUtil.isValidId(nodeName)) {
@@ -85,4 +71,4 @@ public class NodeNameCollector {
85 } 71 }
86 } 72 }
87 } 73 }
88} \ No newline at end of file 74}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
index f28e1791..8d3a552a 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
@@ -1,13 +1,9 @@
1package tools.refinery.language.resource; 1package tools.refinery.language.resource;
2 2
3import java.util.Collection; 3import com.google.inject.Inject;
4import java.util.HashMap; 4import com.google.inject.Provider;
5import java.util.HashSet; 5import com.google.inject.Singleton;
6import java.util.List; 6import com.google.inject.name.Named;
7import java.util.Map;
8import java.util.Set;
9import java.util.function.Function;
10
11import org.eclipse.emf.common.notify.impl.AdapterImpl; 7import org.eclipse.emf.common.notify.impl.AdapterImpl;
12import org.eclipse.emf.ecore.EObject; 8import org.eclipse.emf.ecore.EObject;
13import org.eclipse.emf.ecore.resource.Resource; 9import org.eclipse.emf.ecore.resource.Resource;
@@ -16,37 +12,20 @@ import org.eclipse.xtext.Constants;
16import org.eclipse.xtext.resource.DerivedStateAwareResource; 12import org.eclipse.xtext.resource.DerivedStateAwareResource;
17import org.eclipse.xtext.resource.IDerivedStateComputer; 13import org.eclipse.xtext.resource.IDerivedStateComputer;
18import org.eclipse.xtext.resource.XtextResource; 14import org.eclipse.xtext.resource.XtextResource;
19import org.eclipse.xtext.scoping.IScopeProvider; 15import tools.refinery.language.model.problem.*;
20import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
21
22import com.google.inject.Inject;
23import com.google.inject.Provider;
24import com.google.inject.Singleton;
25import com.google.inject.name.Named;
26 16
27import tools.refinery.language.model.problem.Assertion; 17import java.util.*;
28import tools.refinery.language.model.problem.ClassDeclaration; 18import java.util.function.Function;
29import tools.refinery.language.model.problem.ConstantAssertionArgument;
30import tools.refinery.language.model.problem.Node;
31import tools.refinery.language.model.problem.Problem;
32import tools.refinery.language.model.problem.ProblemFactory;
33import tools.refinery.language.model.problem.Statement;
34 19
35@Singleton 20@Singleton
36public class ProblemDerivedStateComputer implements IDerivedStateComputer { 21public class ProblemDerivedStateComputer implements IDerivedStateComputer {
37 public static final String NEW_NODE = "new"; 22 public static final String NEW_NODE = "new";
38 23
39 public static final String CONSTANT_NODE = "constant";
40
41 @Inject 24 @Inject
42 @Named(Constants.LANGUAGE_NAME) 25 @Named(Constants.LANGUAGE_NAME)
43 private String languageName; 26 private String languageName;
44 27
45 @Inject 28 @Inject
46 @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)
47 private IScopeProvider scopeProvider;
48
49 @Inject
50 private Provider<NodeNameCollector> nodeNameCollectorProvider; 29 private Provider<NodeNameCollector> nodeNameCollectorProvider;
51 30
52 @Inject 31 @Inject
@@ -88,15 +67,6 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer {
88 && declaration.getNewNode() == null) { 67 && declaration.getNewNode() == null) {
89 var newNode = adapter.createNewNodeIfAbsent(declaration, key -> createNode(NEW_NODE)); 68 var newNode = adapter.createNewNodeIfAbsent(declaration, key -> createNode(NEW_NODE));
90 declaration.setNewNode(newNode); 69 declaration.setNewNode(newNode);
91 } else if (statement instanceof Assertion assertion) {
92 for (var argument : assertion.getArguments()) {
93 if (argument instanceof ConstantAssertionArgument constantAssertionArgument
94 && constantAssertionArgument.getNode() == null) {
95 var constantNode = adapter.createConstantNodeIfAbsent(constantAssertionArgument,
96 key -> createNode(CONSTANT_NODE));
97 constantAssertionArgument.setNode(constantNode);
98 }
99 }
100 } 70 }
101 } 71 }
102 } 72 }
@@ -130,22 +100,14 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer {
130 100
131 protected void discardDerivedProblemState(Problem problem, Adapter adapter) { 101 protected void discardDerivedProblemState(Problem problem, Adapter adapter) {
132 Set<ClassDeclaration> classDeclarations = new HashSet<>(); 102 Set<ClassDeclaration> classDeclarations = new HashSet<>();
133 Set<ConstantAssertionArgument> constantAssertionArguments = new HashSet<>();
134 problem.getNodes().clear(); 103 problem.getNodes().clear();
135 for (var statement : problem.getStatements()) { 104 for (var statement : problem.getStatements()) {
136 if (statement instanceof ClassDeclaration classDeclaration) { 105 if (statement instanceof ClassDeclaration classDeclaration) {
137 classDeclaration.setNewNode(null); 106 classDeclaration.setNewNode(null);
138 classDeclarations.add(classDeclaration); 107 classDeclarations.add(classDeclaration);
139 } else if (statement instanceof Assertion assertion) {
140 for (var argument : assertion.getArguments()) {
141 if (argument instanceof ConstantAssertionArgument constantAssertionArgument) {
142 constantAssertionArgument.setNode(null);
143 constantAssertionArguments.add(constantAssertionArgument);
144 }
145 }
146 } 108 }
147 } 109 }
148 adapter.retainAll(classDeclarations, constantAssertionArguments); 110 adapter.retainAll(classDeclarations);
149 derivedVariableComputer.discardDerivedVariables(problem); 111 derivedVariableComputer.discardDerivedVariables(problem);
150 } 112 }
151 113
@@ -166,24 +128,15 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer {
166 } 128 }
167 129
168 protected static class Adapter extends AdapterImpl { 130 protected static class Adapter extends AdapterImpl {
169 private Map<ClassDeclaration, Node> newNodes = new HashMap<>(); 131 private final Map<ClassDeclaration, Node> newNodes = new HashMap<>();
170
171 private Map<ConstantAssertionArgument, Node> constantNodes = new HashMap<>();
172 132
173 public Node createNewNodeIfAbsent(ClassDeclaration classDeclaration, 133 public Node createNewNodeIfAbsent(ClassDeclaration classDeclaration,
174 Function<ClassDeclaration, Node> createNode) { 134 Function<ClassDeclaration, Node> createNode) {
175 return newNodes.computeIfAbsent(classDeclaration, createNode); 135 return newNodes.computeIfAbsent(classDeclaration, createNode);
176 } 136 }
177 137
178 public Node createConstantNodeIfAbsent(ConstantAssertionArgument constantAssertionArgument, 138 public void retainAll(Collection<ClassDeclaration> classDeclarations) {
179 Function<ConstantAssertionArgument, Node> createNode) {
180 return constantNodes.computeIfAbsent(constantAssertionArgument, createNode);
181 }
182
183 public void retainAll(Collection<ClassDeclaration> classDeclarations,
184 Collection<ConstantAssertionArgument> constantAssertionArguments) {
185 newNodes.keySet().retainAll(classDeclarations); 139 newNodes.keySet().retainAll(classDeclarations);
186 constantNodes.keySet().retainAll(constantAssertionArguments);
187 } 140 }
188 141
189 @Override 142 @Override
diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java
index c2045aea..3ab07496 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java
@@ -29,8 +29,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider {
29 @Override 29 @Override
30 public IScope getScope(EObject context, EReference reference) { 30 public IScope getScope(EObject context, EReference reference) {
31 var scope = super.getScope(context, reference); 31 var scope = super.getScope(context, reference);
32 if (reference == ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE 32 if (reference == ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE) {
33 || reference == ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE) {
34 return getNodesScope(context, scope); 33 return getNodesScope(context, scope);
35 } 34 }
36 if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE 35 if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE
diff --git a/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java
new file mode 100644
index 00000000..c51a5e28
--- /dev/null
+++ b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java
@@ -0,0 +1,52 @@
1package tools.refinery.language.serializer;
2
3import com.google.inject.Inject;
4import org.eclipse.xtext.serializer.ISerializationContext;
5import org.eclipse.xtext.serializer.sequencer.ITransientValueService.ListTransient;
6import org.eclipse.xtext.serializer.sequencer.ITransientValueService.ValueTransient;
7import tools.refinery.language.model.problem.Assertion;
8import tools.refinery.language.model.problem.LogicAssertionValue;
9import tools.refinery.language.model.problem.LogicValue;
10import tools.refinery.language.model.problem.ProblemPackage;
11import tools.refinery.language.services.ProblemGrammarAccess;
12
13public class PreferShortAssertionsProblemSemanticSequencer extends ProblemSemanticSequencer {
14 @Inject
15 private ProblemGrammarAccess grammarAccess;
16
17 @Override
18 protected void sequence_Assertion(ISerializationContext context, Assertion semanticObject) {
19 if (semanticObject.isDefault() ||
20 !(semanticObject.getValue() instanceof LogicAssertionValue logicAssertionValue) ||
21 logicAssertionValue.getLogicValue() == LogicValue.ERROR) {
22 super.sequence_Assertion(context, semanticObject);
23 return;
24 }
25 if (errorAcceptor != null) {
26 if (transientValues.isValueTransient(semanticObject, ProblemPackage.Literals.ASSERTION__RELATION) == ValueTransient.YES) {
27 errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject,
28 ProblemPackage.Literals.ASSERTION__RELATION));
29 }
30 if (transientValues.isListTransient(semanticObject, ProblemPackage.Literals.ASSERTION__ARGUMENTS) == ListTransient.YES) {
31 errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject,
32 ProblemPackage.Literals.ASSERTION__ARGUMENTS));
33 }
34 }
35 var feeder = createSequencerFeeder(context, semanticObject);
36 var access = grammarAccess.getAssertionAccess();
37 feeder.accept(access.getValueShortLogicAssertionValueParserRuleCall_1_1_0_0(), logicAssertionValue);
38 feeder.accept(access.getRelationRelationQualifiedNameParserRuleCall_1_1_1_0_1(), semanticObject.getRelation());
39 var iterator = semanticObject.getArguments().iterator();
40 if (iterator.hasNext()) {
41 var firstArgument = iterator.next();
42 feeder.accept(access.getArgumentsAssertionArgumentParserRuleCall_1_1_3_0_0(), firstArgument, 0);
43 int index = 1;
44 while (iterator.hasNext()) {
45 var argument = iterator.next();
46 feeder.accept(access.getArgumentsAssertionArgumentParserRuleCall_1_1_3_1_1_0(), argument, index);
47 index++;
48 }
49 }
50 feeder.finish();
51 }
52}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
index 7e43cecf..d3777cd3 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
@@ -1,14 +1,8 @@
1package tools.refinery.language.utils; 1package tools.refinery.language.utils;
2 2
3import tools.refinery.language.model.problem.ClassDeclaration; 3import tools.refinery.language.model.problem.*;
4import tools.refinery.language.model.problem.EnumDeclaration;
5import tools.refinery.language.model.problem.Node;
6import tools.refinery.language.model.problem.PredicateDefinition;
7import tools.refinery.language.model.problem.Problem;
8import tools.refinery.language.model.problem.ReferenceDeclaration;
9 4
10public record BuiltinSymbols(Problem problem, ClassDeclaration node, ReferenceDeclaration equals, 5public record BuiltinSymbols(Problem problem, ClassDeclaration node, ReferenceDeclaration equals,
11 PredicateDefinition exists, ClassDeclaration domain, ClassDeclaration data, EnumDeclaration bool, Node boolTrue, 6 PredicateDefinition exists, PredicateDefinition contained, PredicateDefinition contains,
12 Node boolFalse, ClassDeclaration intClass, ClassDeclaration real, ClassDeclaration string, 7 PredicateDefinition root) {
13 PredicateDefinition contained, PredicateDefinition contains, PredicateDefinition root) {
14} 8}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
index 38db0e29..c8f47653 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
@@ -1,12 +1,4 @@
1package tools.refinery.language.utils; 1package tools.refinery.language.utils;
2 2
3import java.util.ArrayList; 3public record NodeInfo(String name, boolean individual) {
4import java.util.Collection;
5
6import tools.refinery.language.model.problem.NodeValueAssertion;
7
8public record NodeInfo(String name, boolean individual, Collection<NodeValueAssertion> valueAssertions) {
9 public NodeInfo(String name, boolean individual) {
10 this(name, individual, new ArrayList<>());
11 }
12} 4}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
index 23fd8982..b8200919 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
@@ -40,19 +40,10 @@ public class ProblemDesugarer {
40 var node = doGetDeclaration(builtin, ClassDeclaration.class, "node"); 40 var node = doGetDeclaration(builtin, ClassDeclaration.class, "node");
41 var equals = doGetEqualsReference(node); 41 var equals = doGetEqualsReference(node);
42 var exists = doGetDeclaration(builtin, PredicateDefinition.class, "exists"); 42 var exists = doGetDeclaration(builtin, PredicateDefinition.class, "exists");
43 var domain = doGetDeclaration(builtin, ClassDeclaration.class, "domain");
44 var data = doGetDeclaration(builtin, ClassDeclaration.class, "data");
45 var bool = doGetDeclaration(builtin, EnumDeclaration.class, "bool");
46 var boolTrue = doGetLiteral(bool, "true");
47 var boolFalse = doGetLiteral(bool, "false");
48 var intClass = doGetDeclaration(builtin, ClassDeclaration.class, "int");
49 var real = doGetDeclaration(builtin, ClassDeclaration.class, "real");
50 var string = doGetDeclaration(builtin, ClassDeclaration.class, "string");
51 var contained = doGetDeclaration(builtin, PredicateDefinition.class, "contained"); 43 var contained = doGetDeclaration(builtin, PredicateDefinition.class, "contained");
52 var contains = doGetDeclaration(builtin, PredicateDefinition.class, "contains"); 44 var contains = doGetDeclaration(builtin, PredicateDefinition.class, "contains");
53 var root = doGetDeclaration(builtin, PredicateDefinition.class, "root"); 45 var root = doGetDeclaration(builtin, PredicateDefinition.class, "root");
54 return new BuiltinSymbols(builtin, node, equals, exists, domain, data, bool, boolTrue, boolFalse, intClass, 46 return new BuiltinSymbols(builtin, node, equals, exists, contained, contains, root);
55 real, string, contained, contains, root);
56 } 47 }
57 48
58 private <T extends Statement & NamedElement> T doGetDeclaration(Problem builtin, Class<T> type, String name) { 49 private <T extends Statement & NamedElement> T doGetDeclaration(Problem builtin, Class<T> type, String name) {
@@ -62,16 +53,12 @@ public class ProblemDesugarer {
62 } 53 }
63 54
64 private ReferenceDeclaration doGetEqualsReference(ClassDeclaration nodeClassDeclaration) { 55 private ReferenceDeclaration doGetEqualsReference(ClassDeclaration nodeClassDeclaration) {
65 return nodeClassDeclaration.getReferenceDeclarations().stream() 56 return (ReferenceDeclaration) nodeClassDeclaration.getFeatureDeclarations().stream()
66 .filter(reference -> "equals".equals(reference.getName())).findFirst() 57 .filter(reference -> reference instanceof ReferenceDeclaration &&
58 "equals".equals(reference.getName())).findFirst()
67 .orElseThrow(() -> new IllegalArgumentException("Reference " + "equals" + " not found")); 59 .orElseThrow(() -> new IllegalArgumentException("Reference " + "equals" + " not found"));
68 } 60 }
69 61
70 private Node doGetLiteral(EnumDeclaration enumDeclaration, String name) {
71 return enumDeclaration.getLiterals().stream().filter(literal -> name.equals(literal.getName())).findFirst()
72 .orElseThrow(() -> new IllegalArgumentException("Enum literal " + name + " not found"));
73 }
74
75 public Collection<ClassDeclaration> getSuperclassesAndSelf(ClassDeclaration classDeclaration) { 62 public Collection<ClassDeclaration> getSuperclassesAndSelf(ClassDeclaration classDeclaration) {
76 return cache.get(Tuples.create(classDeclaration, "superclassesAndSelf"), classDeclaration.eResource(), 63 return cache.get(Tuples.create(classDeclaration, "superclassesAndSelf"), classDeclaration.eResource(),
77 () -> doGetSuperclassesAndSelf(classDeclaration)); 64 () -> doGetSuperclassesAndSelf(classDeclaration));
@@ -94,9 +81,6 @@ public class ProblemDesugarer {
94 } 81 }
95 } 82 }
96 } 83 }
97 if (builtinSymbols.isPresent() && !found.contains(builtinSymbols.get().data())) {
98 found.add(builtinSymbols.get().domain());
99 }
100 return found; 84 return found;
101 } 85 }
102 86
@@ -108,31 +92,17 @@ public class ProblemDesugarer {
108 private Collection<ReferenceDeclaration> doGetAllReferenceDeclarations(ClassDeclaration classDeclaration) { 92 private Collection<ReferenceDeclaration> doGetAllReferenceDeclarations(ClassDeclaration classDeclaration) {
109 Set<ReferenceDeclaration> referenceDeclarations = new HashSet<>(); 93 Set<ReferenceDeclaration> referenceDeclarations = new HashSet<>();
110 for (ClassDeclaration superclass : getSuperclassesAndSelf(classDeclaration)) { 94 for (ClassDeclaration superclass : getSuperclassesAndSelf(classDeclaration)) {
111 referenceDeclarations.addAll(superclass.getReferenceDeclarations()); 95 for (FeatureDeclaration featureDeclaration : superclass.getFeatureDeclarations()) {
96 if (featureDeclaration instanceof ReferenceDeclaration referenceDeclaration) {
97 referenceDeclarations.add(referenceDeclaration);
98 }
99 }
112 } 100 }
113 return referenceDeclarations; 101 return referenceDeclarations;
114 } 102 }
115 103
116 public boolean isContainmentReference(ReferenceDeclaration referenceDeclaration) { 104 public boolean isContainmentReference(ReferenceDeclaration referenceDeclaration) {
117 switch (referenceDeclaration.getKind()) { 105 return referenceDeclaration.getKind() == ReferenceKind.CONTAINMENT;
118 case REFERENCE, CONTAINER:
119 return false;
120 case CONTAINMENT:
121 return true;
122 case DEFAULT:
123 return isDataClass(referenceDeclaration.getReferenceType());
124 default:
125 throw new IllegalArgumentException("Unknown reference kind " + referenceDeclaration.getKind());
126 }
127 }
128
129 public boolean isDataClass(Relation relation) {
130 if (relation instanceof ClassDeclaration classDeclaration) {
131 var supertypes = getSuperclassesAndSelf(classDeclaration);
132 var builtinSymbols = getBuiltinSymbols(relation);
133 return builtinSymbols.isPresent() && supertypes.contains(builtinSymbols.get().data());
134 }
135 return false;
136 } 106 }
137 107
138 public CollectedSymbols collectSymbols(Problem problem) { 108 public CollectedSymbols collectSymbols(Problem problem) {
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
index 210e96ab..5412f620 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
@@ -2,7 +2,6 @@ package tools.refinery.language.utils;
2 2
3import com.google.inject.Inject; 3import com.google.inject.Inject;
4import org.eclipse.emf.ecore.EObject; 4import org.eclipse.emf.ecore.EObject;
5import org.eclipse.emf.ecore.util.EcoreUtil;
6import org.eclipse.xtext.naming.IQualifiedNameConverter; 5import org.eclipse.xtext.naming.IQualifiedNameConverter;
7import org.eclipse.xtext.naming.IQualifiedNameProvider; 6import org.eclipse.xtext.naming.IQualifiedNameProvider;
8import tools.refinery.language.model.problem.*; 7import tools.refinery.language.model.problem.*;
@@ -64,43 +63,65 @@ class SymbolCollector {
64 } 63 }
65 64
66 private void collectClass(ClassDeclaration classDeclaration) { 65 private void collectClass(ClassDeclaration classDeclaration) {
67 // node and domain classes are not contained by default, but every other type is 66 var contained = classDeclaration != builtinSymbols.node();
68 // contained, including data types.
69 var contained =
70 classDeclaration != builtinSymbols.node() && classDeclaration != builtinSymbols.domain();
71 var containmentRole = contained ? ContainmentRole.CONTAINED : ContainmentRole.NONE; 67 var containmentRole = contained ? ContainmentRole.CONTAINED : ContainmentRole.NONE;
72 var instanceParameter = ProblemFactory.eINSTANCE.createParameter(); 68 var instanceParameter = ProblemFactory.eINSTANCE.createParameter();
73 instanceParameter.setName("instance"); 69 instanceParameter.setName("instance");
74 var classInfo = new RelationInfo(getQualifiedNameString(classDeclaration), containmentRole, 70 var classInfo = new RelationInfo(getQualifiedNameString(classDeclaration), containmentRole,
75 List.of(instanceParameter), null, null, List.of()); 71 List.of(instanceParameter), null, null, List.of());
76 relations.put(classDeclaration, classInfo); 72 relations.put(classDeclaration, classInfo);
77 collectReferences(classDeclaration); 73 collectFeatures(classDeclaration);
78 } 74 }
79 75
80 private void collectReferences(ClassDeclaration classDeclaration) { 76 private void collectFeatures(ClassDeclaration classDeclaration) {
81 for (var referenceDeclaration : classDeclaration.getReferenceDeclarations()) { 77 for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) {
82 var referenceRole = desugarer.isContainmentReference(referenceDeclaration) ? 78 if (featureDeclaration instanceof ReferenceDeclaration referenceDeclaration) {
83 ContainmentRole.CONTAINMENT : 79 collectReference(classDeclaration, referenceDeclaration);
84 ContainmentRole.NONE; 80 } else if (featureDeclaration instanceof AttributeDeclaration attributeDeclaration) {
85 var sourceParameter = ProblemFactory.eINSTANCE.createParameter(); 81 collectAttribute(classDeclaration, attributeDeclaration);
86 sourceParameter.setName("source"); 82 } else if (featureDeclaration instanceof FlagDeclaration flagDeclaration) {
87 sourceParameter.setParameterType(classDeclaration); 83 collectFlag(classDeclaration, flagDeclaration);
88 var targetParameter = ProblemFactory.eINSTANCE.createParameter(); 84 } else {
89 targetParameter.setName("target"); 85 throw new IllegalArgumentException("Unknown FeatureDeclaration: " + featureDeclaration);
90 var multiplicity = referenceDeclaration.getMultiplicity();
91 if (multiplicity == null) {
92 var exactMultiplicity = ProblemFactory.eINSTANCE.createExactMultiplicity();
93 exactMultiplicity.setExactValue(1);
94 multiplicity = exactMultiplicity;
95 } 86 }
96 targetParameter.setParameterType(referenceDeclaration.getReferenceType());
97 var referenceInfo = new RelationInfo(getQualifiedNameString(referenceDeclaration), referenceRole,
98 List.of(sourceParameter, targetParameter), multiplicity, referenceDeclaration.getOpposite(),
99 List.of());
100 this.relations.put(referenceDeclaration, referenceInfo);
101 } 87 }
102 } 88 }
103 89
90 private void collectReference(ClassDeclaration classDeclaration, ReferenceDeclaration referenceDeclaration) {
91 var referenceRole = desugarer.isContainmentReference(referenceDeclaration) ?
92 ContainmentRole.CONTAINMENT :
93 ContainmentRole.NONE;
94 var sourceParameter = ProblemFactory.eINSTANCE.createParameter();
95 sourceParameter.setName("source");
96 sourceParameter.setParameterType(classDeclaration);
97 var targetParameter = ProblemFactory.eINSTANCE.createParameter();
98 targetParameter.setName("target");
99 var multiplicity = referenceDeclaration.getMultiplicity();
100 if (multiplicity == null) {
101 var exactMultiplicity = ProblemFactory.eINSTANCE.createExactMultiplicity();
102 exactMultiplicity.setExactValue(1);
103 multiplicity = exactMultiplicity;
104 }
105 targetParameter.setParameterType(referenceDeclaration.getReferenceType());
106 var referenceInfo = new RelationInfo(getQualifiedNameString(referenceDeclaration), referenceRole,
107 List.of(sourceParameter, targetParameter), multiplicity, referenceDeclaration.getOpposite(),
108 List.of());
109 this.relations.put(referenceDeclaration, referenceInfo);
110 }
111
112 private void collectAttribute(ClassDeclaration classDeclaration, AttributeDeclaration attributeDeclaration) {
113 // TODO Implement attribute handling.
114 }
115
116 private void collectFlag(ClassDeclaration classDeclaration, FlagDeclaration flagDeclaration) {
117 var parameter = ProblemFactory.eINSTANCE.createParameter();
118 parameter.setName("object");
119 parameter.setParameterType(classDeclaration);
120 var referenceInfo = new RelationInfo(getQualifiedNameString(flagDeclaration), ContainmentRole.NONE,
121 List.of(parameter), null, null, List.of());
122 this.relations.put(flagDeclaration, referenceInfo);
123 }
124
104 private void collectEnum(EnumDeclaration enumDeclaration) { 125 private void collectEnum(EnumDeclaration enumDeclaration) {
105 var instanceParameter = ProblemFactory.eINSTANCE.createParameter(); 126 var instanceParameter = ProblemFactory.eINSTANCE.createParameter();
106 instanceParameter.setName("instance"); 127 instanceParameter.setName("instance");
@@ -117,8 +138,6 @@ class SymbolCollector {
117 collectNewNode(classDeclaration); 138 collectNewNode(classDeclaration);
118 } else if (statement instanceof EnumDeclaration enumDeclaration) { 139 } else if (statement instanceof EnumDeclaration enumDeclaration) {
119 collectEnumLiterals(enumDeclaration); 140 collectEnumLiterals(enumDeclaration);
120 } else if (statement instanceof Assertion assertion) {
121 collectConstantNodes(assertion);
122 } 141 }
123 } 142 }
124 for (var node : problem.getNodes()) { 143 for (var node : problem.getNodes()) {
@@ -145,17 +164,6 @@ class SymbolCollector {
145 } 164 }
146 } 165 }
147 166
148 private void collectConstantNodes(Assertion assertion) {
149 for (var argument : assertion.getArguments()) {
150 if (argument instanceof ConstantAssertionArgument constantAssertionArgument) {
151 var constantNode = constantAssertionArgument.getNode();
152 if (constantNode != null) {
153 addNode(constantNode, false);
154 }
155 }
156 }
157 }
158
159 private void addNode(Node node, boolean individual) { 167 private void addNode(Node node, boolean individual) {
160 var info = new NodeInfo(getQualifiedNameString(node), individual); 168 var info = new NodeInfo(getQualifiedNameString(node), individual);
161 this.nodes.put(node, info); 169 this.nodes.put(node, info);
@@ -173,8 +181,6 @@ class SymbolCollector {
173 for (var statement : problem.getStatements()) { 181 for (var statement : problem.getStatements()) {
174 if (statement instanceof Assertion assertion) { 182 if (statement instanceof Assertion assertion) {
175 collectAssertion(assertion); 183 collectAssertion(assertion);
176 } else if (statement instanceof NodeValueAssertion nodeValueAssertion) {
177 collectNodeValueAssertion(nodeValueAssertion);
178 } else if (statement instanceof PredicateDefinition predicateDefinition) { 184 } else if (statement instanceof PredicateDefinition predicateDefinition) {
179 collectPredicateAssertion(predicateDefinition); 185 collectPredicateAssertion(predicateDefinition);
180 } else if (statement instanceof ClassDeclaration classDeclaration) { 186 } else if (statement instanceof ClassDeclaration classDeclaration) {
@@ -196,48 +202,6 @@ class SymbolCollector {
196 return; 202 return;
197 } 203 }
198 relationInfo.assertions().add(assertion); 204 relationInfo.assertions().add(assertion);
199 for (var argument : assertion.getArguments()) {
200 if (argument instanceof ConstantAssertionArgument constantAssertionArgument) {
201 var constantNode = constantAssertionArgument.getNode();
202 if (constantNode != null) {
203 var valueAssertion = ProblemFactory.eINSTANCE.createNodeValueAssertion();
204 valueAssertion.setNode(constantNode);
205 valueAssertion.setValue(EcoreUtil.copy(constantAssertionArgument.getConstant()));
206 collectNodeValueAssertion(valueAssertion);
207 var logicValue = assertion.getValue();
208 if (logicValue != LogicValue.TRUE) {
209 addAssertion(builtinSymbols.exists(), logicValue, constantNode);
210 }
211 }
212 }
213 }
214 }
215
216 private void collectNodeValueAssertion(NodeValueAssertion nodeValueAssertion) {
217 var node = nodeValueAssertion.getNode();
218 if (node == null) {
219 return;
220 }
221 var nodeInfo = this.nodes.get(node);
222 if (nodeInfo == null) {
223 throw new IllegalStateException("Node value assertion refers to unknown node");
224 }
225 nodeInfo.valueAssertions().add(nodeValueAssertion);
226 var constant = nodeValueAssertion.getValue();
227 if (constant == null) {
228 return;
229 }
230 Relation dataType;
231 if (constant instanceof IntConstant) {
232 dataType = builtinSymbols.intClass();
233 } else if (constant instanceof RealConstant) {
234 dataType = builtinSymbols.real();
235 } else if (constant instanceof StringConstant) {
236 dataType = builtinSymbols.string();
237 } else {
238 throw new IllegalArgumentException("Unknown constant type");
239 }
240 addAssertion(dataType, LogicValue.TRUE, node);
241 } 205 }
242 206
243 private void collectPredicateAssertion(PredicateDefinition predicateDefinition) { 207 private void collectPredicateAssertion(PredicateDefinition predicateDefinition) {
@@ -278,7 +242,9 @@ class SymbolCollector {
278 } 242 }
279 assertion.getArguments().add(argument); 243 assertion.getArguments().add(argument);
280 } 244 }
281 assertion.setValue(logicValue); 245 var value = ProblemFactory.eINSTANCE.createLogicAssertionValue();
246 value.setLogicValue(logicValue);
247 assertion.setValue(value);
282 collectAssertion(assertion); 248 collectAssertion(assertion);
283 } 249 }
284} 250}
diff --git a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
index 38e77237..06b6da1d 100644
--- a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
+++ b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
@@ -6,19 +6,21 @@ abstract class node {
6 6
7pred exists(node node). 7pred exists(node node).
8 8
9abstract class domain extends node. 9% class Integer {
10 10% int intValue
11abstract class data extends node. 11% }
12 12%
13enum bool { 13% class Real {
14 true, false 14% real realValue
15} 15% }
16 16%
17class int extends data. 17% class String {
18 18% string stringValue
19class real extends data. 19% }
20 20%
21class string extends data. 21% enum Boolean {
22% TRUE, FALSE
23% }
22 24
23pred contained(node node). 25pred contained(node node).
24 26
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
index 3a6e015f..e0dee496 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
@@ -24,10 +24,10 @@ class ProblemParsingTest {
24 } 24 }
25 25
26 class Person { 26 class Person {
27 Person[0..*] children opposite parent 27 refers Person[0..*] children opposite parent
28 Person[0..1] parent opposite children 28 refers Person[0..1] parent opposite children
29 int age 29 int age
30 TaxStatus taxStatus 30 refers TaxStatus taxStatus
31 } 31 }
32 32
33 enum TaxStatus { 33 enum TaxStatus {
@@ -46,10 +46,8 @@ class ProblemParsingTest {
46 children(anne, ciri). 46 children(anne, ciri).
47 ?children(bob, ciri). 47 ?children(bob, ciri).
48 taxStatus(anne, adult). 48 taxStatus(anne, adult).
49 age(anne, 35). 49 age(bob) in 21..35.
50 bobAge: 27. 50 age(ciri) = 10.
51 age(bob, bobAge).
52 !age(ciri, bobAge).
53 """); 51 """);
54 assertThat(problem.errors(), empty()); 52 assertThat(problem.errors(), empty());
55 } 53 }
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
index 96d12edf..6e702720 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
@@ -24,7 +24,9 @@ class TransitiveClosureParserTest {
24 @Test 24 @Test
25 void binaryAddOperatorTest() { 25 void binaryAddOperatorTest() {
26 var problem = parseHelper.parse(""" 26 var problem = parseHelper.parse("""
27 pred foo(int a, int b) <-> a + (b) > 10. 27 int a().
28 int b().
29 pred foo() <-> a() + (b()) > 10.
28 """); 30 """);
29 assertThat(problem.errors(), empty()); 31 assertThat(problem.errors(), empty());
30 var literal = problem.pred("foo").conj(0).lit(0).get(); 32 var literal = problem.pred("foo").conj(0).lit(0).get();
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
index 4b42f4aa..72e5e18a 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
@@ -1,10 +1,6 @@
1package tools.refinery.language.tests.rules; 1package tools.refinery.language.tests.rules;
2 2
3import static org.hamcrest.MatcherAssert.assertThat; 3import com.google.inject.Inject;
4import static org.hamcrest.Matchers.empty;
5import static org.hamcrest.Matchers.equalTo;
6import static org.hamcrest.Matchers.not;
7
8import org.eclipse.xtext.testing.InjectWith; 4import org.eclipse.xtext.testing.InjectWith;
9import org.eclipse.xtext.testing.extensions.InjectionExtension; 5import org.eclipse.xtext.testing.extensions.InjectionExtension;
10import org.junit.jupiter.api.Disabled; 6import org.junit.jupiter.api.Disabled;
@@ -12,13 +8,13 @@ import org.junit.jupiter.api.Test;
12import org.junit.jupiter.api.extension.ExtendWith; 8import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 9import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.ValueSource; 10import org.junit.jupiter.params.provider.ValueSource;
15
16import com.google.inject.Inject;
17
18import tools.refinery.language.model.tests.utils.ProblemParseHelper; 11import tools.refinery.language.model.tests.utils.ProblemParseHelper;
19import tools.refinery.language.tests.ProblemInjectorProvider; 12import tools.refinery.language.tests.ProblemInjectorProvider;
20 13
21@Disabled 14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.*;
16
17@Disabled("TODO: Rework transformation rules")
22@ExtendWith(InjectionExtension.class) 18@ExtendWith(InjectionExtension.class)
23@InjectWith(ProblemInjectorProvider.class) 19@InjectWith(ProblemInjectorProvider.class)
24class RuleParsingTest { 20class RuleParsingTest {
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
index 9049b8ec..2fd647e5 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
@@ -3,6 +3,7 @@ package tools.refinery.language.tests.scoping;
3import com.google.inject.Inject; 3import com.google.inject.Inject;
4import org.eclipse.xtext.testing.InjectWith; 4import org.eclipse.xtext.testing.InjectWith;
5import org.eclipse.xtext.testing.extensions.InjectionExtension; 5import org.eclipse.xtext.testing.extensions.InjectionExtension;
6import org.junit.jupiter.api.Disabled;
6import org.junit.jupiter.api.Test; 7import org.junit.jupiter.api.Test;
7import org.junit.jupiter.api.extension.ExtendWith; 8import org.junit.jupiter.api.extension.ExtendWith;
8import org.junit.jupiter.params.ParameterizedTest; 9import org.junit.jupiter.params.ParameterizedTest;
@@ -28,15 +29,11 @@ class NodeScopingTest {
28 @ValueSource(strings = { "", "builtin::" }) 29 @ValueSource(strings = { "", "builtin::" })
29 void builtInArgumentTypeTest(String qualifiedNamePrefix) { 30 void builtInArgumentTypeTest(String qualifiedNamePrefix) {
30 var problem = parse(""" 31 var problem = parse("""
31 pred predicate({PARAM}node a, {PARAM}data b, {PARAM}int c). 32 pred predicate({PARAM}node a).
32 """, qualifiedNamePrefix); 33 """, qualifiedNamePrefix);
33 assertThat(problem.errors(), empty()); 34 assertThat(problem.errors(), empty());
34 assertThat(problem.pred("predicate").param(0).getParameterType(), 35 assertThat(problem.pred("predicate").param(0).getParameterType(),
35 equalTo(problem.builtin().findClass("node").get())); 36 equalTo(problem.builtin().findClass("node").get()));
36 assertThat(problem.pred("predicate").param(1).getParameterType(),
37 equalTo(problem.builtin().findClass("data").get()));
38 assertThat(problem.pred("predicate").param(2).getParameterType(),
39 equalTo(problem.builtin().findClass("int").get()));
40 } 37 }
41 38
42 @Test 39 @Test
@@ -55,16 +52,6 @@ class NodeScopingTest {
55 } 52 }
56 53
57 @Test 54 @Test
58 void implicitNodeInNodeValueAssertionTest() {
59 var problem = parseHelper.parse("""
60 a: 16.
61 """);
62 assertThat(problem.errors(), empty());
63 assertThat(problem.nodeNames(), hasItems("a"));
64 assertThat(problem.nodeValueAssertion(0).getNode(), equalTo(problem.node("a")));
65 }
66
67 @Test
68 void implicitNodeInPredicateTest() { 55 void implicitNodeInPredicateTest() {
69 var problem = parse(""" 56 var problem = parse("""
70 pred predicate(node a) <-> node(b). 57 pred predicate(node a) <-> node(b).
@@ -95,18 +82,6 @@ class NodeScopingTest {
95 82
96 @ParameterizedTest 83 @ParameterizedTest
97 @MethodSource("individualNodeReferenceSource") 84 @MethodSource("individualNodeReferenceSource")
98 void individualNodeInNodeValueAssertionTest(String qualifiedNamePrefix, boolean namedProblem) {
99 var problem = parse("""
100 individual a.
101 {PARAM}a: 16.
102 """, qualifiedNamePrefix, namedProblem);
103 assertThat(problem.errors(), empty());
104 assertThat(problem.nodeNames(), empty());
105 assertThat(problem.nodeValueAssertion(0).getNode(), equalTo(problem.individualNode("a")));
106 }
107
108 @ParameterizedTest
109 @MethodSource("individualNodeReferenceSource")
110 void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) { 85 void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) {
111 var problem = parse(""" 86 var problem = parse("""
112 individual b. 87 individual b.
@@ -121,6 +96,7 @@ class NodeScopingTest {
121 return Stream.of(Arguments.of("", false), Arguments.of("", true), Arguments.of("test::", true)); 96 return Stream.of(Arguments.of("", false), Arguments.of("", true), Arguments.of("test::", true));
122 } 97 }
123 98
99 @Disabled("No nodes are present in builtin.problem currently")
124 @ParameterizedTest 100 @ParameterizedTest
125 @MethodSource("builtInNodeReferencesSource") 101 @MethodSource("builtInNodeReferencesSource")
126 void builtInNodeTest(String qualifiedName) { 102 void builtInNodeTest(String qualifiedName) {
@@ -133,18 +109,7 @@ class NodeScopingTest {
133 assertThat(problem.assertion(0).arg(0).node(), equalTo(problem.builtin().findClass("int").get().getNewNode())); 109 assertThat(problem.assertion(0).arg(0).node(), equalTo(problem.builtin().findClass("int").get().getNewNode()));
134 } 110 }
135 111
136 @ParameterizedTest 112 @Disabled("No nodes are present in builtin.problem currently")
137 @MethodSource("builtInNodeReferencesSource")
138 void builtInNodeInNodeValueAssertionTest(String qualifiedName) {
139 var problem = parse("""
140 {PARAM}: 16.
141 """, qualifiedName);
142 assertThat(problem.errors(), empty());
143 assertThat(problem.nodeNames(), empty());
144 assertThat(problem.nodeValueAssertion(0).getNode(),
145 equalTo(problem.builtin().findClass("int").get().getNewNode()));
146 }
147
148 @ParameterizedTest 113 @ParameterizedTest
149 @MethodSource("builtInNodeReferencesSource") 114 @MethodSource("builtInNodeReferencesSource")
150 void builtInNodeInPredicateTest(String qualifiedName) { 115 void builtInNodeInPredicateTest(String qualifiedName) {
@@ -176,18 +141,6 @@ class NodeScopingTest {
176 141
177 @ParameterizedTest 142 @ParameterizedTest
178 @MethodSource("classNewNodeReferencesSource") 143 @MethodSource("classNewNodeReferencesSource")
179 void classNewNodeInNodeValueAssertionTest(String qualifiedName, boolean namedProblem) {
180 var problem = parse("""
181 class Foo.
182 {PARAM}: 16.
183 """, qualifiedName, namedProblem);
184 assertThat(problem.errors(), empty());
185 assertThat(problem.nodeNames(), empty());
186 assertThat(problem.nodeValueAssertion(0).getNode(), equalTo(problem.findClass("Foo").get().getNewNode()));
187 }
188
189 @ParameterizedTest
190 @MethodSource("classNewNodeReferencesSource")
191 void classNewNodeInPredicateTest(String qualifiedName, boolean namedProblem) { 144 void classNewNodeInPredicateTest(String qualifiedName, boolean namedProblem) {
192 var problem = parse(""" 145 var problem = parse("""
193 class Foo. 146 class Foo.
@@ -231,18 +184,6 @@ class NodeScopingTest {
231 184
232 @ParameterizedTest 185 @ParameterizedTest
233 @MethodSource("enumLiteralReferencesSource") 186 @MethodSource("enumLiteralReferencesSource")
234 void enumLiteralInNodeValueAssertionTest(String qualifiedName, boolean namedProblem) {
235 var problem = parse("""
236 enum Foo { alpha, beta }
237 {PARAM}: 16.
238 """, qualifiedName, namedProblem);
239 assertThat(problem.errors(), empty());
240 assertThat(problem.nodeNames(), empty());
241 assertThat(problem.nodeValueAssertion(0).getNode(), equalTo(problem.findEnum("Foo").literal("alpha")));
242 }
243
244 @ParameterizedTest
245 @MethodSource("enumLiteralReferencesSource")
246 void enumLiteralInPredicateTest(String qualifiedName, boolean namedProblem) { 187 void enumLiteralInPredicateTest(String qualifiedName, boolean namedProblem) {
247 var problem = parse(""" 188 var problem = parse("""
248 enum Foo { alpha, beta } 189 enum Foo { alpha, beta }
@@ -260,6 +201,7 @@ class NodeScopingTest {
260 Arguments.of("test::Foo::alpha", true)); 201 Arguments.of("test::Foo::alpha", true));
261 } 202 }
262 203
204 @Disabled("No enum literals are present in builtin.problem currently")
263 @ParameterizedTest 205 @ParameterizedTest
264 @MethodSource("builtInEnumLiteralReferencesSource") 206 @MethodSource("builtInEnumLiteralReferencesSource")
265 void builtInEnumLiteralTest(String qualifiedName) { 207 void builtInEnumLiteralTest(String qualifiedName) {
@@ -272,18 +214,7 @@ class NodeScopingTest {
272 assertThat(problem.assertion(0).arg(0).node(), equalTo(problem.builtin().findEnum("bool").literal("true"))); 214 assertThat(problem.assertion(0).arg(0).node(), equalTo(problem.builtin().findEnum("bool").literal("true")));
273 } 215 }
274 216
275 @ParameterizedTest 217 @Disabled("No enum literals are present in builtin.problem currently")
276 @MethodSource("builtInEnumLiteralReferencesSource")
277 void builtInEnumLiteralInNodeValueAssertionTest(String qualifiedName) {
278 var problem = parse("""
279 {PARAM}: 16.
280 """, qualifiedName);
281 assertThat(problem.errors(), empty());
282 assertThat(problem.nodeNames(), empty());
283 assertThat(problem.nodeValueAssertion(0).getNode(),
284 equalTo(problem.builtin().findEnum("bool").literal("true")));
285 }
286
287 @ParameterizedTest 218 @ParameterizedTest
288 @MethodSource("builtInEnumLiteralReferencesSource") 219 @MethodSource("builtInEnumLiteralReferencesSource")
289 void bultInEnumLiteralInPredicateTest(String qualifiedName) { 220 void bultInEnumLiteralInPredicateTest(String qualifiedName) {
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
index 150e47a4..5024fb45 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
@@ -68,6 +68,29 @@ class ProblemSerializerTest {
68 Arguments.of(LogicValue.UNKNOWN, "?foo(a)."), Arguments.of(LogicValue.ERROR, "foo(a): error.")); 68 Arguments.of(LogicValue.UNKNOWN, "?foo(a)."), Arguments.of(LogicValue.ERROR, "foo(a): error."));
69 } 69 }
70 70
71 @ParameterizedTest
72 @MethodSource
73 void defaultAssertionTest(LogicValue value, String valueAsString) {
74 var pred = createPred();
75 var node = ProblemFactory.eINSTANCE.createNode();
76 node.setName("a");
77 var individualDeclaration = ProblemFactory.eINSTANCE.createIndividualDeclaration();
78 individualDeclaration.getNodes().add(node);
79 problem.getStatements().add(individualDeclaration);
80 createAssertion(pred, node, value, true);
81
82 assertSerializedResult("""
83 pred foo(node p).
84
85 individual a.
86 default foo(a):\040""" + valueAsString + ".\n");
87 }
88
89 static Stream<Arguments> defaultAssertionTest() {
90 return Stream.of(Arguments.of(LogicValue.TRUE, "true"), Arguments.of(LogicValue.FALSE, "false"),
91 Arguments.of(LogicValue.UNKNOWN, "unknown"), Arguments.of(LogicValue.ERROR, "error"));
92 }
93
71 @Test 94 @Test
72 void implicitNodeTest() { 95 void implicitNodeTest() {
73 var pred = createPred(); 96 var pred = createPred();
@@ -116,13 +139,20 @@ class ProblemSerializerTest {
116 createAssertion(relation, node, LogicValue.TRUE); 139 createAssertion(relation, node, LogicValue.TRUE);
117 } 140 }
118 141
119 private void createAssertion(Relation relation, Node node, LogicValue value) { 142 private void createAssertion(Relation relation, Node node, LogicValue logicValue) {
143 createAssertion(relation, node, logicValue, false);
144 }
145
146 private void createAssertion(Relation relation, Node node, LogicValue logicValue, boolean isDefault) {
120 var assertion = ProblemFactory.eINSTANCE.createAssertion(); 147 var assertion = ProblemFactory.eINSTANCE.createAssertion();
121 assertion.setRelation(relation); 148 assertion.setRelation(relation);
122 var argument = ProblemFactory.eINSTANCE.createNodeAssertionArgument(); 149 var argument = ProblemFactory.eINSTANCE.createNodeAssertionArgument();
123 argument.setNode(node); 150 argument.setNode(node);
124 assertion.getArguments().add(argument); 151 assertion.getArguments().add(argument);
152 var value = ProblemFactory.eINSTANCE.createLogicAssertionValue();
153 value.setLogicValue(logicValue);
125 assertion.setValue(value); 154 assertion.setValue(value);
155 assertion.setDefault(isDefault);
126 problem.getStatements().add(assertion); 156 problem.getStatements().add(assertion);
127 } 157 }
128 158
@@ -143,7 +173,7 @@ class ProblemSerializerTest {
143 var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); 173 var variable = ProblemFactory.eINSTANCE.createImplicitVariable();
144 variable.setName("q"); 174 variable.setName("q");
145 conjunction.getImplicitVariables().add(variable); 175 conjunction.getImplicitVariables().add(variable);
146 var equals = nodeType.reference("equals"); 176 var equals = nodeType.feature("equals");
147 conjunction.getLiterals().add(createAtom(equals, parameter1, variable)); 177 conjunction.getLiterals().add(createAtom(equals, parameter1, variable));
148 conjunction.getLiterals().add(createAtom(equals, variable, parameter2)); 178 conjunction.getLiterals().add(createAtom(equals, variable, parameter2));
149 pred.getBodies().add(conjunction); 179 pred.getBodies().add(conjunction);
@@ -177,7 +207,7 @@ class ProblemSerializerTest {
177 pred.getParameters().add(parameter); 207 pred.getParameters().add(parameter);
178 var conjunction = ProblemFactory.eINSTANCE.createConjunction(); 208 var conjunction = ProblemFactory.eINSTANCE.createConjunction();
179 var atom = ProblemFactory.eINSTANCE.createAtom(); 209 var atom = ProblemFactory.eINSTANCE.createAtom();
180 var equals = nodeType.reference("equals"); 210 var equals = nodeType.feature("equals");
181 atom.setRelation(equals); 211 atom.setRelation(equals);
182 var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr(); 212 var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr();
183 arg1.setVariableOrNode(parameter); 213 arg1.setVariableOrNode(parameter);
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
index 98c16352..66b7f1ab 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
@@ -4,6 +4,7 @@ import com.google.inject.Inject;
4import org.eclipse.xtext.testing.InjectWith; 4import org.eclipse.xtext.testing.InjectWith;
5import org.eclipse.xtext.testing.extensions.InjectionExtension; 5import org.eclipse.xtext.testing.extensions.InjectionExtension;
6import org.hamcrest.Matcher; 6import org.hamcrest.Matcher;
7import org.junit.jupiter.api.Disabled;
7import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
8import org.junit.jupiter.api.extension.ExtendWith; 9import org.junit.jupiter.api.extension.ExtendWith;
9import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
@@ -87,15 +88,15 @@ class SymbolCollectorTest {
87 void referenceTest() { 88 void referenceTest() {
88 var problem = parseHelper.parse(""" 89 var problem = parseHelper.parse("""
89 class Foo { 90 class Foo {
90 Foo[] bar opposite quux 91 refers Foo[] bar opposite quux
91 Foo quux opposite bar 92 refers Foo quux opposite bar
92 } 93 }
93 """); 94 """);
94 var collectedSymbols = desugarer.collectSymbols(problem.get()); 95 var collectedSymbols = desugarer.collectSymbols(problem.get());
95 var fooClass = problem.findClass("Foo"); 96 var fooClass = problem.findClass("Foo");
96 var barReference = fooClass.reference("bar"); 97 var barReference = fooClass.feature("bar");
97 var barInfo = collectedSymbols.relations().get(barReference); 98 var barInfo = collectedSymbols.relations().get(barReference);
98 var quuxReference = fooClass.reference("quux"); 99 var quuxReference = fooClass.feature("quux");
99 var quuxInfo = collectedSymbols.relations().get(quuxReference); 100 var quuxInfo = collectedSymbols.relations().get(quuxReference);
100 assertThat(barInfo.containmentRole(), is(ContainmentRole.NONE)); 101 assertThat(barInfo.containmentRole(), is(ContainmentRole.NONE));
101 assertThat(barInfo.opposite(), is(quuxReference)); 102 assertThat(barInfo.opposite(), is(quuxReference));
@@ -116,10 +117,11 @@ class SymbolCollectorTest {
116 } 117 }
117 """); 118 """);
118 var collectedSymbols = desugarer.collectSymbols(problem.get()); 119 var collectedSymbols = desugarer.collectSymbols(problem.get());
119 assertThat(collectedSymbols.relations().get(problem.findClass("Foo").reference("bar")).containmentRole(), 120 assertThat(collectedSymbols.relations().get(problem.findClass("Foo").feature("bar")).containmentRole(),
120 is(ContainmentRole.CONTAINMENT)); 121 is(ContainmentRole.CONTAINMENT));
121 } 122 }
122 123
124 @Disabled("TODO: Rework numerical references")
123 @Test 125 @Test
124 void dataReferenceTest() { 126 void dataReferenceTest() {
125 var problem = parseHelper.parse(""" 127 var problem = parseHelper.parse("""
@@ -128,7 +130,7 @@ class SymbolCollectorTest {
128 } 130 }
129 """); 131 """);
130 var collectedSymbols = desugarer.collectSymbols(problem.get()); 132 var collectedSymbols = desugarer.collectSymbols(problem.get());
131 assertThat(collectedSymbols.relations().get(problem.findClass("Foo").reference("bar")).containmentRole(), 133 assertThat(collectedSymbols.relations().get(problem.findClass("Foo").feature("bar")).containmentRole(),
132 is(ContainmentRole.CONTAINMENT)); 134 is(ContainmentRole.CONTAINMENT));
133 } 135 }
134 136
@@ -204,61 +206,6 @@ class SymbolCollectorTest {
204 assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), hasSize(0)); 206 assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), hasSize(0));
205 } 207 }
206 208
207 @ParameterizedTest
208 @MethodSource("valueTypes")
209 void nodeValueAssertionTest(String value, String typeName) {
210 var problem = parseHelper.parse("a: %s.".formatted(value));
211 var collectedSymbols = desugarer.collectSymbols(problem.get());
212 var node = problem.node("a");
213 var nodeInfo = collectedSymbols.nodes().get(node);
214 assertThat(nodeInfo.individual(), is(false));
215 assertThat(nodeInfo.valueAssertions(), hasSize(1));
216 assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(),
217 assertsNode(node, LogicValue.TRUE));
218 }
219
220 @ParameterizedTest
221 @MethodSource("valueTypes")
222 void constantInAssertionTest(String value, String typeName) {
223 var problem = parseHelper.parse("""
224 containment pred foo(node x, data y).
225 foo(a, %s).
226 """.formatted(value));
227 var collectedSymbols = desugarer.collectSymbols(problem.get());
228 var node = problem.assertion(0).arg(1).constantNode();
229 var nodeInfo = collectedSymbols.nodes().get(node);
230 assertThat(nodeInfo.individual(), is(false));
231 assertThat(nodeInfo.valueAssertions(), hasSize(1));
232 assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), assertsNode(node,
233 LogicValue.TRUE));
234 assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(),
235 assertsNode(node, LogicValue.TRUE));
236 }
237
238 @ParameterizedTest
239 @MethodSource("valueTypes")
240 void constantInUnknownAssertionTest(String value, String typeName) {
241 var problem = parseHelper.parse("""
242 containment pred foo(node x, data y).
243 foo(a, %s): unknown.
244 """.formatted(value));
245 var collectedSymbols = desugarer.collectSymbols(problem.get());
246 var node = problem.assertion(0).arg(1).constantNode();
247 var nodeInfo = collectedSymbols.nodes().get(node);
248 assertThat(nodeInfo.individual(), is(false));
249 assertThat(nodeInfo.valueAssertions(), hasSize(1));
250 assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), assertsNode(node,
251 LogicValue.UNKNOWN));
252 assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(),
253 assertsNode(node, LogicValue.TRUE));
254 assertThat(collectedSymbols.relations().get(problem.builtinSymbols().exists()).assertions(), assertsNode(node,
255 LogicValue.UNKNOWN));
256 }
257
258 static Stream<Arguments> valueTypes() {
259 return Stream.of(Arguments.of("3", "int"), Arguments.of("3.14", "real"), Arguments.of("\"foo\"", "string"));
260 }
261
262 @Test 209 @Test
263 void invalidProblemTest() { 210 void invalidProblemTest() {
264 var problem = parseHelper.parse(""" 211 var problem = parseHelper.parse("""
@@ -279,13 +226,13 @@ class SymbolCollectorTest {
279 var fooInfo = collectedSymbols.relations().get(problem.pred("foo").get()); 226 var fooInfo = collectedSymbols.relations().get(problem.pred("foo").get());
280 assertThat(fooInfo.assertions(), hasSize(1)); 227 assertThat(fooInfo.assertions(), hasSize(1));
281 var assertion = fooInfo.assertions().stream().findFirst().orElseThrow(); 228 var assertion = fooInfo.assertions().stream().findFirst().orElseThrow();
282 assertThat(assertion.getValue(), is(LogicValue.FALSE)); 229 assertThat(assertion.getValue(), hasProperty("logicValue", is(LogicValue.FALSE)));
283 assertThat(assertion.getArguments(), hasSize(2)); 230 assertThat(assertion.getArguments(), hasSize(2));
284 assertThat(assertion.getArguments(), everyItem(instanceOf(WildcardAssertionArgument.class))); 231 assertThat(assertion.getArguments(), everyItem(instanceOf(WildcardAssertionArgument.class)));
285 } 232 }
286 233
287 private static Matcher<Iterable<? super Assertion>> assertsNode(Node node, LogicValue value) { 234 private static Matcher<Iterable<? super Assertion>> assertsNode(Node node, LogicValue value) {
288 return hasItem(allOf(hasProperty("arguments", hasItem(hasProperty("node", is(node)))), hasProperty("value", 235 return hasItem(allOf(hasProperty("arguments", hasItem(hasProperty("node", is(node)))), hasProperty("value",
289 is(value)))); 236 hasProperty("logicValue", is(value)))));
290 } 237 }
291} 238}
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
index b8b3a7de..840c1f74 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
@@ -1,7 +1,6 @@
1package tools.refinery.language.model.tests.utils; 1package tools.refinery.language.model.tests.utils;
2 2
3import tools.refinery.language.model.problem.AssertionArgument; 3import tools.refinery.language.model.problem.AssertionArgument;
4import tools.refinery.language.model.problem.ConstantAssertionArgument;
5import tools.refinery.language.model.problem.Node; 4import tools.refinery.language.model.problem.Node;
6import tools.refinery.language.model.problem.NodeAssertionArgument; 5import tools.refinery.language.model.problem.NodeAssertionArgument;
7 6
@@ -13,8 +12,4 @@ public record WrappedAssertionArgument(AssertionArgument assertionArgument) {
13 public Node node() { 12 public Node node() {
14 return ((NodeAssertionArgument) assertionArgument).getNode(); 13 return ((NodeAssertionArgument) assertionArgument).getNode();
15 } 14 }
16
17 public Node constantNode() {
18 return ((ConstantAssertionArgument) assertionArgument).getNode();
19 }
20} 15}
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
index d8926c29..41b2ea62 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
@@ -1,14 +1,14 @@
1package tools.refinery.language.model.tests.utils; 1package tools.refinery.language.model.tests.utils;
2 2
3import tools.refinery.language.model.problem.ClassDeclaration; 3import tools.refinery.language.model.problem.ClassDeclaration;
4import tools.refinery.language.model.problem.ReferenceDeclaration; 4import tools.refinery.language.model.problem.FeatureDeclaration;
5 5
6public record WrappedClassDeclaration(ClassDeclaration classDeclaration) { 6public record WrappedClassDeclaration(ClassDeclaration classDeclaration) {
7 public ClassDeclaration get() { 7 public ClassDeclaration get() {
8 return classDeclaration; 8 return classDeclaration;
9 } 9 }
10 10
11 public ReferenceDeclaration reference(String name) { 11 public FeatureDeclaration feature(String name) {
12 return ProblemNavigationUtil.named(classDeclaration.getReferenceDeclarations(), name); 12 return ProblemNavigationUtil.named(classDeclaration.getFeatureDeclarations(), name);
13 } 13 }
14} 14}
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
index aef96b5b..78ca95c7 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
@@ -1,25 +1,14 @@
1package tools.refinery.language.model.tests.utils; 1package tools.refinery.language.model.tests.utils;
2 2
3import java.util.List;
4import java.util.stream.Stream;
5
6import org.eclipse.emf.ecore.resource.Resource.Diagnostic; 3import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
7import org.eclipse.emf.ecore.util.EcoreUtil; 4import org.eclipse.emf.ecore.util.EcoreUtil;
8 5import tools.refinery.language.model.problem.*;
9import tools.refinery.language.model.problem.Assertion;
10import tools.refinery.language.model.problem.ClassDeclaration;
11import tools.refinery.language.model.problem.EnumDeclaration;
12import tools.refinery.language.model.problem.IndividualDeclaration;
13import tools.refinery.language.model.problem.NamedElement;
14import tools.refinery.language.model.problem.Node;
15import tools.refinery.language.model.problem.NodeValueAssertion;
16import tools.refinery.language.model.problem.PredicateDefinition;
17import tools.refinery.language.model.problem.Problem;
18import tools.refinery.language.model.problem.RuleDefinition;
19import tools.refinery.language.model.problem.Statement;
20import tools.refinery.language.utils.BuiltinSymbols; 6import tools.refinery.language.utils.BuiltinSymbols;
21import tools.refinery.language.utils.ProblemDesugarer; 7import tools.refinery.language.utils.ProblemDesugarer;
22 8
9import java.util.List;
10import java.util.stream.Stream;
11
23public record WrappedProblem(Problem problem) { 12public record WrappedProblem(Problem problem) {
24 public Problem get() { 13 public Problem get() {
25 return problem; 14 return problem;
@@ -72,10 +61,6 @@ public record WrappedProblem(Problem problem) {
72 return ProblemNavigationUtil.named(uniqueNodes, name); 61 return ProblemNavigationUtil.named(uniqueNodes, name);
73 } 62 }
74 63
75 public NodeValueAssertion nodeValueAssertion(int i) {
76 return nthStatementOfType(NodeValueAssertion.class, i);
77 }
78
79 private <T extends Statement> Stream<T> statementsOfType(Class<? extends T> type) { 64 private <T extends Statement> Stream<T> statementsOfType(Class<? extends T> type) {
80 return problem.getStatements().stream().filter(type::isInstance).map(type::cast); 65 return problem.getStatements().stream().filter(type::isInstance).map(type::cast);
81 } 66 }