Skip to content

Commit 4d6a9ba

Browse files
authored
Merge pull request scala#6746 from som-snytt/review/6726-more
Accept .5 for half
2 parents 18b9a0a + 86e7697 commit 4d6a9ba

File tree

2 files changed

+36
-34
lines changed

2 files changed

+36
-34
lines changed

src/library/scala/collection/StringParsers.scala

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ final private[scala] object StringParsers {
1616
private final val longOverflowBoundary = -922337203685477580L
1717
private final val longOverflowDigit = 9
1818

19-
2019
@inline
2120
private[this] final def decValue(ch: Char): Int = java.lang.Character.digit(ch, 10)
2221

@@ -38,6 +37,9 @@ final private[scala] object StringParsers {
3837
rec(1, agg)
3938
}
4039

40+
@inline
41+
private[this] final def isDigit(c: Char): Boolean = c >= '0' && c <= '9'
42+
4143
//bool
4244
@inline
4345
final def parseBool(from: String): Option[Boolean] =
@@ -164,11 +166,7 @@ final private[scala] object StringParsers {
164166
//some utilities for working with index bounds into the original string
165167
@inline
166168
def forAllBetween(start: Int, end: Int, pred: Char => Boolean): Boolean = {
167-
def rec(i: Int): Boolean = {
168-
if (i >= end) true
169-
else if (pred(format.charAt(i))) rec(i + 1)
170-
else false
171-
}
169+
def rec(i: Int): Boolean = i >= end || pred(format.charAt(i)) && rec(i + 1)
172170
rec(start)
173171
}
174172

@@ -209,11 +207,11 @@ final private[scala] object StringParsers {
209207

210208
def postfixOK(startIndex: Int, endIndex: Int): Boolean =
211209
(startIndex < endIndex) && {
212-
(forAllBetween(startIndex, endIndex, ch => ch >= '0' && ch <= '9')) || {
210+
(forAllBetween(startIndex, endIndex, isDigit)) || {
213211
val startchar = format.charAt(startIndex)
214212
(startchar == '+' || startchar == '-') &&
215213
(endIndex - startIndex > 1) &&
216-
forAllBetween(startIndex + 1, endIndex, ch => ch >= '0' && ch <= '9')
214+
forAllBetween(startIndex + 1, endIndex, isDigit)
217215
}
218216
}
219217
// prefix [pP] postfix
@@ -224,13 +222,15 @@ final private[scala] object StringParsers {
224222
def isDecFloatLiteral(startIndex: Int, endIndex: Int): Boolean = {
225223
//invariant: endIndex > startIndex
226224

225+
def isExp(c: Char): Boolean = c == 'e' || c == 'E'
226+
227227
def expOK(startIndex: Int, endIndex: Int): Boolean =
228228
(startIndex < endIndex) && {
229229
val startChar = format.charAt(startIndex)
230230
if (startChar == '+' || startChar == '-')
231231
(endIndex > (startIndex + 1)) &&
232-
skipIndexWhile(ch => ch >= '0' && ch <= '9', startIndex + 1, endIndex) == endIndex
233-
else skipIndexWhile(ch => ch >= '0' && ch <= '9', startIndex, endIndex) == endIndex
232+
skipIndexWhile(isDigit, startIndex + 1, endIndex) == endIndex
233+
else skipIndexWhile(isDigit, startIndex, endIndex) == endIndex
234234
}
235235

236236
//significant can be one of
@@ -240,30 +240,26 @@ final private[scala] object StringParsers {
240240
//but not just .
241241
val startChar = format.charAt(startIndex)
242242
if (startChar == '.') {
243-
val noSignificant = skipIndexWhile(ch => ch >= '0' && ch <= '9', startIndex + 1, endIndex)
244-
(noSignificant != startIndex + 1) && { //not just "." or ".Exxx"
245-
val e = format.charAt(noSignificant)
246-
(e == 'e' || e == 'E') && expOK(noSignificant + 1, endIndex)
247-
}
243+
val noSignificant = skipIndexWhile(isDigit, startIndex + 1, endIndex)
244+
// a digit is required followed by optional exp
245+
(noSignificant > startIndex + 1) && (noSignificant >= endIndex ||
246+
isExp(format.charAt(noSignificant)) && expOK(noSignificant + 1, endIndex)
247+
)
248248
}
249-
else if (startChar >= '0' && startChar <= '9'){
250-
//one set of digits, then optionally a period, then optionally another set of digits, then optionally an exponent
251-
val noInt = skipIndexWhile(ch => ch >= '0' && ch <= '9', startIndex, endIndex)
252-
(noInt == endIndex) || { //just the digits
253-
val afterIntChar = format.charAt(noInt)
254-
if (afterIntChar == '.') {
255-
val noSignificant = skipIndexWhile(ch => ch >= '0' && ch <= '9', noInt + 1, endIndex)
256-
(noSignificant >= endIndex) || { //no exponent
257-
val e = format.charAt(noSignificant)
258-
(e == 'e' || e == 'E') && expOK(noSignificant + 1, endIndex)
259-
}
260-
}
261-
else if (afterIntChar == 'e' || afterIntChar == 'E') expOK(noInt + 1, endIndex)
262-
else false
249+
else if (isDigit(startChar)) {
250+
// one set of digits, then optionally a period, then optionally another set of digits, then optionally an exponent
251+
val noInt = skipIndexWhile(isDigit, startIndex, endIndex)
252+
// just the digits
253+
(noInt == endIndex) || {
254+
if (format.charAt(noInt) == '.') {
255+
val noSignificant = skipIndexWhile(isDigit, noInt + 1, endIndex)
256+
(noSignificant >= endIndex) || //no exponent
257+
isExp(format.charAt(noSignificant)) && expOK(noSignificant + 1, endIndex)
258+
} else
259+
isExp(format.charAt(noInt)) && expOK(noInt + 1, endIndex)
263260
}
264261
}
265262
else false
266-
267263
}
268264

269265
//count 0x00 to 0x20 as "whitespace", and nothing else
@@ -307,4 +303,4 @@ final private[scala] object StringParsers {
307303
if (checkFloatFormat(from)) Some(java.lang.Double.parseDouble(from))
308304
else None
309305

310-
}
306+
}

test/junit/scala/collection/StringParsersTest.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class StringParsersTest {
1313
def doubleOK(str: String): Unit = assertTrue(
1414
s"str.toDouble <> str.toDoubleOption for $str",
1515
(str.toDoubleOption, Try(str.toDouble).toOption) match {
16-
case (Some(d1), Some(d2)) if d1.isNaN && d2.isNaN => true
16+
case (Some(d1), Some(d2)) => d1.isNaN && d2.isNaN || d1 == d2
1717
case (o1, o2) => o1 == o2
1818
})
1919

@@ -242,10 +242,16 @@ class StringParsersTest {
242242
"-0x0.000000000000090000000000000000001p-1022",
243243
"-0x0.00000000000009fffffffffffffffffffffffffffffffffp-1022",
244244
"-0x0.0000000000000fffffffffffffffffffffffffffffffffffp-1022",
245+
"",
246+
".",
247+
".4",
245248
".E4",
249+
".E",
250+
".x",
251+
".1E4",
252+
"4.",
246253
"1.1E4",
247254
"1.E4",
248-
".1E4",
249255
"1E4",
250256
"E4",
251257
"0.0",
@@ -307,4 +313,4 @@ class StringParsersTest {
307313
@Test
308314
def nullDouble: Unit = assertThrows[NullPointerException](nullstring.toDoubleOption)
309315

310-
}
316+
}

0 commit comments

Comments
 (0)