diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-02-05 15:18:02 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-02-05 15:18:02 +0100 |
commit | 48c9f84f10d5fbcbe399a0c3335707167f4e7f0d (patch) | |
tree | 72e315d726014966d8c701686962bfb5fbdea5a7 /subprojects | |
parent | refactor: simplify module name inference (diff) | |
download | refinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.tar.gz refinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.tar.zst refinery-48c9f84f10d5fbcbe399a0c3335707167f4e7f0d.zip |
Revert "refactor: simplify module name inference"
This reverts commit c6e70f5a01c877b560d4561f22a830c1ce1c6dbe.
Diffstat (limited to 'subprojects')
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.*; | |||
14 | public abstract class ClasspathBasedLibrary implements RefineryLibrary { | 14 | public 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 | ||
11 | import java.nio.file.Files; | 11 | import java.nio.file.Files; |
12 | import java.nio.file.Path; | 12 | import java.nio.file.Path; |
13 | import java.util.ArrayList; | ||
13 | import java.util.List; | 14 | import java.util.List; |
14 | import java.util.Optional; | 15 | import 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; | |||
8 | import com.google.common.base.Splitter; | 8 | import com.google.common.base.Splitter; |
9 | import com.google.common.cache.Cache; | 9 | import com.google.common.cache.Cache; |
10 | import com.google.common.cache.CacheBuilder; | 10 | import com.google.common.cache.CacheBuilder; |
11 | import org.apache.log4j.Logger; | ||
12 | import org.eclipse.emf.common.notify.Notification; | ||
11 | import org.eclipse.emf.common.notify.impl.AdapterImpl; | 13 | import org.eclipse.emf.common.notify.impl.AdapterImpl; |
12 | import org.eclipse.emf.common.util.URI; | 14 | import org.eclipse.emf.common.util.URI; |
13 | import org.eclipse.emf.ecore.EObject; | 15 | import org.eclipse.emf.ecore.EObject; |
16 | import org.eclipse.emf.ecore.resource.Resource; | ||
14 | import org.eclipse.emf.ecore.resource.ResourceSet; | 17 | import org.eclipse.emf.ecore.resource.ResourceSet; |
15 | import org.eclipse.emf.ecore.util.EcoreUtil; | 18 | import org.eclipse.emf.ecore.util.EcoreUtil; |
16 | import org.eclipse.xtext.naming.QualifiedName; | 19 | import org.eclipse.xtext.naming.QualifiedName; |
@@ -21,6 +24,7 @@ import java.nio.file.Path; | |||
21 | import java.util.*; | 24 | import java.util.*; |
22 | 25 | ||
23 | public class ImportAdapter extends AdapterImpl { | 26 | public 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 | } |