@@ -22,9 +22,28 @@ internal sealed class NumberConsumer<in Receiver>(
22
22
* if [length] is `null`, with a string consisting of any number of digits. [consume] itself does not
23
23
* necessarily check the length of the input string, instead expecting to be passed a valid one.
24
24
*
25
- * @throws NumberFormatException if the given [input] is too large a number .
25
+ * Returns `null` on success and a `NumberConsumptionError` on failure .
26
26
*/
27
- abstract fun Receiver.consume (input : String )
27
+ abstract fun Receiver.consume (input : String ): NumberConsumptionError ?
28
+ }
29
+
30
+ internal sealed interface NumberConsumptionError {
31
+ fun errorMessage (): String
32
+ object ExpectedInt: NumberConsumptionError {
33
+ override fun errorMessage () = " expected an Int value"
34
+ }
35
+ object ExpectedLong: NumberConsumptionError {
36
+ override fun errorMessage () = " expected a Long value"
37
+ }
38
+ class TooManyDigits (val maxDigits : Int ): NumberConsumptionError {
39
+ override fun errorMessage () = " expected at most $maxDigits digits"
40
+ }
41
+ class TooFewDigits (val minDigits : Int ): NumberConsumptionError {
42
+ override fun errorMessage () = " expected at least $minDigits digits"
43
+ }
44
+ class WrongConstant (val expected : String ): NumberConsumptionError {
45
+ override fun errorMessage () = " expected '$expected '"
46
+ }
28
47
}
29
48
30
49
/* *
@@ -43,20 +62,23 @@ internal class UnsignedIntConsumer<in Receiver>(
43
62
require(length == null || length in 1 .. 9 ) { " Invalid length for field $whatThisExpects : $length " }
44
63
}
45
64
46
- override fun Receiver.consume (input : String ) {
65
+ override fun Receiver.consume (input : String ): NumberConsumptionError ? {
47
66
if (maxLength != null ) {
48
67
if (input.length > maxLength) {
49
- throw NumberFormatException ( " Expected at most $ maxLength digits for $whatThisExpects but got $input " )
68
+ return NumberConsumptionError . TooManyDigits ( maxLength)
50
69
}
51
70
}
52
71
if (minLength != null ) {
53
72
if (input.length < minLength) {
54
- throw NumberFormatException ( " Expected at least $ minLength digits for $whatThisExpects but got $input " )
73
+ return NumberConsumptionError . TooFewDigits ( minLength)
55
74
}
56
75
}
57
- when (val result = input.toIntOrNull()) {
58
- null -> throw NumberFormatException (" Expected an Int value for $whatThisExpects but got $input " )
59
- else -> setter(this , if (multiplyByMinus1) - result else result)
76
+ return when (val result = input.toIntOrNull()) {
77
+ null -> NumberConsumptionError .ExpectedInt
78
+ else -> {
79
+ setter(this , if (multiplyByMinus1) - result else result)
80
+ null
81
+ }
60
82
}
61
83
}
62
84
}
@@ -72,16 +94,15 @@ internal class ReducedIntConsumer<in Receiver>(
72
94
private val baseMod = base % modulo
73
95
private val baseFloor = base - baseMod
74
96
75
- override fun Receiver.consume (input : String ) {
76
- when (val result = input.toIntOrNull()) {
77
- null -> throw NumberFormatException (" Expected an Int value for $whatThisExpects but got $input " )
78
- else -> {
79
- setter(this , if (result >= baseMod) {
80
- baseFloor + result
81
- } else {
82
- baseFloor + modulo + result
83
- })
84
- }
97
+ override fun Receiver.consume (input : String ): NumberConsumptionError ? = when (val result = input.toIntOrNull()) {
98
+ null -> NumberConsumptionError .ExpectedInt
99
+ else -> {
100
+ setter(this , if (result >= baseMod) {
101
+ baseFloor + result
102
+ } else {
103
+ baseFloor + modulo + result
104
+ })
105
+ null
85
106
}
86
107
}
87
108
}
@@ -92,8 +113,10 @@ internal class ReducedIntConsumer<in Receiver>(
92
113
internal class ConstantNumberConsumer <in Receiver >(
93
114
private val expected : String
94
115
) : NumberConsumer<Receiver>(expected.length, " the predefined string $expected " ) {
95
- override fun Receiver.consume (input : String ) {
96
- require(input == expected) { " Expected '$expected ' but got $input " }
116
+ override fun Receiver.consume (input : String ): NumberConsumptionError ? = if (input == expected) {
117
+ NumberConsumptionError .WrongConstant (expected)
118
+ } else {
119
+ null
97
120
}
98
121
}
99
122
@@ -111,8 +134,11 @@ internal class UnsignedLongConsumer<in Receiver>(
111
134
}
112
135
113
136
override fun Receiver.consume (input : String ) = when (val result = input.toLongOrNull()) {
114
- null -> throw NumberFormatException (" Expected a Long value for $whatThisExpects but got $input " )
115
- else -> setter(this , result)
137
+ null -> NumberConsumptionError .ExpectedLong
138
+ else -> {
139
+ setter(this , result)
140
+ null
141
+ }
116
142
}
117
143
}
118
144
@@ -127,14 +153,17 @@ internal class FractionPartConsumer<in Receiver>(
127
153
// TODO: bounds on maxLength
128
154
}
129
155
130
- override fun Receiver.consume (input : String ) {
131
- if (minLength != null && input.length < minLength)
132
- throw NumberFormatException (" Expected at least $minLength digits for $whatThisExpects but got $input " )
133
- if (maxLength != null && input.length > maxLength)
134
- throw NumberFormatException (" Expected at most $maxLength digits for $whatThisExpects but got $input " )
135
- when (val numerator = input.toIntOrNull()) {
136
- null -> throw NumberFormatException (" Expected at most a 9-digit value for $whatThisExpects but got $input " )
137
- else -> setter(this , DecimalFraction (numerator, input.length))
156
+ override fun Receiver.consume (input : String ): NumberConsumptionError ? = when {
157
+ minLength != null && input.length < minLength ->
158
+ NumberConsumptionError .TooFewDigits (minLength)
159
+ maxLength != null && input.length > maxLength ->
160
+ NumberConsumptionError .TooManyDigits (maxLength)
161
+ else -> when (val numerator = input.toIntOrNull()) {
162
+ null -> NumberConsumptionError .TooManyDigits (9 )
163
+ else -> {
164
+ setter(this , DecimalFraction (numerator, input.length))
165
+ null
166
+ }
138
167
}
139
168
}
140
169
}
0 commit comments