View Javadoc

1   package io.github.reggert.reb4j;
2   
3   import fj.data.LazyString;
4   
5   /**
6    * Expression that has a quantifier attached to it.
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) // arbitrary value from Pattern source code
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) // arbitrary value from Pattern source code
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 }