Skip to content

Commit b875326

Browse files
committed
Introduce SegmentParser.findAll, which will find all paths based on a modulepattern
1 parent 9767a26 commit b875326

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package org.codehaus.plexus.languages.java.jpms;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.Deque;
7+
import java.util.List;
8+
import java.util.function.Consumer;
9+
import java.util.stream.Collectors;
10+
11+
/**
12+
* This class helps with the module module-pattern form of the module source path.
13+
*
14+
*
15+
* @See https://docs.oracle.com/en/java/javase/23/docs/specs/man/javac.html#the-module-source-path-option
16+
*/
17+
class SegmentParser {
18+
19+
private Consumer<Element> nextAction;
20+
21+
protected List<String> findAll(String segment) {
22+
StringBuilder value = new StringBuilder();
23+
24+
Root root = new Root();
25+
nextAction = root::element;
26+
27+
Deque<Block> blocks = new ArrayDeque<>();
28+
29+
for (int i = 0; i < segment.length(); i++) {
30+
char c = segment.charAt(i);
31+
switch (c) {
32+
case '{': {
33+
Block b = new Block(value.toString());
34+
35+
nextAction.accept(b);
36+
37+
blocks.push(b);
38+
39+
nextAction = b::element;
40+
41+
value = new StringBuilder();
42+
43+
break;
44+
}
45+
case ',': {
46+
nextAction.accept(new Value(value.toString()));
47+
48+
Block b = blocks.peek();
49+
50+
nextAction = b::element;
51+
52+
value = new StringBuilder();
53+
54+
break;
55+
}
56+
case '}': {
57+
nextAction.accept(new Value(value.toString()));
58+
59+
Block b = blocks.poll();
60+
61+
nextAction = b::tail;
62+
63+
value = new StringBuilder();
64+
65+
break;
66+
}
67+
default:
68+
value.append(c);
69+
70+
break;
71+
}
72+
}
73+
74+
if (value.length() > 0) {
75+
nextAction.accept(new Value(value.toString()));
76+
}
77+
78+
return root.resolvePaths();
79+
}
80+
81+
private interface Element {
82+
List<String> resolvePaths(List<String> bases);
83+
}
84+
85+
private final class Value implements Element {
86+
87+
private final String value;
88+
89+
public Value(String value) {
90+
this.value = value;
91+
}
92+
93+
@Override
94+
public List<String> resolvePaths(List<String> bases) {
95+
return bases.stream().map(b -> b + value).collect(Collectors.toList());
96+
}
97+
98+
@Override
99+
public String toString() {
100+
return "Value [value=" + value + "]";
101+
}
102+
}
103+
104+
private final class Block implements Element {
105+
106+
private final String value;
107+
108+
private List<Element> elements = new ArrayList<>();
109+
110+
private Element tail;
111+
112+
public Block(String value) {
113+
this.value = value;
114+
}
115+
116+
public void element(Element element) {
117+
elements.add(element);
118+
}
119+
120+
public void tail(Element element) {
121+
tail = element;
122+
}
123+
124+
@Override
125+
public List<String> resolvePaths(List<String> bases) {
126+
final List<String> valuedBases = bases.stream().map(b -> b + value).collect(Collectors.toList());
127+
128+
List<String> newBases;
129+
if (elements.isEmpty()) {
130+
newBases = valuedBases;
131+
} else {
132+
newBases = elements.stream()
133+
.flatMap(e -> e.resolvePaths(valuedBases).stream())
134+
.collect(Collectors.toList());
135+
}
136+
137+
if (tail == null) {
138+
return newBases;
139+
} else {
140+
return tail.resolvePaths(newBases);
141+
}
142+
}
143+
144+
@Override
145+
public String toString() {
146+
return "Block [value=" + value + ", elements=" + elements + ", tail=" + tail + "]";
147+
}
148+
}
149+
150+
private final class Root {
151+
152+
private Element element;
153+
154+
public void element(Element element) {
155+
this.element = element;
156+
}
157+
158+
public List<String> resolvePaths() {
159+
return element.resolvePaths(Arrays.asList(""));
160+
}
161+
162+
@Override
163+
public String toString() {
164+
return "Root [element=" + element + "]";
165+
}
166+
}
167+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.codehaus.plexus.languages.java.jpms;
2+
3+
import java.util.stream.Stream;
4+
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.Arguments;
7+
import org.junit.jupiter.params.provider.MethodSource;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.junit.jupiter.api.Assertions.*;
11+
12+
class SegmentParserTest {
13+
14+
@ParameterizedTest
15+
@MethodSource
16+
void findAll(String segment, String... expectedValues) {
17+
SegmentParser parser = new SegmentParser();
18+
assertThat(parser.findAll(segment)).containsExactlyInAnyOrder(expectedValues);
19+
}
20+
21+
static Stream<Arguments> findAll() {
22+
return Stream.of(
23+
Arguments.of("foo", new String[] {"foo"}),
24+
Arguments.of("foo/{bar,baz}", new String[] {"foo/bar", "foo/baz"}),
25+
Arguments.of("foo/{bar,baz}/com", new String[] {"foo/bar/com", "foo/baz/com"}),
26+
Arguments.of("foo/{bar,baz}/com/{1,2,3}/zzz", new String[] {
27+
"foo/bar/com/1/zzz",
28+
"foo/baz/com/1/zzz",
29+
"foo/bar/com/2/zzz",
30+
"foo/baz/com/2/zzz",
31+
"foo/bar/com/3/zzz",
32+
"foo/baz/com/3/zzz"
33+
}),
34+
Arguments.of("foo/{bar,baz/com/{1,2,3}/yyy}/zzz", new String[] {
35+
"foo/bar/zzz", "foo/baz/com/1/yyy/zzz", "foo/baz/com/2/yyy/zzz", "foo/baz/com/3/yyy/zzz"
36+
}),
37+
Arguments.of("{foo/{bar},zzz}", new String[] {"foo/bar", "zzz"}));
38+
}
39+
}

0 commit comments

Comments
 (0)