aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-05 15:18:02 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-05 15:18:02 +0100
commit48c9f84f10d5fbcbe399a0c3335707167f4e7f0d (patch)
tree72e315d726014966d8c701686962bfb5fbdea5a7 /subprojects
parentrefactor: simplify module name inference (diff)
downloadrefinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.tar.gz
refinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.tar.zst
refinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.zip
Revert "refactor: simplify module name inference"
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/ClasspathBasedLibrary.java48
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/PathLibrary.java34
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/library/RefineryLibrary.java2
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportAdapter.java84
4 files changed, 164 insertions, 4 deletions
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 bc9ae5ca..4b748c64 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
@@ -14,10 +14,21 @@ import java.util.*;
14public abstract class ClasspathBasedLibrary implements RefineryLibrary { 14public abstract class ClasspathBasedLibrary implements RefineryLibrary {
15 private final QualifiedName prefix; 15 private final QualifiedName prefix;
16 private final List<QualifiedName> automaticImports; 16 private final List<QualifiedName> automaticImports;
17 private final URI rootUri;
17 18
18 protected ClasspathBasedLibrary(QualifiedName prefix, List<QualifiedName> automaticImports) { 19 protected ClasspathBasedLibrary(QualifiedName prefix, List<QualifiedName> automaticImports) {
19 this.prefix = prefix; 20 this.prefix = prefix;
20 this.automaticImports = List.copyOf(automaticImports); 21 this.automaticImports = List.copyOf(automaticImports);
22 var context = this.getClass();
23 var contextPath = context.getCanonicalName().replace('.', '/') + ".class";
24 var contextResource = context.getClassLoader().getResource(contextPath);
25 if (contextResource == null) {
26 throw new IllegalStateException("Failed to find library context");
27 }
28 var contextUri = URI.createURI(contextResource.toString());
29 var segments = Arrays.copyOf(contextUri.segments(), contextUri.segmentCount() - 1);
30 rootUri = URI.createHierarchicalURI(contextUri.scheme(), contextUri.authority(), contextUri.device(),
31 segments, null, null);
21 } 32 }
22 33
23 protected ClasspathBasedLibrary(QualifiedName prefix) { 34 protected ClasspathBasedLibrary(QualifiedName prefix) {
@@ -37,6 +48,43 @@ public abstract class ClasspathBasedLibrary implements RefineryLibrary {
37 return Optional.empty(); 48 return Optional.empty();
38 } 49 }
39 50
51 @Override
52 public Optional<QualifiedName> getQualifiedName(URI uri, List<Path> libraryPaths) {
53 if (!uri.isHierarchical() ||
54 !Objects.equals(rootUri.scheme(), uri.scheme()) ||
55 !Objects.equals(rootUri.authority(), uri.authority()) ||
56 !Objects.equals(rootUri.device(), uri.device()) ||
57 rootUri.segmentCount() >= uri.segmentCount()) {
58 return Optional.empty();
59 }
60 int rootSegmentCount = rootUri.segmentCount();
61 int uriSegmentCount = uri.segmentCount();
62 if (!uri.segment(uriSegmentCount - 1).endsWith(RefineryLibrary.EXTENSION)) {
63 return Optional.empty();
64 }
65 var segments = new ArrayList<String>();
66 int i = 0;
67 while (i < rootSegmentCount) {
68 if (!rootUri.segment(i).equals(uri.segment(i))) {
69 return Optional.empty();
70 }
71 i++;
72 }
73 while (i < uriSegmentCount) {
74 var segment = uri.segment(i);
75 if (i == uriSegmentCount - 1) {
76 segment = segment.substring(0, segment.length() - RefineryLibrary.EXTENSION.length());
77 }
78 segments.add(segment);
79 i++;
80 }
81 var qualifiedName = QualifiedName.create(segments);
82 if (!qualifiedName.startsWith(prefix)) {
83 return Optional.empty();
84 }
85 return Optional.of(qualifiedName);
86 }
87
40 public static Optional<URI> getLibraryUri(Class<?> context, QualifiedName qualifiedName) { 88 public static Optional<URI> getLibraryUri(Class<?> context, QualifiedName qualifiedName) {
41 var packagePath = context.getPackageName().replace('.', '/'); 89 var packagePath = context.getPackageName().replace('.', '/');
42 var libraryPath = String.join("/", qualifiedName.getSegments()); 90 var libraryPath = String.join("/", qualifiedName.getSegments());
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 6f418492..c6f994df 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
@@ -10,6 +10,7 @@ import org.eclipse.xtext.naming.QualifiedName;
10 10
11import java.nio.file.Files; 11import java.nio.file.Files;
12import java.nio.file.Path; 12import java.nio.file.Path;
13import java.util.ArrayList;
13import java.util.List; 14import java.util.List;
14import java.util.Optional; 15import java.util.Optional;
15 16
@@ -53,4 +54,37 @@ public final class PathLibrary implements RefineryLibrary {
53 } 54 }
54 return Path.of(first, rest); 55 return Path.of(first, rest);
55 } 56 }
57
58 @Override
59 public Optional<QualifiedName> getQualifiedName(URI uri, List<Path> libraryPaths) {
60 if (libraryPaths.isEmpty()) {
61 return Optional.empty();
62 }
63 if (!uri.isFile() || !uri.hasAbsolutePath()) {
64 return Optional.empty();
65 }
66 var path = Path.of(uri.toFileString());
67 for (var library : libraryPaths) {
68 if (path.startsWith(library)) {
69 return getRelativeQualifiedName(library, path);
70 }
71 }
72 return Optional.empty();
73 }
74
75 private static Optional<QualifiedName> getRelativeQualifiedName(Path library, Path path) {
76 var relativePath = path.relativize(library);
77 var segments = new ArrayList<String>();
78 for (Path value : relativePath) {
79 segments.add(value.toString());
80 }
81 int lastIndex = segments.size() - 1;
82 var lastSegment = segments.get(lastIndex);
83 if (!lastSegment.endsWith(EXTENSION)) {
84 return Optional.empty();
85 }
86 lastSegment = lastSegment.substring(0, lastSegment.length() - RefineryLibrary.EXTENSION.length());
87 segments.set(lastIndex, lastSegment);
88 return Optional.of(QualifiedName.create(segments));
89 }
56} 90}
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 9c0d72f9..e1f8d7bc 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
@@ -20,4 +20,6 @@ public interface RefineryLibrary {
20 } 20 }
21 21
22 Optional<URI> resolveQualifiedName(QualifiedName qualifiedName, List<Path> libraryPaths); 22 Optional<URI> resolveQualifiedName(QualifiedName qualifiedName, List<Path> libraryPaths);
23
24 Optional<QualifiedName> getQualifiedName(URI uri, List<Path> libraryPaths);
23} 25}
diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportAdapter.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportAdapter.java
index a34c09cc..5a8f7fd7 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportAdapter.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportAdapter.java
@@ -8,9 +8,12 @@ package tools.refinery.language.scoping.imports;
8import com.google.common.base.Splitter; 8import com.google.common.base.Splitter;
9import com.google.common.cache.Cache; 9import com.google.common.cache.Cache;
10import com.google.common.cache.CacheBuilder; 10import com.google.common.cache.CacheBuilder;
11import org.apache.log4j.Logger;
12import org.eclipse.emf.common.notify.Notification;
11import org.eclipse.emf.common.notify.impl.AdapterImpl; 13import org.eclipse.emf.common.notify.impl.AdapterImpl;
12import org.eclipse.emf.common.util.URI; 14import org.eclipse.emf.common.util.URI;
13import org.eclipse.emf.ecore.EObject; 15import org.eclipse.emf.ecore.EObject;
16import org.eclipse.emf.ecore.resource.Resource;
14import org.eclipse.emf.ecore.resource.ResourceSet; 17import org.eclipse.emf.ecore.resource.ResourceSet;
15import org.eclipse.emf.ecore.util.EcoreUtil; 18import org.eclipse.emf.ecore.util.EcoreUtil;
16import org.eclipse.xtext.naming.QualifiedName; 19import org.eclipse.xtext.naming.QualifiedName;
@@ -21,6 +24,7 @@ import java.nio.file.Path;
21import java.util.*; 24import java.util.*;
22 25
23public class ImportAdapter extends AdapterImpl { 26public class ImportAdapter extends AdapterImpl {
27 private static final Logger LOG = Logger.getLogger(ImportAdapter.class);
24 private static final List<RefineryLibrary> DEFAULT_LIBRARIES; 28 private static final List<RefineryLibrary> DEFAULT_LIBRARIES;
25 private static final List<Path> DEFAULT_PATHS; 29 private static final List<Path> DEFAULT_PATHS;
26 30
@@ -49,9 +53,12 @@ public class ImportAdapter extends AdapterImpl {
49 private final Map<QualifiedName, URI> qualifiedNameToUriMap = new LinkedHashMap<>(); 53 private final Map<QualifiedName, URI> qualifiedNameToUriMap = new LinkedHashMap<>();
50 private final Map<URI, QualifiedName> uriToQualifiedNameMap = new LinkedHashMap<>(); 54 private final Map<URI, QualifiedName> uriToQualifiedNameMap = new LinkedHashMap<>();
51 55
52 private ImportAdapter() { 56 private ImportAdapter(ResourceSet resourceSet) {
53 libraries = new ArrayList<>(DEFAULT_LIBRARIES); 57 libraries = new ArrayList<>(DEFAULT_LIBRARIES);
54 libraryPaths = new ArrayList<>(DEFAULT_PATHS); 58 libraryPaths = new ArrayList<>(DEFAULT_PATHS);
59 for (var resource : resourceSet.getResources()) {
60 resourceAdded(resource);
61 }
55 } 62 }
56 63
57 @Override 64 @Override
@@ -113,10 +120,81 @@ public class ImportAdapter extends AdapterImpl {
113 return uriToQualifiedNameMap.get(uri); 120 return uriToQualifiedNameMap.get(uri);
114 } 121 }
115 122
123 @Override
124 public void notifyChanged(Notification msg) {
125 switch (msg.getEventType()) {
126 case Notification.ADD -> {
127 if (msg.getNewValue() instanceof Resource resource) {
128 resourceAdded(resource);
129 }
130 }
131 case Notification.ADD_MANY -> {
132 if (msg.getNewValue() instanceof List<?> list) {
133 manyResourcesAdded(list);
134 }
135 }
136 case Notification.REMOVE -> {
137 if (msg.getOldValue() instanceof Resource resource) {
138 resourceRemoved(resource);
139 }
140 }
141 case Notification.REMOVE_MANY -> {
142 if (msg.getOldValue() instanceof List<?> list) {
143 manyResourcesRemoved(list);
144 }
145 }
146 default -> {
147 // Nothing to update.
148 }
149 }
150 }
151
152 private void manyResourcesAdded(List<?> list) {
153 for (var element : list) {
154 if (element instanceof Resource resource) {
155 resourceAdded(resource);
156 }
157 }
158 }
159
160 private void manyResourcesRemoved(List<?> list) {
161 for (var element : list) {
162 if (element instanceof Resource resource) {
163 resourceRemoved(resource);
164 }
165 }
166 }
167
168 private void resourceAdded(Resource resource) {
169 var uri = resource.getURI();
170 for (var library : libraries) {
171 var result = library.getQualifiedName(uri, libraryPaths);
172 if (result.isPresent()) {
173 var qualifiedName = result.get();
174 var previousQualifiedName = uriToQualifiedNameMap.putIfAbsent(uri, qualifiedName);
175 if (previousQualifiedName == null) {
176 if (qualifiedNameToUriMap.put(qualifiedName, uri) != null) {
177 throw new IllegalArgumentException("Duplicate resource for" + qualifiedName);
178 }
179 } else if (!previousQualifiedName.equals(qualifiedName)) {
180 LOG.warn("Expected %s to have qualified name %s, got %s instead".formatted(
181 uri, previousQualifiedName, qualifiedName));
182 }
183 }
184 }
185 }
186
187 private void resourceRemoved(Resource resource) {
188 var qualifiedName = uriToQualifiedNameMap.remove(resource.getURI());
189 if (qualifiedName != null) {
190 qualifiedNameToUriMap.remove(qualifiedName);
191 }
192 }
193
116 public static ImportAdapter getOrInstall(ResourceSet resourceSet) { 194 public static ImportAdapter getOrInstall(ResourceSet resourceSet) {
117 var adapter = getAdapter(resourceSet); 195 var adapter = getAdapter(resourceSet);
118 if (adapter == null) { 196 if (adapter == null) {
119 adapter = new ImportAdapter(); 197 adapter = new ImportAdapter(resourceSet);
120 resourceSet.eAdapters().add(adapter); 198 resourceSet.eAdapters().add(adapter);
121 } 199 }
122 return adapter; 200 return adapter;
@@ -148,7 +226,5 @@ public class ImportAdapter extends AdapterImpl {
148 newAdapter.libraries.addAll(originalAdapter.libraries); 226 newAdapter.libraries.addAll(originalAdapter.libraries);
149 newAdapter.libraryPaths.clear(); 227 newAdapter.libraryPaths.clear();
150 newAdapter.libraryPaths.addAll(originalAdapter.libraryPaths); 228 newAdapter.libraryPaths.addAll(originalAdapter.libraryPaths);
151 newAdapter.uriToQualifiedNameMap.putAll(originalAdapter.uriToQualifiedNameMap);
152 newAdapter.qualifiedNameToUriMap.putAll(originalAdapter.qualifiedNameToUriMap);
153 } 229 }
154} 230}