1 package io.github.reggert.reb4j;
2
3 import fj.F2;
4 import fj.data.LazyString;
5 import fj.data.List;
6
7
8
9
10 public final class Alternation extends AbstractExpression
11 implements Alternative
12 {
13 private static final long serialVersionUID = 1L;
14 public final List<Alternative> alternatives;
15
16 private Alternation(final List<Alternative> alternatives)
17 {
18 if (alternatives == null) throw new NullPointerException("alternatives");
19 this.alternatives = alternatives;
20 }
21
22
23
24
25
26
27
28
29
30
31
32
33 Alternation(final Alternation left, final Alternation right)
34 {
35 if (left == null) throw new NullPointerException("left");
36 if (right == null) throw new NullPointerException("right");
37 this.alternatives = left.alternatives.append(right.alternatives);
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51 Alternation(final Alternation left, final Alternative right)
52 {
53 if (left == null) throw new NullPointerException("left");
54 if (right == null) throw new NullPointerException("right");
55 this.alternatives = left.alternatives.append(List.single(right));
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69 Alternation(final Alternative left, final Alternation right)
70 {
71 if (left == null) throw new NullPointerException("left");
72 if (right == null) throw new NullPointerException("right");
73 this.alternatives = right.alternatives.cons(left);
74 }
75
76
77
78
79
80
81
82
83
84
85
86 Alternation(final Alternative left, final Alternative right)
87 {
88 if (left == null) throw new NullPointerException("left");
89 if (right == null) throw new NullPointerException("right");
90 this.alternatives = List.list(left, right);
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public static Alternation alternatives(
107 final Alternative first,
108 final Alternative second,
109 final Alternative... rest
110 )
111 {
112 if (first == null) throw new NullPointerException("first");
113 if (second == null) throw new NullPointerException("second");
114 if (rest == null) throw new NullPointerException("rest");
115 return new Alternation(List.list(rest).cons(second).cons(first));
116 }
117
118 @Override
119 public LazyString expression()
120 {
121 return alternatives.tail().foldLeft(
122 new F2<LazyString, Alternative, LazyString>()
123 {
124 @Override
125 public LazyString f(final LazyString a, final Alternative b)
126 {return a.append("|").append(b.expression());}
127 },
128 alternatives.head().expression()
129 );
130 }
131
132 @Override
133 public Alternation or(final Alternation right)
134 {return new Alternation(this, right);}
135
136 @Override
137 public Alternation or(final Alternative right)
138 {return new Alternation(this, right);}
139
140 @Override
141 public int hashCode()
142 {
143 final int prime = 31;
144 int result = 1;
145 result = prime * result + alternatives.hashCode();
146 return result;
147 }
148
149 @Override
150 public boolean equals(final Object obj)
151 {
152 if (this == obj)
153 return true;
154 if (obj == null)
155 return false;
156 if (getClass() != obj.getClass())
157 return false;
158 final Alternation other = (Alternation) obj;
159 return alternatives.equals(other.alternatives);
160 }
161
162 @Override
163 public Integer boundedLength()
164 {
165 int maximumLength = 0;
166 for (final Alternative alternative : alternatives)
167 {
168 final Integer alternativeLength = alternative.boundedLength();
169 if (alternativeLength == null)
170 return null;
171 if (alternativeLength > maximumLength)
172 maximumLength = alternativeLength;
173 }
174 return maximumLength;
175 }
176
177 @Override
178 public boolean repetitionInvalidatesBounds()
179 {
180 return true;
181 }
182
183 @Override
184 public boolean possiblyZeroLength()
185 {
186 for (final Alternative a : alternatives)
187 if (a.possiblyZeroLength())
188 return true;
189 return false;
190 }
191 }
192