aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language/src/main/java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-05 18:54:46 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-06 01:50:23 +0100
commit1ae461bd5319370e12878785d9c7ec9f89429406 (patch)
treea18797b520369a7f40ee13988308de67c66e046d /subprojects/language/src/main/java
parentRevert "refactor: simplify module name inference" (diff)
downloadrefinery-1ae461bd5319370e12878785d9c7ec9f89429406.tar.gz
refinery-1ae461bd5319370e12878785d9c7ec9f89429406.tar.zst
refinery-1ae461bd5319370e12878785d9c7ec9f89429406.zip
feat(language): automatic problem kind inference
Diffstat (limited to 'subprojects/language/src/main/java')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe22
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java19
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java3
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/parser/ProblemEcoreElementFactory.java48
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResource.java24
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollector.java40
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/serializer/ProblemTransientValueService.java25
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java15
10 files changed, 160 insertions, 28 deletions
diff --git a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
index 863e55d4..46ac18fe 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
+++ b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
@@ -51,7 +51,7 @@ Workflow {
51 51
52 language = StandardLanguage { 52 language = StandardLanguage {
53 name = 'tools.refinery.language.Problem' 53 name = 'tools.refinery.language.Problem'
54 fileExtensions = 'refinery,problem' 54 fileExtensions = 'problem,refinery'
55 referencedResource = 'platform:/resource/tools.refinery.refinery-language-model/model/problem.genmodel' 55 referencedResource = 'platform:/resource/tools.refinery.refinery-language-model/model/problem.genmodel'
56 serializer = { 56 serializer = {
57 generateStub = false 57 generateStub = false
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 a846e265..f9a564b0 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
@@ -15,7 +15,9 @@ import org.eclipse.xtext.conversion.IValueConverterService;
15import org.eclipse.xtext.linking.ILinkingService; 15import org.eclipse.xtext.linking.ILinkingService;
16import org.eclipse.xtext.naming.IQualifiedNameConverter; 16import org.eclipse.xtext.naming.IQualifiedNameConverter;
17import org.eclipse.xtext.naming.IQualifiedNameProvider; 17import org.eclipse.xtext.naming.IQualifiedNameProvider;
18import org.eclipse.xtext.parser.IAstFactory;
18import org.eclipse.xtext.parser.IParser; 19import org.eclipse.xtext.parser.IParser;
20import org.eclipse.xtext.parsetree.reconstr.ITransientValueService;
19import org.eclipse.xtext.resource.*; 21import org.eclipse.xtext.resource.*;
20import org.eclipse.xtext.scoping.IGlobalScopeProvider; 22import org.eclipse.xtext.scoping.IGlobalScopeProvider;
21import org.eclipse.xtext.scoping.IScopeProvider; 23import org.eclipse.xtext.scoping.IScopeProvider;
@@ -30,13 +32,18 @@ import tools.refinery.language.linking.ProblemLinkingService;
30import tools.refinery.language.naming.ProblemDelegateQualifiedNameProvider; 32import tools.refinery.language.naming.ProblemDelegateQualifiedNameProvider;
31import tools.refinery.language.naming.ProblemQualifiedNameConverter; 33import tools.refinery.language.naming.ProblemQualifiedNameConverter;
32import tools.refinery.language.naming.ProblemQualifiedNameProvider; 34import tools.refinery.language.naming.ProblemQualifiedNameProvider;
35import tools.refinery.language.parser.ProblemEcoreElementFactory;
33import tools.refinery.language.parser.antlr.TokenSourceInjectingProblemParser; 36import tools.refinery.language.parser.antlr.TokenSourceInjectingProblemParser;
34import tools.refinery.language.resource.*; 37import tools.refinery.language.resource.ProblemLocationInFileProvider;
38import tools.refinery.language.resource.ProblemResource;
39import tools.refinery.language.resource.ProblemResourceDescriptionManager;
40import tools.refinery.language.resource.ProblemResourceDescriptionStrategy;
35import tools.refinery.language.resource.state.ProblemDerivedStateComputer; 41import tools.refinery.language.resource.state.ProblemDerivedStateComputer;
36import tools.refinery.language.scoping.ProblemGlobalScopeProvider; 42import tools.refinery.language.scoping.ProblemGlobalScopeProvider;
37import tools.refinery.language.scoping.ProblemLocalScopeProvider; 43import tools.refinery.language.scoping.ProblemLocalScopeProvider;
38import tools.refinery.language.serializer.PreferShortAssertionsProblemSemanticSequencer; 44import tools.refinery.language.serializer.PreferShortAssertionsProblemSemanticSequencer;
39import tools.refinery.language.serializer.ProblemCrossReferenceSerializer; 45import tools.refinery.language.serializer.ProblemCrossReferenceSerializer;
46import tools.refinery.language.serializer.ProblemTransientValueService;
40import tools.refinery.language.validation.ProblemDiagnosticConverter; 47import tools.refinery.language.validation.ProblemDiagnosticConverter;
41 48
42/** 49/**
@@ -51,6 +58,11 @@ public class ProblemRuntimeModule extends AbstractProblemRuntimeModule {
51 return TokenSourceInjectingProblemParser.class; 58 return TokenSourceInjectingProblemParser.class;
52 } 59 }
53 60
61 @Override
62 public Class<? extends IAstFactory> bindIAstFactory() {
63 return ProblemEcoreElementFactory.class;
64 }
65
54 public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() { 66 public Class<? extends IQualifiedNameConverter> bindIQualifiedNameConverter() {
55 return ProblemQualifiedNameConverter.class; 67 return ProblemQualifiedNameConverter.class;
56 } 68 }
@@ -116,6 +128,11 @@ public class ProblemRuntimeModule extends AbstractProblemRuntimeModule {
116 } 128 }
117 129
118 @Override 130 @Override
131 public Class<? extends ITransientValueService> bindITransientValueService() {
132 return ProblemTransientValueService.class;
133 }
134
135 @Override
119 public Class<? extends ISemanticSequencer> bindISemanticSequencer() { 136 public Class<? extends ISemanticSequencer> bindISemanticSequencer() {
120 return PreferShortAssertionsProblemSemanticSequencer.class; 137 return PreferShortAssertionsProblemSemanticSequencer.class;
121 } 138 }
diff --git a/subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java b/subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java
index 4b748c64..3a9bb920 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java
@@ -59,7 +59,7 @@ public abstract class ClasspathBasedLibrary implements RefineryLibrary {
59 } 59 }
60 int rootSegmentCount = rootUri.segmentCount(); 60 int rootSegmentCount = rootUri.segmentCount();
61 int uriSegmentCount = uri.segmentCount(); 61 int uriSegmentCount = uri.segmentCount();
62 if (!uri.segment(uriSegmentCount - 1).endsWith(RefineryLibrary.EXTENSION)) { 62 if (!uri.segment(uriSegmentCount - 1).endsWith(RefineryLibrary.FILE_NAME_SUFFIX)) {
63 return Optional.empty(); 63 return Optional.empty();
64 } 64 }
65 var segments = new ArrayList<String>(); 65 var segments = new ArrayList<String>();
@@ -73,7 +73,7 @@ public abstract class ClasspathBasedLibrary implements RefineryLibrary {
73 while (i < uriSegmentCount) { 73 while (i < uriSegmentCount) {
74 var segment = uri.segment(i); 74 var segment = uri.segment(i);
75 if (i == uriSegmentCount - 1) { 75 if (i == uriSegmentCount - 1) {
76 segment = segment.substring(0, segment.length() - RefineryLibrary.EXTENSION.length()); 76 segment = segment.substring(0, segment.length() - RefineryLibrary.FILE_NAME_SUFFIX.length());
77 } 77 }
78 segments.add(segment); 78 segments.add(segment);
79 i++; 79 i++;
@@ -88,7 +88,7 @@ public abstract class ClasspathBasedLibrary implements RefineryLibrary {
88 public static Optional<URI> getLibraryUri(Class<?> context, QualifiedName qualifiedName) { 88 public static Optional<URI> getLibraryUri(Class<?> context, QualifiedName qualifiedName) {
89 var packagePath = context.getPackageName().replace('.', '/'); 89 var packagePath = context.getPackageName().replace('.', '/');
90 var libraryPath = String.join("/", qualifiedName.getSegments()); 90 var libraryPath = String.join("/", qualifiedName.getSegments());
91 var resourceName = "%s/%s%s".formatted(packagePath, libraryPath, RefineryLibrary.EXTENSION); 91 var resourceName = "%s/%s%s".formatted(packagePath, libraryPath, RefineryLibrary.FILE_NAME_SUFFIX);
92 var resource = context.getClassLoader().getResource(resourceName); 92 var resource = context.getClassLoader().getResource(resourceName);
93 if (resource == null) { 93 if (resource == null) {
94 return Optional.empty(); 94 return Optional.empty();
diff --git a/subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java b/subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java
index c6f994df..8eaf8458 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java
@@ -41,7 +41,7 @@ public final class PathLibrary implements RefineryLibrary {
41 for (var i = 0; i < segmentCount; i++) { 41 for (var i = 0; i < segmentCount; i++) {
42 var segment = qualifiedName.getSegment(i); 42 var segment = qualifiedName.getSegment(i);
43 if (i == segmentCount - 1) { 43 if (i == segmentCount - 1) {
44 segment = segment + RefineryLibrary.EXTENSION; 44 segment = segment + RefineryLibrary.FILE_NAME_SUFFIX;
45 } 45 }
46 if (i == 0) { 46 if (i == 0) {
47 first = segment; 47 first = segment;
@@ -80,10 +80,10 @@ public final class PathLibrary implements RefineryLibrary {
80 } 80 }
81 int lastIndex = segments.size() - 1; 81 int lastIndex = segments.size() - 1;
82 var lastSegment = segments.get(lastIndex); 82 var lastSegment = segments.get(lastIndex);
83 if (!lastSegment.endsWith(EXTENSION)) { 83 if (!lastSegment.endsWith(FILE_NAME_SUFFIX)) {
84 return Optional.empty(); 84 return Optional.empty();
85 } 85 }
86 lastSegment = lastSegment.substring(0, lastSegment.length() - RefineryLibrary.EXTENSION.length()); 86 lastSegment = lastSegment.substring(0, lastSegment.length() - RefineryLibrary.FILE_NAME_SUFFIX.length());
87 segments.set(lastIndex, lastSegment); 87 segments.set(lastIndex, lastSegment);
88 return Optional.of(QualifiedName.create(segments)); 88 return Optional.of(QualifiedName.create(segments));
89 } 89 }
diff --git a/subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java b/subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java
index e1f8d7bc..2559749a 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java
@@ -7,13 +7,14 @@ package tools.refinery.language.library;
7 7
8import org.eclipse.emf.common.util.URI; 8import org.eclipse.emf.common.util.URI;
9import org.eclipse.xtext.naming.QualifiedName; 9import org.eclipse.xtext.naming.QualifiedName;
10import tools.refinery.language.utils.ProblemUtil;
10 11
11import java.nio.file.Path; 12import java.nio.file.Path;
12import java.util.List; 13import java.util.List;
13import java.util.Optional; 14import java.util.Optional;
14 15
15public interface RefineryLibrary { 16public interface RefineryLibrary {
16 String EXTENSION = ".refinery"; 17 String FILE_NAME_SUFFIX = "." + ProblemUtil.MODULE_EXTENSION;
17 18
18 default List<QualifiedName> getAutomaticImports() { 19 default List<QualifiedName> getAutomaticImports() {
19 return List.of(); 20 return List.of();
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/ProblemEcoreElementFactory.java b/subprojects/language/src/main/java/tools/refinery/language/parser/ProblemEcoreElementFactory.java
new file mode 100644
index 00000000..b54c6970
--- /dev/null
+++ b/subprojects/language/src/main/java/tools/refinery/language/parser/ProblemEcoreElementFactory.java
@@ -0,0 +1,48 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.parser;
7
8import org.eclipse.emf.common.notify.impl.AdapterImpl;
9import org.eclipse.emf.ecore.EObject;
10import org.eclipse.emf.ecore.util.EcoreUtil;
11import org.eclipse.xtext.conversion.ValueConverterException;
12import org.eclipse.xtext.nodemodel.INode;
13import org.eclipse.xtext.parser.DefaultEcoreElementFactory;
14import tools.refinery.language.model.problem.Problem;
15import tools.refinery.language.model.problem.ProblemPackage;
16
17public class ProblemEcoreElementFactory extends DefaultEcoreElementFactory {
18 @Override
19 public void set(
20 EObject object, String feature, Object value, String ruleName, INode node) throws ValueConverterException {
21 super.set(object, feature, value, ruleName, node);
22 if (object instanceof Problem problem && ProblemPackage.Literals.PROBLEM__KIND.getName().equals(feature)) {
23 ExplicitAssignmentTracker.install(problem);
24 }
25 }
26
27 public static boolean hasExplicitlySetProblemKind(Problem problem) {
28 return ExplicitAssignmentTracker.hasAdapter(problem);
29 }
30
31 private static class ExplicitAssignmentTracker extends AdapterImpl {
32 @Override
33 public boolean isAdapterForType(Object type) {
34 return type == ExplicitAssignmentTracker.class;
35 }
36
37 public static boolean hasAdapter(Problem problem) {
38 return EcoreUtil.getAdapter(problem.eAdapters(), ExplicitAssignmentTracker.class) != null;
39 }
40
41 public static void install(Problem problem) {
42 if (hasAdapter(problem)) {
43 throw new IllegalStateException("Duplicate explicit assignment of module kind");
44 }
45 problem.eAdapters().add(new ExplicitAssignmentTracker());
46 }
47 }
48}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResource.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResource.java
index 43239ffe..57b7bb45 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResource.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResource.java
@@ -20,9 +20,13 @@ import org.eclipse.xtext.linking.impl.IllegalNodeException;
20import org.eclipse.xtext.linking.impl.XtextLinkingDiagnostic; 20import org.eclipse.xtext.linking.impl.XtextLinkingDiagnostic;
21import org.eclipse.xtext.linking.lazy.LazyLinkingResource; 21import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
22import org.eclipse.xtext.nodemodel.INode; 22import org.eclipse.xtext.nodemodel.INode;
23import org.eclipse.xtext.parser.IParseResult;
23import org.eclipse.xtext.resource.DerivedStateAwareResource; 24import org.eclipse.xtext.resource.DerivedStateAwareResource;
24import org.eclipse.xtext.util.Triple; 25import org.eclipse.xtext.util.Triple;
25import org.jetbrains.annotations.Nullable; 26import org.jetbrains.annotations.Nullable;
27import tools.refinery.language.model.problem.Problem;
28import tools.refinery.language.parser.ProblemEcoreElementFactory;
29import tools.refinery.language.utils.ProblemUtil;
26 30
27import java.util.Arrays; 31import java.util.Arrays;
28import java.util.List; 32import java.util.List;
@@ -40,6 +44,26 @@ public class ProblemResource extends DerivedStateAwareResource {
40 */ 44 */
41 private int cyclicLinkingDetectionCounter = 0; 45 private int cyclicLinkingDetectionCounter = 0;
42 46
47 @Override
48 protected void updateInternalState(IParseResult oldParseResult, IParseResult newParseResult) {
49 if (isNewRootElement(oldParseResult, newParseResult) &&
50 newParseResult.getRootASTElement() instanceof Problem newRootProblem &&
51 !ProblemEcoreElementFactory.hasExplicitlySetProblemKind(newRootProblem)) {
52 var defaultModuleKind = ProblemUtil.getDefaultModuleKind(getURI());
53 newRootProblem.setKind(defaultModuleKind);
54 }
55 super.updateInternalState(oldParseResult, newParseResult);
56 }
57
58 private boolean isNewRootElement(IParseResult oldParseResult, IParseResult newParseResult) {
59 if (oldParseResult == null) {
60 return true;
61 }
62 var oldRootAstElement = oldParseResult.getRootASTElement();
63 var newRootAstElement = newParseResult.getRootASTElement();
64 return oldRootAstElement != newRootAstElement;
65 }
66
43 /** 67 /**
44 * Tries to resolve a reference and emits a diagnostic if the reference is unresolvable or ambiguous. 68 * Tries to resolve a reference and emits a diagnostic if the reference is unresolvable or ambiguous.
45 * <p> 69 * <p>
diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollector.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollector.java
index 6cdfa63e..fc4ca43c 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollector.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollector.java
@@ -11,6 +11,7 @@ import com.google.inject.Inject;
11import com.google.inject.Provider; 11import com.google.inject.Provider;
12import com.google.inject.Singleton; 12import com.google.inject.Singleton;
13import org.eclipse.emf.common.util.URI; 13import org.eclipse.emf.common.util.URI;
14import org.eclipse.emf.ecore.EObject;
14import org.eclipse.emf.ecore.resource.Resource; 15import org.eclipse.emf.ecore.resource.Resource;
15import org.eclipse.xtext.linking.impl.LinkingHelper; 16import org.eclipse.xtext.linking.impl.LinkingHelper;
16import org.eclipse.xtext.naming.IQualifiedNameConverter; 17import org.eclipse.xtext.naming.IQualifiedNameConverter;
@@ -57,16 +58,10 @@ public class ImportCollector {
57 if (resourceSet == null) { 58 if (resourceSet == null) {
58 return ImportCollection.EMPTY; 59 return ImportCollection.EMPTY;
59 } 60 }
60 Map<QualifiedName, Set<QualifiedName>> aliasesMap = new LinkedHashMap<>();
61 for (var statement : problem.getStatements()) {
62 if (statement instanceof ImportStatement importStatement) {
63 collectImportStatement(importStatement, aliasesMap);
64 }
65 }
66 var adapter = ImportAdapter.getOrInstall(resourceSet); 61 var adapter = ImportAdapter.getOrInstall(resourceSet);
67 var collection = new ImportCollection(); 62 var collection = new ImportCollection();
68 collectAutomaticImports(collection, adapter); 63 collectAutomaticImports(collection, adapter);
69 collectExplicitImports(aliasesMap, collection, adapter); 64 collectExplicitImports(problem, collection, adapter);
70 collection.remove(resource.getURI()); 65 collection.remove(resource.getURI());
71 return collection; 66 return collection;
72 } 67 }
@@ -82,25 +77,30 @@ public class ImportCollector {
82 } 77 }
83 } 78 }
84 79
85 private void collectExplicitImports(Map<QualifiedName, Set<QualifiedName>> aliasesMap, 80 private void collectExplicitImports(Problem problem, ImportCollection collection, ImportAdapter adapter) {
86 ImportCollection collection, ImportAdapter adapter) { 81 for (var statement : problem.getStatements()) {
87 for (var entry : aliasesMap.entrySet()) { 82 if (statement instanceof ImportStatement importStatement) {
88 var qualifiedName = entry.getKey(); 83 collectImportStatement(importStatement, collection, adapter);
89 var uri = adapter.resolveQualifiedName(qualifiedName);
90 if (uri != null) {
91 var aliases = entry.getValue();
92 collection.add(NamedImport.explicit(uri, qualifiedName, List.copyOf(aliases)));
93 } 84 }
94 } 85 }
95 } 86 }
96 87
97 private void collectImportStatement(ImportStatement importStatement, 88 private void collectImportStatement(ImportStatement importStatement, ImportCollection collection,
98 Map<QualifiedName, Set<QualifiedName>> aliasesMap) { 89 ImportAdapter adapter) {
99 var nodes = NodeModelUtils.findNodesForFeature(importStatement, 90 var nodes = NodeModelUtils.findNodesForFeature(importStatement,
100 ProblemPackage.Literals.IMPORT_STATEMENT__IMPORTED_MODULE); 91 ProblemPackage.Literals.IMPORT_STATEMENT__IMPORTED_MODULE);
101 var aliasString = importStatement.getAlias(); 92 var aliasString = importStatement.getAlias();
102 var alias = Strings.isNullOrEmpty(aliasString) ? QualifiedName.EMPTY : 93 var alias = Strings.isNullOrEmpty(aliasString) ? QualifiedName.EMPTY :
103 NamingUtil.stripRootPrefix(qualifiedNameConverter.toQualifiedName(aliasString)); 94 NamingUtil.stripRootPrefix(qualifiedNameConverter.toQualifiedName(aliasString));
95 var referredProblem = (EObject) importStatement.eGet(ProblemPackage.Literals.IMPORT_STATEMENT__IMPORTED_MODULE,
96 false);
97 URI referencedUri = null;
98 if (referredProblem != null && !referredProblem.eIsProxy()) {
99 var resource = referredProblem.eResource();
100 if (resource != null) {
101 referencedUri = resource.getURI();
102 }
103 }
104 for (var node : nodes) { 104 for (var node : nodes) {
105 var qualifiedNameString = linkingHelper.getCrossRefNodeAsString(node, true); 105 var qualifiedNameString = linkingHelper.getCrossRefNodeAsString(node, true);
106 if (Strings.isNullOrEmpty(qualifiedNameString)) { 106 if (Strings.isNullOrEmpty(qualifiedNameString)) {
@@ -108,8 +108,10 @@ public class ImportCollector {
108 } 108 }
109 var qualifiedName = NamingUtil.stripRootPrefix( 109 var qualifiedName = NamingUtil.stripRootPrefix(
110 qualifiedNameConverter.toQualifiedName(qualifiedNameString)); 110 qualifiedNameConverter.toQualifiedName(qualifiedNameString));
111 var aliases = aliasesMap.computeIfAbsent(qualifiedName, ignored -> new LinkedHashSet<>()); 111 var uri = referencedUri == null ? adapter.resolveQualifiedName(qualifiedName) : referencedUri;
112 aliases.add(alias); 112 if (uri != null) {
113 collection.add(NamedImport.explicit(uri, qualifiedName, List.of(alias)));
114 }
113 } 115 }
114 } 116 }
115 117
diff --git a/subprojects/language/src/main/java/tools/refinery/language/serializer/ProblemTransientValueService.java b/subprojects/language/src/main/java/tools/refinery/language/serializer/ProblemTransientValueService.java
new file mode 100644
index 00000000..c364b30b
--- /dev/null
+++ b/subprojects/language/src/main/java/tools/refinery/language/serializer/ProblemTransientValueService.java
@@ -0,0 +1,25 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.serializer;
7
8import org.eclipse.emf.ecore.EObject;
9import org.eclipse.emf.ecore.EStructuralFeature;
10import org.eclipse.xtext.parsetree.reconstr.impl.DefaultTransientValueService;
11import tools.refinery.language.model.problem.Problem;
12import tools.refinery.language.model.problem.ProblemPackage;
13import tools.refinery.language.parser.ProblemEcoreElementFactory;
14import tools.refinery.language.utils.ProblemUtil;
15
16public class ProblemTransientValueService extends DefaultTransientValueService {
17 @Override
18 public boolean isTransient(EObject owner, EStructuralFeature feature, int index) {
19 if (owner instanceof Problem problem && feature == ProblemPackage.Literals.PROBLEM__KIND) {
20 return problem.getName() == null && problem.getKind() == ProblemUtil.getDefaultModuleKind(problem) &&
21 !ProblemEcoreElementFactory.hasExplicitlySetProblemKind(problem);
22 }
23 return super.isTransient(owner, feature, index);
24 }
25}
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 6b48cb5a..f70893e0 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
@@ -5,6 +5,7 @@
5 */ 5 */
6package tools.refinery.language.utils; 6package tools.refinery.language.utils;
7 7
8import org.eclipse.emf.common.util.URI;
8import org.eclipse.emf.ecore.EObject; 9import org.eclipse.emf.ecore.EObject;
9import org.eclipse.emf.ecore.util.EcoreUtil; 10import org.eclipse.emf.ecore.util.EcoreUtil;
10import org.eclipse.xtext.EcoreUtil2; 11import org.eclipse.xtext.EcoreUtil2;
@@ -12,6 +13,8 @@ import tools.refinery.language.library.BuiltinLibrary;
12import tools.refinery.language.model.problem.*; 13import tools.refinery.language.model.problem.*;
13 14
14public final class ProblemUtil { 15public final class ProblemUtil {
16 public static final String MODULE_EXTENSION = "refinery";
17
15 private ProblemUtil() { 18 private ProblemUtil() {
16 throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); 19 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
17 } 20 }
@@ -124,6 +127,18 @@ public final class ProblemUtil {
124 }; 127 };
125 } 128 }
126 129
130 public static ModuleKind getDefaultModuleKind(Problem problem) {
131 var resource = problem.eResource();
132 if (resource == null) {
133 return ModuleKind.PROBLEM;
134 }
135 return getDefaultModuleKind(resource.getURI());
136 }
137
138 public static ModuleKind getDefaultModuleKind(URI uri) {
139 return MODULE_EXTENSION.equals(uri.fileExtension()) ? ModuleKind.MODULE : ModuleKind.PROBLEM;
140 }
141
127 public static boolean isModule(Problem problem) { 142 public static boolean isModule(Problem problem) {
128 return problem.getKind() == ModuleKind.MODULE; 143 return problem.getKind() == ModuleKind.MODULE;
129 } 144 }