on master help sign in
Add numeric parsers
a81c620Adithya Kumar
src/Streamly/Internal/Unicode/Char/Parser.hs+89
@@ -11,11 +11,15 @@
11--
11--
12module Streamly.Internal.Unicode.Char.Parser where
12module Streamly.Internal.Unicode.Char.Parser where
13
13
14+import Control.Applicative (Alternative(..))
14import Control.Monad.Catch (MonadCatch)
15import Control.Monad.Catch (MonadCatch)
16+import Data.Bits (Bits, (.|.), shiftL)
17+import Data.Char (ord)
15import Streamly.Internal.Data.Parser (Parser)
18import Streamly.Internal.Data.Parser (Parser)
16
19
17import qualified Data.Char as Char
20import qualified Data.Char as Char
18import qualified Streamly.Internal.Data.Parser as Parser
21import qualified Streamly.Internal.Data.Parser as Parser
22+import qualified Streamly.Internal.Data.Fold as Fold
19
23
20--------------------------------------------------------------------------------
24--------------------------------------------------------------------------------
21-- Character classification
25-- Character classification
@@ -80,3 +84,88 @@ CHAR_PARSER(asciiUpper,isAsciiUpper)
80
84
81CHAR_PARSER_SIG(asciiLower)
85CHAR_PARSER_SIG(asciiLower)
82CHAR_PARSER(asciiLower,isAsciiLower)
86CHAR_PARSER(asciiLower,isAsciiLower)
87+
88+--------------------------------------------------------------------------------
89+-- Character parsers
90+--------------------------------------------------------------------------------
91+
92+-- | Match a specific character.
93+char :: MonadCatch m => Char -> Parser m Char Char
94+char c = Parser.satisfy (== c)
95+
96+--------------------------------------------------------------------------------
97+-- Numeric parsers
98+--------------------------------------------------------------------------------
99+
100+-- | Parse and decode an unsigned decimal number.
101+{-# INLINE decimal #-}
102+decimal :: (MonadCatch m, Integral a) => Parser m Char a
103+decimal = Parser.takeWhile1 Char.isDigit (Fold.foldl' step 0)
104+
105+ where
106+
107+ step a c = a * 10 + fromIntegral (ord c - 48)
108+
109+
110+-- | Parse and decode an unsigned hexadecimal number. The hex digits
111+-- @\'a\'@ through @\'f\'@ may be upper or lower case.
112+--
113+-- This parser does not accept a leading @\"0x\"@ string.
114+{-# INLINE hexadecimal #-}
115+hexadecimal :: (MonadCatch m, Integral a, Bits a) => Parser m Char a
116+hexadecimal = Parser.takeWhile1 isHexDigit (Fold.foldl' step 0)
117+
118+ where
119+
120+ isHexDigit c =
121+ (c >= '0' && c <= '9')
122+ || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
123+
124+ step a c
125+ | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
126+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
127+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
128+
129+ where
130+
131+ w = ord c
132+
133+-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
134+-- character.
135+{-# INLINE signed #-}
136+signed :: (Num a, MonadCatch m) => Parser m Char a -> Parser m Char a
137+signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
138+
139+-- | Parse a 'Double'.
140+--
141+-- This parser accepts an optional leading sign character, followed by
142+-- at most one decimal digit. The syntax is similar to that accepted by
143+-- the 'read' function, with the exception that a trailing @\'.\'@ is
144+-- consumed.
145+--
146+-- === Examples
147+--
148+-- These examples use this helper:
149+--
150+-- Examples with behaviour identical to 'read', if you feed an empty
151+-- continuation to the first result:
152+--
153+-- > IS.parse double (IS.fromList "3") == 3.0
154+-- > IS.parse double (IS.fromList "3.1") == 3.1
155+-- > IS.parse double (IS.fromList "3e4") == 30000.0
156+-- > IS.parse double (IS.fromList "3.1e4") == 31000.0
157+-- > IS.parse double (IS.fromList "3e") == 30
158+--
159+-- Examples with behaviour identical to 'read':
160+--
161+-- > IS.parse (IS.fromList ".3") == error "Parse failed"
162+-- > IS.parse (IS.fromList "e3") == error "Parse failed"
163+--
164+-- Example of difference from 'read':
165+--
166+-- > IS.parse double (IS.fromList "3.foo") == 3.0
167+--
168+-- This function does not accept string representations of \"NaN\" or
169+-- \"Infinity\".
170+double :: Parser m Char Double
171+double = undefined
streamly.cabal+1−1
@@ -537,7 +537,7 @@ library
537 , transformers-base >= 0.4 && < 0.5
537 , transformers-base >= 0.4 && < 0.5
538
538
539 , fusion-plugin-types >= 0.1 && < 0.2
539 , fusion-plugin-types >= 0.1 && < 0.2
540− , unicode-data >= 0.1 && < 0.2
540+ , unicode-data >= 0.1 && < 0.2
541
541
542 -- Network
542 -- Network
543 , network >= 2.6 && < 4
543 , network >= 2.6 && < 4