{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE PolyKinds #-} module Symantic.Parser.Machine.Input where import Data.Array.Base (UArray(..), listArray) -- import Data.Array.Unboxed (UArray) import Data.Bool import Data.ByteString.Internal (ByteString(..)) import Data.Char (Char) import Data.Word (Word8) import Data.Eq (Eq(..)) import Data.Function (on) import Data.Int (Int) import Data.Kind (Type) import Data.Ord (Ord(..), Ordering) import Data.String (String) import Data.Text () import Data.Text.Array ({-aBA, empty-}) import Data.Text.Internal (Text(..)) import Data.Text.Unsafe (iter, Iter(..), iter_, reverseIter_) import Text.Show (Show(..)) import GHC.Exts (Int(..), Char(..) {-, RuntimeRep(..)-}, TYPE) import GHC.Word (Word8(..)) import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents) import GHC.Prim ({-Int#,-} Addr#, nullAddr#, indexWideCharArray#, {-indexWord16Array#,-} readWord8OffAddr#, word2Int#, chr#, touch#, realWorld#, plusAddr#, (+#)) import Language.Haskell.TH (CodeQ) import Prelude ((+), (-), error) import qualified Data.ByteString.Lazy.Internal as BSL import qualified Data.List as List -- * Class 'Cursorable' class Show cur => Cursorable cur where offset :: cur -> Int compareOffset :: CodeQ (cur -> cur -> Ordering) compareOffset = [|| compare `on` offset ||] lowerOffset :: CodeQ (cur -> cur -> Bool) sameOffset :: CodeQ (cur -> cur -> Bool) shiftRight :: CodeQ (Int -> cur -> cur) instance Cursorable Int where offset = \inp -> inp compareOffset = [|| compare @Int ||] lowerOffset = [|| (<) @Int ||] sameOffset = [|| (==) @Int ||] shiftRight = [|| (+) @Int ||] instance Cursorable Text where offset = \(Text _ i _) -> i lowerOffset = [|| \(Text _ i _) (Text _ j _) -> i < j ||] sameOffset = [|| \(Text _ i _) (Text _ j _) -> i == j ||] shiftRight = [||shiftRightText||] shiftRightText :: Int -> Text -> Text shiftRightText i (Text arr off unconsumed) = go i off unconsumed where go 0 off' unconsumed' = Text arr off' unconsumed' go n off' unconsumed' | unconsumed' > 0 , !d <- iter_ (Text arr off' unconsumed') 0 = go (n-1) (off'+d) (unconsumed'-d) | otherwise = Text arr off' unconsumed' shiftLeftText :: Int -> Text -> Text shiftLeftText i (Text arr off unconsumed) = go i off unconsumed where go 0 off' unconsumed' = Text arr off' unconsumed' go n off' unconsumed' | off' > 0 , !d <- reverseIter_ (Text arr off' unconsumed') 0 = go (n-1) (off'+d) (unconsumed'-d) | otherwise = Text arr off' unconsumed' instance Cursorable UnpackedLazyByteString where offset = \(UnpackedLazyByteString i _ _ _ _ _) -> i lowerOffset = [||\(UnpackedLazyByteString i _ _ _ _ _) (UnpackedLazyByteString j _ _ _ _ _) -> i <= j||] sameOffset = [||\(UnpackedLazyByteString i _ _ _ _ _) (UnpackedLazyByteString j _ _ _ _ _) -> i == j||] shiftRight = [||shiftRightByteString||] shiftRightByteString :: Int -> UnpackedLazyByteString -> UnpackedLazyByteString shiftRightByteString j !(UnpackedLazyByteString i addr# final off size cs) | j < size = UnpackedLazyByteString (i + j) addr# final (off + j) (size - j) cs | otherwise = case cs of BSL.Chunk (PS (ForeignPtr addr'# final') off' size') cs' -> shiftRightByteString (j - size) (UnpackedLazyByteString (i + size) addr'# final' off' size' cs') BSL.Empty -> emptyUnpackedLazyByteString (i + size) shiftLeftByteString :: Int -> UnpackedLazyByteString -> UnpackedLazyByteString shiftLeftByteString j !(UnpackedLazyByteString i addr# final off size cs) = UnpackedLazyByteString (i - d) addr# final (off - d) (size + d) cs where d = min off j offWith :: CodeQ (ts -> OffWith ts) offWith = [|| OffWith 0 ||] -- ** Type 'Text16' newtype Text16 = Text16 Text --newtype CacheText = CacheText Text -- ** Type 'CharList' newtype CharList = CharList String -- ** Type 'Stream' data Stream = {-# UNPACK #-} !Char :> Stream nomore :: Stream nomore = '\0' :> nomore {- instance Cursorable (OffWith Stream) where lowerOffset = [|| \(OffWith i _) (OffWith j _) -> i < j ||] sameOffset = [|| \(OffWith i _) (OffWith j _) -> i == j ||] shiftRight = [|| \i (OffWith o ts) -> OffWith (o + i) (dropStream i ts) ||] where dropStream :: Int -> Stream -> Stream dropStream 0 cs = cs dropStream n (_ :> cs) = dropStream (n-1) cs -} -- ** Type 'OffWith' data OffWith ts = OffWith {-# UNPACK #-} !Int ts deriving (Show) instance Cursorable (OffWith String) where offset = \(OffWith i _) -> i lowerOffset = [|| \(OffWith i _) (OffWith j _) -> i < j ||] sameOffset = [|| \(OffWith i _) (OffWith j _) -> i == j ||] shiftRight = [|| \i (OffWith o ts) -> OffWith (o + i) (List.drop i ts) ||] -- ** Type 'OffWithStreamAnd' data OffWithStreamAnd ts = OffWithStreamAnd {-# UNPACK #-} !Int !Stream ts -- ** Type 'UnpackedLazyByteString' data UnpackedLazyByteString = UnpackedLazyByteString {-# UNPACK #-} !Int !Addr# ForeignPtrContents {-# UNPACK #-} !Int {-# UNPACK #-} !Int BSL.ByteString instance Show UnpackedLazyByteString where show (UnpackedLazyByteString _i _addr _p _off _size _cs) = "UnpackedLazyByteString" -- FIXME {-# INLINE emptyUnpackedLazyByteString #-} emptyUnpackedLazyByteString :: Int -> UnpackedLazyByteString emptyUnpackedLazyByteString i = UnpackedLazyByteString i nullAddr# (error "nullForeignPtr") 0 0 BSL.Empty -- * Class 'Inputable' class Cursorable (Cursor inp) => Inputable inp where type Cursor inp :: Type type InputToken inp :: Type cursorOf :: CodeQ inp -> CodeQ (CursorOps inp) type CursorOps (inp :: TYPE r) = (# {-init-} Cursor inp , {-more-} Cursor inp -> Bool , {-next-} Cursor inp -> (# InputToken inp, Cursor inp #) #) instance Inputable String where type Cursor String = Int type InputToken String = Char cursorOf input = cursorOf @(UArray Int Char) [|| listArray (0, List.length $$input-1) $$input ||] instance Inputable (UArray Int Char) where type Cursor (UArray Int Char) = Int type InputToken (UArray Int Char) = Char cursorOf qinput = [|| -- Pattern bindings containing unlifted types should use an outermost bang pattern. let !(UArray _ _ size input#) = $$qinput next (I# i#) = (# C# (indexWideCharArray# input# i#) , I# (i# +# 1#) #) in (# 0, (< size), next #) ||] instance Inputable Text where type Cursor Text = Text type InputToken Text = Char cursorOf inp = [|| let _ = "cursorOf" in let next t@(Text arr off unconsumed) = let !(Iter c d) = iter t 0 in (# c, Text arr (off+d) (unconsumed-d) #) more (Text _ _ unconsumed) = unconsumed > 0 in (# $$inp, more, next #) ||] instance Inputable ByteString where type Cursor ByteString = Int type InputToken ByteString = Word8 cursorOf qinput = [|| -- Pattern bindings containing unlifted types should use an outermost bang pattern. let !(PS (ForeignPtr addr# final) off size) = $$qinput next i@(I# i#) = case readWord8OffAddr# (addr# `plusAddr#` i#) 0# realWorld# of (# s', x #) -> case touch# final s' of _ -> (# W8# (x), i + 1 #) in (# off, (< size), next #) ||] instance Inputable BSL.ByteString where type Cursor BSL.ByteString = UnpackedLazyByteString type InputToken BSL.ByteString = Char cursorOf qinput = [|| let next (UnpackedLazyByteString i addr# final off@(I# off#) size cs) = case readWord8OffAddr# addr# off# realWorld# of (# s', x #) -> case touch# final s' of _ -> (# C# (chr# (word2Int# x)) , if size /= 1 then UnpackedLazyByteString (i+1) addr# final (off+1) (size-1) cs else case cs of BSL.Chunk (PS (ForeignPtr addr'# final') off' size') cs' -> UnpackedLazyByteString (i+1) addr'# final' off' size' cs' BSL.Empty -> emptyUnpackedLazyByteString (i+1) #) more (UnpackedLazyByteString _ _ _ _ 0 _) = False more _ = True init = case $$qinput of BSL.Chunk (PS (ForeignPtr addr# final) off size) cs -> UnpackedLazyByteString 0 addr# final off size cs BSL.Empty -> emptyUnpackedLazyByteString 0 in (# init, more, next #) ||] {- instance Inputable Text16 where type Cursor Text16 = Int cursorOf qinput = [|| let Text16 (Text arr off size) = $$qinput arr# = aBA arr next (I# i#) = (# C# (chr# (word2Int# (indexWord16Array# arr# i#))) , I# (i# +# 1#) #) in (# off, (< size), next #) ||] instance Inputable CharList where type Cursor CharList = OffWith String cursorOf qinput = [|| let CharList input = $$qinput next (OffWith i (c:cs)) = (# c, OffWith (i+1) cs #) size = List.length input more (OffWith i _) = i < size --more (OffWith _ []) = False --more _ = True in (# $$offWith input, more, next #) ||] instance Inputable Stream where type Cursor Stream = OffWith Stream cursorOf qinput = [|| let next (OffWith o (c :> cs)) = (# c, OffWith (o + 1) cs #) in (# $$offWith $$qinput, const True, next #) ||] -} {- -- type instance Cursor CacheText = (Text, Stream) -- type instance Cursor BSL.ByteString = OffWith BSL.ByteString -}