symparsec-1.1.0: src/Symparsec/Parser/Count.hs
{-# LANGUAGE UndecidableInstances #-}
module Symparsec.Parser.Count where
import Symparsec.Parser.Common
import GHC.TypeLits hiding ( ErrorMessage(..) )
import Singleraeh.Tuple
import Singleraeh.List
import Singleraeh.Either
import Singleraeh.Natural
import DeFun.Core
import Data.Type.Equality
import Unsafe.Coerce ( unsafeCoerce )
type CountS s r = (Natural, [r], s)
type family Count n p where
Count n ('PParser pCh pEnd s0) = Count' n pCh pEnd s0
type Count' n pCh pEnd s0 =
'PParser (CountChSym pCh s0) (CountEndSym pEnd s0) '(n, '[], s0)
type SCountS ss sr = STuple3 SNat (SList sr) ss
sCount
:: SNat n
-> SParser ss sr ('PParser pCh pEnd s0)
-> SParser (SCountS ss sr) (SList sr) (Count' n pCh pEnd s0)
sCount n (SParser pCh pEnd s0) =
SParser (sCountChSym pCh s0) (sCountEndSym pEnd s0) (STuple3 n SNil s0)
instance
( p ~ 'PParser pCh pEnd s0, SingParser p, KnownNat n
) => SingParser (Count' n pCh pEnd s0) where
type PS (Count' n pCh pEnd s0) =
SCountS (PS ('PParser pCh pEnd s0)) (PR ('PParser pCh pEnd s0))
type PR (Count' n pCh pEnd s0) = SList (PR ('PParser pCh pEnd s0))
singParser' = sCount SNat (singParser @p)
type family CountCh pCh s0 ch s where
CountCh pCh s0 ch '(n, rs, s) = CountCh' pCh s0 ch n rs s
sCountChSym
:: SParserChSym ss sr pCh
-> ss s0
-> SParserChSym (SCountS ss sr) (SList sr) (CountChSym pCh s0)
sCountChSym pCh s0 = Lam2 $ \ch (STuple3 n rs s) ->
sCountCh' pCh s0 ch n rs s
type family CountCh' pCh s0 ch n rs s where
CountCh' pCh s0 ch 0 rs s = Done (Reverse rs)
CountCh' pCh s0 ch n rs s = CountChN pCh ch n rs s0 (pCh @@ ch @@ s)
sCountCh'
:: SParserChSym ss sr pCh
-> ss s0
-> SChar ch
-> SNat n
-> SList sr rs
-> ss s
-> SResult (SCountS ss sr) (SList sr) (CountCh' pCh s0 ch n rs s)
sCountCh' pCh s0 ch n rs s =
case testEquality n (SNat @0) of
Just Refl -> SDone $ sReverse rs
Nothing -> unsafeCoerce $ sCountChN pCh ch n rs s0 (pCh @@ ch @@ s)
type family CountChN pCh ch n rs s0 res where
CountChN pCh ch n rs s0 (Cont s) = Cont '(n, rs, s)
CountChN pCh ch n rs s0 (Done r) = CountCh' pCh s0 ch (n-1) (r:rs) s0
CountChN pCh ch n rs s0 (Err e) = Err (ECount e)
sCountChN
:: SParserChSym ss sr pCh
-> SChar ch
-> SNat n
-> SList sr rs
-> ss s0
-> SResult ss sr res
-> SResult (SCountS ss sr) (SList sr) (CountChN pCh ch n rs s0 res)
sCountChN pCh ch n rs s0 = \case
SCont s -> SCont $ STuple3 n rs s
SDone r -> sCountCh' pCh s0 ch (n %- SNat @1) (SCons r rs) s0
SErr e -> SErr $ eCount e
type ECount e = EIn "Count" e
eCount :: SE e -> SE (ECount e)
eCount e = withSingE e $ singE
type CountChSym
:: ParserChSym s r
-> s
-> ParserChSym (CountS s r) [r]
data CountChSym pCh s0 f
type instance App (CountChSym pCh s0) f = CountChSym1 pCh s0 f
type CountChSym1
:: ParserChSym s r
-> s
-> ParserChSym1 (CountS s r) [r]
data CountChSym1 pCh s0 ch s
type instance App (CountChSym1 pCh s0 ch) s = CountCh pCh s0 ch s
type family CountEnd pEnd s0 s where
CountEnd pEnd s0 '(n, rs, s) = CountEnd' pEnd s0 n rs s
type family CountEnd' pEnd s0 n rs s where
CountEnd' pEnd s0 0 rs s = Right (Reverse rs)
CountEnd' pEnd s0 n rs s = CountEndN pEnd s0 n rs (pEnd @@ s)
sCountEnd'
:: SParserEndSym ss sr pEnd
-> ss s0
-> SNat n
-> SList sr rs
-> ss s
-> SResultEnd (SList sr) (CountEnd' pEnd s0 n rs s)
sCountEnd' pEnd s0 n rs s =
case testEquality n (SNat @0) of
Just Refl -> SRight $ sReverse rs
Nothing -> unsafeCoerce $ sCountEndN pEnd s0 n rs (pEnd @@ s)
type family CountEndN pEnd s0 n rs res where
CountEndN pEnd s0 n rs (Right r) = CountEnd' pEnd s0 (n-1) (r:rs) s0
CountEndN pEnd s0 n rs (Left e) = Left (ECount e)
sCountEndN
:: SParserEndSym ss sr pEnd
-> ss s0
-> SNat n
-> SList sr rs
-> SResultEnd sr res
-> SResultEnd (SList sr) (CountEndN pEnd s0 n rs res)
sCountEndN pEnd s0 n rs = \case
SRight r -> sCountEnd' pEnd s0 (n %- SNat @1) (SCons r rs) s0
SLeft e -> SLeft $ eCount e
type CountEndSym
:: ParserEndSym s r
-> s
-> ParserEndSym (CountS s r) [r]
data CountEndSym pEnd s0 s
type instance App (CountEndSym pEnd s0) s = CountEnd pEnd s0 s
sCountEndSym
:: SParserEndSym ss sr pEnd
-> ss s0
-> SParserEndSym (SCountS ss sr) (SList sr) (CountEndSym pEnd s0)
sCountEndSym pEnd s0 = Lam $ \(STuple3 n rs s) -> sCountEnd' pEnd s0 n rs s