@@ -35,27 +35,38 @@ public final class ArgumentConstraints {
3535 private static final String EXPRESSION_TYPE = "expression" ;
3636
3737 /**
38- * Describes a heterogenous list of arguments. Each argument is checked against
38+ * Describes a heterogeneous list of arguments. Each argument is checked against
3939 * the corresponding constraint. An {@link ArityException} will be thrown when
4040 * the number of arguments does not exactly match the number of constraints.
4141 * <p>
4242 * May only be used as a top level constraint – and is already built in to
4343 * {@link Function}, so direct usage of this method should not be needed.
4444 */
4545 public static ArgumentConstraint listOf (ArgumentConstraint ... constraints ) {
46- return new HeterogenousListOf (constraints );
46+ return new HeterogeneousListOf (constraints );
4747 }
4848
4949 /**
50- * Descripes a homogenous list of arguments, of fixed or variable length.
50+ * Describes a homogeneous list of arguments, of fixed or variable length.
5151 * An {@link ArityException} will be thrown when there are fewer arguments
5252 * than the specified minimum arity, or when there are more arguments than
5353 * the specified maximum arity.
5454 * <p>
5555 * May only be used as a top level constraint.
5656 */
5757 public static ArgumentConstraint listOf (int min , int max , ArgumentConstraint constraint ) {
58- return new HomogenousListOf (min , max , constraint );
58+ return new HomogeneousListOf (min , max , constraint );
59+ }
60+
61+ /**
62+ * Describes a homogeneous list of arguments without upper limit.
63+ * An {@link ArityException} will be thrown when there are fewer arguments
64+ * than the specified minimum arity.
65+ * <p>
66+ * May only be used as a top level constraint.
67+ */
68+ public static ArgumentConstraint listOf (int min , ArgumentConstraint constraint ) {
69+ return new VariadicListOf (min , constraint );
5970 }
6071
6172 /**
@@ -115,7 +126,7 @@ public BaseArgumentConstraint(int minArity, int maxArity, String expectedTypeDes
115126 this .expectedTypeDescription = expectedTypeDescription ;
116127 }
117128
118- protected <T > Iterator <ArgumentError > checkNoRemaingArguments (Iterator <FunctionArgument <T >> arguments , boolean expectNoRemainingArguments ) {
129+ protected <T > Iterator <ArgumentError > checkNoRemainingArguments (Iterator <FunctionArgument <T >> arguments , boolean expectNoRemainingArguments ) {
119130 if (expectNoRemainingArguments && arguments .hasNext ()) {
120131 return singletonIterator (ArgumentError .createArityError ());
121132 } else {
@@ -133,6 +144,9 @@ public int maxArity() {
133144 return maxArity ;
134145 }
135146
147+ @ Override
148+ public boolean arityViolated (int n ) { return (n < minArity || maxArity < n ); }
149+
136150 @ Override
137151 public String expectedType () {
138152 return expectedTypeDescription ;
@@ -147,10 +161,10 @@ protected <U> Iterator<U> emptyIterator() {
147161 }
148162 }
149163
150- private static class HomogenousListOf extends BaseArgumentConstraint {
164+ private static class HomogeneousListOf extends BaseArgumentConstraint {
151165 private final ArgumentConstraint subConstraint ;
152166
153- public HomogenousListOf (int minArity , int maxArity , ArgumentConstraint subConstraint ) {
167+ public HomogeneousListOf (int minArity , int maxArity , ArgumentConstraint subConstraint ) {
154168 super (minArity , maxArity , subConstraint .expectedType ());
155169 this .subConstraint = subConstraint ;
156170 }
@@ -178,14 +192,14 @@ public <T> Iterator<ArgumentError> check(Adapter<T> runtime, Iterator<FunctionAr
178192 break ;
179193 }
180194 }
181- return checkNoRemaingArguments (arguments , expectNoRemainingArguments );
195+ return checkNoRemainingArguments (arguments , expectNoRemainingArguments );
182196 }
183197 }
184198
185- private static class HeterogenousListOf extends BaseArgumentConstraint {
199+ private static class HeterogeneousListOf extends BaseArgumentConstraint {
186200 private final ArgumentConstraint [] subConstraints ;
187201
188- public HeterogenousListOf (ArgumentConstraint [] subConstraints ) {
202+ public HeterogeneousListOf (ArgumentConstraint [] subConstraints ) {
189203 super (calculateMinArity (subConstraints ), calculateMaxArity (subConstraints ), null );
190204 this .subConstraints = subConstraints ;
191205 }
@@ -218,10 +232,39 @@ public <T> Iterator<ArgumentError> check(Adapter<T> runtime, Iterator<FunctionAr
218232 return singletonIterator (ArgumentError .createArityError ());
219233 }
220234 }
221- return checkNoRemaingArguments (arguments , expectNoRemainingArguments );
235+ return checkNoRemainingArguments (arguments , expectNoRemainingArguments );
236+ }
237+ }
238+
239+ private static class VariadicListOf extends BaseArgumentConstraint {
240+ private final ArgumentConstraint subConstraint ;
241+
242+ public VariadicListOf (int minArity , ArgumentConstraint subConstraint ) {
243+ super (minArity , -1 , subConstraint .expectedType ());
244+ this .subConstraint = subConstraint ;
245+ }
246+
247+ @ Override
248+ public <T > Iterator <ArgumentError > check (Adapter <T > runtime , Iterator <FunctionArgument <T >> arguments , boolean expectNoRemainingArguments ) {
249+ int i = 0 ;
250+ for ( ;arguments .hasNext (); ++i ) {
251+ Iterator <ArgumentError > error = subConstraint .check (runtime , arguments , false );
252+ if (error .hasNext ()) {
253+ return error ;
254+ }
255+ }
256+ if (i < minArity ()) {
257+ return singletonIterator (ArgumentError .createArityError ());
258+ } else {
259+ return emptyIterator ();
260+ }
222261 }
262+
263+ @ Override
264+ public boolean arityViolated (int n ) { return n < minArity (); }
223265 }
224266
267+
225268 private static abstract class TypeCheck extends BaseArgumentConstraint {
226269 public TypeCheck (String expectedType ) {
227270 super (1 , 1 , expectedType );
@@ -234,7 +277,7 @@ public <T> Iterator<ArgumentError> check(Adapter<T> runtime, Iterator<FunctionAr
234277 if (error .hasNext ()) {
235278 return error ;
236279 } else {
237- return checkNoRemaingArguments (arguments , expectNoRemainingArguments );
280+ return checkNoRemainingArguments (arguments , expectNoRemainingArguments );
238281 }
239282 } else {
240283 return singletonIterator (ArgumentError .createArityError ());
@@ -359,7 +402,7 @@ public <T> Iterator<ArgumentError> check(Adapter<T> runtime, Iterator<FunctionAr
359402 return singletonIterator ((ArgumentError ) ArgumentError .createArgumentTypeError (expectedType (), type .toString ()));
360403 }
361404 }
362- return checkNoRemaingArguments (arguments , expectNoRemainingArguments );
405+ return checkNoRemainingArguments (arguments , expectNoRemainingArguments );
363406 } else {
364407 return singletonIterator (ArgumentError .createArityError ());
365408 }
0 commit comments