symantic-parser-0.2.0.20210703: src/Symantic/Parser/Machine/Input.hs
{-# 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.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(..)-})
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
(# {-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
-}