Skip to main content

Parsing Bounded Integers (Part 2)

I realized that I missed a significant issue with the DecimalMaxSO and DecimalMaxFixed implementations in the Parsing Bounded Integers blog entry! These parsers limit the number of characters that are consumed by counting digits, where the maximum number of digits is the number of digits of the maximum bound. They do not take leading zeros into account, however. In some cases, this leads to failure in cases where the decimal parser succeeds, and the failures have potentially puzzling error messages.

The new tests are as follows:

tests :: TestTree
tests = testGroup "DecimalMaxSO"
    [
    ...
    , testCase "paddedOK" $ Right 42 @=? parseWord8 "00042"
    , testCase "paddedLarge" $
        Left "Failed reading: decimalMax: parsed decimal exeeded 255"
          @=? parseWord8 "01000"
    ...
    ]

Both the DecimalMaxSO and DecimalMaxFixed implementations fail these tests with errors like the following:

paddedOK:      FAIL
  test/DecimalMaxSO/Test.hs:44:
  expected: Right 42
   but got: Left "endOfInput"
  Use -p '/DecimalMaxSO.paddedOK/' to rerun this test only.
paddedLarge:   FAIL
  test/DecimalMaxSO/Test.hs:46:
  expected: Left "Failed reading: decimalMax: parsed decimal exeeded 255"
   but got: Left "endOfInput"
  Use -p '/DecimalMaxSO.paddedLarge/' to rerun this test only.

In the paddedOK test, the scan function consumes four digits, returning the ByteString value 0004 and leaving the 2 unconsumed. (Notice that numDigs is 3, but four digits are consumed because the state starts at zero. This is essential because that extra digit is sometimes required to determine that there is an overflow.) The decimalMax parser succeeds, returning 4, and then the endOfInput function fails because 2 remains.

In the paddedLarge test, the scan function consumes four digits, returning the ByteString value 0100 and leaving the final 0 unconsumed. The decimalMax parser succeeds, returning 100, and then the endOfInput function fails because 0 remains.