@@ -660,20 +660,20 @@ lexStdToken = do
660
660
661
661
' 0' : c: d: _ | toLower c == ' o' && isOctDigit d -> do
662
662
discard 2
663
- (n, str) <- lexOctal
663
+ (n, str) <- lexOctal $ numUnderscoresEnabled exts
664
664
con <- intHash
665
665
return (con (n, ' 0' : c: str))
666
666
| toLower c == ' b' && isBinDigit d && BinaryLiterals `elem` exts -> do
667
667
discard 2
668
- (n, str) <- lexBinary
668
+ (n, str) <- lexBinary $ numUnderscoresEnabled exts
669
669
con <- intHash
670
670
return (con (n, ' 0' : c: str))
671
671
| toLower c == ' x' && isHexDigit d && HexFloatLiterals `elem` exts -> do
672
672
discard 2
673
- lexHexadecimalFloat c
673
+ lexHexadecimalFloat (numUnderscoresEnabled exts) c
674
674
| toLower c == ' x' && isHexDigit d -> do
675
675
discard 2
676
- (n, str) <- lexHexadecimal
676
+ (n, str) <- lexHexadecimal $ numUnderscoresEnabled exts
677
677
con <- intHash
678
678
return (con (n, ' 0' : c: str))
679
679
@@ -806,7 +806,7 @@ lexStdToken = do
806
806
return $ LabelVarId ident
807
807
808
808
809
- c: _ | isDigit c -> lexDecimalOrFloat
809
+ c: _ | isDigit c -> lexDecimalOrFloat $ numUnderscoresEnabled exts
810
810
811
811
| isUpper c -> lexConIdOrQual " "
812
812
@@ -1012,77 +1012,76 @@ lexRawPragma = lexRawPragmaAux
1012
1012
rpr' <- lexRawPragma
1013
1013
return $ rpr ++ ' #' : rpr'
1014
1014
1015
- lexDecimalOrFloat :: Lex a Token
1016
- lexDecimalOrFloat = do
1017
- ds <- lexWhile isDigit
1015
+ lexDecimalOrFloat :: NumericUnderscoresAllowed -> Lex a Token
1016
+ lexDecimalOrFloat underAllowed = do
1017
+ (n, raw) <- lexHandleUnderAllowed underAllowed isDigit
1018
1018
rest <- getInput
1019
1019
exts <- getExtensionsL
1020
1020
case rest of
1021
1021
(' .' : d: _) | isDigit d -> do
1022
1022
discard 1
1023
- frac <- lexWhile isDigit
1024
- let num = parseInteger 10 (ds ++ frac)
1023
+ ( frac, fracRaw) <- lexHandleUnderAllowed underAllowed isDigit
1024
+ let num = parseInteger 10 (n ++ frac)
1025
1025
decimals = toInteger (length frac)
1026
1026
(exponent , estr) <- do
1027
1027
rest2 <- getInput
1028
1028
case rest2 of
1029
- ' e' : _ -> lexExponent
1030
- ' E' : _ -> lexExponent
1029
+ ' e' : _ -> lexExponent underAllowed
1030
+ ' E' : _ -> lexExponent underAllowed
1031
1031
_ -> return (0 ," " )
1032
1032
con <- lexHash FloatTok FloatTokHash (Right DoubleTokHash )
1033
- return $ con ((num% 1 ) * 10 ^^ (exponent - decimals), ds ++ ' .' : frac ++ estr)
1033
+ return $ con ((num% 1 ) * 10 ^^ (exponent - decimals), raw ++ ' .' : fracRaw ++ estr)
1034
1034
e: _ | toLower e == ' e' -> do
1035
- (exponent , estr) <- lexExponent
1035
+ (exponent , estr) <- lexExponent underAllowed
1036
1036
con <- lexHash FloatTok FloatTokHash (Right DoubleTokHash )
1037
- return $ con ((parseInteger 10 ds % 1 ) * 10 ^^ exponent , ds ++ estr)
1038
- ' #' : ' #' : _ | MagicHash `elem` exts -> discard 2 >> return (WordTokHash (parseInteger 10 ds, ds ))
1039
- ' #' : _ | MagicHash `elem` exts -> discard 1 >> return (IntTokHash (parseInteger 10 ds, ds ))
1040
- _ -> return (IntTok (parseInteger 10 ds, ds ))
1037
+ return $ con ((parseInteger 10 n % 1 ) * 10 ^^ exponent , raw ++ estr)
1038
+ ' #' : ' #' : _ | MagicHash `elem` exts -> discard 2 >> return (WordTokHash (parseInteger 10 n, raw ))
1039
+ ' #' : _ | MagicHash `elem` exts -> discard 1 >> return (IntTokHash (parseInteger 10 n, raw ))
1040
+ _ -> return (IntTok (parseInteger 10 n, raw ))
1041
1041
1042
- lexExponent :: Lex a (Integer , String )
1043
- lexExponent = do
1042
+ lexExponent :: NumericUnderscoresAllowed -> Lex a (Integer , String )
1043
+ lexExponent underAllowed = do
1044
1044
(e: r) <- getInput
1045
1045
discard 1 -- discard ex notation
1046
1046
case r of
1047
1047
' +' : d: _ | isDigit d -> do
1048
1048
discard 1
1049
- (n, str) <- lexDecimal
1049
+ (n, str) <- lexDecimal underAllowed
1050
1050
return (n, e: ' +' : str)
1051
1051
' -' : d: _ | isDigit d -> do
1052
1052
discard 1
1053
- (n, str) <- lexDecimal
1053
+ (n, str) <- lexDecimal underAllowed
1054
1054
return (negate n, e: ' -' : str)
1055
- d: _ | isDigit d -> lexDecimal >>= \ (n,str) -> return (n, e: str)
1055
+ d: _ | isDigit d -> lexDecimal underAllowed >>= \ (n,str) -> return (n, e: str)
1056
1056
_ -> fail " Float with missing exponent"
1057
1057
1058
- lexHexadecimalFloat :: Char -> Lex a Token
1059
- lexHexadecimalFloat c = do
1060
- ds <- lexWhile isHexDigit
1058
+ lexHexadecimalFloat :: NumericUnderscoresAllowed -> Char -> Lex a Token
1059
+ lexHexadecimalFloat underAllowed c = do
1060
+ (n, raw) <- lexHandleUnderAllowed underAllowed isHexDigit
1061
1061
rest <- getInput
1062
- exts <- getExtensionsL
1063
1062
case rest of
1064
1063
(' .' : d: _) | isHexDigit d -> do
1065
1064
discard 1
1066
- frac <- lexWhile isHexDigit
1067
- let num = parseInteger 16 ds
1065
+ ( frac, fracRaw) <- lexHandleUnderAllowed underAllowed isHexDigit
1066
+ let num = parseInteger 16 n
1068
1067
numFrac = parseFrac frac
1069
1068
(exponent , estr) <- do
1070
1069
rest2 <- getInput
1071
1070
case rest2 of
1072
- ' p' : _ -> lexExponent
1073
- ' P' : _ -> lexExponent
1071
+ ' p' : _ -> lexExponent underAllowed
1072
+ ' P' : _ -> lexExponent underAllowed
1074
1073
_ -> return (0 ," " )
1075
1074
con <- lexHash FloatTok FloatTokHash (Right DoubleTokHash )
1076
- return $ con (((num% 1 ) + numFrac) * 2 ^^ (exponent ), ' 0' : c: ds ++ ' .' : frac ++ estr)
1075
+ return $ con (((num% 1 ) + numFrac) * 2 ^^ (exponent ), ' 0' : c: raw ++ ' .' : fracRaw ++ estr)
1077
1076
e: _ | toLower e == ' p' -> do
1078
- (exponent , estr) <- lexExponent
1077
+ (exponent , estr) <- lexExponent underAllowed
1079
1078
con <- lexHash FloatTok FloatTokHash (Right DoubleTokHash )
1080
- return $ con (((parseInteger 16 ds )% 1 ) * 2 ^^ exponent , ' 0' : c: ds ++ estr)
1081
- _ -> return (IntTok (parseInteger 16 ds , ' 0' : c: ds ))
1079
+ return $ con (((parseInteger 16 n )% 1 ) * 2 ^^ exponent , ' 0' : c: raw ++ estr)
1080
+ _ -> return (IntTok (parseInteger 16 n , ' 0' : c: raw ))
1082
1081
where
1083
1082
parseFrac :: String -> Rational
1084
1083
parseFrac ds =
1085
- foldl (\ n (dp, d) -> n + (d / (16 ^^ dp))) (0 % 1 ) $ zip [1 .. ] (map ((% 1 ) . toInteger . digitToInt) ds)
1084
+ foldl (\ n (dp, d) -> n + (d / (16 ^^ dp))) (0 % 1 ) $ zip [( 1 :: Integer ) .. ] (map ((% 1 ) . toInteger . digitToInt) ds)
1086
1085
1087
1086
lexHash :: (b -> Token ) -> (b -> Token ) -> Either String (b -> Token ) -> Lex a (b -> Token )
1088
1087
lexHash a b c = do
@@ -1281,16 +1280,16 @@ lexEscape = do
1281
1280
1282
1281
' o' : c: _ | isOctDigit c -> do
1283
1282
discard 1
1284
- (n, raw) <- lexOctal
1283
+ (n, raw) <- lexOctal NoUnderscoresAllowedInNumeric
1285
1284
n' <- checkChar n
1286
1285
return (n', ' o' : raw)
1287
1286
' x' : c: _ | isHexDigit c -> do
1288
1287
discard 1
1289
- (n, raw) <- lexHexadecimal
1288
+ (n, raw) <- lexHexadecimal NoUnderscoresAllowedInNumeric
1290
1289
n' <- checkChar n
1291
1290
return (n', ' x' : raw)
1292
1291
c: _ | isDigit c -> do
1293
- (n, raw) <- lexDecimal
1292
+ (n, raw) <- lexDecimal NoUnderscoresAllowedInNumeric
1294
1293
n' <- checkChar n
1295
1294
return (n', raw)
1296
1295
@@ -1307,28 +1306,28 @@ lexEscape = do
1307
1306
cntrl _ = fail " Illegal control character"
1308
1307
1309
1308
-- assumes at least one octal digit
1310
- lexOctal :: Lex a (Integer , String )
1311
- lexOctal = do
1312
- ds <- lexWhile isOctDigit
1313
- return (parseInteger 8 ds, ds )
1309
+ lexOctal :: NumericUnderscoresAllowed -> Lex a (Integer , String )
1310
+ lexOctal underAllowed = do
1311
+ (n, raw) <- lexHandleUnderAllowed underAllowed isOctDigit
1312
+ return (parseInteger 8 n, raw )
1314
1313
1315
1314
-- assumes at least one binary digit
1316
- lexBinary :: Lex a (Integer , String )
1317
- lexBinary = do
1318
- ds <- lexWhile isBinDigit
1319
- return (parseInteger 2 ds, ds )
1315
+ lexBinary :: NumericUnderscoresAllowed -> Lex a (Integer , String )
1316
+ lexBinary underAllowed = do
1317
+ (n, raw) <- lexHandleUnderAllowed underAllowed isBinDigit
1318
+ return (parseInteger 2 n, raw )
1320
1319
1321
1320
-- assumes at least one hexadecimal digit
1322
- lexHexadecimal :: Lex a (Integer , String )
1323
- lexHexadecimal = do
1324
- ds <- lexWhile isHexDigit
1325
- return (parseInteger 16 ds, ds )
1321
+ lexHexadecimal :: NumericUnderscoresAllowed -> Lex a (Integer , String )
1322
+ lexHexadecimal underAllowed = do
1323
+ (n, raw) <- lexHandleUnderAllowed underAllowed isHexDigit
1324
+ return (parseInteger 16 n, raw )
1326
1325
1327
1326
-- assumes at least one decimal digit
1328
- lexDecimal :: Lex a (Integer , String )
1329
- lexDecimal = do
1330
- ds <- lexWhile isDigit
1331
- return (parseInteger 10 ds, ds )
1327
+ lexDecimal :: NumericUnderscoresAllowed -> Lex a (Integer , String )
1328
+ lexDecimal underAllowed = do
1329
+ (n, raw) <- lexHandleUnderAllowed underAllowed isDigit
1330
+ return (parseInteger 10 n, raw )
1332
1331
1333
1332
-- Stolen from Hugs's Prelude
1334
1333
parseInteger :: Integer -> String -> Integer
@@ -1341,6 +1340,30 @@ flagKW t =
1341
1340
exts <- getExtensionsL
1342
1341
when (NondecreasingIndentation `elem` exts) flagDo
1343
1342
1343
+ data NumericUnderscoresAllowed = UnderscoresAllowedInNumeric | NoUnderscoresAllowedInNumeric
1344
+ deriving Show
1345
+
1346
+ numUnderscoresEnabled :: [KnownExtension ] -> NumericUnderscoresAllowed
1347
+ numUnderscoresEnabled exts = if (NumericUnderscores `elem` exts)
1348
+ then UnderscoresAllowedInNumeric
1349
+ else NoUnderscoresAllowedInNumeric
1350
+
1351
+ lexHandleUnderAllowed :: NumericUnderscoresAllowed -> (Char -> Bool ) -> Lex a (String , String )
1352
+ lexHandleUnderAllowed NoUnderscoresAllowedInNumeric p = do
1353
+ ds <- lexWhile p
1354
+ return (ds, ds)
1355
+ lexHandleUnderAllowed UnderscoresAllowedInNumeric p = do
1356
+ s <- getInput
1357
+ case s of
1358
+ c: _ | p c -> do
1359
+ raw <- lexWhile (\ ic -> p ic || ic == ' _' )
1360
+ if (not $ null raw) && last raw == ' _'
1361
+ then fail $ " lexHandleUnderAllowed: numeric must not end with _: " ++ show raw
1362
+ else return (filter (/= ' _' ) raw, raw)
1363
+ c: _ -> fail $ " lexHandleUnderAllowed: numeric must start with proper digit: " ++ show c
1364
+ _ -> fail $ " lexHandleUnderAllowed: token stream exhausted"
1365
+
1366
+
1344
1367
-- | Selects ASCII binary digits, i.e. @\'0\'@..@\'1\'@.
1345
1368
isBinDigit :: Char -> Bool
1346
1369
isBinDigit c = c >= ' 0' && c <= ' 1'
0 commit comments