packages feed

symparsec-1.0.1: src/Symparsec/Parser/Skip.hs

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser.Skip where

import Symparsec.Parser.Common
import GHC.TypeLits hiding ( ErrorMessage(..) )
import TypeLevelShow.Natural ( ShowNatDec, sShowNatDec )
import Data.Type.Equality
import Singleraeh.Tuple
import Singleraeh.Either
import Singleraeh.Natural
import DeFun.Core
import Unsafe.Coerce ( unsafeCoerce )

-- | Skip forward @n@ characters. Fails if fewer than @n@ characters are
--   available'.
type Skip :: Natural -> PParser Natural ()
type Skip n = 'PParser SkipChSym SkipEndSym n

sSkip :: SNat n -> SParser SNat SUnit (Skip n)
sSkip n = SParser sSkipChSym sSkipEndSym n

instance KnownNat n => SingParser (Skip n) where
    type PS (Skip n) = SNat
    type PR (Skip n) = SUnit
    singParser' = sSkip SNat

type SkipCh :: PParserCh Natural ()
type family SkipCh ch n where
    SkipCh _ 0 = Done '()
    SkipCh _ n = Cont (n-1)

type SkipChSym :: ParserChSym Natural ()
data SkipChSym f
type instance App SkipChSym f = SkipChSym1 f

type SkipChSym1 :: ParserChSym1 Natural ()
data SkipChSym1 ch n
type instance App (SkipChSym1 ch) n = SkipCh ch n

sSkipChSym :: SParserChSym SNat SUnit SkipChSym
sSkipChSym = Lam2 $ \_ n ->
    case testEquality n (SNat @0) of
      Just Refl -> SDone SUnit
      Nothing   -> unsafeCoerce $ SCont $ n %- (SNat @1)

type SkipEnd :: PParserEnd Natural ()
type family SkipEnd n where
    SkipEnd 0 = Right '()
    SkipEnd n = Left (ESkipPastEnd n)

type ESkipPastEnd n = EBase "Skip"
    (      Text "tried to skip "
      :<>: Text (ShowNatDec n) :<>: Text " chars from empty string")
eSkipPastEnd :: SNat n -> SE (ESkipPastEnd n)
eSkipPastEnd n = withKnownSymbol (sShowNatDec n) singE

type SkipEndSym :: ParserEndSym Natural ()
data SkipEndSym n
type instance App SkipEndSym n = SkipEnd n

sSkipEndSym :: SParserEndSym SNat SUnit SkipEndSym
sSkipEndSym = Lam $ \n ->
    case testEquality n (SNat @0) of
      Just Refl -> SRight SUnit
      Nothing   -> unsafeCoerce $ SLeft $ eSkipPastEnd n