packages feed

symparsec-1.1.0: src/Symparsec/Parser/While.hs

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser.While where

import Symparsec.Parser.Common
import DeFun.Core
import GHC.TypeLits
import Singleraeh.Bool
import Singleraeh.Either
import Symparsec.Parser.While.Predicates

-- | Run the given parser while the given character predicate succeeds.
type family While chPred p where
    While chPred ('PParser pCh pEnd s0) = While' chPred pCh pEnd s0
type While' chPred pCh pEnd s0 = 'PParser (WhileChSym chPred pCh pEnd) pEnd s0

sWhile
    :: Lam SChar SBool chPred
    -> SParser ss sr ('PParser pCh pEnd s0)
    -> SParser ss sr (While' chPred pCh pEnd s0)
sWhile chPred (SParser pCh pEnd s0) =
    SParser (sWhileChSym chPred pCh pEnd) pEnd s0

instance
  ( p ~ 'PParser pCh pEnd s0, SingParser p
  , SingChPred chPred
  ) => SingParser (While' chPred pCh pEnd s0) where
    type PS (While' chPred pCh pEnd s0) = PS ('PParser pCh pEnd s0)
    type PR (While' chPred pCh pEnd s0) = PR ('PParser pCh pEnd s0)
    singParser' = sWhile (singChPred @chPred) (singParser @p)

type WhileCh chPred pCh pEnd ch s = WhileCh' pCh pEnd ch s (chPred @@ ch)
type family WhileCh' pCh pEnd ch s res where
    WhileCh' pCh pEnd ch s True  = pCh @@ ch @@ s
    WhileCh' pCh pEnd ch s False = WhileCh'' (pEnd @@ s)

type family WhileCh'' res where
    WhileCh'' (Right r) = Done r
    WhileCh'' (Left  e) = Err (EWhile e)

type EWhile e = EIn "While" e
eWhile :: SE e -> SE (EWhile e)
eWhile e = withSingE e $ singE

type WhileChSym
    :: (Char ~> Bool)
    -> ParserChSym  s r
    -> ParserEndSym s r
    -> ParserChSym  s r
data WhileChSym chPred pCh pEnd f
type instance App (WhileChSym chPred pCh pEnd) f = WhileChSym1 chPred pCh pEnd f

type WhileChSym1
    :: (Char ~> Bool)
    -> ParserChSym  s r
    -> ParserEndSym s r
    -> ParserChSym1 s r
data WhileChSym1 chPred pCh pEnd ch s
type instance App (WhileChSym1 chPred pCh pEnd ch) s = WhileCh chPred pCh pEnd ch s

sWhileChSym
    :: Lam SChar SBool chPred
    -> SParserChSym  ss sr pCh
    -> SParserEndSym ss sr pEnd
    -> SParserChSym  ss sr (WhileChSym chPred pCh pEnd)
sWhileChSym chPred pCh pEnd = Lam2 $ \ch s ->
    case chPred @@ ch of
      STrue  -> pCh @@ ch @@ s
      SFalse ->
        case pEnd @@ s of
          SRight r -> SDone r
          SLeft  e -> SErr $ eWhile e