1 package io.github.reggert.reb4j;
2
3 import fj.data.LazyString;
4
5
6
7
8 public abstract class Quantified extends AbstractSequenceableAlternative
9 {
10 private static final long serialVersionUID = 2L;
11 public final Quantifiable base;
12 private final LazyString quantifier;
13 public final Mode mode;
14
15 public static enum Mode
16 {
17 GREEDY(LazyString.empty),
18 RELUCTANT(LazyString.str("?")),
19 POSSESSIVE(LazyString.str("+"));
20
21 public final LazyString symbol;
22
23 private Mode(final LazyString symbol)
24 {this.symbol = symbol;}
25 }
26
27 private Quantified(final Quantifiable base, final Mode mode, final LazyString quantifier)
28 {
29 if (base == null) throw new NullPointerException("base");
30 if (quantifier == null) throw new NullPointerException("quantifier");
31 this.base = base;
32 this.quantifier = quantifier;
33 this.mode = mode;
34 }
35
36 public String quantifier()
37 {return quantifier.toString();}
38
39
40 public static final class AnyTimes extends Quantified
41 {
42 private static final long serialVersionUID = 1L;
43 private static final LazyString SYMBOL = LazyString.str("*");
44
45 public AnyTimes(final Quantifiable base, final Mode mode)
46 {
47 super(base, mode, SYMBOL.append(mode.symbol));
48 }
49
50 @Override
51 public Integer boundedLength()
52 {
53 return null;
54 }
55
56 @Override
57 public boolean repetitionInvalidatesBounds()
58 {
59 return true;
60 }
61
62 @Override
63 public boolean possiblyZeroLength()
64 {
65 return true;
66 }
67 }
68
69 @Deprecated
70 public static AnyTimes anyTimes(final Quantifiable base)
71 {
72 return new AnyTimes(base, Mode.GREEDY);
73 }
74
75 @Deprecated
76 public static AnyTimes anyTimesReluctantly(final Quantifiable base)
77 {
78 return new AnyTimes(base, Mode.RELUCTANT);
79 }
80
81 @Deprecated
82 public static AnyTimes anyTimesPossessively(final Quantifiable base)
83 {
84 return new AnyTimes(base, Mode.POSSESSIVE);
85 }
86
87 public static final class AtLeastOnce extends Quantified
88 {
89 private static final long serialVersionUID = 1L;
90 private static final LazyString SYMBOL = LazyString.str("+");
91
92 public AtLeastOnce(final Quantifiable base, final Mode mode)
93 {
94 super(base, mode, SYMBOL.append(mode.symbol));
95 }
96
97 @Override
98 public Integer boundedLength()
99 {
100 return null;
101 }
102
103 @Override
104 public boolean repetitionInvalidatesBounds()
105 {
106 return false;
107 }
108
109 @Override
110 public boolean possiblyZeroLength()
111 {
112 return base.possiblyZeroLength();
113 }
114 }
115
116 @Deprecated
117 public static AtLeastOnce atLeastOnce(final Quantifiable base)
118 {
119 return new AtLeastOnce(base, Mode.GREEDY);
120 }
121
122 @Deprecated
123 public static AtLeastOnce atLeastOnceReluctantly(final Quantifiable base)
124 {
125 return new AtLeastOnce(base, Mode.RELUCTANT);
126 }
127
128 @Deprecated
129 public static AtLeastOnce atLeastOncePossessively(final Quantifiable base)
130 {
131 return new AtLeastOnce(base, Mode.POSSESSIVE);
132 }
133
134 public static final class Optional extends Quantified
135 {
136 private static final long serialVersionUID = 1L;
137 private static final LazyString SYMBOL = LazyString.str("?");
138
139 public Optional(final Quantifiable base, final Mode mode)
140 {
141 super(base, mode, SYMBOL.append(mode.symbol));
142 }
143
144 @Override
145 public Integer boundedLength()
146 {
147 return base.boundedLength();
148 }
149
150 @Override
151 public boolean repetitionInvalidatesBounds()
152 {
153 return true;
154 }
155
156 @Override
157 public boolean possiblyZeroLength()
158 {
159 return true;
160 }
161 }
162
163 @Deprecated
164 public static Optional optional(final Quantifiable base)
165 {
166 return new Optional(base, Mode.GREEDY);
167 }
168
169 @Deprecated
170 public static Optional optionalReluctantly(final Quantifiable base)
171 {
172 return new Optional(base, Mode.RELUCTANT);
173 }
174
175 @Deprecated
176 public static Optional optionalPossessively(final Quantifiable base)
177 {
178 return new Optional(base, Mode.POSSESSIVE);
179 }
180
181 public static final class RepeatExactly extends Quantified
182 {
183 private static final long serialVersionUID = 1L;
184 public final int repetitions;
185
186 public RepeatExactly(final Quantifiable base, final int n, final Mode mode)
187 {
188 super(base, mode, LazyString.str("{").append(Integer.toString(n)).append("}").append(mode.symbol));
189 this.repetitions = n;
190 }
191
192 @Override
193 public Integer boundedLength()
194 {
195 if (base.repetitionInvalidatesBounds())
196 return null;
197 final Integer baseLength = base.boundedLength();
198 if (baseLength == null)
199 return null;
200 final long maximumLength = baseLength.longValue() * repetitions;
201 if (maximumLength <= 0xfffffffL)
202 return (int)maximumLength;
203 return null;
204 }
205
206 @Override
207 public boolean repetitionInvalidatesBounds()
208 {
209 return base.repetitionInvalidatesBounds();
210 }
211
212 @Override
213 public boolean possiblyZeroLength()
214 {
215 return repetitions == 0 || base.possiblyZeroLength();
216 }
217 }
218
219 @Deprecated
220 public static RepeatExactly repeat(final Quantifiable base, final int n)
221 {
222 return new RepeatExactly(base, n, Mode.GREEDY);
223 }
224
225 @Deprecated
226 public static RepeatExactly repeatReluctantly(final Quantifiable base, final int n)
227 {
228 return new RepeatExactly(base, n, Mode.RELUCTANT);
229 }
230
231 @Deprecated
232 public static RepeatExactly repeatPossessively(final Quantifiable base, final int n)
233 {
234 return new RepeatExactly(base, n, Mode.POSSESSIVE);
235 }
236
237 public static final class RepeatRange extends Quantified
238 {
239 private static final long serialVersionUID = 1L;
240 public final int minRepetitions;
241 public final Integer maxRepetitions;
242
243 public RepeatRange(final Quantifiable base, final int min, final Integer max, final Mode mode)
244 {
245 super(
246 base,
247 mode,
248 LazyString.str("{")
249 .append(Integer.toString(min))
250 .append(",")
251 .append(max == null ? "" : max.toString())
252 .append("}")
253 .append(mode.symbol)
254 );
255 this.minRepetitions = min;
256 this.maxRepetitions = max;
257 }
258
259 @Override
260 public Integer boundedLength()
261 {
262 if (base.repetitionInvalidatesBounds())
263 return null;
264 final Integer baseLength = base.boundedLength();
265 if (baseLength == null || maxRepetitions == null)
266 return null;
267 final long maximumLength = baseLength.longValue() * maxRepetitions.longValue();
268 if (maximumLength <= 0xfffffffL)
269 return (int)maximumLength;
270 return null;
271 }
272
273 @Override
274 public boolean repetitionInvalidatesBounds()
275 {
276 return minRepetitions == 0 || base.repetitionInvalidatesBounds();
277 }
278
279 @Override
280 public boolean possiblyZeroLength()
281 {
282 return minRepetitions == 0 || base.possiblyZeroLength();
283 }
284 }
285
286 @Deprecated
287 public static RepeatRange repeat(final Quantifiable base, final int min, final int max)
288 {
289 return new RepeatRange(base, min, max, Mode.GREEDY);
290 }
291
292 @Deprecated
293 public static RepeatRange repeatReluctantly(final Quantifiable base, final int min, final int max)
294 {
295 return new RepeatRange(base, min, max, Mode.RELUCTANT);
296 }
297
298 @Deprecated
299 public static RepeatRange repeatPossessively(final Quantifiable base, final int min, final int max)
300 {
301 return new RepeatRange(base, min, max, Mode.POSSESSIVE);
302 }
303
304 @Deprecated
305 public static RepeatRange atLeast(final Quantifiable base, final int n)
306 {
307 return new RepeatRange(base, n, null, Mode.GREEDY);
308 }
309
310 @Deprecated
311 public static RepeatRange atLeastReluctantly(final Quantifiable base, final int n)
312 {
313 return new RepeatRange(base, n, null, Mode.RELUCTANT);
314 }
315
316 @Deprecated
317 public static RepeatRange atLeastPossessively(final Quantifiable base, final int n)
318 {
319 return new RepeatRange(base, n, null, Mode.POSSESSIVE);
320 }
321
322 @Override
323 public LazyString expression()
324 {
325 return base.expression().append(quantifier);
326 }
327
328 @Override
329 public int hashCode()
330 {
331 final int prime = 31;
332 int result = 1;
333 result = prime * result + base.hashCode();
334 result = prime * result + quantifier.hashCode();
335 return result;
336 }
337
338 @Override
339 public boolean equals(final Object obj)
340 {
341 if (this == obj)
342 return true;
343 if (obj == null)
344 return false;
345 if (getClass() != obj.getClass())
346 return false;
347 final Quantified other = (Quantified) obj;
348 return base.equals(other.base) && quantifier.equals(other.quantifier);
349 }
350
351 }