Skip to content

Commit

Permalink
[#331] Hexidecimal value with underscore (#332)
Browse files Browse the repository at this point in the history
* [#331] adding test for hexadecimal representation

* [#331] adding test for octal representation

* [#331] adding test for binary representation with underscore

* [#331] corrected wrong types in function parseInteger

* [#331] add Data.Char module for ascii value and parsec modules for hex,oct and bin digits

* [#331] add more tests with underscore

* [#331] implemented parser for hex, oct and bin with underscore feature

* [#331] haskell style guide

* [#331] removed trailing spaces

* [#311] removed additional trailing spaces

* [#331] changed tests to check for exceptions and added new test group

* [#331] implemented parser for hex, oct and bin with underscore using megaparsec lib function

* [#331] added test cases that check when number ends with underscore

* [#331] resolved issues with code style and naming convention
  • Loading branch information
dariodsa committed Aug 13, 2020
1 parent 316c893 commit 38d74d3
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/Toml/Parser/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Data.Void (Void)

import Text.Megaparsec (Parsec, anySingle, eof, errorBundlePretty, match, parse, satisfy, try,
(<?>))
import Text.Megaparsec.Char (alphaNumChar, char, digitChar, eol, hexDigitChar, space, space1,
import Text.Megaparsec.Char (alphaNumChar, char, digitChar, eol, hexDigitChar, octDigitChar, binDigitChar, space, space1,
string, tab)
import Text.Megaparsec.Char.Lexer (binary, float, hexadecimal, octal, signed, skipLineComment,
symbol)
Expand Down
29 changes: 25 additions & 4 deletions src/Toml/Parser/Value.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import Control.Applicative.Combinators (between, count, option, optional, sepBy1
import Data.Fixed (Pico)
import Data.Time (Day, LocalTime (..), TimeOfDay, ZonedTime (..), fromGregorianValid,
makeTimeOfDayValid, minutesToTimeZone)
import Data.String (fromString)

import Text.Read (readMaybe)
import Text.Megaparsec (parseMaybe)

import Toml.Parser.Core (Parser, binary, char, digitChar, hexadecimal, lexeme, octal, sc, signed,
import Toml.Parser.Core (Parser, char, digitChar, hexDigitChar, octDigitChar, binDigitChar, hexadecimal, octal, binary, lexeme, sc, signed,
string, text, try, (<?>))
import Toml.Parser.String (textP)
import Toml.Type (AnyValue, UValue (..), typeCheck)
Expand All @@ -41,15 +44,33 @@ decimalP = zero <|> more
check :: Maybe Integer -> Parser Integer
check = maybe (fail "Not an integer") pure

-- | Parser for hexadecimal, octal and binary numbers : included parsing
numberP :: Parser Integer -> Parser Char -> String -> Parser Integer
numberP parseInteger parseDigit errorMessage = more
where
more :: Parser Integer
more = check =<< intValueMaybe . concat <$> sepBy1 (some parseDigit) (char '_')

intValueMaybe :: String -> Maybe Integer
intValueMaybe = parseMaybe parseInteger . fromString

check :: Maybe Integer -> Parser Integer
check = maybe (fail errorMessage) pure



-- | Parser for 'Integer' value.
integerP :: Parser Integer
integerP = lexeme (bin <|> oct <|> hex <|> dec) <?> "integer"
where
bin, oct, hex, dec :: Parser Integer
bin = try (char '0' *> char 'b') *> binary <?> "bin"
oct = try (char '0' *> char 'o') *> octal <?> "oct"
hex = try (char '0' *> char 'x') *> hexadecimal <?> "hex"
bin = try (char '0' *> char 'b') *> binaryP <?> "bin"
oct = try (char '0' *> char 'o') *> octalP <?> "oct"
hex = try (char '0' *> char 'x') *> hexadecimalP <?> "hex"
dec = signed sc decimalP <?> "dec"
binaryP = numberP binary binDigitChar "Invalid binary number"
octalP = numberP octal octDigitChar "Invalid ocatl number"
hexadecimalP = numberP hexadecimal hexDigitChar "Invalid hexadecimal number"

-- | Parser for 'Double' value.
doubleP :: Parser Double
Expand Down
38 changes: 38 additions & 0 deletions test/Test/Toml/Parser/Integer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,41 @@ integerSpecs = describe "integerP" $ do
it "can parse numbers when hex digits are in both lowercase and uppercase" $ do
parseInteger "0xAbCdEf" 0xAbCdEf
parseInteger "0xaBcDeF" 0xaBcDeF
context "when there is underscore in hexadecimal, octal and binary representation" $ do
it "can parse numbers with underscore in hexadecimal representation" $ do
parseInteger "0xAb_Cd_Ef" 0xabcdef
parseInteger "0xA_bcd_ef" 0xabcdef
parseInteger "0x123_abc" 0x123abc
parseInteger "0xa_b_c_1_2_3" 0xabc123
it "can't parse when underscore is between hexadecimal prefix and suffix" $ do
integerFailOn "0x_Abab_ca"
integerFailOn "0x_ababbac"
it "can parse numbers with underscore in octal representation" $ do
parseInteger "0o12_34_56" 0o123456
parseInteger "0o1_2345_6" 0o123456
parseInteger "0o76_54_21" 0o765421
parseInteger "0o4_5_3_2_6" 0o45326
it "can't parse when underscore is between octal prefix and suffix" $ do
integerFailOn "0o_123_4567"
integerFailOn "0o_1234567"
it "can parse numbers with underscore in binary representation" $ do
parseInteger "0b10_101_0" 42
parseInteger "0b10_10_10" 42
parseInteger "0b1_0_1" 5
parseInteger "0b1_0" 2
it "can't parse numbers when underscore is between binary prefix and suffix" $ do
integerFailOn "0b_10101_0"
integerFailOn "0b_101010"
it "doesn't parse underscore not followed by any numbers" $ do
integerFailOn "0b_"
integerFailOn "0o_"
integerFailOn "0x_"
it "doesn't parse when number is ending with underscore" $ do
integerFailOn "0b101_110_"
integerFailOn "0b10101_"
integerFailOn "0x1_23_daf_"
integerFailOn "0x1214adf_"
integerFailOn "0o1_15_41_"
integerFailOn "0o1215147_"


0 comments on commit 38d74d3

Please sign in to comment.