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 |   -> Maybe Integer | ||||||
|   -> Either String |   -> Either String | ||||||
|             (Quantity, Word8, Maybe Char, Maybe DigitGroupStyle) |             (Quantity, Word8, Maybe Char, Maybe DigitGroupStyle) | ||||||
| fromRawNumber raw mExp = case raw of | fromRawNumber (WithSeparators _ _ _) (Just _) = | ||||||
| 
 |     Left "invalid number: mixing digit separators with exponents is not allowed" | ||||||
|   NoSeparators digitGrp mDecimals -> | fromRawNumber raw mExp = do | ||||||
|     let mDecPt = fmap fst mDecimals |     (quantity, precision) <- toQuantity (fromMaybe 0 mExp) (digitGroup raw) (decimalGroup raw) | ||||||
|         decimalGrp = maybe mempty snd mDecimals |     return (quantity, precision, mDecPt raw, digitGroupStyle raw) | ||||||
| 
 |  | ||||||
|         (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" |  | ||||||
| 
 |  | ||||||
|   where |   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 |     -- Outputs digit group sizes from least significant to most significant | ||||||
|     groupSizes :: [DigitGrp] -> [Word8] |     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 |       (a:b:cs) | a < b -> b:cs | ||||||
|       gs               -> gs |       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 :: Maybe AmountStyle -> AmbiguousNumber -> RawNumber | ||||||
| disambiguateNumber suggestedStyle (AmbiguousNumber grp1 sep grp2) = | 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. | -- | Description of a single digit group in a number literal. | ||||||
| -- "Thousands" is one well known digit grouping, but there are others. | -- "Thousands" is one well known digit grouping, but there are others. | ||||||
| data DigitGrp = DigitGrp { | 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. |   digitGroupNumber :: !Integer  -- ^ The natural number formed by this group's digits. This should always be positive. | ||||||
| } deriving (Eq) | } deriving (Eq) | ||||||
| 
 | 
 | ||||||
| @ -1403,6 +1391,8 @@ tests_Common = tests "Common" [ | |||||||
|      assertParseError p "1..1" "" |      assertParseError p "1..1" "" | ||||||
|      assertParseError p ".1," "" |      assertParseError p ".1," "" | ||||||
|      assertParseError p ",1." "" |      assertParseError p ",1." "" | ||||||
|  |      assertParseEq    p "1.555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555" (1.555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555, 255, Just '.', Nothing) | ||||||
|  |      assertParseError p "1.5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555" "" | ||||||
| 
 | 
 | ||||||
|   ,tests "spaceandamountormissingp" [ |   ,tests "spaceandamountormissingp" [ | ||||||
|      test "space and amount" $ assertParseEq spaceandamountormissingp " $47.18" (Mixed [usd 47.18]) |      test "space and amount" $ assertParseEq spaceandamountormissingp " $47.18" (Mixed [usd 47.18]) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user