rel8-1.5.0.0: src/Rel8/Type/Parser/ByteString.hs
{-# language OverloadedStrings #-}
{-# language TypeApplications #-}
module Rel8.Type.Parser.ByteString
( bytestring
)
where
-- attoparsec
import qualified Data.Attoparsec.ByteString.Char8 as A
-- base
import Control.Applicative ((<|>), many)
import Control.Monad (guard)
import Data.Bits ((.|.), shiftL)
import Data.Char (isOctDigit)
import Data.Foldable (fold)
import Prelude
-- base16
import Data.ByteString.Base16 (decodeBase16Untyped)
-- bytestring
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
-- text
import qualified Data.Text as Text
bytestring :: A.Parser ByteString
bytestring = hex <|> escape
where
hex = do
digits <- "\\x" *> A.takeByteString
either (fail . Text.unpack) pure $ decodeBase16Untyped digits
escape = fold <$> many (escaped <|> unescaped)
where
unescaped = A.takeWhile1 (/= '\\')
escaped = BS.singleton <$> (backslash <|> octal)
where
backslash = '\\' <$ "\\\\"
octal = do
a <- A.char '\\' *> digit
b <- digit
c <- digit
let
result = a `shiftL` 6 .|. b `shiftL` 3 .|. c
guard $ result < 0o400
pure $ toEnum result
where
digit = do
c <- A.satisfy isOctDigit
pure $ fromEnum c - fromEnum '0'