diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-11-19 14:00:12 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-11-22 16:40:03 +0100 |
commit | 383137c190cab040d2609f8295ef822c3917b88d (patch) | |
tree | d0d88528de2020da51cb6e92459b84cf63609feb /subprojects/language/src | |
parent | chore(deps): bump dependencies (diff) | |
download | refinery-383137c190cab040d2609f8295ef822c3917b88d.tar.gz refinery-383137c190cab040d2609f8295ef822c3917b88d.tar.zst refinery-383137c190cab040d2609f8295ef822c3917b88d.zip |
feat(language): numeric expressions
Diffstat (limited to 'subprojects/language/src')
26 files changed, 846 insertions, 317 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 2a8429a3..bc1ee465 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext | |||
@@ -8,9 +8,10 @@ Problem: | |||
8 | statements+=Statement*; | 8 | statements+=Statement*; |
9 | 9 | ||
10 | Statement: | 10 | Statement: |
11 | ClassDeclaration | EnumDeclaration | PredicateDefinition | /* RuleDefinition | */ Assertion | NodeValueAssertion | | 11 | ClassDeclaration | EnumDeclaration | |
12 | ScopeDeclaration | | 12 | PredicateDefinition | FunctionDefinition | /* RuleDefinition | */ |
13 | IndividualDeclaration; | 13 | Assertion | NodeValueAssertion | |
14 | ScopeDeclaration | IndividualDeclaration; | ||
14 | 15 | ||
15 | ClassDeclaration: | 16 | ClassDeclaration: |
16 | abstract?="abstract"? "class" | 17 | abstract?="abstract"? "class" |
@@ -30,53 +31,51 @@ enum ReferenceKind: | |||
30 | REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; | 31 | REFERENCE="refers" | CONTAINMENT="contains" | CONTAINER="container"; |
31 | 32 | ||
32 | ReferenceDeclaration: | 33 | ReferenceDeclaration: |
33 | ( | 34 | (kind=ReferenceKind referenceType=[Relation|QualifiedName] | |
34 | kind=ReferenceKind referenceType=[Relation|QualifiedName] | | 35 | referenceType=[Relation|NonRelationKindQualifiedName]) |
35 | referenceType=[Relation|NonRelationKindQualifiedName] | ||
36 | ) | ||
37 | ("[" multiplicity=Multiplicity "]")? | 36 | ("[" multiplicity=Multiplicity "]")? |
38 | name=Identifier | 37 | name=Identifier |
39 | ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; | 38 | ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; |
40 | 39 | ||
40 | enum ErrorKind returns PredicateKind: | ||
41 | ERROR="error"; | ||
42 | |||
41 | enum PredicateKind: | 43 | enum PredicateKind: |
42 | ERROR="error" | CONTAINED="contained" | CONTAINMENT="containment"; | 44 | ERROR="error" | CONTAINED="contained" | CONTAINMENT="containment"; |
43 | 45 | ||
44 | PredicateDefinition: | 46 | PredicateDefinition: |
45 | (kind=PredicateKind "pred"? | "pred") | 47 | (kind=ErrorKind | kind=PredicateKind? "pred") |
46 | name=Identifier | 48 | name=Identifier |
47 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" | 49 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" |
48 | ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? | 50 | ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? |
49 | "."; | 51 | "."; |
50 | 52 | ||
53 | Conjunction: | ||
54 | literals+=Expr ("," literals+=Expr)*; | ||
55 | |||
56 | FunctionDefinition: | ||
57 | functionType=[Relation|QualifiedName] name=Identifier | ||
58 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" | ||
59 | ("=" cases+=Case (";" cases+=Case)*)? | ||
60 | "."; | ||
61 | |||
62 | Case: | ||
63 | Conjunction ({Match.condition=current} "->" value=Expr)?; | ||
64 | |||
51 | //RuleDefinition: | 65 | //RuleDefinition: |
52 | // "rule" | 66 | // "rule" |
53 | // name=Identifier | 67 | // name=Identifier |
54 | // "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" | 68 | // "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" |
55 | // (":" bodies+=Conjunction (";" bodies+=Conjunction)* | 69 | // (":" preconditions+=Conjunction (";" preconditions+=Conjunction)*)? |
56 | // "==>" consequents+=Consequent (";" consequents+=Consequent)*)? | 70 | // "==>" consequents+=Consequent (";" consequents+=Consequent)*)? |
57 | // "."; | 71 | // "."; |
58 | 72 | ||
59 | Parameter: | 73 | Parameter: |
60 | (modality=Modality? parameterType=[Relation|QualifiedName])? name=Identifier; | 74 | (modality=Modality? parameterType=[Relation|QualifiedName])? name=Identifier; |
61 | 75 | ||
62 | Conjunction: | ||
63 | literals+=Literal ("," literals+=Literal)*; | ||
64 | |||
65 | //Consequent: | 76 | //Consequent: |
66 | // actions+=Action ("," actions+=Action)*; | 77 | // actions+=Action ("," actions+=Action)*; |
67 | 78 | // | |
68 | Literal: | ||
69 | Atom | NegativeLiteral | CountLiteral; | ||
70 | |||
71 | NegativeLiteral: | ||
72 | modality=Modality? "!" atom=Atom; | ||
73 | |||
74 | enum ComparisonOp: | ||
75 | LESS="<" | LESS_EQ="<=" | GREATER=">" | GREATER_EQ=">=" | EQ="==" | NOT_EQ="!="; | ||
76 | |||
77 | CountLiteral: | ||
78 | modality=Modality? "count" atom=Atom op=ComparisonOp threshold=INT; | ||
79 | |||
80 | //Action: | 79 | //Action: |
81 | // AssertionAction | DeleteAction | NewAction; | 80 | // AssertionAction | DeleteAction | NewAction; |
82 | // | 81 | // |
@@ -93,22 +92,74 @@ CountLiteral: | |||
93 | //NewVariable: | 92 | //NewVariable: |
94 | // name=Identifier; | 93 | // name=Identifier; |
95 | 94 | ||
95 | Expr: | ||
96 | ComparisonExpr; | ||
97 | |||
98 | enum ComparisonOp: | ||
99 | LESS="<" | LESS_EQ="<=" | GREATER=">" | GREATER_EQ=">=" | EQ="==" | NOT_EQ="!="; | ||
100 | |||
101 | ComparisonExpr returns Expr: | ||
102 | AdditiveExpr ({ComparisonExpr.left=current} | ||
103 | op=ComparisonOp right=AdditiveExpr)*; | ||
104 | |||
105 | enum AdditiveOp returns BinaryOp: | ||
106 | ADD="+" | SUB="-"; | ||
107 | |||
108 | AdditiveExpr returns Expr: | ||
109 | MultiplicativeExpr ({ArithmeticBinaryExpr.left=current} | ||
110 | op=AdditiveOp right=MultiplicativeExpr)*; | ||
111 | |||
112 | enum MultiplicativeOp returns BinaryOp: | ||
113 | MUL="*" | DIV="/"; | ||
114 | |||
115 | MultiplicativeExpr returns Expr: | ||
116 | ExponentialExpr ({ArithmeticBinaryExpr.left=current} | ||
117 | op=MultiplicativeOp right=ExponentialExpr)*; | ||
118 | |||
119 | enum ExponentialOp returns BinaryOp: | ||
120 | POW="**"; | ||
121 | |||
122 | ExponentialExpr returns Expr: | ||
123 | UnaryExpr ({ArithmeticBinaryExpr.left=current} | ||
124 | op=ExponentialOp right=ExponentialExpr)?; | ||
125 | |||
126 | UnaryExpr returns Expr: | ||
127 | ArithmeticUnaryExpr | ModalExpr | NegationExpr | CountExpr | AggregationExpr | | ||
128 | Atom | VariableOrNodeExpr | ConstantExpr | "(" Expr ")"; | ||
129 | |||
130 | enum UnaryOp: | ||
131 | PLUS="+" | MINUS="-"; | ||
132 | |||
133 | ArithmeticUnaryExpr: | ||
134 | op=UnaryOp body=UnaryExpr; | ||
135 | |||
96 | enum Modality: | 136 | enum Modality: |
97 | MAY="may" | MUST="must" | CURRENT="current"; | 137 | MAY="may" | MUST="must" | CURRENT="current"; |
98 | 138 | ||
139 | ModalExpr: | ||
140 | modality=Modality body=UnaryExpr; | ||
141 | |||
142 | NegationExpr: | ||
143 | "!" body=UnaryExpr; | ||
144 | |||
145 | CountExpr: | ||
146 | "#" body=UnaryExpr; | ||
147 | |||
148 | enum AggregationOp: | ||
149 | SUM="sum" | PROD="prod" | MIN="min" | MAX="max"; | ||
150 | |||
151 | AggregationExpr: | ||
152 | op=AggregationOp "{" value=Expr "|" condition=Expr "}"; | ||
153 | |||
99 | Atom: | 154 | Atom: |
100 | modality=Modality? | ||
101 | relation=[Relation|QualifiedName] | 155 | relation=[Relation|QualifiedName] |
102 | transitiveClosure?="+"? | 156 | transitiveClosure?=TRANSITIVE_CLOSURE? |
103 | "(" (arguments+=Argument ("," arguments+=Argument)*)? ")"; | 157 | "(" (arguments+=Expr ("," arguments+=Expr)*)? ")"; |
104 | |||
105 | Argument: | ||
106 | VariableOrNodeArgument | ConstantArgument; | ||
107 | 158 | ||
108 | VariableOrNodeArgument: | 159 | VariableOrNodeExpr: |
109 | variableOrNode=[VariableOrNode|QualifiedName]; | 160 | variableOrNode=[VariableOrNode|QualifiedName]; |
110 | 161 | ||
111 | ConstantArgument: | 162 | ConstantExpr: |
112 | constant=Constant; | 163 | constant=Constant; |
113 | 164 | ||
114 | Assertion: | 165 | Assertion: |
@@ -131,7 +182,7 @@ WildcardAssertionArgument: | |||
131 | {WildcardAssertionArgument} "*"; | 182 | {WildcardAssertionArgument} "*"; |
132 | 183 | ||
133 | ConstantAssertionArgument: | 184 | ConstantAssertionArgument: |
134 | constant=Constant; | 185 | negative?="-"? constant=Constant; |
135 | 186 | ||
136 | enum LogicValue: | 187 | enum LogicValue: |
137 | TRUE="true" | FALSE="false" | UNKNOWN="unknown" | ERROR="error"; | 188 | TRUE="true" | FALSE="false" | UNKNOWN="unknown" | ERROR="error"; |
@@ -146,7 +197,7 @@ Constant: | |||
146 | RealConstant | IntConstant | StringConstant; | 197 | RealConstant | IntConstant | StringConstant; |
147 | 198 | ||
148 | IntConstant: | 199 | IntConstant: |
149 | intValue=Integer; | 200 | intValue=INT; |
150 | 201 | ||
151 | RealConstant: | 202 | RealConstant: |
152 | realValue=Real; | 203 | realValue=Real; |
@@ -178,7 +229,7 @@ ExactMultiplicity: | |||
178 | exactValue=INT; | 229 | exactValue=INT; |
179 | 230 | ||
180 | IndividualDeclaration: | 231 | IndividualDeclaration: |
181 | "indiv" nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; | 232 | "individual" nodes+=EnumLiteral ("," nodes+=EnumLiteral)* "."; |
182 | 233 | ||
183 | UpperBound returns ecore::EInt: | 234 | UpperBound returns ecore::EInt: |
184 | INT | "*"; | 235 | INT | "*"; |
@@ -190,18 +241,16 @@ QualifiedName hidden(): | |||
190 | Identifier ("::" Identifier)*; | 241 | Identifier ("::" Identifier)*; |
191 | 242 | ||
192 | NonRelationKindIdentifier: | 243 | NonRelationKindIdentifier: |
193 | ID | "true" | "false" | "unknown" | "error" | "class" | "abstract" | "extends" | "enum" | | 244 | ID | "true" | "false" | "contained" | "sum" | "prod" | "min" | "max"; |
194 | "pred" | "indiv" | "problem" | /* "new" | "delete" | "rule" | */ "may" | "must" | "current" | | ||
195 | "count" | "default" | "scope" | "contained" | "containment"; | ||
196 | 245 | ||
197 | Identifier: | 246 | Identifier: |
198 | NonRelationKindIdentifier | "refers" | "contains" | "container"; | 247 | NonRelationKindIdentifier | "contains"; |
199 | |||
200 | Integer returns ecore::EInt hidden(): | ||
201 | "-"? INT; | ||
202 | 248 | ||
203 | Real returns ecore::EDouble: | 249 | Real returns ecore::EDouble: |
204 | "-"? (EXPONENTIAL | INT "." (INT | EXPONENTIAL)); | 250 | EXPONENTIAL | INT "." (INT | EXPONENTIAL); |
251 | |||
252 | terminal TRANSITIVE_CLOSURE: | ||
253 | "synthetic:TRANSITIVE_CLOSURE"; | ||
205 | 254 | ||
206 | @Override | 255 | @Override |
207 | terminal ID: | 256 | terminal ID: |
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 dd7731b4..c0777038 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java +++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java | |||
@@ -5,6 +5,7 @@ package tools.refinery.language; | |||
5 | 5 | ||
6 | import org.eclipse.xtext.conversion.IValueConverterService; | 6 | import org.eclipse.xtext.conversion.IValueConverterService; |
7 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | 7 | import org.eclipse.xtext.naming.IQualifiedNameConverter; |
8 | import org.eclipse.xtext.parser.IParser; | ||
8 | import org.eclipse.xtext.resource.DerivedStateAwareResource; | 9 | import org.eclipse.xtext.resource.DerivedStateAwareResource; |
9 | import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager; | 10 | import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager; |
10 | import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; | 11 | import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; |
@@ -23,6 +24,7 @@ import com.google.inject.name.Names; | |||
23 | 24 | ||
24 | import tools.refinery.language.conversion.ProblemValueConverterService; | 25 | import tools.refinery.language.conversion.ProblemValueConverterService; |
25 | import tools.refinery.language.naming.ProblemQualifiedNameConverter; | 26 | import tools.refinery.language.naming.ProblemQualifiedNameConverter; |
27 | import tools.refinery.language.parser.antlr.TokenSourceInjectingProblemParser; | ||
26 | import tools.refinery.language.resource.ProblemDerivedStateComputer; | 28 | import tools.refinery.language.resource.ProblemDerivedStateComputer; |
27 | import tools.refinery.language.resource.ProblemLocationInFileProvider; | 29 | import tools.refinery.language.resource.ProblemLocationInFileProvider; |
28 | import tools.refinery.language.resource.ProblemResourceDescriptionStrategy; | 30 | import tools.refinery.language.resource.ProblemResourceDescriptionStrategy; |
@@ -34,6 +36,11 @@ import tools.refinery.language.scoping.ProblemLocalScopeProvider; | |||
34 | * Equinox extension registry. | 36 | * Equinox extension registry. |
35 | */ | 37 | */ |
36 | public class ProblemRuntimeModule extends AbstractProblemRuntimeModule { | 38 | public class ProblemRuntimeModule extends AbstractProblemRuntimeModule { |
39 | @Override | ||
40 | public Class<? extends IParser> bindIParser() { | ||
41 | return TokenSourceInjectingProblemParser.class; | ||
42 | } | ||
43 | |||
37 | public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() { | 44 | public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() { |
38 | return ProblemQualifiedNameConverter.class; | 45 | return ProblemQualifiedNameConverter.class; |
39 | } | 46 | } |
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 df5d2090..a65e0750 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 | |||
@@ -11,17 +11,9 @@ import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegionsFinder; | |||
11 | import org.eclipse.xtext.formatting2.regionaccess.ISequentialRegion; | 11 | import org.eclipse.xtext.formatting2.regionaccess.ISequentialRegion; |
12 | import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; | 12 | import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; |
13 | 13 | ||
14 | import tools.refinery.language.model.problem.Assertion; | 14 | import tools.refinery.language.model.problem.*; |
15 | import tools.refinery.language.model.problem.Atom; | ||
16 | import tools.refinery.language.model.problem.ClassDeclaration; | ||
17 | import tools.refinery.language.model.problem.Conjunction; | ||
18 | import tools.refinery.language.model.problem.IndividualDeclaration; | ||
19 | import tools.refinery.language.model.problem.NegativeLiteral; | ||
20 | import tools.refinery.language.model.problem.Parameter; | ||
21 | import tools.refinery.language.model.problem.PredicateDefinition; | ||
22 | import tools.refinery.language.model.problem.Problem; | ||
23 | import tools.refinery.language.model.problem.ProblemPackage; | ||
24 | 15 | ||
16 | @SuppressWarnings("UnstableApiUsage") | ||
25 | public class ProblemFormatter extends AbstractJavaFormatter { | 17 | public class ProblemFormatter extends AbstractJavaFormatter { |
26 | 18 | ||
27 | protected void format(Problem problem, IFormattableDocument doc) { | 19 | protected void format(Problem problem, IFormattableDocument doc) { |
@@ -95,16 +87,14 @@ public class ProblemFormatter extends AbstractJavaFormatter { | |||
95 | } | 87 | } |
96 | } | 88 | } |
97 | 89 | ||
98 | protected void format(NegativeLiteral literal, IFormattableDocument doc) { | 90 | protected void format(NegationExpr literal, IFormattableDocument doc) { |
99 | var region = regionFor(literal); | 91 | var region = regionFor(literal); |
100 | doc.append(region.feature(ProblemPackage.Literals.LITERAL__MODALITY), this::oneSpace); | ||
101 | doc.append(region.keyword("!"), this::noSpace); | 92 | doc.append(region.keyword("!"), this::noSpace); |
102 | doc.format(literal.getAtom()); | 93 | doc.format(literal.getBody()); |
103 | } | 94 | } |
104 | 95 | ||
105 | protected void format(Atom atom, IFormattableDocument doc) { | 96 | protected void format(Atom atom, IFormattableDocument doc) { |
106 | var region = regionFor(atom); | 97 | var region = regionFor(atom); |
107 | doc.append(region.feature(ProblemPackage.Literals.LITERAL__MODALITY), this::oneSpace); | ||
108 | doc.append(region.feature(ProblemPackage.Literals.ATOM__RELATION), this::noSpace); | 98 | doc.append(region.feature(ProblemPackage.Literals.ATOM__RELATION), this::noSpace); |
109 | doc.append(region.feature(ProblemPackage.Literals.ATOM__TRANSITIVE_CLOSURE), this::noSpace); | 99 | doc.append(region.feature(ProblemPackage.Literals.ATOM__TRANSITIVE_CLOSURE), this::noSpace); |
110 | formatParenthesizedList(region, doc); | 100 | formatParenthesizedList(region, doc); |
@@ -116,7 +106,7 @@ public class ProblemFormatter extends AbstractJavaFormatter { | |||
116 | protected void format(IndividualDeclaration individualDeclaration, IFormattableDocument doc) { | 106 | protected void format(IndividualDeclaration individualDeclaration, IFormattableDocument doc) { |
117 | surroundNewLines(doc, individualDeclaration, this::singleNewLine); | 107 | surroundNewLines(doc, individualDeclaration, this::singleNewLine); |
118 | var region = regionFor(individualDeclaration); | 108 | var region = regionFor(individualDeclaration); |
119 | doc.append(region.keyword("indiv"), this::oneSpace); | 109 | doc.append(region.keyword("individual"), this::oneSpace); |
120 | formatList(region, ",", doc); | 110 | formatList(region, ",", doc); |
121 | doc.prepend(region.keyword("."), this::noSpace); | 111 | doc.prepend(region.keyword("."), this::noSpace); |
122 | } | 112 | } |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java new file mode 100644 index 00000000..ab133a90 --- /dev/null +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java | |||
@@ -0,0 +1,89 @@ | |||
1 | package tools.refinery.language.parser.antlr; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import com.google.inject.Singleton; | ||
5 | import org.eclipse.xtext.*; | ||
6 | import org.eclipse.xtext.parser.antlr.ITokenDefProvider; | ||
7 | import tools.refinery.language.services.ProblemGrammarAccess; | ||
8 | |||
9 | import java.util.HashMap; | ||
10 | import java.util.HashSet; | ||
11 | import java.util.Set; | ||
12 | |||
13 | @Singleton | ||
14 | public class IdentifierTokenProvider { | ||
15 | private final int[] identifierTokensArray; | ||
16 | |||
17 | @Inject | ||
18 | private IdentifierTokenProvider(Initializer initializer) { | ||
19 | this.identifierTokensArray = initializer.getIdentifierTokesArray(); | ||
20 | } | ||
21 | |||
22 | public boolean isIdentifierToken(int tokenId) { | ||
23 | for (int identifierTokenId : identifierTokensArray) { | ||
24 | if (identifierTokenId == tokenId) { | ||
25 | return true; | ||
26 | } | ||
27 | } | ||
28 | return false; | ||
29 | } | ||
30 | |||
31 | private static class Initializer { | ||
32 | @Inject | ||
33 | private ITokenDefProvider tokenDefProvider; | ||
34 | |||
35 | @Inject | ||
36 | private ProblemGrammarAccess problemGrammarAccess; | ||
37 | |||
38 | private HashMap<String, Integer> valueToTokenIdMap; | ||
39 | |||
40 | private Set<Integer> identifierTokens; | ||
41 | |||
42 | public int[] getIdentifierTokesArray() { | ||
43 | createValueToTokenIdMap(); | ||
44 | identifierTokens = new HashSet<>(); | ||
45 | collectIdentifierTokensFromRule(problemGrammarAccess.getIdentifierRule()); | ||
46 | var identifierTokensArray = new int[identifierTokens.size()]; | ||
47 | int i = 0; | ||
48 | for (var tokenId : identifierTokens) { | ||
49 | identifierTokensArray[i] = tokenId; | ||
50 | i++; | ||
51 | } | ||
52 | return identifierTokensArray; | ||
53 | } | ||
54 | |||
55 | private void createValueToTokenIdMap() { | ||
56 | var tokenIdToValueMap = tokenDefProvider.getTokenDefMap(); | ||
57 | valueToTokenIdMap = new HashMap<>(tokenIdToValueMap.size()); | ||
58 | for (var entry : tokenIdToValueMap.entrySet()) { | ||
59 | valueToTokenIdMap.put(entry.getValue(), entry.getKey()); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | private void collectIdentifierTokensFromRule(AbstractRule rule) { | ||
64 | if (rule instanceof TerminalRule) { | ||
65 | collectToken("RULE_" + rule.getName()); | ||
66 | return; | ||
67 | } | ||
68 | collectIdentifierTokensFromElement(rule.getAlternatives()); | ||
69 | } | ||
70 | |||
71 | private void collectIdentifierTokensFromElement(AbstractElement element) { | ||
72 | if (element instanceof Alternatives alternatives) { | ||
73 | for (var alternative : alternatives.getElements()) { | ||
74 | collectIdentifierTokensFromElement(alternative); | ||
75 | } | ||
76 | } else if (element instanceof RuleCall ruleCall) { | ||
77 | collectIdentifierTokensFromRule(ruleCall.getRule()); | ||
78 | } else if (element instanceof Keyword keyword) { | ||
79 | collectToken("'" + keyword.getValue() + "'"); | ||
80 | } else { | ||
81 | throw new IllegalArgumentException("Unknown Xtext grammar element: " + element); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | private void collectToken(String value) { | ||
86 | identifierTokens.add(valueToTokenIdMap.get(value)); | ||
87 | } | ||
88 | } | ||
89 | } | ||
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java new file mode 100644 index 00000000..0b4e7185 --- /dev/null +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.29.0.M2 | ||
3 | */ | ||
4 | package tools.refinery.language.parser.antlr; | ||
5 | |||
6 | import com.google.inject.Inject; | ||
7 | import org.antlr.runtime.Token; | ||
8 | import org.antlr.runtime.TokenSource; | ||
9 | import tools.refinery.language.parser.antlr.internal.InternalProblemParser; | ||
10 | |||
11 | import java.util.ArrayDeque; | ||
12 | import java.util.Deque; | ||
13 | |||
14 | public class ProblemTokenSource implements TokenSource { | ||
15 | private IdentifierTokenProvider identifierTokenProvider; | ||
16 | |||
17 | private final TokenSource delegate; | ||
18 | |||
19 | private final Deque<Token> buffer = new ArrayDeque<>(); | ||
20 | |||
21 | private boolean recursive; | ||
22 | |||
23 | private boolean seenId; | ||
24 | |||
25 | public ProblemTokenSource(TokenSource delegate) { | ||
26 | this.delegate = delegate; | ||
27 | } | ||
28 | |||
29 | @Inject | ||
30 | public void setIdentifierTokenProvider(IdentifierTokenProvider identifierTokenProvider) { | ||
31 | this.identifierTokenProvider = identifierTokenProvider; | ||
32 | } | ||
33 | |||
34 | public boolean isRecursive() { | ||
35 | return recursive; | ||
36 | } | ||
37 | |||
38 | public void setRecursive(boolean recursive) { | ||
39 | this.recursive = recursive; | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public Token nextToken() { | ||
44 | if (!buffer.isEmpty()) { | ||
45 | return buffer.removeFirst(); | ||
46 | } | ||
47 | var token = delegate.nextToken(); | ||
48 | if (isIdentifier(token)) { | ||
49 | seenId = true; | ||
50 | } else if (seenId && isPlusOrTransitiveClosure(token)) { | ||
51 | if (peekForTransitiveClosure()) { | ||
52 | token.setType(InternalProblemParser.RULE_TRANSITIVE_CLOSURE); | ||
53 | } | ||
54 | } else if (isVisibleToken(token)) { | ||
55 | seenId = false; | ||
56 | } | ||
57 | return token; | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public String getSourceName() { | ||
62 | return "[%s]%s".formatted(this.getClass().getSimpleName(), delegate.getSourceName()); | ||
63 | } | ||
64 | |||
65 | protected boolean isIdentifier(Token token) { | ||
66 | return identifierTokenProvider.isIdentifierToken(token.getType()); | ||
67 | } | ||
68 | |||
69 | protected boolean isPlusOrTransitiveClosure(Token token) { | ||
70 | return token.getType() == InternalProblemParser.PlusSign; | ||
71 | } | ||
72 | |||
73 | protected boolean isVisibleToken(Token token) { | ||
74 | int tokenId = token.getType(); | ||
75 | return tokenId != InternalProblemParser.RULE_WS && tokenId != InternalProblemParser.RULE_SL_COMMENT && | ||
76 | tokenId != InternalProblemParser.RULE_ML_COMMENT; | ||
77 | } | ||
78 | |||
79 | protected boolean peekForTransitiveClosure() { | ||
80 | Token token = peekWithSkipWhitespace(); | ||
81 | if (token.getType() != InternalProblemParser.LeftParenthesis) { | ||
82 | return false; | ||
83 | } | ||
84 | while (true) { | ||
85 | token = peekWithSkipWhitespace(); | ||
86 | if (!isIdentifier(token)) { | ||
87 | return false; | ||
88 | } | ||
89 | token = peekWithSkipWhitespace(); | ||
90 | switch (token.getType()) { | ||
91 | case InternalProblemParser.Comma: | ||
92 | return true; | ||
93 | case InternalProblemParser.ColonColon: | ||
94 | break; | ||
95 | default: | ||
96 | // By default, we do not peek at inner plus signs to limit recursion depth. | ||
97 | // Such expressions are never valid, so we don't have to parse them correctly. | ||
98 | if (recursive && isPlusOrTransitiveClosure(token) && peekForTransitiveClosure()) { | ||
99 | token.setType(InternalProblemParser.RULE_TRANSITIVE_CLOSURE); | ||
100 | } | ||
101 | // Not a transitive closure for the initial position where we started peeking. | ||
102 | return false; | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | protected Token peekToken() { | ||
108 | var token = delegate.nextToken(); | ||
109 | if (isIdentifier(token)) { | ||
110 | seenId = true; | ||
111 | } else if (isVisibleToken(token)) { | ||
112 | seenId = false; | ||
113 | } | ||
114 | buffer.addLast(token); | ||
115 | return token; | ||
116 | } | ||
117 | |||
118 | protected Token peekWithSkipWhitespace() { | ||
119 | Token token; | ||
120 | do { | ||
121 | token = peekToken(); | ||
122 | } while (token != null && !isVisibleToken(token)); | ||
123 | return token; | ||
124 | } | ||
125 | } | ||
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java new file mode 100644 index 00000000..0cdd38d8 --- /dev/null +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java | |||
@@ -0,0 +1,18 @@ | |||
1 | package tools.refinery.language.parser.antlr; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import com.google.inject.Injector; | ||
5 | import org.antlr.runtime.CharStream; | ||
6 | import org.antlr.runtime.TokenSource; | ||
7 | |||
8 | public class TokenSourceInjectingProblemParser extends ProblemParser { | ||
9 | @Inject | ||
10 | private Injector injector; | ||
11 | |||
12 | @Override | ||
13 | protected TokenSource createLexer(CharStream stream) { | ||
14 | var tokenSource = super.createLexer(stream); | ||
15 | injector.injectMembers(tokenSource); | ||
16 | return tokenSource; | ||
17 | } | ||
18 | } | ||
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java index b76c4bf7..6176b0c4 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java | |||
@@ -1,36 +1,15 @@ | |||
1 | package tools.refinery.language.resource; | 1 | package tools.refinery.language.resource; |
2 | 2 | ||
3 | import java.util.HashSet; | 3 | import com.google.inject.Inject; |
4 | import java.util.List; | 4 | import com.google.inject.Singleton; |
5 | import java.util.Set; | 5 | import com.google.inject.name.Named; |
6 | |||
7 | import org.eclipse.xtext.linking.impl.LinkingHelper; | 6 | import org.eclipse.xtext.linking.impl.LinkingHelper; |
8 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | 7 | import org.eclipse.xtext.naming.IQualifiedNameConverter; |
9 | import org.eclipse.xtext.nodemodel.INode; | ||
10 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils; | ||
11 | import org.eclipse.xtext.scoping.IScope; | ||
12 | import org.eclipse.xtext.scoping.IScopeProvider; | 8 | import org.eclipse.xtext.scoping.IScopeProvider; |
13 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | 9 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; |
10 | import tools.refinery.language.model.problem.*; | ||
14 | 11 | ||
15 | import com.google.inject.Inject; | 12 | import java.util.*; |
16 | import com.google.inject.Singleton; | ||
17 | import com.google.inject.name.Named; | ||
18 | |||
19 | import tools.refinery.language.model.problem.Argument; | ||
20 | import tools.refinery.language.model.problem.Atom; | ||
21 | import tools.refinery.language.model.problem.CompoundLiteral; | ||
22 | import tools.refinery.language.model.problem.Conjunction; | ||
23 | import tools.refinery.language.model.problem.ExistentialQuantifier; | ||
24 | import tools.refinery.language.model.problem.ImplicitVariable; | ||
25 | import tools.refinery.language.model.problem.Literal; | ||
26 | import tools.refinery.language.model.problem.Parameter; | ||
27 | import tools.refinery.language.model.problem.ParametricDefinition; | ||
28 | import tools.refinery.language.model.problem.Problem; | ||
29 | import tools.refinery.language.model.problem.ProblemFactory; | ||
30 | import tools.refinery.language.model.problem.ProblemPackage; | ||
31 | import tools.refinery.language.model.problem.Statement; | ||
32 | import tools.refinery.language.model.problem.VariableOrNodeArgument; | ||
33 | import tools.refinery.language.naming.NamingUtil; | ||
34 | 13 | ||
35 | @Singleton | 14 | @Singleton |
36 | public class DerivedVariableComputer { | 15 | public class DerivedVariableComputer { |
@@ -53,107 +32,60 @@ public class DerivedVariableComputer { | |||
53 | } | 32 | } |
54 | 33 | ||
55 | protected void installDerivedParametricDefinitionState(ParametricDefinition definition, Set<String> nodeNames) { | 34 | protected void installDerivedParametricDefinitionState(ParametricDefinition definition, Set<String> nodeNames) { |
56 | Set<String> knownVariables = new HashSet<>(); | 35 | Set<String> knownVariables = new HashSet<>(nodeNames); |
57 | knownVariables.addAll(nodeNames); | ||
58 | for (Parameter parameter : definition.getParameters()) { | 36 | for (Parameter parameter : definition.getParameters()) { |
59 | String name = parameter.getName(); | 37 | String name = parameter.getName(); |
60 | if (name != null) { | 38 | if (name != null) { |
61 | knownVariables.add(name); | 39 | knownVariables.add(name); |
62 | } | 40 | } |
63 | } | 41 | } |
64 | for (Conjunction body : definition.getBodies()) { | 42 | if (definition instanceof PredicateDefinition predicateDefinition) { |
65 | installDeriveConjunctionState(body, knownVariables); | 43 | installDerivedPredicateDefinitionState(predicateDefinition, knownVariables); |
44 | } else if (definition instanceof FunctionDefinition functionDefinition) { | ||
45 | installDerivedFunctionDefinitionState(functionDefinition, knownVariables); | ||
46 | } else if (definition instanceof RuleDefinition ruleDefinition) { | ||
47 | installDerivedRuleDefinitionState(ruleDefinition, knownVariables); | ||
48 | } else { | ||
49 | throw new IllegalArgumentException("Unknown ParametricDefinition: " + definition); | ||
66 | } | 50 | } |
67 | } | 51 | } |
68 | 52 | ||
69 | protected void installDeriveConjunctionState(Conjunction conjunction, Set<String> knownVariables) { | 53 | protected void installDerivedPredicateDefinitionState(PredicateDefinition definition, Set<String> knownVariables) { |
70 | Set<String> newVariables = new HashSet<>(); | 54 | for (Conjunction body : definition.getBodies()) { |
71 | for (Literal literal : conjunction.getLiterals()) { | 55 | createVariablesForScope(new ImplicitVariableScope(body, knownVariables)); |
72 | if (literal instanceof Atom atom) { | ||
73 | createSigletonVariablesAndCollectVariables(atom, knownVariables, newVariables); | ||
74 | } | ||
75 | } | ||
76 | createVariables(conjunction, newVariables); | ||
77 | newVariables.addAll(knownVariables); | ||
78 | for (Literal literal : conjunction.getLiterals()) { | ||
79 | if (literal instanceof CompoundLiteral compoundLiteral) { | ||
80 | installDerivedCompoundLiteralState(compoundLiteral, newVariables); | ||
81 | } | ||
82 | } | 56 | } |
83 | } | 57 | } |
84 | 58 | ||
85 | protected void installDerivedCompoundLiteralState(CompoundLiteral compoundLiteral, Set<String> knownVariables) { | 59 | protected void installDerivedFunctionDefinitionState(FunctionDefinition definition, Set<String> knownVariables) { |
86 | Set<String> newVariables = new HashSet<>(); | 60 | for (Case body : definition.getCases()) { |
87 | createSigletonVariablesAndCollectVariables(compoundLiteral.getAtom(), knownVariables, newVariables); | 61 | if (body instanceof Conjunction conjunction) { |
88 | createVariables(compoundLiteral, newVariables); | 62 | createVariablesForScope(new ImplicitVariableScope(conjunction, knownVariables)); |
89 | } | 63 | } else if (body instanceof Match match) { |
90 | 64 | var condition = match.getCondition(); | |
91 | protected void createSigletonVariablesAndCollectVariables(Atom atom, Set<String> knownVariables, | 65 | if (condition != null) { |
92 | Set<String> newVariables) { | 66 | createVariablesForScope(new ImplicitVariableScope(match, match.getCondition(), knownVariables)); |
93 | for (Argument argument : atom.getArguments()) { | ||
94 | if (argument instanceof VariableOrNodeArgument variableOrNodeArgument) { | ||
95 | IScope scope = scopeProvider.getScope(variableOrNodeArgument, | ||
96 | ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE); | ||
97 | List<INode> nodes = NodeModelUtils.findNodesForFeature(variableOrNodeArgument, | ||
98 | ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE); | ||
99 | for (INode node : nodes) { | ||
100 | var variableName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
101 | var created = tryCreateVariableForArgument(variableOrNodeArgument, variableName, scope, | ||
102 | knownVariables, newVariables); | ||
103 | if (created) { | ||
104 | break; | ||
105 | } | ||
106 | } | 67 | } |
68 | } else { | ||
69 | throw new IllegalArgumentException("Unknown Case: " + body); | ||
107 | } | 70 | } |
108 | } | 71 | } |
109 | } | 72 | } |
110 | 73 | ||
111 | protected boolean tryCreateVariableForArgument(VariableOrNodeArgument variableOrNodeArgument, String variableName, | 74 | protected void installDerivedRuleDefinitionState(RuleDefinition definition, Set<String> knownVariables) { |
112 | IScope scope, Set<String> knownVariables, Set<String> newVariables) { | 75 | for (Conjunction precondition : definition.getPreconditions()) { |
113 | if (!NamingUtil.isValidId(variableName)) { | 76 | createVariablesForScope(new ImplicitVariableScope(precondition, knownVariables)); |
114 | return false; | ||
115 | } | ||
116 | var qualifiedName = qualifiedNameConverter.toQualifiedName(variableName); | ||
117 | if (scope.getSingleElement(qualifiedName) != null) { | ||
118 | return false; | ||
119 | } | ||
120 | if (NamingUtil.isSingletonVariableName(variableName)) { | ||
121 | createSingletonVariable(variableOrNodeArgument, variableName); | ||
122 | return true; | ||
123 | } | ||
124 | if (!knownVariables.contains(variableName)) { | ||
125 | newVariables.add(variableName); | ||
126 | return true; | ||
127 | } | ||
128 | return false; | ||
129 | } | ||
130 | |||
131 | protected void createVariables(ExistentialQuantifier quantifier, Set<String> newVariables) { | ||
132 | for (String variableName : newVariables) { | ||
133 | createVariable(quantifier, variableName); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | protected void createVariable(ExistentialQuantifier quantifier, String variableName) { | ||
138 | if (NamingUtil.isValidId(variableName)) { | ||
139 | ImplicitVariable variable = createNamedVariable(variableName); | ||
140 | quantifier.getImplicitVariables().add(variable); | ||
141 | } | 77 | } |
142 | } | 78 | } |
143 | 79 | ||
144 | protected void createSingletonVariable(VariableOrNodeArgument argument, String variableName) { | 80 | protected void createVariablesForScope(ImplicitVariableScope scope) { |
145 | if (NamingUtil.isValidId(variableName)) { | 81 | var queue = new ArrayDeque<ImplicitVariableScope>(); |
146 | ImplicitVariable variable = createNamedVariable(variableName); | 82 | queue.addLast(scope); |
147 | argument.setSingletonVariable(variable); | 83 | while (!queue.isEmpty()) { |
84 | var nextScope = queue.removeFirst(); | ||
85 | nextScope.createVariables(scopeProvider, linkingHelper, qualifiedNameConverter, queue); | ||
148 | } | 86 | } |
149 | } | 87 | } |
150 | 88 | ||
151 | protected ImplicitVariable createNamedVariable(String variableName) { | ||
152 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | ||
153 | variable.setName(variableName); | ||
154 | return variable; | ||
155 | } | ||
156 | |||
157 | public void discardDerivedVariables(Problem problem) { | 89 | public void discardDerivedVariables(Problem problem) { |
158 | for (Statement statement : problem.getStatements()) { | 90 | for (Statement statement : problem.getStatements()) { |
159 | if (statement instanceof ParametricDefinition parametricDefinition) { | 91 | if (statement instanceof ParametricDefinition parametricDefinition) { |
@@ -163,28 +95,31 @@ public class DerivedVariableComputer { | |||
163 | } | 95 | } |
164 | 96 | ||
165 | protected void discardParametricDefinitionState(ParametricDefinition definition) { | 97 | protected void discardParametricDefinitionState(ParametricDefinition definition) { |
166 | for (Conjunction body : definition.getBodies()) { | 98 | List<ExistentialQuantifier> existentialQuantifiers = new ArrayList<>(); |
167 | body.getImplicitVariables().clear(); | 99 | List<VariableOrNodeExpr> variableOrNodeExprs = new ArrayList<>(); |
168 | for (Literal literal : body.getLiterals()) { | 100 | var treeIterator = definition.eAllContents(); |
169 | if (literal instanceof Atom atom) { | 101 | // We must collect the nodes where we are discarding derived state and only discard them after the iteration, |
170 | discardDerivedAtomState(atom); | 102 | // because modifying the containment hierarchy during iteration causes the TreeIterator to fail with |
171 | } | 103 | // IndexOutOfBoundsException. |
172 | if (literal instanceof CompoundLiteral compoundLiteral) { | 104 | while (treeIterator.hasNext()) { |
173 | compoundLiteral.getImplicitVariables().clear(); | 105 | var child = treeIterator.next(); |
174 | discardDerivedAtomState(compoundLiteral.getAtom()); | 106 | var containingFeature = child.eContainingFeature(); |
175 | } | 107 | if (containingFeature == ProblemPackage.Literals.EXISTENTIAL_QUANTIFIER__IMPLICIT_VARIABLES || |
108 | containingFeature == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__SINGLETON_VARIABLE) { | ||
109 | treeIterator.prune(); | ||
110 | } else if (child instanceof ExistentialQuantifier existentialQuantifier && | ||
111 | !existentialQuantifier.getImplicitVariables().isEmpty()) { | ||
112 | existentialQuantifiers.add(existentialQuantifier); | ||
113 | } else if (child instanceof VariableOrNodeExpr variableOrNodeExpr && | ||
114 | variableOrNodeExpr.getSingletonVariable() != null) { | ||
115 | variableOrNodeExprs.add(variableOrNodeExpr); | ||
176 | } | 116 | } |
177 | } | 117 | } |
178 | } | 118 | for (var existentialQuantifier : existentialQuantifiers) { |
179 | 119 | existentialQuantifier.getImplicitVariables().clear(); | |
180 | protected void discardDerivedAtomState(Atom atom) { | ||
181 | if (atom == null) { | ||
182 | return; | ||
183 | } | 120 | } |
184 | for (Argument argument : atom.getArguments()) { | 121 | for (var variableOrNodeExpr : variableOrNodeExprs) { |
185 | if (argument instanceof VariableOrNodeArgument variableOrNodeArgument) { | 122 | variableOrNodeExpr.setSingletonVariable(null); |
186 | variableOrNodeArgument.setSingletonVariable(null); | ||
187 | } | ||
188 | } | 123 | } |
189 | } | 124 | } |
190 | } | 125 | } |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java new file mode 100644 index 00000000..b0ac2ab6 --- /dev/null +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java | |||
@@ -0,0 +1,138 @@ | |||
1 | package tools.refinery.language.resource; | ||
2 | |||
3 | import org.eclipse.emf.ecore.EObject; | ||
4 | import org.eclipse.xtext.linking.impl.LinkingHelper; | ||
5 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
6 | import org.eclipse.xtext.naming.QualifiedName; | ||
7 | import org.eclipse.xtext.nodemodel.INode; | ||
8 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils; | ||
9 | import org.eclipse.xtext.scoping.IScope; | ||
10 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
11 | import tools.refinery.language.model.problem.*; | ||
12 | import tools.refinery.language.naming.NamingUtil; | ||
13 | |||
14 | import java.util.Deque; | ||
15 | import java.util.HashSet; | ||
16 | import java.util.List; | ||
17 | import java.util.Set; | ||
18 | |||
19 | public class ImplicitVariableScope { | ||
20 | private final EObject root; | ||
21 | |||
22 | private final ExistentialQuantifier quantifier; | ||
23 | |||
24 | private final ImplicitVariableScope parent; | ||
25 | |||
26 | private Set<String> knownVariables; | ||
27 | |||
28 | private ImplicitVariableScope(ExistentialQuantifier quantifier, ImplicitVariableScope parent) { | ||
29 | this.root = quantifier; | ||
30 | this.quantifier = quantifier; | ||
31 | this.parent = parent; | ||
32 | this.knownVariables = null; | ||
33 | } | ||
34 | |||
35 | public ImplicitVariableScope(EObject root, ExistentialQuantifier quantifier, Set<String> knownVariables) { | ||
36 | this.root = root; | ||
37 | this.quantifier = quantifier; | ||
38 | this.parent = null; | ||
39 | this.knownVariables = new HashSet<>(knownVariables); | ||
40 | } | ||
41 | |||
42 | public ImplicitVariableScope(ExistentialQuantifier root, Set<String> knownVariables) { | ||
43 | this(root, root, knownVariables); | ||
44 | } | ||
45 | |||
46 | public void createVariables(IScopeProvider scopeProvider, LinkingHelper linkingHelper, | ||
47 | IQualifiedNameConverter qualifiedNameConverter, | ||
48 | Deque<ImplicitVariableScope> scopeQueue) { | ||
49 | initializeKnownVariables(); | ||
50 | processEObject(root, scopeProvider, linkingHelper, qualifiedNameConverter); | ||
51 | var treeIterator = root.eAllContents(); | ||
52 | while (treeIterator.hasNext()) { | ||
53 | var child = treeIterator.next(); | ||
54 | if (child instanceof ExistentialQuantifier nestedQuantifier) { | ||
55 | scopeQueue.addLast(new ImplicitVariableScope(nestedQuantifier, this)); | ||
56 | treeIterator.prune(); | ||
57 | } else { | ||
58 | processEObject(child, scopeProvider, linkingHelper, qualifiedNameConverter); | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | private void initializeKnownVariables() { | ||
64 | boolean hasKnownVariables = knownVariables != null; | ||
65 | boolean hasParent = parent != null; | ||
66 | if ((hasKnownVariables && hasParent) || (!hasKnownVariables && !hasParent)) { | ||
67 | throw new IllegalStateException("Either known variables or parent must be provided, but not both"); | ||
68 | } | ||
69 | if (hasKnownVariables) { | ||
70 | return; | ||
71 | } | ||
72 | if (parent.knownVariables == null) { | ||
73 | throw new IllegalStateException("Parent scope must be processed before current scope"); | ||
74 | } | ||
75 | knownVariables = new HashSet<>(parent.knownVariables); | ||
76 | } | ||
77 | |||
78 | private void processEObject(EObject eObject, IScopeProvider scopeProvider, LinkingHelper linkingHelper, | ||
79 | IQualifiedNameConverter qualifiedNameConverter) { | ||
80 | if (!(eObject instanceof VariableOrNodeExpr variableOrNodeExpr)) { | ||
81 | return; | ||
82 | } | ||
83 | IScope scope = scopeProvider.getScope(variableOrNodeExpr, | ||
84 | ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE); | ||
85 | List<INode> nodes = NodeModelUtils.findNodesForFeature(variableOrNodeExpr, | ||
86 | ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE); | ||
87 | for (INode node : nodes) { | ||
88 | var variableName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
89 | var created = tryCreateVariableForArgument(variableOrNodeExpr, variableName, qualifiedNameConverter, | ||
90 | scope); | ||
91 | if (created) { | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | protected boolean tryCreateVariableForArgument(VariableOrNodeExpr variableOrNodeExpr, String variableName, | ||
98 | IQualifiedNameConverter qualifiedNameConverter, IScope scope) { | ||
99 | if (!NamingUtil.isValidId(variableName)) { | ||
100 | return false; | ||
101 | } | ||
102 | QualifiedName qualifiedName; | ||
103 | try { | ||
104 | qualifiedName = qualifiedNameConverter.toQualifiedName(variableName); | ||
105 | } catch (IllegalArgumentException e) { | ||
106 | return false; | ||
107 | } | ||
108 | if (scope.getSingleElement(qualifiedName) != null) { | ||
109 | return false; | ||
110 | } | ||
111 | if (NamingUtil.isSingletonVariableName(variableName)) { | ||
112 | createSingletonVariable(variableOrNodeExpr, variableName); | ||
113 | return true; | ||
114 | } | ||
115 | if (!knownVariables.contains(variableName)) { | ||
116 | createVariable(variableName); | ||
117 | return true; | ||
118 | } | ||
119 | return false; | ||
120 | } | ||
121 | |||
122 | protected void createVariable(String variableName) { | ||
123 | knownVariables.add(variableName); | ||
124 | ImplicitVariable variable = createNamedVariable(variableName); | ||
125 | quantifier.getImplicitVariables().add(variable); | ||
126 | } | ||
127 | |||
128 | protected void createSingletonVariable(VariableOrNodeExpr variableOrNodeExpr, String variableName) { | ||
129 | ImplicitVariable variable = createNamedVariable(variableName); | ||
130 | variableOrNodeExpr.setSingletonVariable(variable); | ||
131 | } | ||
132 | |||
133 | protected ImplicitVariable createNamedVariable(String variableName) { | ||
134 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | ||
135 | variable.setName(variableName); | ||
136 | return variable; | ||
137 | } | ||
138 | } | ||
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemXmiResourceFactory.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemXmiResourceFactory.java deleted file mode 100644 index 68aa6016..00000000 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemXmiResourceFactory.java +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | package tools.refinery.language.resource; | ||
2 | |||
3 | import org.eclipse.emf.common.util.URI; | ||
4 | import org.eclipse.emf.ecore.resource.Resource; | ||
5 | import org.eclipse.xtext.resource.IResourceFactory; | ||
6 | |||
7 | import tools.refinery.language.model.problem.util.ProblemResourceFactoryImpl; | ||
8 | |||
9 | public class ProblemXmiResourceFactory implements IResourceFactory { | ||
10 | private Resource.Factory problemResourceFactory = new ProblemResourceFactoryImpl(); | ||
11 | |||
12 | @Override | ||
13 | public Resource createResource(URI uri) { | ||
14 | return problemResourceFactory.createResource(uri); | ||
15 | } | ||
16 | } | ||
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 567c3c26..c2045aea 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 | |||
@@ -3,34 +3,23 @@ | |||
3 | */ | 3 | */ |
4 | package tools.refinery.language.scoping; | 4 | package tools.refinery.language.scoping; |
5 | 5 | ||
6 | import java.util.ArrayList; | 6 | import com.google.inject.Inject; |
7 | import java.util.List; | ||
8 | |||
9 | import org.eclipse.emf.ecore.EObject; | 7 | import org.eclipse.emf.ecore.EObject; |
10 | import org.eclipse.emf.ecore.EReference; | 8 | import org.eclipse.emf.ecore.EReference; |
11 | import org.eclipse.xtext.EcoreUtil2; | 9 | import org.eclipse.xtext.EcoreUtil2; |
12 | import org.eclipse.xtext.scoping.IScope; | 10 | import org.eclipse.xtext.scoping.IScope; |
13 | import org.eclipse.xtext.scoping.Scopes; | 11 | import org.eclipse.xtext.scoping.Scopes; |
14 | 12 | import tools.refinery.language.model.problem.*; | |
15 | import com.google.inject.Inject; | ||
16 | |||
17 | import tools.refinery.language.model.problem.ClassDeclaration; | ||
18 | import tools.refinery.language.model.problem.Consequent; | ||
19 | import tools.refinery.language.model.problem.ExistentialQuantifier; | ||
20 | import tools.refinery.language.model.problem.NewAction; | ||
21 | import tools.refinery.language.model.problem.ParametricDefinition; | ||
22 | import tools.refinery.language.model.problem.Problem; | ||
23 | import tools.refinery.language.model.problem.ProblemPackage; | ||
24 | import tools.refinery.language.model.problem.ReferenceDeclaration; | ||
25 | import tools.refinery.language.model.problem.Variable; | ||
26 | import tools.refinery.language.model.problem.VariableOrNodeArgument; | ||
27 | import tools.refinery.language.utils.ProblemDesugarer; | 13 | import tools.refinery.language.utils.ProblemDesugarer; |
28 | 14 | ||
15 | import java.util.ArrayList; | ||
16 | import java.util.List; | ||
17 | |||
29 | /** | 18 | /** |
30 | * This class contains custom scoping description. | 19 | * This class contains custom scoping description. |
31 | * | 20 | * <p> |
32 | * See | 21 | * See |
33 | * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping | 22 | * <a href="https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping">...</a> |
34 | * on how and when to use it. | 23 | * on how and when to use it. |
35 | */ | 24 | */ |
36 | public class ProblemScopeProvider extends AbstractProblemScopeProvider { | 25 | public class ProblemScopeProvider extends AbstractProblemScopeProvider { |
@@ -44,7 +33,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { | |||
44 | || reference == ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE) { | 33 | || reference == ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE) { |
45 | return getNodesScope(context, scope); | 34 | return getNodesScope(context, scope); |
46 | } | 35 | } |
47 | if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE | 36 | if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE |
48 | || reference == ProblemPackage.Literals.NEW_ACTION__PARENT | 37 | || reference == ProblemPackage.Literals.NEW_ACTION__PARENT |
49 | || reference == ProblemPackage.Literals.DELETE_ACTION__VARIABLE_OR_NODE) { | 38 | || reference == ProblemPackage.Literals.DELETE_ACTION__VARIABLE_OR_NODE) { |
50 | return getVariableScope(context, scope); | 39 | return getVariableScope(context, scope); |
@@ -80,8 +69,8 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { | |||
80 | } | 69 | } |
81 | 70 | ||
82 | protected void addSingletonVariableToScope(EObject context, List<Variable> variables) { | 71 | protected void addSingletonVariableToScope(EObject context, List<Variable> variables) { |
83 | if (context instanceof VariableOrNodeArgument argument) { | 72 | if (context instanceof VariableOrNodeExpr expr) { |
84 | Variable singletonVariable = argument.getSingletonVariable(); | 73 | Variable singletonVariable = expr.getSingletonVariable(); |
85 | if (singletonVariable != null) { | 74 | if (singletonVariable != null) { |
86 | variables.add(singletonVariable); | 75 | variables.add(singletonVariable); |
87 | } | 76 | } |
@@ -91,6 +80,8 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { | |||
91 | protected void addExistentiallyQualifiedVariableToScope(EObject currentContext, List<Variable> variables) { | 80 | protected void addExistentiallyQualifiedVariableToScope(EObject currentContext, List<Variable> variables) { |
92 | if (currentContext instanceof ExistentialQuantifier quantifier) { | 81 | if (currentContext instanceof ExistentialQuantifier quantifier) { |
93 | variables.addAll(quantifier.getImplicitVariables()); | 82 | variables.addAll(quantifier.getImplicitVariables()); |
83 | } else if (currentContext instanceof Match match) { | ||
84 | variables.addAll(match.getCondition().getImplicitVariables()); | ||
94 | } else if (currentContext instanceof Consequent consequent) { | 85 | } else if (currentContext instanceof Consequent consequent) { |
95 | for (var literal : consequent.getActions()) { | 86 | for (var literal : consequent.getActions()) { |
96 | if (literal instanceof NewAction newAction && newAction.getVariable() != null) { | 87 | if (literal instanceof NewAction newAction && newAction.getVariable() != null) { |
@@ -106,10 +97,9 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { | |||
106 | return delegateScope; | 97 | return delegateScope; |
107 | } | 98 | } |
108 | var relation = referenceDeclaration.getReferenceType(); | 99 | var relation = referenceDeclaration.getReferenceType(); |
109 | if (!(relation instanceof ClassDeclaration)) { | 100 | if (!(relation instanceof ClassDeclaration classDeclaration)) { |
110 | return delegateScope; | 101 | return delegateScope; |
111 | } | 102 | } |
112 | var classDeclaration = (ClassDeclaration) relation; | ||
113 | var referenceDeclarations = desugarer.getAllReferenceDeclarations(classDeclaration); | 103 | var referenceDeclarations = desugarer.getAllReferenceDeclarations(classDeclaration); |
114 | return Scopes.scopeFor(referenceDeclarations, delegateScope); | 104 | return Scopes.scopeFor(referenceDeclarations, delegateScope); |
115 | } | 105 | } |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java index a7acd747..1e5164d3 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java | |||
@@ -44,7 +44,7 @@ public final class ProblemUtil { | |||
44 | } | 44 | } |
45 | 45 | ||
46 | public static boolean isSingletonVariable(Variable variable) { | 46 | public static boolean isSingletonVariable(Variable variable) { |
47 | return variable.eContainingFeature() == ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__SINGLETON_VARIABLE; | 47 | return variable.eContainingFeature() == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__SINGLETON_VARIABLE; |
48 | } | 48 | } |
49 | 49 | ||
50 | public static boolean isImplicitVariable(Variable variable) { | 50 | public static boolean isImplicitVariable(Variable variable) { |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index a0e78e1d..659d882c 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | |||
@@ -8,19 +8,15 @@ import org.eclipse.xtext.validation.Check; | |||
8 | 8 | ||
9 | import com.google.inject.Inject; | 9 | import com.google.inject.Inject; |
10 | 10 | ||
11 | import tools.refinery.language.model.problem.Node; | 11 | import tools.refinery.language.model.problem.*; |
12 | import tools.refinery.language.model.problem.Problem; | ||
13 | import tools.refinery.language.model.problem.ProblemPackage; | ||
14 | import tools.refinery.language.model.problem.Variable; | ||
15 | import tools.refinery.language.model.problem.VariableOrNodeArgument; | ||
16 | import tools.refinery.language.resource.ReferenceCounter; | 12 | import tools.refinery.language.resource.ReferenceCounter; |
17 | import tools.refinery.language.utils.ProblemUtil; | 13 | import tools.refinery.language.utils.ProblemUtil; |
18 | 14 | ||
19 | /** | 15 | /** |
20 | * This class contains custom validation rules. | 16 | * This class contains custom validation rules. |
21 | * | 17 | * <p> |
22 | * See | 18 | * See |
23 | * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation | 19 | * <a href="https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation">...</a> |
24 | */ | 20 | */ |
25 | public class ProblemValidator extends AbstractProblemValidator { | 21 | public class ProblemValidator extends AbstractProblemValidator { |
26 | private static final String ISSUE_PREFIX = "tools.refinery.language.validation.ProblemValidator."; | 22 | private static final String ISSUE_PREFIX = "tools.refinery.language.validation.ProblemValidator."; |
@@ -33,29 +29,29 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
33 | private ReferenceCounter referenceCounter; | 29 | private ReferenceCounter referenceCounter; |
34 | 30 | ||
35 | @Check | 31 | @Check |
36 | public void checkUniqueVariable(VariableOrNodeArgument argument) { | 32 | public void checkUniqueVariable(VariableOrNodeExpr expr) { |
37 | var variableOrNode = argument.getVariableOrNode(); | 33 | var variableOrNode = expr.getVariableOrNode(); |
38 | if (variableOrNode instanceof Variable variable && ProblemUtil.isImplicitVariable(variable) | 34 | if (variableOrNode instanceof Variable variable && ProblemUtil.isImplicitVariable(variable) |
39 | && !ProblemUtil.isSingletonVariable(variable)) { | 35 | && !ProblemUtil.isSingletonVariable(variable)) { |
40 | var problem = EcoreUtil2.getContainerOfType(variable, Problem.class); | 36 | var problem = EcoreUtil2.getContainerOfType(variable, Problem.class); |
41 | if (problem != null && referenceCounter.countReferences(problem, variable) <= 1) { | 37 | if (problem != null && referenceCounter.countReferences(problem, variable) <= 1) { |
42 | var name = variable.getName(); | 38 | var name = variable.getName(); |
43 | var message = "Variable '%s' has only a single reference. Add another reference or mark is as a singleton variable: '_%s'" | 39 | var message = ("Variable '%s' has only a single reference. " + |
44 | .formatted(name, name); | 40 | "Add another reference or mark is as a singleton variable: '_%s'").formatted(name, name); |
45 | warning(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, | 41 | warning(message, expr, ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE, |
46 | INSIGNIFICANT_INDEX, SINGLETON_VARIABLE_ISSUE); | 42 | INSIGNIFICANT_INDEX, SINGLETON_VARIABLE_ISSUE); |
47 | } | 43 | } |
48 | } | 44 | } |
49 | } | 45 | } |
50 | 46 | ||
51 | @Check | 47 | @Check |
52 | public void checkNonUniqueNode(VariableOrNodeArgument argument) { | 48 | public void checkNonUniqueNode(VariableOrNodeExpr expr) { |
53 | var variableOrNode = argument.getVariableOrNode(); | 49 | var variableOrNode = expr.getVariableOrNode(); |
54 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { | 50 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { |
55 | var name = node.getName(); | 51 | var name = node.getName(); |
56 | var message = "Only individual nodes can be referenced in predicates. Mark '%s' as individual with the declaration 'indiv %s.'" | 52 | var message = ("Only individual nodes can be referenced in predicates. " + |
57 | .formatted(name, name); | 53 | "Mark '%s' as individual with the declaration 'indiv %s.'").formatted(name, name); |
58 | error(message, argument, ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE, | 54 | error(message, expr, ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE, |
59 | INSIGNIFICANT_INDEX, NON_INDIVIDUAL_NODE_ISSUE); | 55 | INSIGNIFICANT_INDEX, NON_INDIVIDUAL_NODE_ISSUE); |
60 | } | 56 | } |
61 | } | 57 | } |
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 2f7c667a..38e77237 100644 --- a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem +++ b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem | |||
@@ -30,7 +30,7 @@ pred root(node node). | |||
30 | % !contains(node, _), !root(node). | 30 | % !contains(node, _), !root(node). |
31 | % | 31 | % |
32 | % error tooManyContainers(contained node) <-> | 32 | % error tooManyContainers(contained node) <-> |
33 | % count contains(_, node) > 1 | 33 | % #contains(_, node) > 1 |
34 | % ; | 34 | % ; |
35 | % contains(_, node), root(node) | 35 | % contains(_, node), root(node) |
36 | % ; | 36 | % ; |
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 1e8682a3..3a6e015f 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 | |||
@@ -1,17 +1,15 @@ | |||
1 | package tools.refinery.language.tests; | 1 | package tools.refinery.language.tests; |
2 | 2 | ||
3 | import static org.hamcrest.MatcherAssert.assertThat; | 3 | import com.google.inject.Inject; |
4 | import static org.hamcrest.Matchers.empty; | ||
5 | |||
6 | import org.eclipse.xtext.testing.InjectWith; | 4 | import org.eclipse.xtext.testing.InjectWith; |
7 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | 5 | import org.eclipse.xtext.testing.extensions.InjectionExtension; |
8 | import org.junit.jupiter.api.Test; | 6 | import org.junit.jupiter.api.Test; |
9 | import org.junit.jupiter.api.extension.ExtendWith; | 7 | import org.junit.jupiter.api.extension.ExtendWith; |
10 | |||
11 | import com.google.inject.Inject; | ||
12 | |||
13 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; | 8 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; |
14 | 9 | ||
10 | import static org.hamcrest.MatcherAssert.assertThat; | ||
11 | import static org.hamcrest.Matchers.empty; | ||
12 | |||
15 | @ExtendWith(InjectionExtension.class) | 13 | @ExtendWith(InjectionExtension.class) |
16 | @InjectWith(ProblemInjectorProvider.class) | 14 | @InjectWith(ProblemInjectorProvider.class) |
17 | class ProblemParsingTest { | 15 | class ProblemParsingTest { |
@@ -40,7 +38,7 @@ class ProblemParsingTest { | |||
40 | error invalidTaxStatus(Person p) <-> | 38 | error invalidTaxStatus(Person p) <-> |
41 | taxStatus(p, child), children(p, _q). | 39 | taxStatus(p, child), children(p, _q). |
42 | 40 | ||
43 | indiv family. | 41 | individual family. |
44 | Family(family). | 42 | Family(family). |
45 | members(family, anne): true. | 43 | members(family, anne): true. |
46 | members(family, bob). | 44 | members(family, bob). |
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java index 083c5184..a6e38130 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java | |||
@@ -1,10 +1,7 @@ | |||
1 | package tools.refinery.language.tests.formatting2; | 1 | package tools.refinery.language.tests.formatting2; |
2 | 2 | ||
3 | import static org.hamcrest.MatcherAssert.assertThat; | 3 | import com.google.inject.Inject; |
4 | import static org.hamcrest.Matchers.equalTo; | 4 | import com.google.inject.Provider; |
5 | |||
6 | import java.util.List; | ||
7 | |||
8 | import org.eclipse.xtext.formatting2.FormatterRequest; | 5 | import org.eclipse.xtext.formatting2.FormatterRequest; |
9 | import org.eclipse.xtext.formatting2.IFormatter2; | 6 | import org.eclipse.xtext.formatting2.IFormatter2; |
10 | import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess; | 7 | import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess; |
@@ -16,13 +13,14 @@ import org.eclipse.xtext.testing.extensions.InjectionExtension; | |||
16 | import org.eclipse.xtext.testing.util.ParseHelper; | 13 | import org.eclipse.xtext.testing.util.ParseHelper; |
17 | import org.junit.jupiter.api.Test; | 14 | import org.junit.jupiter.api.Test; |
18 | import org.junit.jupiter.api.extension.ExtendWith; | 15 | import org.junit.jupiter.api.extension.ExtendWith; |
19 | |||
20 | import com.google.inject.Inject; | ||
21 | import com.google.inject.Provider; | ||
22 | |||
23 | import tools.refinery.language.model.problem.Problem; | 16 | import tools.refinery.language.model.problem.Problem; |
24 | import tools.refinery.language.tests.ProblemInjectorProvider; | 17 | import tools.refinery.language.tests.ProblemInjectorProvider; |
25 | 18 | ||
19 | import java.util.List; | ||
20 | |||
21 | import static org.hamcrest.MatcherAssert.assertThat; | ||
22 | import static org.hamcrest.Matchers.equalTo; | ||
23 | |||
26 | @ExtendWith(InjectionExtension.class) | 24 | @ExtendWith(InjectionExtension.class) |
27 | @InjectWith(ProblemInjectorProvider.class) | 25 | @InjectWith(ProblemInjectorProvider.class) |
28 | class ProblemFormatterTest { | 26 | class ProblemFormatterTest { |
@@ -181,7 +179,7 @@ class ProblemFormatterTest { | |||
181 | 179 | ||
182 | @Test | 180 | @Test |
183 | void individualDeclarationTest() { | 181 | void individualDeclarationTest() { |
184 | testFormatter(" indiv a , b . ", "indiv a, b.\n"); | 182 | testFormatter(" individual a , b . ", "individual a, b.\n"); |
185 | } | 183 | } |
186 | 184 | ||
187 | @Test | 185 | @Test |
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java new file mode 100644 index 00000000..abff8d9c --- /dev/null +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java | |||
@@ -0,0 +1,39 @@ | |||
1 | package tools.refinery.language.tests.parser.antlr; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import org.eclipse.xtext.testing.InjectWith; | ||
5 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
6 | import org.junit.jupiter.api.extension.ExtendWith; | ||
7 | import org.junit.jupiter.params.ParameterizedTest; | ||
8 | import org.junit.jupiter.params.provider.Arguments; | ||
9 | import org.junit.jupiter.params.provider.MethodSource; | ||
10 | import tools.refinery.language.parser.antlr.IdentifierTokenProvider; | ||
11 | import tools.refinery.language.parser.antlr.internal.InternalProblemParser; | ||
12 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
13 | |||
14 | import java.util.stream.Stream; | ||
15 | |||
16 | import static org.hamcrest.MatcherAssert.assertThat; | ||
17 | import static org.hamcrest.Matchers.equalTo; | ||
18 | |||
19 | @ExtendWith(InjectionExtension.class) | ||
20 | @InjectWith(ProblemInjectorProvider.class) | ||
21 | class IdentifierTokenProviderTest { | ||
22 | @Inject | ||
23 | private IdentifierTokenProvider identifierTokenProvider; | ||
24 | |||
25 | @ParameterizedTest(name = "{0} is identifier: {2}") | ||
26 | @MethodSource | ||
27 | void isIdentifierTokenTest(String ignoredTokenName, int tokenId, boolean expected) { | ||
28 | assertThat(identifierTokenProvider.isIdentifierToken(tokenId), equalTo(expected)); | ||
29 | } | ||
30 | |||
31 | static Stream<Arguments> isIdentifierTokenTest() { | ||
32 | return Stream.of( | ||
33 | Arguments.of("RULE_ID", InternalProblemParser.RULE_ID, true), | ||
34 | Arguments.of("contained", InternalProblemParser.Contained, true), | ||
35 | Arguments.of("contains", InternalProblemParser.Contains, true), | ||
36 | Arguments.of("(", InternalProblemParser.LeftParenthesis, false) | ||
37 | ); | ||
38 | } | ||
39 | } | ||
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java new file mode 100644 index 00000000..cb42d5d0 --- /dev/null +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java | |||
@@ -0,0 +1,134 @@ | |||
1 | package tools.refinery.language.tests.parser.antlr; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import com.google.inject.Provider; | ||
5 | import com.google.inject.name.Named; | ||
6 | import org.antlr.runtime.ANTLRStringStream; | ||
7 | import org.antlr.runtime.Token; | ||
8 | import org.eclipse.xtext.parser.antlr.Lexer; | ||
9 | import org.eclipse.xtext.parser.antlr.LexerBindings; | ||
10 | import org.eclipse.xtext.testing.InjectWith; | ||
11 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
12 | import org.hamcrest.Matcher; | ||
13 | import org.junit.jupiter.api.extension.ExtendWith; | ||
14 | import org.junit.jupiter.params.ParameterizedTest; | ||
15 | import org.junit.jupiter.params.provider.Arguments; | ||
16 | import org.junit.jupiter.params.provider.MethodSource; | ||
17 | import org.junit.jupiter.params.provider.ValueSource; | ||
18 | import tools.refinery.language.parser.antlr.IdentifierTokenProvider; | ||
19 | import tools.refinery.language.parser.antlr.ProblemTokenSource; | ||
20 | import tools.refinery.language.parser.antlr.internal.InternalProblemParser; | ||
21 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
22 | |||
23 | import java.util.ArrayList; | ||
24 | import java.util.List; | ||
25 | import java.util.stream.Stream; | ||
26 | |||
27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
28 | import static org.hamcrest.Matchers.*; | ||
29 | |||
30 | @ExtendWith(InjectionExtension.class) | ||
31 | @InjectWith(ProblemInjectorProvider.class) | ||
32 | class ProblemTokenSourceTest { | ||
33 | @Inject | ||
34 | @Named(LexerBindings.RUNTIME) | ||
35 | private Provider<Lexer> lexerProvider; | ||
36 | |||
37 | @Inject | ||
38 | private IdentifierTokenProvider identifierTokenProvider; | ||
39 | |||
40 | @ParameterizedTest | ||
41 | @ValueSource(strings = { | ||
42 | "a+b", | ||
43 | "a+(b)", | ||
44 | "a+(b(x, y), x)", | ||
45 | "a + (b)", | ||
46 | "a+(b::x)", | ||
47 | "c+(a+(b)", | ||
48 | "a+(1, b)", | ||
49 | // These are never valid expressions, so we do try to peek at the inner plus sign | ||
50 | // to limit recursion depth in the token source: | ||
51 | "c+(equals+(a, b))", | ||
52 | "equals+(equals+(a, b), c)", | ||
53 | }) | ||
54 | void plusSignInTokenStreamTest(String text) { | ||
55 | var tokenList = createTokenList(text); | ||
56 | assertThat(tokenList, hasTokenOfType(InternalProblemParser.PlusSign)); | ||
57 | assertThat(tokenList, not(hasTokenOfType(InternalProblemParser.RULE_TRANSITIVE_CLOSURE))); | ||
58 | } | ||
59 | |||
60 | @ParameterizedTest | ||
61 | @ValueSource(strings = { | ||
62 | "equals+(a, b)", | ||
63 | "equals + (a, b)", | ||
64 | "equals+(a::x, b)" | ||
65 | }) | ||
66 | void transitiveClosureInTokenStreamTest(String text) { | ||
67 | var tokenList = createTokenList(text); | ||
68 | assertThat(tokenList, not(hasTokenOfType(InternalProblemParser.PlusSign))); | ||
69 | assertThat(tokenList, hasTokenOfType(InternalProblemParser.RULE_TRANSITIVE_CLOSURE)); | ||
70 | } | ||
71 | |||
72 | @ParameterizedTest | ||
73 | @MethodSource | ||
74 | void plusAndTransitiveClosureInSameTokenStreamTest(String text, boolean recursive) { | ||
75 | var tokenSource = createTokenSource(text); | ||
76 | tokenSource.setRecursive(recursive); | ||
77 | Token token; | ||
78 | int i = 0; | ||
79 | int plusIndex = -1; | ||
80 | int transitiveClosureIndex = -1; | ||
81 | do { | ||
82 | token = tokenSource.nextToken(); | ||
83 | switch (token.getType()) { | ||
84 | case InternalProblemParser.PlusSign -> { | ||
85 | assertThat("multiple plus signs", plusIndex, equalTo(-1)); | ||
86 | plusIndex = i; | ||
87 | } | ||
88 | case InternalProblemParser.RULE_TRANSITIVE_CLOSURE -> { | ||
89 | assertThat("multiple transitive closures", transitiveClosureIndex, equalTo(-1)); | ||
90 | transitiveClosureIndex = i; | ||
91 | } | ||
92 | } | ||
93 | i++; | ||
94 | } while (token.getType() != InternalProblemParser.EOF); | ||
95 | assertThat("no plus sign", plusIndex, not(equalTo(-1))); | ||
96 | assertThat("no transitive closure", transitiveClosureIndex, not(equalTo(-1))); | ||
97 | assertThat("transitive closure before plus", transitiveClosureIndex, greaterThan(plusIndex)); | ||
98 | } | ||
99 | |||
100 | static Stream<Arguments> plusAndTransitiveClosureInSameTokenStreamTest() { | ||
101 | return Stream.of( | ||
102 | Arguments.of("c+(d), equals+(a, b)", false), | ||
103 | Arguments.of("foo+(bar baz+(a, b))", false), | ||
104 | // Here we can peek at the inner plus sign without recursion: | ||
105 | Arguments.of("c+(1, equals+(a, b))", false), | ||
106 | // But these cases need recursion: | ||
107 | Arguments.of("c+(equals+(a, b))", true), | ||
108 | Arguments.of("equals+(equals+(a, b), c)", true) | ||
109 | ); | ||
110 | } | ||
111 | |||
112 | private ProblemTokenSource createTokenSource(String text) { | ||
113 | var lexer = lexerProvider.get(); | ||
114 | lexer.setCharStream(new ANTLRStringStream(text)); | ||
115 | var tokenSource = new ProblemTokenSource(lexer); | ||
116 | tokenSource.setIdentifierTokenProvider(identifierTokenProvider); | ||
117 | return tokenSource; | ||
118 | } | ||
119 | |||
120 | private List<Token> createTokenList(String text) { | ||
121 | var tokenSource = createTokenSource(text); | ||
122 | var tokens = new ArrayList<Token>(); | ||
123 | Token token; | ||
124 | do { | ||
125 | token = tokenSource.nextToken(); | ||
126 | tokens.add(token); | ||
127 | } while (token.getType() != InternalProblemParser.EOF); | ||
128 | return tokens; | ||
129 | } | ||
130 | |||
131 | private Matcher<Iterable<? super Token>> hasTokenOfType(int tokenId) { | ||
132 | return hasItem(hasProperty("type", equalTo(tokenId))); | ||
133 | } | ||
134 | } | ||
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 new file mode 100644 index 00000000..96d12edf --- /dev/null +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java | |||
@@ -0,0 +1,49 @@ | |||
1 | package tools.refinery.language.tests.parser.antlr; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import org.eclipse.xtext.testing.InjectWith; | ||
5 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
6 | import org.junit.jupiter.api.Test; | ||
7 | import org.junit.jupiter.api.extension.ExtendWith; | ||
8 | import tools.refinery.language.model.problem.ArithmeticBinaryExpr; | ||
9 | import tools.refinery.language.model.problem.Atom; | ||
10 | import tools.refinery.language.model.problem.BinaryOp; | ||
11 | import tools.refinery.language.model.problem.ComparisonExpr; | ||
12 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; | ||
13 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
14 | |||
15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
16 | import static org.hamcrest.Matchers.*; | ||
17 | |||
18 | @ExtendWith(InjectionExtension.class) | ||
19 | @InjectWith(ProblemInjectorProvider.class) | ||
20 | class TransitiveClosureParserTest { | ||
21 | @Inject | ||
22 | private ProblemParseHelper parseHelper; | ||
23 | |||
24 | @Test | ||
25 | void binaryAddOperatorTest() { | ||
26 | var problem = parseHelper.parse(""" | ||
27 | pred foo(int a, int b) <-> a + (b) > 10. | ||
28 | """); | ||
29 | assertThat(problem.errors(), empty()); | ||
30 | var literal = problem.pred("foo").conj(0).lit(0).get(); | ||
31 | assertThat(literal, instanceOf(ComparisonExpr.class)); | ||
32 | var left = ((ComparisonExpr) literal).getLeft(); | ||
33 | assertThat(left, instanceOf(ArithmeticBinaryExpr.class)); | ||
34 | var binary = (ArithmeticBinaryExpr) left; | ||
35 | assertThat(binary.getOp(), equalTo(BinaryOp.ADD)); | ||
36 | } | ||
37 | |||
38 | @Test | ||
39 | void transitiveClosureTest() { | ||
40 | var problem = parseHelper.parse(""" | ||
41 | pred foo(a, b) <-> equals+(a, b). | ||
42 | """); | ||
43 | assertThat(problem.errors(), empty()); | ||
44 | var literal = problem.pred("foo").conj(0).lit(0).get(); | ||
45 | assertThat(literal, instanceOf(Atom.class)); | ||
46 | var atom = (Atom) literal; | ||
47 | assertThat(atom.isTransitiveClosure(), equalTo(true)); | ||
48 | } | ||
49 | } | ||
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 5c905ede..9049b8ec 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 | |||
@@ -1,13 +1,6 @@ | |||
1 | package tools.refinery.language.tests.scoping; | 1 | package tools.refinery.language.tests.scoping; |
2 | 2 | ||
3 | import static org.hamcrest.MatcherAssert.assertThat; | 3 | import com.google.inject.Inject; |
4 | import static org.hamcrest.Matchers.empty; | ||
5 | import static org.hamcrest.Matchers.equalTo; | ||
6 | import static org.hamcrest.Matchers.hasItems; | ||
7 | import static org.hamcrest.Matchers.not; | ||
8 | |||
9 | import java.util.stream.Stream; | ||
10 | |||
11 | import org.eclipse.xtext.testing.InjectWith; | 4 | import org.eclipse.xtext.testing.InjectWith; |
12 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | 5 | import org.eclipse.xtext.testing.extensions.InjectionExtension; |
13 | import org.junit.jupiter.api.Test; | 6 | import org.junit.jupiter.api.Test; |
@@ -16,13 +9,15 @@ import org.junit.jupiter.params.ParameterizedTest; | |||
16 | import org.junit.jupiter.params.provider.Arguments; | 9 | import org.junit.jupiter.params.provider.Arguments; |
17 | import org.junit.jupiter.params.provider.MethodSource; | 10 | import org.junit.jupiter.params.provider.MethodSource; |
18 | import org.junit.jupiter.params.provider.ValueSource; | 11 | import org.junit.jupiter.params.provider.ValueSource; |
19 | |||
20 | import com.google.inject.Inject; | ||
21 | |||
22 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; | 12 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; |
23 | import tools.refinery.language.model.tests.utils.WrappedProblem; | 13 | import tools.refinery.language.model.tests.utils.WrappedProblem; |
24 | import tools.refinery.language.tests.ProblemInjectorProvider; | 14 | import tools.refinery.language.tests.ProblemInjectorProvider; |
25 | 15 | ||
16 | import java.util.stream.Stream; | ||
17 | |||
18 | import static org.hamcrest.MatcherAssert.assertThat; | ||
19 | import static org.hamcrest.Matchers.*; | ||
20 | |||
26 | @ExtendWith(InjectionExtension.class) | 21 | @ExtendWith(InjectionExtension.class) |
27 | @InjectWith(ProblemInjectorProvider.class) | 22 | @InjectWith(ProblemInjectorProvider.class) |
28 | class NodeScopingTest { | 23 | class NodeScopingTest { |
@@ -85,7 +80,7 @@ class NodeScopingTest { | |||
85 | @MethodSource("individualNodeReferenceSource") | 80 | @MethodSource("individualNodeReferenceSource") |
86 | void individualNodeInAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { | 81 | void individualNodeInAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { |
87 | var problem = parse(""" | 82 | var problem = parse(""" |
88 | indiv a, b. | 83 | individual a, b. |
89 | pred predicate(node x, node y) <-> node(x). | 84 | pred predicate(node x, node y) <-> node(x). |
90 | predicate({PARAM}a, {PARAM}a). | 85 | predicate({PARAM}a, {PARAM}a). |
91 | ?predicate({PARAM}a, {PARAM}b). | 86 | ?predicate({PARAM}a, {PARAM}b). |
@@ -102,7 +97,7 @@ class NodeScopingTest { | |||
102 | @MethodSource("individualNodeReferenceSource") | 97 | @MethodSource("individualNodeReferenceSource") |
103 | void individualNodeInNodeValueAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { | 98 | void individualNodeInNodeValueAssertionTest(String qualifiedNamePrefix, boolean namedProblem) { |
104 | var problem = parse(""" | 99 | var problem = parse(""" |
105 | indiv a. | 100 | individual a. |
106 | {PARAM}a: 16. | 101 | {PARAM}a: 16. |
107 | """, qualifiedNamePrefix, namedProblem); | 102 | """, qualifiedNamePrefix, namedProblem); |
108 | assertThat(problem.errors(), empty()); | 103 | assertThat(problem.errors(), empty()); |
@@ -114,7 +109,7 @@ class NodeScopingTest { | |||
114 | @MethodSource("individualNodeReferenceSource") | 109 | @MethodSource("individualNodeReferenceSource") |
115 | void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) { | 110 | void individualNodeInPredicateTest(String qualifiedNamePrefix, boolean namedProblem) { |
116 | var problem = parse(""" | 111 | var problem = parse(""" |
117 | indiv b. | 112 | individual b. |
118 | pred predicate(node a) <-> node({PARAM}b). | 113 | pred predicate(node a) <-> node({PARAM}b). |
119 | """); | 114 | """); |
120 | assertThat(problem.errors(), empty()); | 115 | assertThat(problem.errors(), empty()); |
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 ea858e92..150e47a4 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 | |||
@@ -1,13 +1,6 @@ | |||
1 | package tools.refinery.language.tests.serializer; | 1 | package tools.refinery.language.tests.serializer; |
2 | 2 | ||
3 | import static org.hamcrest.MatcherAssert.assertThat; | 3 | import com.google.inject.Inject; |
4 | import static org.hamcrest.Matchers.equalTo; | ||
5 | |||
6 | import java.io.ByteArrayOutputStream; | ||
7 | import java.io.IOException; | ||
8 | import java.util.Map; | ||
9 | import java.util.stream.Stream; | ||
10 | |||
11 | import org.eclipse.emf.common.util.URI; | 4 | import org.eclipse.emf.common.util.URI; |
12 | import org.eclipse.emf.ecore.resource.Resource; | 5 | import org.eclipse.emf.ecore.resource.Resource; |
13 | import org.eclipse.emf.ecore.resource.ResourceSet; | 6 | import org.eclipse.emf.ecore.resource.ResourceSet; |
@@ -19,20 +12,18 @@ import org.junit.jupiter.api.extension.ExtendWith; | |||
19 | import org.junit.jupiter.params.ParameterizedTest; | 12 | import org.junit.jupiter.params.ParameterizedTest; |
20 | import org.junit.jupiter.params.provider.Arguments; | 13 | import org.junit.jupiter.params.provider.Arguments; |
21 | import org.junit.jupiter.params.provider.MethodSource; | 14 | import org.junit.jupiter.params.provider.MethodSource; |
22 | 15 | import tools.refinery.language.model.problem.*; | |
23 | import com.google.inject.Inject; | ||
24 | |||
25 | import tools.refinery.language.model.problem.Atom; | ||
26 | import tools.refinery.language.model.problem.LogicValue; | ||
27 | import tools.refinery.language.model.problem.Node; | ||
28 | import tools.refinery.language.model.problem.PredicateDefinition; | ||
29 | import tools.refinery.language.model.problem.Problem; | ||
30 | import tools.refinery.language.model.problem.ProblemFactory; | ||
31 | import tools.refinery.language.model.problem.Relation; | ||
32 | import tools.refinery.language.model.problem.VariableOrNode; | ||
33 | import tools.refinery.language.model.tests.utils.WrappedProblem; | 16 | import tools.refinery.language.model.tests.utils.WrappedProblem; |
34 | import tools.refinery.language.tests.ProblemInjectorProvider; | 17 | import tools.refinery.language.tests.ProblemInjectorProvider; |
35 | 18 | ||
19 | import java.io.ByteArrayOutputStream; | ||
20 | import java.io.IOException; | ||
21 | import java.util.Map; | ||
22 | import java.util.stream.Stream; | ||
23 | |||
24 | import static org.hamcrest.MatcherAssert.assertThat; | ||
25 | import static org.hamcrest.Matchers.equalTo; | ||
26 | |||
36 | @ExtendWith(InjectionExtension.class) | 27 | @ExtendWith(InjectionExtension.class) |
37 | @InjectWith(ProblemInjectorProvider.class) | 28 | @InjectWith(ProblemInjectorProvider.class) |
38 | class ProblemSerializerTest { | 29 | class ProblemSerializerTest { |
@@ -68,7 +59,7 @@ class ProblemSerializerTest { | |||
68 | assertSerializedResult(""" | 59 | assertSerializedResult(""" |
69 | pred foo(node p). | 60 | pred foo(node p). |
70 | 61 | ||
71 | indiv a. | 62 | individual a. |
72 | """ + serializedAssertion + "\n"); | 63 | """ + serializedAssertion + "\n"); |
73 | } | 64 | } |
74 | 65 | ||
@@ -166,10 +157,10 @@ class ProblemSerializerTest { | |||
166 | private Atom createAtom(Relation relation, VariableOrNode variable1, VariableOrNode variable2) { | 157 | private Atom createAtom(Relation relation, VariableOrNode variable1, VariableOrNode variable2) { |
167 | var atom = ProblemFactory.eINSTANCE.createAtom(); | 158 | var atom = ProblemFactory.eINSTANCE.createAtom(); |
168 | atom.setRelation(relation); | 159 | atom.setRelation(relation); |
169 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | 160 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr(); |
170 | arg1.setVariableOrNode(variable1); | 161 | arg1.setVariableOrNode(variable1); |
171 | atom.getArguments().add(arg1); | 162 | atom.getArguments().add(arg1); |
172 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | 163 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr(); |
173 | arg2.setVariableOrNode(variable2); | 164 | arg2.setVariableOrNode(variable2); |
174 | atom.getArguments().add(arg2); | 165 | atom.getArguments().add(arg2); |
175 | return atom; | 166 | return atom; |
@@ -188,10 +179,10 @@ class ProblemSerializerTest { | |||
188 | var atom = ProblemFactory.eINSTANCE.createAtom(); | 179 | var atom = ProblemFactory.eINSTANCE.createAtom(); |
189 | var equals = nodeType.reference("equals"); | 180 | var equals = nodeType.reference("equals"); |
190 | atom.setRelation(equals); | 181 | atom.setRelation(equals); |
191 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | 182 | var arg1 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr(); |
192 | arg1.setVariableOrNode(parameter); | 183 | arg1.setVariableOrNode(parameter); |
193 | atom.getArguments().add(arg1); | 184 | atom.getArguments().add(arg1); |
194 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeArgument(); | 185 | var arg2 = ProblemFactory.eINSTANCE.createVariableOrNodeExpr(); |
195 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | 186 | var variable = ProblemFactory.eINSTANCE.createImplicitVariable(); |
196 | variable.setName("_q"); | 187 | variable.setName("_q"); |
197 | arg2.setSingletonVariable(variable); | 188 | arg2.setSingletonVariable(variable); |
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 a05f3335..98c16352 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 | |||
@@ -44,7 +44,7 @@ class SymbolCollectorTest { | |||
44 | @Test | 44 | @Test |
45 | void individualNodeTest() { | 45 | void individualNodeTest() { |
46 | var problem = parseHelper.parse(""" | 46 | var problem = parseHelper.parse(""" |
47 | indiv a. | 47 | individual a. |
48 | """); | 48 | """); |
49 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | 49 | var collectedSymbols = desugarer.collectSymbols(problem.get()); |
50 | var node = problem.individualNode("a"); | 50 | var node = problem.individualNode("a"); |
@@ -161,7 +161,7 @@ class SymbolCollectorTest { | |||
161 | 161 | ||
162 | static Stream<Arguments> predicateTest() { | 162 | static Stream<Arguments> predicateTest() { |
163 | return Stream.of(Arguments.of("pred", ContainmentRole.NONE), Arguments.of("error", ContainmentRole.NONE), | 163 | return Stream.of(Arguments.of("pred", ContainmentRole.NONE), Arguments.of("error", ContainmentRole.NONE), |
164 | Arguments.of("contained", ContainmentRole.CONTAINED), Arguments.of("containment", | 164 | Arguments.of("contained pred", ContainmentRole.CONTAINED), Arguments.of("containment pred", |
165 | ContainmentRole.CONTAINMENT)); | 165 | ContainmentRole.CONTAINMENT)); |
166 | } | 166 | } |
167 | 167 | ||
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java index ad57a438..9e4c59f5 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java | |||
@@ -2,13 +2,13 @@ package tools.refinery.language.model.tests.utils; | |||
2 | 2 | ||
3 | import tools.refinery.language.model.problem.*; | 3 | import tools.refinery.language.model.problem.*; |
4 | 4 | ||
5 | public record WrappedArgument(Argument argument) { | 5 | public record WrappedArgument(Expr expr) { |
6 | public Argument get() { | 6 | public Expr get() { |
7 | return argument; | 7 | return expr; |
8 | } | 8 | } |
9 | 9 | ||
10 | public VariableOrNode variableOrNode() { | 10 | public VariableOrNode variableOrNode() { |
11 | return ((VariableOrNodeArgument) argument).getVariableOrNode(); | 11 | return ((VariableOrNodeExpr) expr).getVariableOrNode(); |
12 | } | 12 | } |
13 | 13 | ||
14 | public Variable variable() { | 14 | public Variable variable() { |
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java index 2282198d..4aa71b99 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java | |||
@@ -1,20 +1,20 @@ | |||
1 | package tools.refinery.language.model.tests.utils; | 1 | package tools.refinery.language.model.tests.utils; |
2 | 2 | ||
3 | import tools.refinery.language.model.problem.Atom; | 3 | import tools.refinery.language.model.problem.Atom; |
4 | import tools.refinery.language.model.problem.Literal; | 4 | import tools.refinery.language.model.problem.Expr; |
5 | import tools.refinery.language.model.problem.NegativeLiteral; | 5 | import tools.refinery.language.model.problem.NegationExpr; |
6 | 6 | ||
7 | public record WrappedLiteral(Literal literal) { | 7 | public record WrappedLiteral(Expr expr) { |
8 | public Literal get() { | 8 | public Expr get() { |
9 | return literal; | 9 | return expr; |
10 | } | 10 | } |
11 | 11 | ||
12 | public WrappedAtom atom() { | 12 | public WrappedAtom atom() { |
13 | return new WrappedAtom((Atom) literal); | 13 | return new WrappedAtom((Atom) expr); |
14 | } | 14 | } |
15 | 15 | ||
16 | public WrappedAtom negated() { | 16 | public WrappedAtom negated() { |
17 | return new WrappedAtom(((NegativeLiteral) literal).getAtom()); | 17 | return new WrappedAtom((Atom) ((NegationExpr) expr).getBody()); |
18 | } | 18 | } |
19 | 19 | ||
20 | public WrappedArgument arg(int i) { | 20 | public WrappedArgument arg(int i) { |
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java index b390051a..c2f18a60 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java | |||
@@ -4,13 +4,9 @@ import tools.refinery.language.model.problem.Parameter; | |||
4 | import tools.refinery.language.model.problem.ParametricDefinition; | 4 | import tools.refinery.language.model.problem.ParametricDefinition; |
5 | 5 | ||
6 | public interface WrappedParametricDefinition { | 6 | public interface WrappedParametricDefinition { |
7 | public ParametricDefinition get(); | 7 | ParametricDefinition get(); |
8 | |||
9 | public default Parameter param(int i) { | ||
10 | return get().getParameters().get(i); | ||
11 | } | ||
12 | 8 | ||
13 | public default WrappedConjunction conj(int i) { | 9 | default Parameter param(int i) { |
14 | return new WrappedConjunction(get().getBodies().get(i)); | 10 | return get().getParameters().get(i); |
15 | } | 11 | } |
16 | } | 12 | } |
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java index 6b07366d..7b95ecc1 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java | |||
@@ -8,4 +8,8 @@ public record WrappedPredicateDefinition(PredicateDefinition predicateDefinition | |||
8 | public PredicateDefinition get() { | 8 | public PredicateDefinition get() { |
9 | return predicateDefinition; | 9 | return predicateDefinition; |
10 | } | 10 | } |
11 | |||
12 | public WrappedConjunction conj(int i) { | ||
13 | return new WrappedConjunction(predicateDefinition.getBodies().get(i)); | ||
14 | } | ||
11 | } | 15 | } |
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java index b9f299f6..a4cf2eaf 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java | |||
@@ -7,7 +7,11 @@ public record WrappedRuleDefinition(RuleDefinition ruleDefinition) implements Wr | |||
7 | public RuleDefinition get() { | 7 | public RuleDefinition get() { |
8 | return ruleDefinition; | 8 | return ruleDefinition; |
9 | } | 9 | } |
10 | 10 | ||
11 | public WrappedConjunction conj(int i) { | ||
12 | return new WrappedConjunction(ruleDefinition.getPreconditions().get(i)); | ||
13 | } | ||
14 | |||
11 | public WrappedConsequent consequent(int i) { | 15 | public WrappedConsequent consequent(int i) { |
12 | return new WrappedConsequent(ruleDefinition.getConsequents().get(i)); | 16 | return new WrappedConsequent(ruleDefinition.getConsequents().get(i)); |
13 | } | 17 | } |