lib: Fail when parsing number with more than 255 decimal places.
This commit is contained in:
parent
ba59fed6b2
commit
ee1ef9606b
@ -845,51 +845,37 @@ fromRawNumber
|
||||
-> Maybe Integer
|
||||
-> Either String
|
||||
(Quantity, Word8, Maybe Char, Maybe DigitGroupStyle)
|
||||
fromRawNumber raw mExp = case raw of
|
||||
|
||||
NoSeparators digitGrp mDecimals ->
|
||||
let mDecPt = fmap fst mDecimals
|
||||
decimalGrp = maybe mempty snd mDecimals
|
||||
|
||||
(quantity, precision) =
|
||||
maybe id applyExp mExp $ toQuantity digitGrp decimalGrp
|
||||
|
||||
in Right (quantity, precision, mDecPt, Nothing)
|
||||
|
||||
WithSeparators digitSep digitGrps mDecimals -> case mExp of
|
||||
Nothing ->
|
||||
let mDecPt = fmap fst mDecimals
|
||||
decimalGrp = maybe mempty snd mDecimals
|
||||
digitGroupStyle = DigitGroups digitSep (groupSizes digitGrps)
|
||||
|
||||
(quantity, precision) = toQuantity (mconcat digitGrps) decimalGrp
|
||||
|
||||
in Right (quantity, precision, mDecPt, Just digitGroupStyle)
|
||||
Just _ -> Left
|
||||
"invalid number: mixing digit separators with exponents is not allowed"
|
||||
|
||||
fromRawNumber (WithSeparators _ _ _) (Just _) =
|
||||
Left "invalid number: mixing digit separators with exponents is not allowed"
|
||||
fromRawNumber raw mExp = do
|
||||
(quantity, precision) <- toQuantity (fromMaybe 0 mExp) (digitGroup raw) (decimalGroup raw)
|
||||
return (quantity, precision, mDecPt raw, digitGroupStyle raw)
|
||||
where
|
||||
toQuantity :: Integer -> DigitGrp -> DigitGrp -> Either String (Quantity, Word8)
|
||||
toQuantity e preDecimalGrp postDecimalGrp
|
||||
| precision < 0 = Right (Decimal 0 (digitGrpNum * 10^(-precision)), 0)
|
||||
| precision < 256 = Right (Decimal precision8 digitGrpNum, precision8)
|
||||
| otherwise = Left "invalid number: numbers with more than 255 decimal digits are now allowed at this time"
|
||||
where
|
||||
digitGrpNum = digitGroupNumber $ preDecimalGrp <> postDecimalGrp
|
||||
precision = toInteger (digitGroupLength postDecimalGrp) - e
|
||||
precision8 = fromIntegral precision :: Word8
|
||||
|
||||
mDecPt (NoSeparators _ mDecimals) = fst <$> mDecimals
|
||||
mDecPt (WithSeparators _ _ mDecimals) = fst <$> mDecimals
|
||||
decimalGroup (NoSeparators _ mDecimals) = maybe mempty snd mDecimals
|
||||
decimalGroup (WithSeparators _ _ mDecimals) = maybe mempty snd mDecimals
|
||||
digitGroup (NoSeparators digitGrp _) = digitGrp
|
||||
digitGroup (WithSeparators _ digitGrps _) = mconcat digitGrps
|
||||
digitGroupStyle (NoSeparators _ _) = Nothing
|
||||
digitGroupStyle (WithSeparators sep grps _) = Just . DigitGroups sep $ groupSizes grps
|
||||
|
||||
-- Outputs digit group sizes from least significant to most significant
|
||||
groupSizes :: [DigitGrp] -> [Word8]
|
||||
groupSizes digitGrps = reverse $ case map digitGroupLength digitGrps of
|
||||
groupSizes digitGrps = reverse $ case map (fromIntegral . digitGroupLength) digitGrps of
|
||||
(a:b:cs) | a < b -> b:cs
|
||||
gs -> gs
|
||||
|
||||
toQuantity :: DigitGrp -> DigitGrp -> (Quantity, Word8)
|
||||
toQuantity preDecimalGrp postDecimalGrp = (quantity, precision)
|
||||
where
|
||||
quantity = Decimal precision
|
||||
(digitGroupNumber $ preDecimalGrp <> postDecimalGrp)
|
||||
precision = digitGroupLength postDecimalGrp
|
||||
|
||||
applyExp :: Integer -> (Decimal, Word8) -> (Decimal, Word8)
|
||||
applyExp exponent (quantity, precision) = (quantity * 10^^exponent, newPrecision)
|
||||
where
|
||||
newPrecision | precisionDiff >= 255 = maxBound
|
||||
| precisionDiff <= 0 = 0
|
||||
| otherwise = fromInteger precisionDiff
|
||||
precisionDiff = toInteger precision - exponent
|
||||
|
||||
|
||||
disambiguateNumber :: Maybe AmountStyle -> AmbiguousNumber -> RawNumber
|
||||
disambiguateNumber suggestedStyle (AmbiguousNumber grp1 sep grp2) =
|
||||
@ -1015,7 +1001,9 @@ data AmbiguousNumber = AmbiguousNumber DigitGrp Char DigitGrp
|
||||
-- | Description of a single digit group in a number literal.
|
||||
-- "Thousands" is one well known digit grouping, but there are others.
|
||||
data DigitGrp = DigitGrp {
|
||||
digitGroupLength :: !Word8, -- ^ The number of digits in this group.
|
||||
digitGroupLength :: !Word, -- ^ The number of digits in this group.
|
||||
-- This is Word to avoid the need to do overflow
|
||||
-- checking for the Semigroup instance of DigitGrp.
|
||||
digitGroupNumber :: !Integer -- ^ The natural number formed by this group's digits. This should always be positive.
|
||||
} deriving (Eq)
|
||||
|
||||
@ -1403,6 +1391,8 @@ tests_Common = tests "Common" [
|
||||
assertParseError p "1..1" ""
|
||||
assertParseError p ".1," ""
|
||||
assertParseError p ",1." ""
|
||||
assertParseEq p "1.555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555" (1.555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555, 255, Just '.', Nothing)
|
||||
assertParseError p "1.5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555" ""
|
||||
|
||||
,tests "spaceandamountormissingp" [
|
||||
test "space and amount" $ assertParseEq spaceandamountormissingp " $47.18" (Mixed [usd 47.18])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user