{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UnboxedTuples #-} 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.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(..)-}) 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 (cur -> Int -> 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 :: Text -> Int -> Text shiftRightText (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' shiftLeftText :: Text -> Int -> Text shiftLeftText (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' 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 :: UnpackedLazyByteString -> Int -> UnpackedLazyByteString shiftRightByteString !(UnpackedLazyByteString i addr# final off size cs) j | 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 (UnpackedLazyByteString (i + size) addr'# final' off' size' cs') (j - size) BSL.Empty -> emptyUnpackedLazyByteString (i + size) shiftLeftByteString :: UnpackedLazyByteString -> Int -> UnpackedLazyByteString shiftLeftByteString (UnpackedLazyByteString i addr# final off size cs) j = 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 = [|| \(OffWith o ts) i -> 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 = [|| \(OffWith o ts) i -> 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 'Input' class Cursorable (Cursor inp) => Input inp where type Cursor inp :: Type type InputToken inp :: Type cursorOf :: CodeQ inp -> CodeQ (# {-init-} Cursor inp , {-more-} Cursor inp -> Bool , {-next-} Cursor inp -> (# InputToken inp, Cursor inp #) #) instance Input String where type Cursor String = Int type InputToken String = Char cursorOf input = cursorOf @(UArray Int Char) [|| listArray (0, List.length $$input-1) $$input ||] instance Input (UArray Int Char) where type Cursor (UArray Int Char) = Int type InputToken (UArray Int Char) = Char cursorOf qinput = [|| let UArray _ _ size input# = $$qinput next (I# i#) = (# C# (indexWideCharArray# input# i#) , I# (i# +# 1#) #) in (# 0, (< size), next #) ||] instance Input 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 Input ByteString where type Cursor ByteString = Int type InputToken ByteString = Char cursorOf qinput = [|| 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 _ -> (# C# (chr# (word2Int# x)), i + 1 #) in (# off, (< size), next #) ||] instance Input 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 Input 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 Input 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 Input 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 -}