@@ -21,6 +21,8 @@ import config.Feature.migrateTo3
21
21
import config .SourceVersion .`3.0`
22
22
import reporting .{NoProfile , Profile }
23
23
24
+ import java .lang .Character .isDigit
25
+
24
26
object Scanners {
25
27
26
28
/** Offset into source character array */
@@ -152,9 +154,9 @@ object Scanners {
152
154
strVal = litBuf.toString
153
155
litBuf.clear()
154
156
155
- @ inline def isNumberSeparator (c : Char ): Boolean = c == '_'
157
+ inline def isNumberSeparator (c : Char ): Boolean = c == '_'
156
158
157
- @ inline def removeNumberSeparators (s : String ): String = if ( s.indexOf('_' ) == - 1 ) s else s.replace(" _" , " " )
159
+ inline def removeNumberSeparators (s : String ): String = if s.indexOf('_' ) == - 1 then s else s.replace(" _" , " " )
158
160
159
161
// disallow trailing numeric separator char, but continue lexing
160
162
def checkNoTrailingSeparator (): Unit =
@@ -887,7 +889,7 @@ object Scanners {
887
889
// case 'b' | 'B' => base = 2 ; nextChar()
888
890
case _ => base = 10 ; putChar('0' )
889
891
}
890
- if ( base != 10 && ! isNumberSeparator(ch) && digit2int(ch, base) < 0 )
892
+ if base != 10 && ! isNumberSeparator(ch) && digit2int(ch, base) < 0 then
891
893
error(" invalid literal number" )
892
894
}
893
895
fetchLeadingZero()
@@ -967,7 +969,7 @@ object Scanners {
967
969
case '.' =>
968
970
nextChar()
969
971
if ('0' <= ch && ch <= '9' ) {
970
- putChar('.' ); getFraction(); setStrVal()
972
+ putChar('.' ); getFraction()
971
973
}
972
974
else
973
975
token = DOT
@@ -1427,7 +1429,7 @@ object Scanners {
1427
1429
/** read fractional part and exponent of floating point number
1428
1430
* if one is present.
1429
1431
*/
1430
- protected def getFraction (): Unit = {
1432
+ protected def getFraction (): Unit =
1431
1433
token = DECILIT
1432
1434
while ('0' <= ch && ch <= '9' || isNumberSeparator(ch)) {
1433
1435
putChar(ch)
@@ -1465,41 +1467,44 @@ object Scanners {
1465
1467
token = FLOATLIT
1466
1468
}
1467
1469
checkNoLetter()
1468
- }
1470
+ setStrVal()
1471
+ end getFraction
1469
1472
def checkNoLetter (): Unit =
1470
1473
if (isIdentifierPart(ch) && ch >= ' ' )
1471
1474
error(" Invalid literal number" )
1472
1475
1473
1476
/** Read a number into strVal and set base
1474
1477
*/
1475
- protected def getNumber (): Unit = {
1476
- while (isNumberSeparator(ch) || digit2int(ch, base) >= 0 ) {
1477
- putChar(ch)
1478
- nextChar()
1479
- }
1480
- checkNoTrailingSeparator()
1481
- token = INTLIT
1482
- if (base == 10 && ch == '.' ) {
1483
- val lch = lookaheadChar()
1484
- if ('0' <= lch && lch <= '9' ) {
1485
- putChar('.' )
1486
- nextChar()
1487
- getFraction()
1488
- }
1489
- }
1490
- else (ch : @ switch) match {
1491
- case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' =>
1492
- if (base == 10 ) getFraction()
1493
- case 'l' | 'L' =>
1478
+ protected def getNumber (): Unit =
1479
+ def consumeDigits (): Unit =
1480
+ while isNumberSeparator(ch) || digit2int(ch, base) >= 0 do
1481
+ putChar(ch)
1494
1482
nextChar()
1495
- token = LONGLIT
1496
- case _ =>
1497
- }
1483
+ // at dot with digit following
1484
+ def restOfNonIntegralNumber (): Unit =
1485
+ putChar('.' )
1486
+ nextChar()
1487
+ getFraction()
1488
+ // 1l is an acknowledged bad practice
1489
+ def lintel (): Unit =
1490
+ if ch == 'l' then
1491
+ val msg = " Lowercase el for long is not recommended because it is easy to confuse with numeral 1; use uppercase L instead"
1492
+ report.deprecationWarning(msg, sourcePos(offset + litBuf.length))
1493
+ // after int: 5e7f, 42L, 42.toDouble but not 42b.
1494
+ def restOfNumber (): Unit =
1495
+ ch match
1496
+ case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => getFraction()
1497
+ case 'l' | 'L' => lintel() ; token = LONGLIT ; setStrVal() ; nextChar()
1498
+ case _ => token = INTLIT ; setStrVal() ; checkNoLetter()
1499
+
1500
+ // consume leading digits
1501
+ consumeDigits()
1498
1502
1499
1503
checkNoTrailingSeparator()
1500
1504
1501
- setStrVal()
1502
- }
1505
+ val detectedFloat : Boolean = base == 10 && ch == '.' && isDigit(lookaheadChar())
1506
+ if detectedFloat then restOfNonIntegralNumber() else restOfNumber()
1507
+ end getNumber
1503
1508
1504
1509
private def finishCharLit (): Unit = {
1505
1510
nextChar()
0 commit comments