@@ -20,6 +20,8 @@ import config.Feature
2020import config .Feature .migrateTo3
2121import config .SourceVersion .`3.0`
2222
23+ import java .lang .Character .isDigit
24+
2325object Scanners {
2426
2527 /** Offset into source character array */
@@ -156,9 +158,9 @@ object Scanners {
156158 strVal = litBuf.toString
157159 litBuf.clear()
158160
159- @ inline def isNumberSeparator (c : Char ): Boolean = c == '_'
161+ inline def isNumberSeparator (c : Char ): Boolean = c == '_'
160162
161- @ inline def removeNumberSeparators (s : String ): String = if ( s.indexOf('_' ) == - 1 ) s else s.replace(" _" , " " )
163+ inline def removeNumberSeparators (s : String ): String = if s.indexOf('_' ) == - 1 then s else s.replace(" _" , " " )
162164
163165 // disallow trailing numeric separator char, but continue lexing
164166 def checkNoTrailingSeparator (): Unit =
@@ -849,7 +851,7 @@ object Scanners {
849851 // case 'b' | 'B' => base = 2 ; nextChar()
850852 case _ => base = 10 ; putChar('0' )
851853 }
852- if ( base != 10 && ! isNumberSeparator(ch) && digit2int(ch, base) < 0 )
854+ if base != 10 && ! isNumberSeparator(ch) && digit2int(ch, base) < 0 then
853855 error(" invalid literal number" )
854856 }
855857 fetchLeadingZero()
@@ -929,7 +931,7 @@ object Scanners {
929931 case '.' =>
930932 nextChar()
931933 if ('0' <= ch && ch <= '9' ) {
932- putChar('.' ); getFraction(); setStrVal()
934+ putChar('.' ); getFraction()
933935 }
934936 else
935937 token = DOT
@@ -1389,7 +1391,7 @@ object Scanners {
13891391 /** read fractional part and exponent of floating point number
13901392 * if one is present.
13911393 */
1392- protected def getFraction (): Unit = {
1394+ protected def getFraction (): Unit =
13931395 token = DECILIT
13941396 while ('0' <= ch && ch <= '9' || isNumberSeparator(ch)) {
13951397 putChar(ch)
@@ -1427,41 +1429,44 @@ object Scanners {
14271429 token = FLOATLIT
14281430 }
14291431 checkNoLetter()
1430- }
1432+ setStrVal()
1433+ end getFraction
14311434 def checkNoLetter (): Unit =
14321435 if (isIdentifierPart(ch) && ch >= ' ' )
14331436 error(" Invalid literal number" )
14341437
14351438 /** Read a number into strVal and set base
14361439 */
1437- protected def getNumber (): Unit = {
1438- while (isNumberSeparator(ch) || digit2int(ch, base) >= 0 ) {
1439- putChar(ch)
1440- nextChar()
1441- }
1442- checkNoTrailingSeparator()
1443- token = INTLIT
1444- if (base == 10 && ch == '.' ) {
1445- val lch = lookaheadChar()
1446- if ('0' <= lch && lch <= '9' ) {
1447- putChar('.' )
1448- nextChar()
1449- getFraction()
1450- }
1451- }
1452- else (ch : @ switch) match {
1453- case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' =>
1454- if (base == 10 ) getFraction()
1455- case 'l' | 'L' =>
1440+ protected def getNumber (): Unit =
1441+ def consumeDigits (): Unit =
1442+ while isNumberSeparator(ch) || digit2int(ch, base) >= 0 do
1443+ putChar(ch)
14561444 nextChar()
1457- token = LONGLIT
1458- case _ =>
1459- }
1445+ // at dot with digit following
1446+ def restOfNonIntegralNumber (): Unit =
1447+ putChar('.' )
1448+ nextChar()
1449+ getFraction()
1450+ // 1l is an acknowledged bad practice
1451+ def lintel (): Unit =
1452+ if ch == 'l' then
1453+ val msg = " Lowercase el for long is not recommended because it is easy to confuse with numeral 1; use uppercase L instead"
1454+ report.deprecationWarning(msg, sourcePos(offset + litBuf.length))
1455+ // after int: 5e7f, 42L, 42.toDouble but not 42b.
1456+ def restOfNumber (): Unit =
1457+ ch match
1458+ case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => getFraction()
1459+ case 'l' | 'L' => lintel() ; token = LONGLIT ; setStrVal() ; nextChar()
1460+ case _ => token = INTLIT ; setStrVal() ; checkNoLetter()
1461+
1462+ // consume leading digits
1463+ consumeDigits()
14601464
14611465 checkNoTrailingSeparator()
14621466
1463- setStrVal()
1464- }
1467+ val detectedFloat : Boolean = base == 10 && ch == '.' && isDigit(lookaheadChar())
1468+ if detectedFloat then restOfNonIntegralNumber() else restOfNumber()
1469+ end getNumber
14651470
14661471 private def finishCharLit (): Unit = {
14671472 nextChar()
0 commit comments