aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language/src/main/java/tools/refinery/language/scoping/imports/ImportCollection.java
blob: 6317113825c5aa98961b13eef4e4312bda031949 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package tools.refinery.language.scoping.imports;

import org.eclipse.emf.common.util.URI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class ImportCollection {
	public static ImportCollection EMPTY = new ImportCollection() {
		@Override
		public void add(Import importEntry) {
			throw new UnsupportedOperationException("Read-only collection");
		}

		@Override
		public void remove(URI uri) {
			throw new UnsupportedOperationException("Read-only collection");
		}
	};

	private final Map<URI, Import> importMap = new HashMap<>();

	public void add(Import importEntry) {
		importMap.compute(importEntry.uri(), (ignored, originalEntry) -> merge(originalEntry, importEntry));
	}

	public void addAll(Iterable<? extends Import> imports) {
		imports.forEach(this::add);
	}

	public void remove(URI uri) {
		importMap.remove(uri);
	}

	public List<Import> toList() {
		return List.copyOf(importMap.values());
	}

	public Set<URI> toUriSet() {
		return new LinkedHashSet<>(importMap.keySet());
	}

	@NotNull
	private static Import merge(@Nullable Import left, @NotNull Import right) {
		if (left == null) {
			return right;
		}
		if (!left.uri().equals(right.uri())) {
			throw new IllegalArgumentException("Expected URIs '%s' and '%s' to be equal".formatted(
					left.uri(), right.uri()));
		}
		return switch (left) {
			case TransitiveImport transitiveLeft ->
					right instanceof TransitiveImport ? left : merge(right, transitiveLeft);
			case NamedImport namedLeft -> switch (right) {
				case TransitiveImport ignored -> namedLeft;
				case NamedImport namedRight -> {
					if (!namedLeft.qualifiedName().equals(namedRight.qualifiedName())) {
						throw new IllegalArgumentException("Expected qualified names '%s' and '%s' to be equal"
								.formatted(namedLeft.qualifiedName(), namedRight.qualifiedName()));
					}
					var mergedAliases = new LinkedHashSet<>(namedLeft.aliases());
					mergedAliases.addAll(namedRight.aliases());
					yield new NamedImport(namedLeft.uri(), namedLeft.qualifiedName(),
							List.copyOf(mergedAliases), namedLeft.alsoImplicit() || namedRight.alsoImplicit());
				}
			};
		};
	}
}