on master help sign in
Add docs, todos, fix formatting
6a04559Harendra Kumar
.hlint.yaml+1
@@ -32,6 +32,7 @@
32
32
33- ignore: {name: "Redundant <*", within: Serial.NestedStream}
33- ignore: {name: "Redundant <*", within: Serial.NestedStream}
34- ignore: {name: "Use ++", within: Serial.NestedStream}
34- ignore: {name: "Use ++", within: Serial.NestedStream}
35+- ignore: {name: "Use isDigit", within: Streamly.Internal.Unicode.Char.Parser}
35
36
36# Specify additional command line arguments
37# Specify additional command line arguments
37#
38#
src/Streamly/Internal/Unicode/Char/Parser.hs+32−16
@@ -1,14 +1,16 @@
1−{-# LANGUAGE CPP #-}
2−
3-- |
1-- |
4-- Module : Streamly.Internal.Unicode.Char.Parser
2-- Module : Streamly.Internal.Unicode.Char.Parser
5-- Copyright : (c) 2021 Composewell Technologies
3-- Copyright : (c) 2021 Composewell Technologies
6−--
7-- License : BSD-3-Clause
4-- License : BSD-3-Clause
8-- Maintainer : streamly@composewell.com
5-- Maintainer : streamly@composewell.com
9-- Stability : experimental
6-- Stability : experimental
10-- Portability : GHC
7-- Portability : GHC
11--
8--
9+-- To parse a text input, use the decode routines from
10+-- "Streamly.Unicode.Stream" module to convert an input byte stream to a
11+-- Unicode Char stream and then use these parsers on the Char stream.
12+
13+-- XXX Add explicit export list.
12module Streamly.Internal.Unicode.Char.Parser where
14module Streamly.Internal.Unicode.Char.Parser where
13
15
14import Control.Applicative (Alternative(..))
16import Control.Applicative (Alternative(..))
@@ -25,9 +27,17 @@ import qualified Streamly.Internal.Data.Fold as Fold
25-- Character classification
27-- Character classification
26--------------------------------------------------------------------------------
28--------------------------------------------------------------------------------
27
29
30+-- XXX It may be possible to implement faster predicates for ASCII byte stream.
31+-- We can measure if there is a signficant difference and if so we can add such
32+-- predicates to Streamly.Unicode.Char.Parser.Latin1.
33+--
28#define CHAR_PARSER_SIG(NAME) NAME :: MonadCatch m => Parser m Char Char
34#define CHAR_PARSER_SIG(NAME) NAME :: MonadCatch m => Parser m Char Char
35+-- XXX Need to use the predicates from Unicode.Char module/unicode-data package
29#define CHAR_PARSER(NAME, PREDICATE) NAME = Parser.satisfy Char.PREDICATE
36#define CHAR_PARSER(NAME, PREDICATE) NAME = Parser.satisfy Char.PREDICATE
30
37
38+-- XXX Add haddock documentation
39+-- XXX Add INLINE pragmas
40+
31CHAR_PARSER_SIG(space)
41CHAR_PARSER_SIG(space)
32CHAR_PARSER(space,isSpace)
42CHAR_PARSER(space,isSpace)
33
43
@@ -90,6 +100,7 @@ CHAR_PARSER(asciiLower,isAsciiLower)
90--------------------------------------------------------------------------------
100--------------------------------------------------------------------------------
91
101
92-- | Match a specific character.
102-- | Match a specific character.
103+{-# INLINE char #-}
93char :: MonadCatch m => Char -> Parser m Char Char
104char :: MonadCatch m => Char -> Parser m Char Char
94char c = Parser.satisfy (== c)
105char c = Parser.satisfy (== c)
95
106
@@ -97,7 +108,9 @@ char c = Parser.satisfy (== c)
97-- Numeric parsers
108-- Numeric parsers
98--------------------------------------------------------------------------------
109--------------------------------------------------------------------------------
99
110
111+-- XXX It should fail if the number is larger than the size of the type.
112+--
100−-- | Parse and decode an unsigned decimal number.
113+-- | Parse and decode an unsigned integral decimal number.
101{-# INLINE decimal #-}
114{-# INLINE decimal #-}
102decimal :: (MonadCatch m, Integral a) => Parser m Char a
115decimal :: (MonadCatch m, Integral a) => Parser m Char a
103decimal = Parser.takeWhile1 Char.isDigit (Fold.foldl' step 0)
116decimal = Parser.takeWhile1 Char.isDigit (Fold.foldl' step 0)
@@ -106,11 +119,10 @@ decimal = Parser.takeWhile1 Char.isDigit (Fold.foldl' step 0)
106
119
107 step a c = a * 10 + fromIntegral (ord c - 48)
120 step a c = a * 10 + fromIntegral (ord c - 48)
108
121
109−
110−-- | Parse and decode an unsigned hexadecimal number. The hex digits
122+-- | Parse and decode an unsigned integral hexadecimal number. The hex digits
111-- @\'a\'@ through @\'f\'@ may be upper or lower case.
123-- @\'a\'@ through @\'f\'@ may be upper or lower case.
112--
124--
113−-- This parser does not accept a leading @\"0x\"@ string.
125+-- Note: This parser does not accept a leading @\"0x\"@ string.
114{-# INLINE hexadecimal #-}
126{-# INLINE hexadecimal #-}
115hexadecimal :: (MonadCatch m, Integral a, Bits a) => Parser m Char a
127hexadecimal :: (MonadCatch m, Integral a, Bits a) => Parser m Char a
116hexadecimal = Parser.takeWhile1 isHexDigit (Fold.foldl' step 0)
128hexadecimal = Parser.takeWhile1 isHexDigit (Fold.foldl' step 0)
@@ -118,20 +130,24 @@ hexadecimal = Parser.takeWhile1 isHexDigit (Fold.foldl' step 0)
118 where
130 where
119
131
120 isHexDigit c =
132 isHexDigit c =
121− (c >= '0' && c <= '9')
133+ (c >= '0' && c <= '9')
122− || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
134+ || (c >= 'a' && c <= 'f')
135+ || (c >= 'A' && c <= 'F')
123
136
124 step a c
137 step a c
138+ | w >= 48 && w <= 57 =
125− | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
139+ (a `shiftL` 4) .|. fromIntegral (w - 48)
140+ | w >= 97 =
126− | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
141+ (a `shiftL` 4) .|. fromIntegral (w - 87)
142+ | otherwise =
127− | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
143+ (a `shiftL` 4) .|. fromIntegral (w - 55)
128
144
129 where
145 where
130
146
131 w = ord c
147 w = ord c
132
148
133−-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
149+-- | Allow an optional leading @\'+\'@ or @\'-\'@ sign character before any
134−-- character.
150+-- parser.
135{-# INLINE signed #-}
151{-# INLINE signed #-}
136signed :: (Num a, MonadCatch m) => Parser m Char a -> Parser m Char a
152signed :: (Num a, MonadCatch m) => Parser m Char a -> Parser m Char a
137signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
153signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
@@ -145,8 +161,6 @@ signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
145--
161--
146-- === Examples
162-- === Examples
147--
163--
148−-- These examples use this helper:
149−--
150-- Examples with behaviour identical to 'read', if you feed an empty
164-- Examples with behaviour identical to 'read', if you feed an empty
151-- continuation to the first result:
165-- continuation to the first result:
152--
166--
@@ -167,5 +181,7 @@ signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
167--
181--
168-- This function does not accept string representations of \"NaN\" or
182-- This function does not accept string representations of \"NaN\" or
169-- \"Infinity\".
183-- \"Infinity\".
184+--
185+-- /Unimplemented/
170double :: Parser m Char Double
186double :: Parser m Char Double
171double = undefined
187double = undefined