View Javadoc

1   package io.github.reggert.reb4j;
2   
3   import java.util.Arrays;
4   
5   import fj.data.LazyString;
6   import fj.data.List;
7   
8   /**
9    * Expression that has been grouped in parentheses.
10   */
11  public abstract class Group extends AbstractQuantifiableSequenceableAlternative 
12  	implements Quantifiable
13  {
14  	private static final long serialVersionUID = 1L;
15  	
16  	/**
17  	 * The expression that is enclosed in parentheses.
18  	 */
19  	public final Expression nested;
20  	
21  	private final LazyString expression;
22  
23  	private Group(final Expression nested, final LazyString opening)
24  	{
25  		if (nested == null) throw new NullPointerException("nested");
26  		assert opening != null;
27  		this.nested = nested;
28  		this.expression = opening.append(nested.expression()).append(")");
29  	}
30  	
31  	@Override
32  	public LazyString expression()
33  	{
34  		return expression;
35  	}
36  	
37  	@Override
38  	public final Integer boundedLength() 
39  	{
40  		return nested.boundedLength();
41  	}
42  	
43  	@Override 
44  	public final boolean repetitionInvalidatesBounds() 
45  	{
46  		return nested.repetitionInvalidatesBounds();
47  	}
48  			
49  	@Override 
50  	public final boolean possiblyZeroLength() 
51  	{
52  		return nested.possiblyZeroLength();
53  	}
54  	
55  	
56  	public final static class Capture extends Group
57  	{
58  		private static final long serialVersionUID = 1L;
59  		private static final LazyString OPENING = LazyString.str("(");
60  		
61  		public Capture(final Expression nested)
62  		{
63  			super(nested, OPENING);
64  		}
65  	}
66  	
67  	/**
68  	 * Constructs a capturing group.
69  	 * 
70  	 * @param nested
71  	 * 	the expression to enclose; must not be <code>null</code>.
72  	 * @return a new Group.
73  	 * @throws NullPointerException
74  	 * 	if <var>nested</var> is <code>null</code>.
75  	 */
76  	public static Capture capture(final Expression nested)
77  	{
78  		return new Capture(nested);
79  	}
80  	
81  	public final static class NonCapturing extends Group
82  	{
83  		private static final long serialVersionUID = 1L;
84  		private static final LazyString OPENING = LazyString.str("(?:");
85  		
86  		public NonCapturing(final Expression nested)
87  		{
88  			super(nested, OPENING);
89  		}
90  	}
91  	
92  	/**
93  	 * Constructs a non-capturing group.
94  	 * 
95  	 * @param nested
96  	 * 	the expression to enclose; must not be <code>null</code>.
97  	 * @return a new Group.
98  	 * @throws NullPointerException
99  	 * 	if <var>nested</var> is <code>null</code>.
100 	 */
101 	public static NonCapturing nonCapturing(final Expression nested)
102 	{
103 		return new NonCapturing(nested);
104 	}
105 	
106 	public final static class Independent extends Group
107 	{
108 		private static final long serialVersionUID = 1L;
109 		private static final LazyString OPENING = LazyString.str("(?>");
110 		
111 		public Independent(final Expression nested)
112 		{
113 			super(nested, OPENING);
114 		}
115 	}
116 	
117 	/**
118 	 * Constructs an independent group.
119 	 * 
120 	 * @param nested
121 	 * 	the expression to enclose; must not be <code>null</code>.
122 	 * @return a new Group.
123 	 * @throws NullPointerException
124 	 * 	if <var>nested</var> is <code>null</code>.
125 	 */
126 	public static Independent independent(final Expression nested) 
127 	{
128 		return new Independent(nested);
129 	}
130 	
131 	public final static class PositiveLookAhead extends Group
132 	{
133 		private static final long serialVersionUID = 1L;
134 		private static final LazyString OPENING = LazyString.str("(?=");
135 		
136 		public PositiveLookAhead(final Expression nested)
137 		{
138 			super(nested, OPENING);
139 		}
140 	}
141 	
142 	/**
143 	 * Constructs a group that uses positive look-ahead.
144 	 * 
145 	 * @param nested
146 	 * 	the expression to enclose; must not be <code>null</code>.
147 	 * @return a new Group.
148 	 * @throws NullPointerException
149 	 * 	if <var>nested</var> is <code>null</code>.
150 	 */
151 	public static PositiveLookAhead positiveLookAhead(final Expression nested) 
152 	{
153 		return new PositiveLookAhead(nested);
154 	}
155 	
156 	public final static class NegativeLookAhead extends Group
157 	{
158 		private static final long serialVersionUID = 1L;
159 		private static final LazyString OPENING = LazyString.str("(?!");
160 		
161 		public NegativeLookAhead(final Expression nested)
162 		{
163 			super(nested, OPENING);
164 		}
165 	}
166 	
167 	/**
168 	 * Constructs a group that uses negative look-ahead.
169 	 * 
170 	 * @param nested
171 	 * 	the expression to enclose; must not be <code>null</code>.
172 	 * @return a new Group.
173 	 * @throws NullPointerException
174 	 * 	if <var>nested</var> is <code>null</code>.
175 	 */
176 	public static NegativeLookAhead negativeLookAhead(final Expression nested) 
177 	{
178 		return new NegativeLookAhead(nested);
179 	}
180 	
181 	public final static class PositiveLookBehind extends Group
182 	{
183 		private static final long serialVersionUID = 1L;
184 		private static final LazyString OPENING = LazyString.str("(?<=");
185 		
186 		public PositiveLookBehind(final Expression nested) throws UnboundedLookBehindException
187 		{
188 			super(nested, OPENING);
189 			if (nested.boundedLength() == null)
190 				throw new UnboundedLookBehindException(nested);
191 		}
192 	}
193 	
194 	/**
195 	 * Constructs a group that uses positive look-behind.
196 	 * 
197 	 * @param nested
198 	 * 	the expression to enclose; must not be <code>null</code>.
199 	 * @return a new Group.
200 	 * @throws UnboundedLookBehindException 
201 	 *  if <var>nested</var> does not have a maximum length.
202 	 * @throws NullPointerException
203 	 * 	if <var>nested</var> is <code>null</code>.
204 	 */
205 	public static PositiveLookBehind positiveLookBehind(final Expression nested) throws UnboundedLookBehindException 
206 	{
207 		return new PositiveLookBehind(nested);
208 	}
209 	
210 	public final static class NegativeLookBehind extends Group
211 	{
212 		private static final long serialVersionUID = 1L;
213 		private static final LazyString OPENING = LazyString.str("(?<!");
214 		
215 		public NegativeLookBehind(final Expression nested) throws UnboundedLookBehindException
216 		{
217 			super(nested, OPENING);
218 			if (nested.boundedLength() == null)
219 				throw new UnboundedLookBehindException(nested);
220 		}
221 	}
222 	
223 	/**
224 	 * Constructs a group that uses negative look-behind.
225 	 * 
226 	 * @param nested
227 	 * 	the expression to enclose; must not be <code>null</code>.
228 	 * @return a new Group.
229 	 * @throws UnboundedLookBehindException 
230 	 * 	if <var>nested</var> does not have a maximum length.
231 	 * @throws NullPointerException
232 	 * 	if <var>nested</var> is <code>null</code>.
233 	 */
234 	public static NegativeLookBehind negativeLookBehind(final Expression nested) 
235 		throws UnboundedLookBehindException 
236 	{
237 		return new NegativeLookBehind(nested);
238 	}
239 	
240 	public final static class EnableFlags extends Group
241 	{
242 		private static final long serialVersionUID = 1L;
243 		public final List<Flag> flags;
244 		
245 		private static LazyString opening(final Flag... flags)
246 		{
247 			return LazyString.str("(?").append(Flag.toString(flags)).append(":");
248 		}
249 		
250 		public EnableFlags(final Expression nested, final Flag... flags)
251 		{
252 			super(nested, opening(flags));
253 			this.flags = List.iterableList(Arrays.asList(flags));
254 		}
255 	}
256 	
257 	/**
258 	 * Constructs a group that enables the specified matcher flags.
259 	 * 
260 	 * @param nested
261 	 * 	the expression to enclose; must not be <code>null</code>.
262 	 * @param flags
263 	 *  the flags to enable.
264 	 * @return a new Group.
265 	 * @throws NullPointerException
266 	 * 	if <var>nested</var> is <code>null</code>.
267 	 */
268 	public static EnableFlags enableFlags(final Expression nested, final Flag... flags) 
269 	{
270 		return new EnableFlags(nested, flags);
271 	}
272 	
273 	public final static class DisableFlags extends Group
274 	{
275 		private static final long serialVersionUID = 1L;
276 		public final List<Flag> flags;
277 		
278 		private static LazyString opening(final Flag... flags)
279 		{
280 			return LazyString.str("(?-").append(Flag.toString(flags)).append(":");
281 		}
282 		
283 		public DisableFlags(final Expression nested, final Flag... flags)
284 		{
285 			super(nested, opening(flags));
286 			this.flags = List.iterableList(Arrays.asList(flags));
287 		}
288 	}
289 	/**
290 	 * Constructs a group that disables the specified matcher flags.
291 	 * 
292 	 * @param nested
293 	 * 	the expression to enclose; must not be <code>null</code>.
294 	 * @param flags
295 	 *  the flags to disable.
296 	 * @return a new Group.
297 	 * @throws NullPointerException
298 	 * 	if <var>nested</var> is <code>null</code>.
299 	 */
300 	public static DisableFlags disableFlags(final Expression nested, final Flag... flags) 
301 	{
302 		return new DisableFlags(nested, flags);
303 	}
304 
305 	@Override
306 	public int hashCode()
307 	{
308 		final int prime = 31;
309 		int result = 1;
310 		result = prime * result + expression.hashCode();
311 		result = prime * result + nested.hashCode();
312 		return result;
313 	}
314 
315 	@Override
316 	public boolean equals(final Object obj)
317 	{
318 		if (this == obj)
319 			return true;
320 		if (obj == null)
321 			return false;
322 		if (getClass() != obj.getClass())
323 			return false;
324 		final Group other = (Group) obj;
325 		return expression.equals(other.expression) && nested.equals(other.nested);
326 	}
327 
328 }