View Javadoc

1   package io.github.reggert.reb4j;
2   
3   import fj.F;
4   import fj.F2;
5   import fj.data.LazyString;
6   import fj.data.List;
7   
8   
9   /**
10   * Base class for expressions that are readily combined with other similar expressions.
11   * 
12   * This encompasses special predefined expressions, processed literals, 
13   * and combinations thereof. 
14   * This class mainly exists so that long sequences of such expressions can be flattened rather
15   * than causing the construction of deep trees.
16   */
17  public abstract class Raw extends AbstractSequenceableAlternative
18  {
19  	private static final long serialVersionUID = 1L;
20  	private final LazyString rawExpression;
21  	
22  	Raw(final LazyString rawExpression)
23  	{
24  		assert rawExpression != null;
25  		this.rawExpression = rawExpression;
26  	}
27  
28  	@Override
29  	public final LazyString expression()
30  	{return rawExpression;}
31  	
32  	/**
33  	 * @Deprecated Use {@link #andThen(Raw)} instead.
34  	 */
35  	@Deprecated
36  	public Compound then(final Raw right)
37  	{return andThen(right);}
38  
39  	/**
40  	 * @Deprecated Use {@link #andThen(Compound)} instead.
41  	 */
42  	@Deprecated
43  	public Compound then(final Compound right)
44  	{return andThen(right);}
45  
46  	/**
47  	 * @Deprecated Use {@link #andThen(Literal)} instead.
48  	 */
49  	@Deprecated
50  	public Compound then(final Literal right)
51  	{return andThen(right);}
52  	
53  	
54  	/**
55  	 * Overloaded version of {@link Sequenceable#andThen(net.sourceforge.reb4j.Sequence.Sequenceable)} 
56  	 * for when the argument is an instance of {@link Raw}.
57  	 * 
58  	 * @param right an instance of {@link Raw}; must not be <code>null</code>.
59  	 * @return an instance of {@link Compound}.
60  	 * @throws NullPointerException
61  	 * 	if <var>right</var> is <code>null</code>.
62  	 */
63  	public Compound andThen(final Raw right)
64  	{
65  		if (right == null) throw new NullPointerException("right");
66  		return new Compound(List.list(this, right));
67  	}
68  
69  	/**
70  	 * Overloaded version of {@link Sequenceable#andThen(net.sourceforge.reb4j.Sequence.Sequenceable)} 
71  	 * for when the argument is an instance of {@link Compound}.
72  	 * 
73  	 * @param right an instance of {@link Compound}; must not be <code>null</code>.
74  	 * @return an instance of {@link Compound}.
75  	 * @throws NullPointerException
76  	 * 	if <var>right</var> is <code>null</code>.
77  	 */
78  	public Compound andThen(final Compound right)
79  	{
80  		if (right == null) throw new NullPointerException("right");
81  		return new Compound(right.components.cons(this));
82  	}
83  
84  	/**
85  	 * Overloaded version of {@link Sequenceable#andThen(net.sourceforge.reb4j.Sequence.Sequenceable)} 
86  	 * for when the argument is an instance of {@link Literal}.
87  	 * 
88  	 * @param right an instance of {@link Literal}; must not be <code>null</code>.
89  	 * @return an instance of {@link Compound}.
90  	 * @throws NullPointerException
91  	 * 	if <var>right</var> is <code>null</code>.
92  	 */
93  	public Compound andThen(final Literal right)
94  	{
95  		if (right == null) throw new NullPointerException("right");
96  		return this.then(new EscapedLiteral(right));
97  	}
98  	
99  
100 	/**
101 	 * Expression consisting of multiple 
102 	 */
103 	public static final class Compound extends Raw
104 	{
105 		private static final long serialVersionUID = 1L;
106 		public final List<Raw> components;
107 		
108 		private Compound(final List<Raw> components)
109 		{
110 			super(compoundExpression(components));
111 			this.components = components;
112 		}
113 		
114 		private static LazyString compoundExpression(final List<Raw> components)
115 		{
116 			return components.foldLeft(
117 					new F2<LazyString, Raw, LazyString>()
118 					{
119 						@Override
120 						public LazyString f(final LazyString a, final Raw b)
121 						{return a.append(b.rawExpression);}
122 					},
123 					LazyString.empty
124 				);
125 		}
126 		
127 		@Override
128 		@Deprecated
129 		public Compound then(final Raw right)
130 		{return andThen(right);}
131 		
132 		@Override
133 		@Deprecated
134 		public Compound then(final Compound right)
135 		{return andThen(right);}
136 		
137 		@Override
138 		public Compound andThen(final Raw right)
139 		{
140 			return new Compound(components.append(List.single(right)));
141 		}
142 		
143 		@Override
144 		public Compound andThen(final Compound right)
145 		{
146 			return new Compound(components.append(right.components));
147 		}
148 
149 		@Override
150 		public Integer boundedLength() 
151 		{
152 			final Long maximumLength = components.foldLeft(
153 					new F2<Long, Raw, Long>()
154 					{
155 						@Override public Long f(final Long a, final Raw b) 
156 						{
157 							if (a == null)
158 								return null;
159 							final Integer next = b.boundedLength();
160 							if (next == null)
161 								return null;
162 							return a + next;
163 						}
164 					},
165 					0L
166 				);
167 			if (maximumLength == null || maximumLength > 0xfffffffL) // arbitrary large value that appears in Pattern source code.
168 				return null;
169 			return maximumLength.intValue();
170 		}
171 		
172 		@Override 
173 		public boolean repetitionInvalidatesBounds() 
174 		{
175 			return components.forall(
176 					new F<Raw, Boolean>()
177 					{
178 						@Override public Boolean f(final Raw a) 
179 						{return a.repetitionInvalidatesBounds();}
180 					}
181 				);
182 		}
183 		
184 		@Override 
185 		public boolean possiblyZeroLength()
186 		{
187 			return components.forall(
188 					new F<Raw, Boolean>()
189 					{
190 						@Override public Boolean f(final Raw a) 
191 						{return a.possiblyZeroLength();}
192 					}
193 				);
194 		}
195 	}
196 	
197 	
198 	/**
199 	 * Adapter from {@link Literal} to {@link Raw} to facilitate
200 	 * merging literals.
201 	 */
202 	public static final class EscapedLiteral extends Raw
203 	{
204 		private static final long serialVersionUID = 1L;
205 		public final Literal literal;
206 		
207 		public EscapedLiteral(final Literal literal)
208 		{
209 			super(literal.escaped());
210 			this.literal = literal;
211 		}
212 
213 		@Override
214 		public Integer boundedLength() 
215 		{
216 			return literal.boundedLength();
217 		}
218 		
219 		@Override 
220 		public boolean repetitionInvalidatesBounds() 
221 		{
222 			return possiblyZeroLength();
223 		}
224 		
225 		@Override 
226 		public boolean possiblyZeroLength()
227 		{
228 			return literal.possiblyZeroLength();
229 		}
230 	}
231 
232 
233 	@Override
234 	public int hashCode()
235 	{
236 		final int prime = 31;
237 		int result = 1;
238 		result = prime * result + rawExpression.hashCode();
239 		return result;
240 	}
241 
242 	@Override
243 	public boolean equals(final Object obj)
244 	{
245 		if (this == obj)
246 			return true;
247 		if (obj == null)
248 			return false;
249 		if (getClass() != obj.getClass())
250 			return false;
251 		final Raw other = (Raw) obj;
252 		return rawExpression.equals(other.rawExpression);
253 	}
254 	
255 }
256 
257 
258