diff options
Diffstat (limited to 'language/src/main/java')
16 files changed, 1064 insertions, 0 deletions
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 b/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 new file mode 100644 index 00000000..76563e2c --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 | |||
@@ -0,0 +1,59 @@ | |||
1 | module org.eclipse.viatra.solver.language.GenerateProblem | ||
2 | |||
3 | import org.eclipse.xtext.xtext.generator.* | ||
4 | import org.eclipse.xtext.xtext.generator.model.project.* | ||
5 | |||
6 | var rootPath = ".." | ||
7 | |||
8 | Workflow { | ||
9 | component = XtextGenerator { | ||
10 | configuration = { | ||
11 | project = StandardProjectConfig { | ||
12 | baseName = "language" | ||
13 | rootPath = rootPath | ||
14 | runtimeTest = { | ||
15 | enabled = true | ||
16 | } | ||
17 | genericIde = { | ||
18 | name = "language-ide" | ||
19 | } | ||
20 | web = { | ||
21 | enabled = true | ||
22 | name = "language-web" | ||
23 | } | ||
24 | mavenLayout = true | ||
25 | } | ||
26 | code = { | ||
27 | encoding = "UTF-8" | ||
28 | lineDelimiter = "\n" | ||
29 | fileHeader = "/*\n * generated by Xtext \${version}\n */" | ||
30 | preferXtendStubs = false | ||
31 | } | ||
32 | } | ||
33 | |||
34 | language = StandardLanguage { | ||
35 | name = "org.eclipse.viatra.solver.language.Problem" | ||
36 | fileExtensions = "problem" | ||
37 | referencedResource = "platform:/resource/language-model/model/problem.genmodel" | ||
38 | |||
39 | serializer = { | ||
40 | generateStub = false | ||
41 | } | ||
42 | validator = { | ||
43 | // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator" | ||
44 | // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage | ||
45 | generateDeprecationValidation = true | ||
46 | } | ||
47 | generator = { | ||
48 | generateXtendStub = true | ||
49 | } | ||
50 | junitSupport = { | ||
51 | junitVersion = "5" | ||
52 | } | ||
53 | webSupport = { | ||
54 | framework = "CodeMirror" | ||
55 | suppressPattern = "string_singleQuote" | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext b/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext new file mode 100644 index 00000000..5f8b35f3 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext | |||
@@ -0,0 +1,116 @@ | |||
1 | grammar org.eclipse.viatra.solver.language.Problem with org.eclipse.xtext.common.Terminals | ||
2 | |||
3 | import "http://www.eclipse.org/emf/2002/Ecore" as ecore | ||
4 | import "http://www.eclipse.org/viatra/solver/language/model/Problem" | ||
5 | |||
6 | Problem: | ||
7 | ("problem" name=Identifier ".")? | ||
8 | statements+=Statement*; | ||
9 | |||
10 | Statement: | ||
11 | ClassDeclaration | EnumDeclaration | PredicateDefinition | Assertion | ScopeDeclaration; | ||
12 | |||
13 | ClassDeclaration: | ||
14 | abstract?="abstract"? "class" | ||
15 | name=Identifier | ||
16 | ("extends" superTypes+=[Relation|QualifiedName] ("," superTypes+=[Relation|QualifiedName])*)? | ||
17 | ("{" (referenceDeclarations+=ReferenceDeclaration ";"?)* "}" | "."); | ||
18 | |||
19 | EnumDeclaration: | ||
20 | "enum" | ||
21 | name=Identifier | ||
22 | ("{" (literals+=EnumLiteral ("," literals+=EnumLiteral)* ("," | ";")?)? "}" | "."); | ||
23 | |||
24 | EnumLiteral returns Node: | ||
25 | name=QuotedOrUnquotedId; | ||
26 | |||
27 | ReferenceDeclaration: | ||
28 | (containment?="contains" | "refers")? | ||
29 | referenceType=[Relation|QualifiedName] | ||
30 | ("[" multiplicity=Multiplicity "]")? | ||
31 | name=Identifier | ||
32 | ("opposite" opposite=[ReferenceDeclaration|QualifiedName])?; | ||
33 | |||
34 | PredicateDefinition: | ||
35 | (error?="error" "pred"? | "pred") | ||
36 | name=Identifier | ||
37 | "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" | ||
38 | (":-" bodies+=Conjunction (";" bodies+=Conjunction)*)? | ||
39 | "."; | ||
40 | |||
41 | Parameter: | ||
42 | parameterType=[Relation|QualifiedName]? name=Identifier; | ||
43 | |||
44 | Conjunction: | ||
45 | literals+=Literal ("," literals+=Literal)*; | ||
46 | |||
47 | Literal: | ||
48 | Atom | NegativeLiteral; | ||
49 | |||
50 | NegativeLiteral: | ||
51 | "!" atom=Atom; | ||
52 | |||
53 | Atom: | ||
54 | relation=[Relation|QualifiedName] | ||
55 | transitiveClosure?="+"? | ||
56 | "(" (arguments+=Argument ("," arguments+=Argument)*)? ")"; | ||
57 | |||
58 | Argument: | ||
59 | variableOrNode=[VariableOrNode|QualifiedName]; | ||
60 | |||
61 | Assertion: | ||
62 | (relation=[Relation|QualifiedName] | ||
63 | "(" (arguments+=[Node|QualifiedName] ("," arguments+=[Node|QualifiedName])*)? ")" | ||
64 | ":" value=LogicValue | | ||
65 | value=ShortLogicValue? | ||
66 | relation=[Relation|QualifiedName] | ||
67 | "(" (arguments+=[Node|QualifiedName] ("," arguments+=[Node|QualifiedName])*)? ")") | ||
68 | "."; | ||
69 | |||
70 | enum LogicValue: | ||
71 | TRUE="true" | FALSE="false" | UNKNOWN="unknown"; | ||
72 | |||
73 | enum ShortLogicValue returns LogicValue: | ||
74 | FALSE="!" | UNKNOWN="?"; | ||
75 | |||
76 | ScopeDeclaration: | ||
77 | "scope" typeScopes+=TypeScope ("," typeScopes+=TypeScope)* "."; | ||
78 | |||
79 | TypeScope: | ||
80 | targetType=[ClassDeclaration] | ||
81 | (increment?="+=" | "=") | ||
82 | multiplicity=DefiniteMultiplicity; | ||
83 | |||
84 | Multiplicity: | ||
85 | UnboundedMultiplicity | DefiniteMultiplicity; | ||
86 | |||
87 | DefiniteMultiplicity returns Multiplicity: | ||
88 | RangeMultiplicity | ExactMultiplicity; | ||
89 | |||
90 | UnboundedMultiplicity: | ||
91 | {UnboundedMultiplicity}; | ||
92 | |||
93 | RangeMultiplicity: | ||
94 | lowerBound=INT ".." upperBound=UpperBound; | ||
95 | |||
96 | ExactMultiplicity: | ||
97 | exactValue=INT; | ||
98 | |||
99 | UpperBound returns ecore::EInt: | ||
100 | INT | "*"; | ||
101 | |||
102 | QuotedOrUnquotedId: | ||
103 | QUOTED_ID | Identifier; | ||
104 | |||
105 | QualifiedName: | ||
106 | QUOTED_ID | Identifier (":" Identifier)* (":" QUOTED_ID)?; | ||
107 | |||
108 | Identifier: | ||
109 | ID | "true" | "false"; | ||
110 | |||
111 | @Override | ||
112 | terminal STRING: | ||
113 | '"' ('\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\' | '"'))* '"'; | ||
114 | |||
115 | terminal QUOTED_ID: | ||
116 | "'" ('\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\' | "'"))* "'"; | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/ProblemRuntimeModule.java b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemRuntimeModule.java new file mode 100644 index 00000000..eb9ddd77 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemRuntimeModule.java | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language; | ||
5 | |||
6 | import org.eclipse.viatra.solver.language.conversion.ProblemValueConverterService; | ||
7 | import org.eclipse.viatra.solver.language.naming.ProblemQualifiedNameConverter; | ||
8 | import org.eclipse.viatra.solver.language.resource.ProblemDerivedStateComputer; | ||
9 | import org.eclipse.viatra.solver.language.resource.ProblemLocationInFileProvider; | ||
10 | import org.eclipse.viatra.solver.language.resource.ProblemResourceDescriptionStrategy; | ||
11 | import org.eclipse.viatra.solver.language.scoping.ProblemGlobalScopeProvider; | ||
12 | import org.eclipse.viatra.solver.language.scoping.ProblemLocalScopeProvider; | ||
13 | import org.eclipse.xtext.conversion.IValueConverterService; | ||
14 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
15 | import org.eclipse.xtext.resource.DerivedStateAwareResource; | ||
16 | import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager; | ||
17 | import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; | ||
18 | import org.eclipse.xtext.resource.IDerivedStateComputer; | ||
19 | import org.eclipse.xtext.resource.ILocationInFileProvider; | ||
20 | import org.eclipse.xtext.resource.IResourceDescription; | ||
21 | import org.eclipse.xtext.resource.XtextResource; | ||
22 | import org.eclipse.xtext.scoping.IGlobalScopeProvider; | ||
23 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
24 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | ||
25 | import org.eclipse.xtext.validation.IResourceValidator; | ||
26 | import org.eclipse.xtext.xbase.annotations.validation.DerivedStateAwareResourceValidator; | ||
27 | |||
28 | import com.google.inject.Binder; | ||
29 | import com.google.inject.name.Names; | ||
30 | |||
31 | /** | ||
32 | * Use this class to register components to be used at runtime / without the | ||
33 | * Equinox extension registry. | ||
34 | */ | ||
35 | public class ProblemRuntimeModule extends AbstractProblemRuntimeModule { | ||
36 | public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() { | ||
37 | return ProblemQualifiedNameConverter.class; | ||
38 | } | ||
39 | |||
40 | public Class<? extends IDefaultResourceDescriptionStrategy> bindIDefaultResourceDescriptionStrategy() { | ||
41 | return ProblemResourceDescriptionStrategy.class; | ||
42 | } | ||
43 | |||
44 | @Override | ||
45 | public Class<? extends IValueConverterService> bindIValueConverterService() { | ||
46 | return ProblemValueConverterService.class; | ||
47 | } | ||
48 | |||
49 | @Override | ||
50 | public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() { | ||
51 | return ProblemGlobalScopeProvider.class; | ||
52 | } | ||
53 | |||
54 | @Override | ||
55 | public void configureIScopeProviderDelegate(Binder binder) { | ||
56 | binder.bind(IScopeProvider.class).annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)) | ||
57 | .to(ProblemLocalScopeProvider.class); | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public Class<? extends XtextResource> bindXtextResource() { | ||
62 | return DerivedStateAwareResource.class; | ||
63 | } | ||
64 | |||
65 | public Class<? extends IResourceDescription.Manager> bindIResourceDescription$Manager() { | ||
66 | return DerivedStateAwareResourceDescriptionManager.class; | ||
67 | } | ||
68 | |||
69 | public Class<? extends IResourceValidator> bindIResourceValidator() { | ||
70 | return DerivedStateAwareResourceValidator.class; | ||
71 | } | ||
72 | |||
73 | public Class<? extends IDerivedStateComputer> bindIDerivedStateComputer() { | ||
74 | return ProblemDerivedStateComputer.class; | ||
75 | } | ||
76 | |||
77 | public Class<? extends ILocationInFileProvider> bindILocationInFileProvider() { | ||
78 | return ProblemLocationInFileProvider.class; | ||
79 | } | ||
80 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/ProblemStandaloneSetup.java b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemStandaloneSetup.java new file mode 100644 index 00000000..5652f859 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemStandaloneSetup.java | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language; | ||
5 | |||
6 | import org.eclipse.emf.ecore.EPackage; | ||
7 | import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; | ||
8 | |||
9 | import com.google.inject.Injector; | ||
10 | |||
11 | /** | ||
12 | * Initialization support for running Xtext languages without Equinox extension registry. | ||
13 | */ | ||
14 | public class ProblemStandaloneSetup extends ProblemStandaloneSetupGenerated { | ||
15 | |||
16 | public static void doSetup() { | ||
17 | new ProblemStandaloneSetup().createInjectorAndDoEMFRegistration(); | ||
18 | } | ||
19 | |||
20 | @Override | ||
21 | public Injector createInjectorAndDoEMFRegistration() { | ||
22 | if (!EPackage.Registry.INSTANCE.containsKey(ProblemPackage.eNS_URI)) | ||
23 | EPackage.Registry.INSTANCE.put(ProblemPackage.eNS_URI, ProblemPackage.eINSTANCE); | ||
24 | return super.createInjectorAndDoEMFRegistration(); | ||
25 | } | ||
26 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/ProblemUtil.java b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemUtil.java new file mode 100644 index 00000000..09f062f5 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/ProblemUtil.java | |||
@@ -0,0 +1,98 @@ | |||
1 | package org.eclipse.viatra.solver.language; | ||
2 | |||
3 | import java.util.ArrayDeque; | ||
4 | import java.util.Collection; | ||
5 | import java.util.Deque; | ||
6 | import java.util.HashSet; | ||
7 | import java.util.Optional; | ||
8 | import java.util.Set; | ||
9 | |||
10 | import org.eclipse.emf.ecore.EObject; | ||
11 | import org.eclipse.emf.ecore.resource.Resource; | ||
12 | import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; | ||
13 | import org.eclipse.viatra.solver.language.model.problem.Node; | ||
14 | import org.eclipse.viatra.solver.language.model.problem.Problem; | ||
15 | import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; | ||
16 | import org.eclipse.viatra.solver.language.model.problem.ReferenceDeclaration; | ||
17 | import org.eclipse.viatra.solver.language.model.problem.Relation; | ||
18 | import org.eclipse.viatra.solver.language.model.problem.Variable; | ||
19 | import org.eclipse.viatra.solver.language.scoping.ProblemGlobalScopeProvider; | ||
20 | |||
21 | import com.google.common.collect.ImmutableList; | ||
22 | import com.google.inject.Singleton; | ||
23 | |||
24 | @Singleton | ||
25 | public final class ProblemUtil { | ||
26 | private ProblemUtil() { | ||
27 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
28 | } | ||
29 | |||
30 | public static final String SINGLETON_VARIABLE_PREFIX = "_"; | ||
31 | |||
32 | public static final String ENUM_NODE_NAME_QUOTE = "'"; | ||
33 | |||
34 | public static final String NODE_CLASS_NAME = "node"; | ||
35 | |||
36 | public static boolean isSingletonVariableName(String name) { | ||
37 | return name != null && name.startsWith(SINGLETON_VARIABLE_PREFIX); | ||
38 | } | ||
39 | |||
40 | public static boolean isSingletonVariable(Variable variable) { | ||
41 | return variable.eContainingFeature() == ProblemPackage.Literals.ARGUMENT__SINGLETON_VARIABLE; | ||
42 | } | ||
43 | |||
44 | public static boolean isEnumLiteral(Node node) { | ||
45 | return node.eContainingFeature() == ProblemPackage.Literals.ENUM_DECLARATION__LITERALS; | ||
46 | } | ||
47 | |||
48 | public static boolean isEnumNode(Node node) { | ||
49 | String name = node.getName(); | ||
50 | boolean isNameQuoted = name != null && name.startsWith(ENUM_NODE_NAME_QUOTE) | ||
51 | && name.endsWith(ENUM_NODE_NAME_QUOTE); | ||
52 | return isNameQuoted || isEnumLiteral(node); | ||
53 | } | ||
54 | |||
55 | public static boolean isNewNode(Node node) { | ||
56 | return node.eContainingFeature() == ProblemPackage.Literals.CLASS_DECLARATION__NEW_NODE; | ||
57 | } | ||
58 | |||
59 | public static Optional<Problem> getBuiltInLibrary(EObject context) { | ||
60 | return Optional.ofNullable(context.eResource()).map(Resource::getResourceSet) | ||
61 | .map(resourceSet -> resourceSet.getResource(ProblemGlobalScopeProvider.BULTIN_LIBRARY_URI, true)) | ||
62 | .map(Resource::getContents).filter(contents -> !contents.isEmpty()).map(contents -> contents.get(0)) | ||
63 | .filter(Problem.class::isInstance).map(Problem.class::cast); | ||
64 | } | ||
65 | |||
66 | public static Optional<ClassDeclaration> getNodeClassDeclaration(EObject context) { | ||
67 | return getBuiltInLibrary(context).flatMap(problem -> problem.getStatements().stream() | ||
68 | .filter(ClassDeclaration.class::isInstance).map(ClassDeclaration.class::cast) | ||
69 | .filter(declaration -> NODE_CLASS_NAME.equals(declaration.getName())).findFirst()); | ||
70 | } | ||
71 | |||
72 | public static Collection<ClassDeclaration> getSuperclassesAndSelf(ClassDeclaration classDeclaration) { | ||
73 | Set<ClassDeclaration> found = new HashSet<>(); | ||
74 | getNodeClassDeclaration(classDeclaration).ifPresent(found::add); | ||
75 | Deque<ClassDeclaration> queue = new ArrayDeque<>(); | ||
76 | queue.addLast(classDeclaration); | ||
77 | while (!queue.isEmpty()) { | ||
78 | ClassDeclaration current = queue.removeFirst(); | ||
79 | if (!found.contains(current)) { | ||
80 | found.add(current); | ||
81 | for (Relation superType : current.getSuperTypes()) { | ||
82 | if (superType instanceof ClassDeclaration) { | ||
83 | queue.addLast((ClassDeclaration) superType); | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | return found; | ||
89 | } | ||
90 | |||
91 | public static Collection<ReferenceDeclaration> getAllReferenceDeclarations(ClassDeclaration classDeclaration) { | ||
92 | ImmutableList.Builder<ReferenceDeclaration> builder = ImmutableList.builder(); | ||
93 | for (ClassDeclaration superclass : getSuperclassesAndSelf(classDeclaration)) { | ||
94 | builder.addAll(superclass.getReferenceDeclarations()); | ||
95 | } | ||
96 | return builder.build(); | ||
97 | } | ||
98 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/conversion/ProblemValueConverterService.java b/language/src/main/java/org/eclipse/viatra/solver/language/conversion/ProblemValueConverterService.java new file mode 100644 index 00000000..4f5fd069 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/conversion/ProblemValueConverterService.java | |||
@@ -0,0 +1,17 @@ | |||
1 | package org.eclipse.viatra.solver.language.conversion; | ||
2 | |||
3 | import org.eclipse.xtext.common.services.DefaultTerminalConverters; | ||
4 | import org.eclipse.xtext.conversion.IValueConverter; | ||
5 | import org.eclipse.xtext.conversion.ValueConverter; | ||
6 | |||
7 | import com.google.inject.Inject; | ||
8 | |||
9 | public class ProblemValueConverterService extends DefaultTerminalConverters { | ||
10 | @Inject | ||
11 | private UpperBoundValueConverter upperBoundValueConverter; | ||
12 | |||
13 | @ValueConverter(rule = "UpperBound") | ||
14 | public IValueConverter<Integer> UpperBound() { | ||
15 | return upperBoundValueConverter; | ||
16 | } | ||
17 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/conversion/UpperBoundValueConverter.java b/language/src/main/java/org/eclipse/viatra/solver/language/conversion/UpperBoundValueConverter.java new file mode 100644 index 00000000..3111b69b --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/conversion/UpperBoundValueConverter.java | |||
@@ -0,0 +1,35 @@ | |||
1 | package org.eclipse.viatra.solver.language.conversion; | ||
2 | |||
3 | import org.eclipse.xtext.conversion.ValueConverterException; | ||
4 | import org.eclipse.xtext.conversion.impl.AbstractValueConverter; | ||
5 | import org.eclipse.xtext.conversion.impl.INTValueConverter; | ||
6 | import org.eclipse.xtext.nodemodel.INode; | ||
7 | |||
8 | import com.google.inject.Inject; | ||
9 | import com.google.inject.Singleton; | ||
10 | |||
11 | @Singleton | ||
12 | public class UpperBoundValueConverter extends AbstractValueConverter<Integer> { | ||
13 | public static final String INFINITY = "*"; | ||
14 | |||
15 | @Inject | ||
16 | private INTValueConverter intValueConverter; | ||
17 | |||
18 | @Override | ||
19 | public Integer toValue(String string, INode node) throws ValueConverterException { | ||
20 | if (INFINITY.equals(string)) { | ||
21 | return -1; | ||
22 | } else { | ||
23 | return intValueConverter.toValue(string, node); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString(Integer value) throws ValueConverterException { | ||
29 | if (value < 0) { | ||
30 | return INFINITY; | ||
31 | } else { | ||
32 | return intValueConverter.toString(value); | ||
33 | } | ||
34 | } | ||
35 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend b/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend new file mode 100644 index 00000000..0930f244 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language.generator | ||
5 | |||
6 | import org.eclipse.emf.ecore.resource.Resource | ||
7 | import org.eclipse.xtext.generator.AbstractGenerator | ||
8 | import org.eclipse.xtext.generator.IFileSystemAccess2 | ||
9 | import org.eclipse.xtext.generator.IGeneratorContext | ||
10 | |||
11 | /** | ||
12 | * Generates code from your model files on save. | ||
13 | * | ||
14 | * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation | ||
15 | */ | ||
16 | class ProblemGenerator extends AbstractGenerator { | ||
17 | |||
18 | override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { | ||
19 | // fsa.generateFile('greetings.txt', 'People to greet: ' + | ||
20 | // resource.allContents | ||
21 | // .filter(Greeting) | ||
22 | // .map[name] | ||
23 | // .join(', ')) | ||
24 | } | ||
25 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/naming/ProblemQualifiedNameConverter.java b/language/src/main/java/org/eclipse/viatra/solver/language/naming/ProblemQualifiedNameConverter.java new file mode 100644 index 00000000..3cee31f3 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/naming/ProblemQualifiedNameConverter.java | |||
@@ -0,0 +1,15 @@ | |||
1 | package org.eclipse.viatra.solver.language.naming; | ||
2 | |||
3 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
4 | |||
5 | import com.google.inject.Singleton; | ||
6 | |||
7 | @Singleton | ||
8 | public class ProblemQualifiedNameConverter extends IQualifiedNameConverter.DefaultImpl { | ||
9 | public static final String DELIMITER = ":"; | ||
10 | |||
11 | @Override | ||
12 | public String getDelimiter() { | ||
13 | return DELIMITER; | ||
14 | } | ||
15 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java new file mode 100644 index 00000000..b885ce0e --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java | |||
@@ -0,0 +1,299 @@ | |||
1 | package org.eclipse.viatra.solver.language.resource; | ||
2 | |||
3 | import java.util.HashSet; | ||
4 | import java.util.List; | ||
5 | import java.util.Set; | ||
6 | import java.util.function.Predicate; | ||
7 | import java.util.regex.Pattern; | ||
8 | |||
9 | import org.eclipse.emf.ecore.EObject; | ||
10 | import org.eclipse.emf.ecore.EStructuralFeature; | ||
11 | import org.eclipse.viatra.solver.language.ProblemUtil; | ||
12 | import org.eclipse.viatra.solver.language.model.problem.Argument; | ||
13 | import org.eclipse.viatra.solver.language.model.problem.Assertion; | ||
14 | import org.eclipse.viatra.solver.language.model.problem.Atom; | ||
15 | import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; | ||
16 | import org.eclipse.viatra.solver.language.model.problem.Conjunction; | ||
17 | import org.eclipse.viatra.solver.language.model.problem.ExistentialQuantifier; | ||
18 | import org.eclipse.viatra.solver.language.model.problem.ImplicitVariable; | ||
19 | import org.eclipse.viatra.solver.language.model.problem.Literal; | ||
20 | import org.eclipse.viatra.solver.language.model.problem.NegativeLiteral; | ||
21 | import org.eclipse.viatra.solver.language.model.problem.Node; | ||
22 | import org.eclipse.viatra.solver.language.model.problem.Parameter; | ||
23 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; | ||
24 | import org.eclipse.viatra.solver.language.model.problem.Problem; | ||
25 | import org.eclipse.viatra.solver.language.model.problem.ProblemFactory; | ||
26 | import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; | ||
27 | import org.eclipse.viatra.solver.language.model.problem.Statement; | ||
28 | import org.eclipse.xtext.linking.impl.LinkingHelper; | ||
29 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
30 | import org.eclipse.xtext.naming.QualifiedName; | ||
31 | import org.eclipse.xtext.nodemodel.INode; | ||
32 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils; | ||
33 | import org.eclipse.xtext.resource.DerivedStateAwareResource; | ||
34 | import org.eclipse.xtext.resource.IDerivedStateComputer; | ||
35 | import org.eclipse.xtext.scoping.IScope; | ||
36 | import org.eclipse.xtext.scoping.IScopeProvider; | ||
37 | import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; | ||
38 | |||
39 | import com.google.inject.Inject; | ||
40 | import com.google.inject.Singleton; | ||
41 | import com.google.inject.name.Named; | ||
42 | |||
43 | @Singleton | ||
44 | public class ProblemDerivedStateComputer implements IDerivedStateComputer { | ||
45 | public static final String NEW_NODE = "new"; | ||
46 | |||
47 | private static final Pattern ID_REGEX = Pattern.compile("[_a-zA-Z][_0-9a-zA-Z]*"); | ||
48 | |||
49 | private static final Pattern QUOTED_ID_REGEX = Pattern.compile("'(\\\\.|[^\\'])*'"); | ||
50 | |||
51 | @Inject | ||
52 | private LinkingHelper linkingHelper; | ||
53 | |||
54 | @Inject | ||
55 | private IQualifiedNameConverter qualifiedNameConverter; | ||
56 | |||
57 | @Inject | ||
58 | @Named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE) | ||
59 | private IScopeProvider scopeProvider; | ||
60 | |||
61 | @Override | ||
62 | public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) { | ||
63 | for (EObject object : resource.getContents()) { | ||
64 | if (object instanceof Problem) { | ||
65 | installDerivedProblemState((Problem) object, preLinkingPhase); | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | protected void installDerivedProblemState(Problem problem, boolean preLinkingPhase) { | ||
71 | installNewNodes(problem); | ||
72 | if (!preLinkingPhase) { | ||
73 | installDerivedNodes(problem); | ||
74 | for (Statement statement : problem.getStatements()) { | ||
75 | if (statement instanceof PredicateDefinition) { | ||
76 | PredicateDefinition definition = (PredicateDefinition) statement; | ||
77 | installDerivedPredicateDefinitionState(definition); | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | protected void installNewNodes(Problem problem) { | ||
84 | for (Statement statement : problem.getStatements()) { | ||
85 | if (statement instanceof ClassDeclaration) { | ||
86 | ClassDeclaration declaration = (ClassDeclaration) statement; | ||
87 | if (!declaration.isAbstract()) { | ||
88 | Node newNode = createNode(NEW_NODE); | ||
89 | declaration.setNewNode(newNode); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | protected void installDerivedNodes(Problem problem) { | ||
96 | IScope nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__ARGUMENTS); | ||
97 | Set<String> nodeNames = new HashSet<>(); | ||
98 | for (Statement statement : problem.getStatements()) { | ||
99 | if (statement instanceof Assertion) { | ||
100 | addNodeNames(nodeNames, nodeScope, statement, ProblemPackage.Literals.ASSERTION__ARGUMENTS, | ||
101 | ProblemDerivedStateComputer::validNodeName); | ||
102 | } else if (statement instanceof PredicateDefinition) { | ||
103 | PredicateDefinition predicateDefinition = (PredicateDefinition) statement; | ||
104 | for (Conjunction body : predicateDefinition.getBodies()) { | ||
105 | for (Literal literal : body.getLiterals()) { | ||
106 | Atom atom = null; | ||
107 | if (literal instanceof Atom) { | ||
108 | atom = (Atom) literal; | ||
109 | } else if (literal instanceof NegativeLiteral) { | ||
110 | NegativeLiteral negativeLiteral = (NegativeLiteral) literal; | ||
111 | atom = negativeLiteral.getAtom(); | ||
112 | } | ||
113 | if (atom == null) { | ||
114 | continue; | ||
115 | } | ||
116 | for (Argument argument : atom.getArguments()) { | ||
117 | addNodeNames(nodeNames, nodeScope, argument, | ||
118 | ProblemPackage.Literals.ARGUMENT__VARIABLE_OR_NODE, | ||
119 | ProblemDerivedStateComputer::validQuotedId); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | List<Node> grapNodes = problem.getNodes(); | ||
126 | for (String nodeName : nodeNames) { | ||
127 | Node graphNode = createNode(nodeName); | ||
128 | grapNodes.add(graphNode); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | private void addNodeNames(Set<String> nodeNames, IScope nodeScope, EObject eObject, EStructuralFeature feature, | ||
133 | Predicate<String> condition) { | ||
134 | List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject, feature); | ||
135 | for (INode node : nodes) { | ||
136 | String nodeName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
137 | if (!condition.test(nodeName)) { | ||
138 | continue; | ||
139 | } | ||
140 | QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(nodeName); | ||
141 | if (!nodeNames.contains(nodeName) && nodeScope.getSingleElement(qualifiedName) == null) { | ||
142 | nodeNames.add(nodeName); | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | protected Node createNode(String name) { | ||
148 | Node node = ProblemFactory.eINSTANCE.createNode(); | ||
149 | node.setName(name); | ||
150 | return node; | ||
151 | } | ||
152 | |||
153 | protected void installDerivedPredicateDefinitionState(PredicateDefinition definition) { | ||
154 | Set<String> parameterNames = new HashSet<>(); | ||
155 | for (Parameter parameter : definition.getParameters()) { | ||
156 | String name = parameter.getName(); | ||
157 | if (name != null) { | ||
158 | parameterNames.add(name); | ||
159 | } | ||
160 | } | ||
161 | for (Conjunction body : definition.getBodies()) { | ||
162 | installDeriveConjunctionState(body, parameterNames); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | protected void installDeriveConjunctionState(Conjunction conjunction, Set<String> knownVariables) { | ||
167 | Set<String> newVariables = new HashSet<>(); | ||
168 | for (Literal literal : conjunction.getLiterals()) { | ||
169 | if (literal instanceof Atom) { | ||
170 | Atom atom = (Atom) literal; | ||
171 | createSigletonVariablesAndCollectVariables(atom, knownVariables, newVariables); | ||
172 | } | ||
173 | } | ||
174 | createVariables(conjunction, newVariables); | ||
175 | newVariables.addAll(knownVariables); | ||
176 | for (Literal literal : conjunction.getLiterals()) { | ||
177 | if (literal instanceof NegativeLiteral) { | ||
178 | NegativeLiteral negativeLiteral = (NegativeLiteral) literal; | ||
179 | installDeriveNegativeLiteralState(negativeLiteral, newVariables); | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | protected void installDeriveNegativeLiteralState(NegativeLiteral negativeLiteral, Set<String> knownVariables) { | ||
185 | Set<String> newVariables = new HashSet<>(); | ||
186 | createSigletonVariablesAndCollectVariables(negativeLiteral.getAtom(), knownVariables, newVariables); | ||
187 | createVariables(negativeLiteral, newVariables); | ||
188 | } | ||
189 | |||
190 | protected void createSigletonVariablesAndCollectVariables(Atom atom, Set<String> knownVariables, | ||
191 | Set<String> newVariables) { | ||
192 | IScope scope = scopeProvider.getScope(atom, ProblemPackage.Literals.ARGUMENT__VARIABLE_OR_NODE); | ||
193 | List<INode> nodes = NodeModelUtils.findNodesForFeature(atom, ProblemPackage.Literals.ATOM__ARGUMENTS); | ||
194 | int nodesSize = nodes.size(); | ||
195 | List<Argument> arguments = atom.getArguments(); | ||
196 | int argumentsSize = arguments.size(); | ||
197 | for (int i = 0; i < nodesSize; i++) { | ||
198 | INode node = nodes.get(i); | ||
199 | String variableName = linkingHelper.getCrossRefNodeAsString(node, true); | ||
200 | if (!validId(variableName)) { | ||
201 | continue; | ||
202 | } | ||
203 | QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(variableName); | ||
204 | if (scope.getSingleElement(qualifiedName) != null) { | ||
205 | continue; | ||
206 | } | ||
207 | if (ProblemUtil.isSingletonVariableName(variableName)) { | ||
208 | if (i < argumentsSize) { | ||
209 | createSingletonVariable(arguments.get(i), variableName); | ||
210 | } | ||
211 | continue; | ||
212 | } | ||
213 | if (!knownVariables.contains(variableName)) { | ||
214 | newVariables.add(variableName); | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | protected void createVariables(ExistentialQuantifier quantifier, Set<String> newVariables) { | ||
220 | for (String variableName : newVariables) { | ||
221 | createVariable(quantifier, variableName); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | protected void createVariable(ExistentialQuantifier quantifier, String variableName) { | ||
226 | if (validId(variableName)) { | ||
227 | ImplicitVariable variable = createNamedVariable(variableName); | ||
228 | quantifier.getImplicitVariables().add(variable); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | protected void createSingletonVariable(Argument argument, String variableName) { | ||
233 | if (validId(variableName)) { | ||
234 | ImplicitVariable variable = createNamedVariable(variableName); | ||
235 | argument.setSingletonVariable(variable); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | protected ImplicitVariable createNamedVariable(String variableName) { | ||
240 | ImplicitVariable variable = ProblemFactory.eINSTANCE.createImplicitVariable(); | ||
241 | variable.setName(variableName); | ||
242 | return variable; | ||
243 | } | ||
244 | |||
245 | @Override | ||
246 | public void discardDerivedState(DerivedStateAwareResource resource) { | ||
247 | for (EObject object : resource.getContents()) { | ||
248 | if (object instanceof Problem) { | ||
249 | discardDerivedProblemState((Problem) object); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | protected void discardDerivedProblemState(Problem problem) { | ||
255 | problem.getNodes().clear(); | ||
256 | for (Statement statement : problem.getStatements()) { | ||
257 | if (statement instanceof ClassDeclaration) { | ||
258 | ClassDeclaration classDeclaration = (ClassDeclaration) statement; | ||
259 | classDeclaration.setNewNode(null); | ||
260 | } else if (statement instanceof PredicateDefinition) { | ||
261 | PredicateDefinition definition = (PredicateDefinition) statement; | ||
262 | for (Conjunction body : definition.getBodies()) { | ||
263 | body.getImplicitVariables().clear(); | ||
264 | for (Literal literal : body.getLiterals()) { | ||
265 | if (literal instanceof Atom) { | ||
266 | discardDerivedAtomState((Atom) literal); | ||
267 | } | ||
268 | if (literal instanceof NegativeLiteral) { | ||
269 | NegativeLiteral negativeLiteral = (NegativeLiteral) literal; | ||
270 | negativeLiteral.getImplicitVariables().clear(); | ||
271 | discardDerivedAtomState(negativeLiteral.getAtom()); | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | protected void discardDerivedAtomState(Atom atom) { | ||
280 | if (atom == null) { | ||
281 | return; | ||
282 | } | ||
283 | for (Argument argument : atom.getArguments()) { | ||
284 | argument.setSingletonVariable(null); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | protected static boolean validId(String name) { | ||
289 | return name != null && ID_REGEX.matcher(name).matches(); | ||
290 | } | ||
291 | |||
292 | protected static boolean validQuotedId(String name) { | ||
293 | return name != null && QUOTED_ID_REGEX.matcher(name).matches(); | ||
294 | } | ||
295 | |||
296 | protected static boolean validNodeName(String name) { | ||
297 | return validId(name) || validQuotedId(name); | ||
298 | } | ||
299 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemLocationInFileProvider.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemLocationInFileProvider.java new file mode 100644 index 00000000..94dbdfee --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemLocationInFileProvider.java | |||
@@ -0,0 +1,32 @@ | |||
1 | package org.eclipse.viatra.solver.language.resource; | ||
2 | |||
3 | import org.eclipse.emf.ecore.EObject; | ||
4 | import org.eclipse.viatra.solver.language.ProblemUtil; | ||
5 | import org.eclipse.viatra.solver.language.model.problem.ImplicitVariable; | ||
6 | import org.eclipse.viatra.solver.language.model.problem.Node; | ||
7 | import org.eclipse.xtext.resource.DefaultLocationInFileProvider; | ||
8 | import org.eclipse.xtext.util.ITextRegion; | ||
9 | |||
10 | public class ProblemLocationInFileProvider extends DefaultLocationInFileProvider { | ||
11 | @Override | ||
12 | protected ITextRegion doGetTextRegion(EObject obj, RegionDescription query) { | ||
13 | if (obj instanceof Node) { | ||
14 | return getNodeTextRegion((Node) obj, query); | ||
15 | } | ||
16 | if (obj instanceof ImplicitVariable) { | ||
17 | return ITextRegion.EMPTY_REGION; | ||
18 | } | ||
19 | return super.doGetTextRegion(obj, query); | ||
20 | } | ||
21 | |||
22 | protected ITextRegion getNodeTextRegion(Node node, RegionDescription query) { | ||
23 | if (ProblemUtil.isEnumLiteral(node)) { | ||
24 | return super.doGetTextRegion(node, query); | ||
25 | } | ||
26 | if (ProblemUtil.isNewNode(node)) { | ||
27 | EObject container = node.eContainer(); | ||
28 | return doGetTextRegion(container, query); | ||
29 | } | ||
30 | return ITextRegion.EMPTY_REGION; | ||
31 | } | ||
32 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java new file mode 100644 index 00000000..edb25a1c --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java | |||
@@ -0,0 +1,89 @@ | |||
1 | package org.eclipse.viatra.solver.language.resource; | ||
2 | |||
3 | import org.eclipse.emf.ecore.EObject; | ||
4 | import org.eclipse.viatra.solver.language.ProblemUtil; | ||
5 | import org.eclipse.viatra.solver.language.model.problem.NamedElement; | ||
6 | import org.eclipse.viatra.solver.language.model.problem.Node; | ||
7 | import org.eclipse.viatra.solver.language.model.problem.Problem; | ||
8 | import org.eclipse.viatra.solver.language.model.problem.Variable; | ||
9 | import org.eclipse.xtext.EcoreUtil2; | ||
10 | import org.eclipse.xtext.naming.IQualifiedNameConverter; | ||
11 | import org.eclipse.xtext.naming.QualifiedName; | ||
12 | import org.eclipse.xtext.resource.EObjectDescription; | ||
13 | import org.eclipse.xtext.resource.IEObjectDescription; | ||
14 | import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionStrategy; | ||
15 | import org.eclipse.xtext.util.IAcceptor; | ||
16 | |||
17 | import com.google.inject.Inject; | ||
18 | import com.google.inject.Singleton; | ||
19 | |||
20 | @Singleton | ||
21 | public class ProblemResourceDescriptionStrategy extends DefaultResourceDescriptionStrategy { | ||
22 | @Inject | ||
23 | private IQualifiedNameConverter qualifiedNameConverter; | ||
24 | |||
25 | @Override | ||
26 | public boolean createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) { | ||
27 | if (eObject instanceof Variable) { | ||
28 | return false; | ||
29 | } | ||
30 | if (eObject instanceof NamedElement) { | ||
31 | NamedElement namedElement = (NamedElement) eObject; | ||
32 | String name = namedElement.getName(); | ||
33 | if (name == null || name.isEmpty()) { | ||
34 | return true; | ||
35 | } | ||
36 | Problem problem = EcoreUtil2.getContainerOfType(namedElement, Problem.class); | ||
37 | QualifiedName problemQualifiedName = null; | ||
38 | if (problem != null) { | ||
39 | String problemName = problem.getName(); | ||
40 | if (problemName != null && !problemName.isEmpty()) { | ||
41 | problemQualifiedName = qualifiedNameConverter.toQualifiedName(problemName); | ||
42 | } | ||
43 | } | ||
44 | QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(namedElement.getName()); | ||
45 | boolean nameExported; | ||
46 | if (shouldExportSimpleName(namedElement)) { | ||
47 | acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); | ||
48 | nameExported = true; | ||
49 | } else { | ||
50 | nameExported = false; | ||
51 | } | ||
52 | EObject parent = namedElement.eContainer(); | ||
53 | while (parent != null && parent != problem) { | ||
54 | if (parent instanceof NamedElement) { | ||
55 | NamedElement namedParent = (NamedElement) parent; | ||
56 | String parentName = namedParent.getName(); | ||
57 | if (parentName != null || !name.isEmpty()) { | ||
58 | QualifiedName parentQualifiedName = qualifiedNameConverter.toQualifiedName(parentName); | ||
59 | qualifiedName = parentQualifiedName.append(qualifiedName); | ||
60 | if (shouldExportSimpleName(parent)) { | ||
61 | acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); | ||
62 | nameExported = true; | ||
63 | } else { | ||
64 | nameExported = false; | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | parent = parent.eContainer(); | ||
69 | } | ||
70 | if (!nameExported) { | ||
71 | acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); | ||
72 | } | ||
73 | } | ||
74 | return true; | ||
75 | } | ||
76 | |||
77 | protected boolean shouldExportSimpleName(EObject eObject) { | ||
78 | if (eObject instanceof Node) { | ||
79 | return !ProblemUtil.isNewNode((Node) eObject); | ||
80 | } | ||
81 | return true; | ||
82 | } | ||
83 | |||
84 | private void acceptEObjectDescription(EObject eObject, QualifiedName prefix, QualifiedName qualifiedName, | ||
85 | IAcceptor<IEObjectDescription> acceptor) { | ||
86 | QualifiedName qualifiedNameWithPrefix = prefix == null ? qualifiedName : prefix.append(qualifiedName); | ||
87 | acceptor.accept(EObjectDescription.create(qualifiedNameWithPrefix, eObject)); | ||
88 | } | ||
89 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemGlobalScopeProvider.java b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemGlobalScopeProvider.java new file mode 100644 index 00000000..05da277a --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemGlobalScopeProvider.java | |||
@@ -0,0 +1,25 @@ | |||
1 | package org.eclipse.viatra.solver.language.scoping; | ||
2 | |||
3 | import java.util.LinkedHashSet; | ||
4 | |||
5 | import org.eclipse.emf.common.util.URI; | ||
6 | import org.eclipse.emf.ecore.resource.Resource; | ||
7 | import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider; | ||
8 | |||
9 | public class ProblemGlobalScopeProvider extends ImportUriGlobalScopeProvider { | ||
10 | public static final String BUILTIN_LIBRARY_NAME = "builtin"; | ||
11 | |||
12 | public static final URI BULTIN_LIBRARY_URI = getLibraryUri(BUILTIN_LIBRARY_NAME); | ||
13 | |||
14 | @Override | ||
15 | protected LinkedHashSet<URI> getImportedUris(Resource resource) { | ||
16 | LinkedHashSet<URI> importedUris = new LinkedHashSet<>(); | ||
17 | importedUris.add(BULTIN_LIBRARY_URI); | ||
18 | return importedUris; | ||
19 | } | ||
20 | |||
21 | private static URI getLibraryUri(String libraryName) { | ||
22 | return URI.createURI(ProblemGlobalScopeProvider.class.getClassLoader() | ||
23 | .getResource("org/eclipse/viatra/solver/language/" + libraryName + ".problem").toString()); | ||
24 | } | ||
25 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemLocalScopeProvider.java b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemLocalScopeProvider.java new file mode 100644 index 00000000..e832bb09 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemLocalScopeProvider.java | |||
@@ -0,0 +1,40 @@ | |||
1 | package org.eclipse.viatra.solver.language.scoping; | ||
2 | |||
3 | import java.util.List; | ||
4 | |||
5 | import org.eclipse.emf.ecore.EObject; | ||
6 | import org.eclipse.emf.ecore.resource.Resource; | ||
7 | import org.eclipse.xtext.naming.QualifiedName; | ||
8 | import org.eclipse.xtext.resource.IResourceDescriptions; | ||
9 | import org.eclipse.xtext.resource.IResourceDescriptionsProvider; | ||
10 | import org.eclipse.xtext.resource.ISelectable; | ||
11 | import org.eclipse.xtext.scoping.impl.ImportNormalizer; | ||
12 | import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider; | ||
13 | |||
14 | import com.google.inject.Inject; | ||
15 | |||
16 | public class ProblemLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { | ||
17 | private static final QualifiedName BUILTIN_LIBRARY_QUALIFIED_NAME = QualifiedName | ||
18 | .create(ProblemGlobalScopeProvider.BUILTIN_LIBRARY_NAME); | ||
19 | |||
20 | @Inject | ||
21 | private IResourceDescriptionsProvider resourceDescriptionsProvider; | ||
22 | |||
23 | @Override | ||
24 | protected List<ImportNormalizer> getImplicitImports(boolean ignoreCase) { | ||
25 | return List.of(doCreateImportNormalizer(BUILTIN_LIBRARY_QUALIFIED_NAME, true, ignoreCase)); | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | protected List<ImportNormalizer> getImportedNamespaceResolvers(EObject context, boolean ignoreCase) { | ||
30 | return List.of(); | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | protected ISelectable internalGetAllDescriptions(Resource resource) { | ||
35 | // Force the use of ProblemResourceDescriptionStrategy to include all QualifiedNames of objects. | ||
36 | IResourceDescriptions resourceDescriptions = resourceDescriptionsProvider | ||
37 | .getResourceDescriptions(resource.getResourceSet()); | ||
38 | return resourceDescriptions.getResourceDescription(resource.getURI()); | ||
39 | } | ||
40 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java new file mode 100644 index 00000000..fc4034ae --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language.scoping; | ||
5 | |||
6 | import java.util.ArrayList; | ||
7 | import java.util.Collection; | ||
8 | import java.util.List; | ||
9 | |||
10 | import org.eclipse.emf.ecore.EObject; | ||
11 | import org.eclipse.emf.ecore.EReference; | ||
12 | import org.eclipse.viatra.solver.language.ProblemUtil; | ||
13 | import org.eclipse.viatra.solver.language.model.problem.Argument; | ||
14 | import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; | ||
15 | import org.eclipse.viatra.solver.language.model.problem.ExistentialQuantifier; | ||
16 | import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; | ||
17 | import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; | ||
18 | import org.eclipse.viatra.solver.language.model.problem.ReferenceDeclaration; | ||
19 | import org.eclipse.viatra.solver.language.model.problem.Relation; | ||
20 | import org.eclipse.viatra.solver.language.model.problem.Variable; | ||
21 | import org.eclipse.xtext.EcoreUtil2; | ||
22 | import org.eclipse.xtext.scoping.IScope; | ||
23 | import org.eclipse.xtext.scoping.Scopes; | ||
24 | |||
25 | /** | ||
26 | * This class contains custom scoping description. | ||
27 | * | ||
28 | * See | ||
29 | * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping | ||
30 | * on how and when to use it. | ||
31 | */ | ||
32 | public class ProblemScopeProvider extends AbstractProblemScopeProvider { | ||
33 | |||
34 | @Override | ||
35 | public IScope getScope(EObject context, EReference reference) { | ||
36 | IScope scope = super.getScope(context, reference); | ||
37 | if (reference == ProblemPackage.Literals.ARGUMENT__VARIABLE_OR_NODE) { | ||
38 | return getVariableScope(context, scope); | ||
39 | } else if (reference == ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE) { | ||
40 | return getOppositeScope(context, scope); | ||
41 | } | ||
42 | return scope; | ||
43 | } | ||
44 | |||
45 | protected IScope getVariableScope(EObject context, IScope delegateScope) { | ||
46 | List<Variable> variables = new ArrayList<>(); | ||
47 | EObject currentContext = context; | ||
48 | if (context instanceof Argument) { | ||
49 | Argument argument = (Argument) context; | ||
50 | Variable singletonVariable = argument.getSingletonVariable(); | ||
51 | if (singletonVariable != null) { | ||
52 | variables.add(singletonVariable); | ||
53 | } | ||
54 | } | ||
55 | while (currentContext != null && !(currentContext instanceof PredicateDefinition)) { | ||
56 | if (currentContext instanceof ExistentialQuantifier) { | ||
57 | ExistentialQuantifier quantifier = (ExistentialQuantifier) currentContext; | ||
58 | variables.addAll(quantifier.getImplicitVariables()); | ||
59 | } | ||
60 | currentContext = currentContext.eContainer(); | ||
61 | } | ||
62 | if (currentContext instanceof PredicateDefinition) { | ||
63 | PredicateDefinition definition = (PredicateDefinition) currentContext; | ||
64 | variables.addAll(definition.getParameters()); | ||
65 | } | ||
66 | return Scopes.scopeFor(variables, delegateScope); | ||
67 | } | ||
68 | |||
69 | protected IScope getOppositeScope(EObject context, IScope delegateScope) { | ||
70 | ReferenceDeclaration referenceDeclaration = EcoreUtil2.getContainerOfType(context, ReferenceDeclaration.class); | ||
71 | if (referenceDeclaration == null) { | ||
72 | return delegateScope; | ||
73 | } | ||
74 | Relation relation = referenceDeclaration.getReferenceType(); | ||
75 | if (!(relation instanceof ClassDeclaration)) { | ||
76 | return delegateScope; | ||
77 | } | ||
78 | ClassDeclaration classDeclaration = (ClassDeclaration) relation; | ||
79 | Collection<ReferenceDeclaration> referenceDeclarations = ProblemUtil | ||
80 | .getAllReferenceDeclarations(classDeclaration); | ||
81 | return Scopes.scopeFor(referenceDeclarations, delegateScope); | ||
82 | } | ||
83 | } | ||
diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/validation/ProblemValidator.java b/language/src/main/java/org/eclipse/viatra/solver/language/validation/ProblemValidator.java new file mode 100644 index 00000000..2b17e222 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/validation/ProblemValidator.java | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * generated by Xtext 2.25.0 | ||
3 | */ | ||
4 | package org.eclipse.viatra.solver.language.validation; | ||
5 | |||
6 | |||
7 | /** | ||
8 | * This class contains custom validation rules. | ||
9 | * | ||
10 | * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation | ||
11 | */ | ||
12 | public class ProblemValidator extends AbstractProblemValidator { | ||
13 | |||
14 | // public static final String INVALID_NAME = "invalidName"; | ||
15 | // | ||
16 | // @Check | ||
17 | // public void checkGreetingStartsWithCapital(Greeting greeting) { | ||
18 | // if (!Character.isUpperCase(greeting.getName().charAt(0))) { | ||
19 | // warning("Name should start with a capital", | ||
20 | // ProblemPackage.Literals.GREETING__NAME, | ||
21 | // INVALID_NAME); | ||
22 | // } | ||
23 | // } | ||
24 | |||
25 | } | ||