kangaroo-0.3.0: src/Data/ParserCombinators/Kangaroo/Prim.hs
{-# OPTIONS -Wall #-}
--------------------------------------------------------------------------------
-- |
-- Module : Data.ParserCombinators.Kangaroo.Prim
-- Copyright : (c) Stephen Tetley 2009-2010
-- License : BSD3
--
-- Maintainer : Stephen Tetley <stephen.tetley@gmail.com>
-- Stability : highly unstable
-- Portability : to be determined.
--
-- Primitive parsers - charactors, numbers...
--
--------------------------------------------------------------------------------
module Data.ParserCombinators.Kangaroo.Prim
(
-- * Char and String parsers
char
, anyChar
, text
, string
, cstring
-- * Byte parsers
, w8Zero
, getBytes
-- * Number parsers
, int8
-- ** Word - big endian
, word16be
, word24be
, word32be
, word64be
-- ** Word - little endian
, word16le
, word24le
, word32le
-- ** Int - big endian
, int16be
, int32be
-- ** Int - little endian
, int16le
, int32le
-- ** IEEE754 single precision float
, ieeeFloatSP
) where
import Data.ParserCombinators.Kangaroo.Combinators
import Data.ParserCombinators.Kangaroo.IEEEFloat
import Data.ParserCombinators.Kangaroo.ParseMonad
import Data.ParserCombinators.Kangaroo.Utils
import Control.Applicative
import Data.Char
import Data.Int
import Data.Word
-- | Attempt to parse the supplied single character (the supplied
-- char must be in the ASCII range 0-255).
--
-- If the parse succeeds return the char, otherwise a parse-error
-- will be thrown with 'reportError'.
--
char :: Char -> GenKangaroo ust Char
char ch = satisfy (==chi) >> return ch
where
chi = fromIntegral $ ord ch
-- | Parse any single character. The parser consumes one byte and
-- uses 'chr' to convert it.
--
anyChar :: GenKangaroo ust Char
anyChar = (chr . fromIntegral) <$> word8
-- | Parse a string of the supplied length @n@.
--
-- If @n@ is less than or equal to zero the empty string is
-- returned.
--
text :: Int -> GenKangaroo ust String
text i | i <= 0 = return ""
| otherwise = count i anyChar
-- | Parse the supplied string. All characters should be within
-- the range 0-255.
--
-- If the parse succeeds return the char, otherwise a parse-error
-- will be thrown with 'reportError'.
--
string :: String -> GenKangaroo ust String
string = (substError `flip` "string" ) . mapM char
-- | Parse a null-terminated C-style string.
--
cstring :: GenKangaroo ust String
cstring = manyTill anyChar w8Zero
--------------------------------------------------------------------------------
-- Byte parsers
-- | Parse the literal @0x00@.
--
w8Zero :: GenKangaroo ust Word8
w8Zero = satisfy (==0)
-- | Get @n@ bytes.
--
-- If @n@ is less than or equal to zero an empty list is returned.
--
getBytes :: Integral a => a -> GenKangaroo ust [Word8]
getBytes i | i < 0 = return []
| otherwise = count (fromIntegral i) word8
--------------------------------------------------------------------------------
-- Numbers
-- | Parse a single byte, returning it as an Int8.
--
-- The conversion from a byte (0-255) to an Int8 uses the Prelude
-- function 'fromIntegral'.
--
-- The conversion is summarized as:
--
-- > 0..127 = 0..127
-- > 128 = -128
-- > 129 = -127
-- > 130 = -126
-- > ...
-- > 254 = -2
-- > 255 = -1
-- >
-- > wtoi :: Word8 -> Int8
-- > wtoi i | i < 128 = i
-- > | otherwise = -128 + (clearBit i 7)
--
int8 :: GenKangaroo ust Int8
int8 = fromIntegral <$> word8
--------------------------------------------------------------------------------
-- Data.Word
-- | Parse a Word16 in big endian form.
--
word16be :: GenKangaroo ust Word16
word16be = w16be <$> word8 <*> word8
-- | Parse a \"Word24\" in big endian form.
--
-- 3 bytes are read - the answer is returned as a Word32.
--
word24be :: GenKangaroo ust Word32
word24be = w32be 0 <$> word8 <*> word8 <*> word8
-- | Parse a Word32 in big endian form.
--
word32be :: GenKangaroo ust Word32
word32be = w32be <$> word8 <*> word8 <*> word8 <*> word8
-- | Parse a Word64 in big endian form.
--
word64be :: GenKangaroo ust Word64
word64be = w64be <$> word8 <*> word8 <*> word8 <*> word8
<*> word8 <*> word8 <*> word8 <*> word8
-- | Parse a Word16 in little endian form.
--
word16le :: GenKangaroo ust Word16
word16le = w16le <$> word8 <*> word8
-- | Parse a \"Word24\" in little endian form.
--
-- 3 bytes are read - the answer is returned as a Word32.
--
word24le :: GenKangaroo ust Word32
word24le = w24le <$> word8 <*> word8 <*> word8
-- | Parse a Word32 in little endian form.
--
word32le :: GenKangaroo ust Word32
word32le = w32le <$> word8 <*> word8 <*> word8 <*> word8
--------------------------------------------------------------------------------
-- Data.Int
-- | Parse an Int16 in big endian form.
--
-- The ans is parsed as a Word16 (big endian) then converted to
-- an Int16 using the Prelude function 'fromIntegral'.
--
int16be :: GenKangaroo ust Int16
int16be = i16be <$> word8 <*> word8
-- | Parse an Int32 in big endian form.
--
-- The ans is parsed as a Word32 (big endian) then converted to
-- an Int32 using the Prelude function 'fromIntegral'.
--
int32be :: GenKangaroo ust Int32
int32be = i32be <$> word8 <*> word8 <*> word8 <*> word8
-- | Parse an Int16 in little endian form.
--
-- The ans is parsed as a Word16 (little endian) then converted
-- to an Int16 using the Prelude function 'fromIntegral'.
--
int16le :: GenKangaroo ust Int16
int16le = i16le <$> word8 <*> word8
-- | Parse an Int32 in little endian form.
--
-- The ans is parsed as a Word32 (little endian) then converted
-- to an Int32 using the Prelude function 'fromIntegral'.
--
int32le :: GenKangaroo ust Int32
int32le = i32le <$> word8 <*> word8 <*> word8 <*> word8
-- | Parse an 4-byte IEEE single precision float.
--
-- NOTE - THIS FUNCTION IS UNTESTED!
--
ieeeFloatSP :: Fractional a => GenKangaroo ust a
ieeeFloatSP = unpackIEEESingle <$> word8 <*> word8 <*> word8 <*> word8