parsley-core-1.0.0.0: src/ghc-8.10+/Parsley/Internal/Backend/Machine/InputRep.hs
{-# LANGUAGE MagicHash,
TypeFamilies,
UnboxedTuples,
StandaloneKindSignatures #-}
module Parsley.Internal.Backend.Machine.InputRep (
Rep, RepKind,
intSame, intLess, min#, max#,
OffWith, offWith, offWithSame, offWithShiftRight,
--OffWithStreamAnd(..),
UnpackedLazyByteString, emptyUnpackedLazyByteString,
Stream, dropStream,
offsetText,
representationTypes,
-- These must be exposed
textShiftRight, textShiftLeft,
byteStringShiftRight, byteStringShiftLeft
) where
import Data.Array.Unboxed (UArray)
import Data.ByteString.Internal (ByteString(..))
import Data.Kind (Type)
import Data.Text.Internal (Text(..))
import Data.Text.Unsafe (iter_, reverseIter_)
import GHC.Exts (Int(..), TYPE, RuntimeRep(..), (==#), (<#), (+#), (-#), isTrue#)
import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents)
import GHC.Prim (Int#, Addr#, nullAddr#)
import Parsley.Internal.Common.Utils (Code)
import Parsley.Internal.Core.InputTypes (Text16, CharList, Stream(..))
import qualified Data.ByteString.Lazy.Internal as Lazy (ByteString(..))
import qualified Language.Haskell.TH as TH (Q, Type)
{- Representation Types -}
type OffWith ts = (# Int#, ts #)
--data OffWithStreamAnd ts = OffWithStreamAnd {-# UNPACK #-} !Int !Stream ts
type UnpackedLazyByteString = (#
Int#,
Addr#,
ForeignPtrContents,
Int#,
Int#,
Lazy.ByteString
#)
representationTypes :: [TH.Q TH.Type]
representationTypes = [[t|[Char]|], [t|UArray Int Char|], [t|Text16|], [t|ByteString|], [t|CharList|], [t|Stream|], [t|Lazy.ByteString|], [t|Text|]]
offWith :: Code ts -> Code (OffWith ts)
offWith qts = [||(# 0#, $$qts #)||]
emptyUnpackedLazyByteString :: Code Int# -> Code UnpackedLazyByteString
emptyUnpackedLazyByteString qi# = [|| (# $$(qi#), nullAddr#, error "nullForeignPtr", 0#, 0#, Lazy.Empty #) ||]
{- Representation Mappings -}
-- When a new input type is added here, it needs an Input instance in Parsley.Backend.Machine
type RepKind :: Type -> RuntimeRep
type family RepKind input where
RepKind [Char] = IntRep
RepKind (UArray Int Char) = IntRep
RepKind Text16 = IntRep
RepKind ByteString = IntRep
RepKind Text = LiftedRep
RepKind Lazy.ByteString = 'TupleRep '[IntRep, AddrRep, LiftedRep, IntRep, IntRep, LiftedRep]
RepKind CharList = 'TupleRep '[IntRep, LiftedRep]
RepKind Stream = 'TupleRep '[IntRep, LiftedRep]
--RepKind (OffWithStreamAnd _) = 'TupleRep '[IntRep, LiftedRep, LiftedRep] --REMOVE
--RepKind (Text, Stream) = 'TupleRep '[LiftedRep, LiftedRep] --REMOVE
type Rep :: forall (rep :: Type) -> TYPE (RepKind rep)
type family Rep input where
Rep [Char] = Int#
Rep (UArray Int Char) = Int#
Rep Text16 = Int#
Rep ByteString = Int#
Rep Text = Text
Rep Lazy.ByteString = UnpackedLazyByteString
Rep CharList = (# Int#, String #)
Rep Stream = (# Int#, Stream #)
--Rep (OffWithStreamAnd ts) = (# Int#, Stream, ts #)
--Rep (Text, Stream) = (# Text, Stream #)
{- Generic Representation Operations -}
intSame :: Code Int# -> Code Int# -> Code Bool
intSame qi# qj# = [||isTrue# ($$(qi#) ==# $$(qj#))||]
intLess :: Code Int# -> Code Int# -> Code Bool
intLess qi# qj# = [||isTrue# ($$(qi#) <# $$(qj#))||]
offsetText :: Code Text -> Code Int
offsetText qt = [||case $$qt of Text _ off _ -> off||]
offWithSame :: Code (# Int#, ts #) -> Code (# Int#, ts #) -> Code Bool
offWithSame qi# qj# = [||
case $$(qi#) of
(# i#, _ #) -> case $$(qj#) of
(# j#, _ #) -> $$(intSame [||i#||] [||j#||])
||]
offWithShiftRight :: Code (Int -> ts -> ts) -> Code (# Int#, ts #) -> Code Int# -> Code (# Int#, ts #)
offWithShiftRight drop qo# qi# = [||
case $$(qo#) of (# o#, ts #) -> (# (o# +# $$(qi#)), ($$drop (I# $$(qi#)) ts) #)
||]
{-offWithStreamAnd :: ts -> OffWithStreamAnd ts
offWithStreamAnd ts = OffWithStreamAnd 0 nomore ts
offWithStreamAndToInt :: OffWithStreamAnd ts -> Int
offWithStreamAndToInt (OffWithStreamAnd i _ _) = i-}
dropStream :: Int -> Stream -> Stream
dropStream 0 cs = cs
dropStream n (_ :> cs) = dropStream (n-1) cs
textShiftRight :: Text -> Int -> Text
textShiftRight (Text arr off unconsumed) i = go i off unconsumed
where
go 0 off' unconsumed' = Text arr off' unconsumed'
go n off' unconsumed'
| unconsumed' > 0 = let !d = iter_ (Text arr off' unconsumed') 0
in go (n-1) (off'+d) (unconsumed'-d)
| otherwise = Text arr off' unconsumed'
textShiftLeft :: Text -> Int -> Text
textShiftLeft (Text arr off unconsumed) i = go i off unconsumed
where
go 0 off' unconsumed' = Text arr off' unconsumed'
go n off' unconsumed'
| off' > 0 = let !d = reverseIter_ (Text arr off' unconsumed') 0 in go (n-1) (off'+d) (unconsumed'-d)
| otherwise = Text arr off' unconsumed'
{-# INLINE emptyUnpackedLazyByteString' #-}
emptyUnpackedLazyByteString' :: Int# -> UnpackedLazyByteString
emptyUnpackedLazyByteString' i# = (# i#, nullAddr#, error "nullForeignPtr", 0#, 0#, Lazy.Empty #)
byteStringShiftRight :: UnpackedLazyByteString -> Int# -> UnpackedLazyByteString
byteStringShiftRight (# i#, addr#, final, off#, size#, cs #) j#
| isTrue# (j# <# size#) = (# i# +# j#, addr#, final, off# +# j#, size# -# j#, cs #)
| otherwise = case cs of
Lazy.Chunk (PS (ForeignPtr addr'# final') (I# off'#) (I# size'#)) cs' -> byteStringShiftRight (# i# +# size#, addr'#, final', off'#, size'#, cs' #) (j# -# size#)
Lazy.Empty -> emptyUnpackedLazyByteString' (i# +# size#)
byteStringShiftLeft :: UnpackedLazyByteString -> Int# -> UnpackedLazyByteString
byteStringShiftLeft (# i#, addr#, final, off#, size#, cs #) j# =
let d# = min# off# j#
in (# i# -# d#, addr#, final, off# -# d#, size# +# d#, cs #)
min# :: Int# -> Int# -> Int#
min# i# j# = case i# <# j# of
0# -> j#
_ -> i#
max# :: Int# -> Int# -> Int#
max# i# j# = case i# <# j# of
0# -> i#
_ -> j#