packages feed

symparsec-1.0.0: src/Symparsec/Parser/Then.hs

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser.Then where

import Symparsec.Parser.Common
import Singleraeh.Either ( SEither(..) )
import Singleraeh.Tuple ( STuple2(..) )
import DeFun.Core

type SPThen ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r =
    SParser
        (SEither ssl (STuple2 srl ssr))
        (STuple2 srl srr)
        (Then' plCh plEnd s0l prCh prEnd s0r)

sThen
    :: SParser ssl srl ('PParser plCh plEnd s0l)
    -> SParser ssr srr ('PParser prCh prEnd s0r)
    -> SPThen  ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r
sThen (SParser plCh plEnd s0l) (SParser prCh prEnd s0r) =
    SParser (sThenChSym plCh prCh s0r) (sThenEndSym plEnd prEnd s0r) (SLeft s0l)

instance
  -- Shame I can't use pl, pr in associated type synonyms! :(
  ( pl ~ 'PParser plCh plEnd s0l
  , pr ~ 'PParser prCh prEnd s0r
  , SingParser pl
  , SingParser pr
  ) => SingParser (Then' plCh plEnd s0l prCh prEnd s0r) where
    type PS (Then' plCh plEnd s0l prCh prEnd s0r) =
        SEither
            (PS ('PParser plCh plEnd s0l))
            (STuple2
                (PR ('PParser plCh plEnd s0l))
                (PS ('PParser prCh prEnd s0r)))
    type PR (Then' plCh plEnd s0l prCh prEnd s0r) =
        STuple2
            (PR ('PParser plCh plEnd s0l))
            (PR ('PParser prCh prEnd s0r))
    singParser' = sThen (singParser @pl) (singParser @pr)

-- | Sequence two parsers, running left then right, and return both results.
infixl 4 :<*>:
type (:<*>:)
    :: PParser sl rl
    -> PParser sr rr
    -> PParser (Either sl (rl, sr)) (rl, rr)
type family pl :<*>: pr where
    'PParser plCh plEnd s0l :<*>: 'PParser prCh prEnd s0r =
        Then' plCh plEnd s0l prCh prEnd s0r

type Then'
    :: ParserChSym  sl rl
    -> ParserEndSym sl rl
    -> sl
    -> ParserChSym  sr rr
    -> ParserEndSym sr rr
    -> sr
    -> PParser (Either sl (rl, sr)) (rl, rr)
type Then' plCh plEnd s0l prCh prEnd s0r =
    'PParser (ThenChSym plCh prCh s0r) (ThenEndSym plEnd prEnd s0r) (Left s0l)

type ThenCh
    :: ParserChSym sl rl
    -> ParserChSym sr rr
    -> sr
    -> PParserCh (Either sl (rl, sr)) (rl, rr)
type family ThenCh plCh prCh s0r ch s where
    ThenCh plCh prCh s0r ch (Left  sl) =
        ThenChL prCh s0r ch (plCh @@ ch @@ sl)
    ThenCh plCh prCh s0r ch (Right '(rl, sr)) =
        ThenChR rl (prCh @@ ch @@ sr)

type family ThenChL prCh s0r ch resl where
    ThenChL prCh s0r ch (Cont sl) = Cont (Left  sl)
    ThenChL prCh s0r ch (Done rl) =
        -- 'Done' doesn't consume, so re-parse with the R parser.
        ThenChR rl (prCh @@ ch @@ s0r)
    ThenChL prCh s0r ch (Err  el) = Err  (EThenChL el)

type EThenChL el = EIn "Then(L)" el
eThenChL :: SE el -> SE (EThenChL el)
eThenChL el = withSingE el $ singE

type family ThenChR rl resr where
    ThenChR rl (Cont sr) = Cont (Right '(rl, sr))
    ThenChR rl (Done rr) = Done '(rl, rr)
    ThenChR rl (Err  er) = Err  (EThenChR er)

type EThenChR er = EIn "Then(R)" er
eThenChR :: SE er -> SE (EThenChR er)
eThenChR er = withSingE er $ singE

sThenChR
    :: srl rl
    -> SResult ssr srr resr
    -> SResult (SEither ssl (STuple2 srl ssr)) (STuple2 srl srr)
        (ThenChR rl resr)
sThenChR rl = \case
  SCont sr -> SCont $ SRight $ STuple2 rl sr
  SDone rr -> SDone $ STuple2 rl rr
  SErr  er -> SErr  $ eThenChR er

sThenChSym
    :: SParserChSym ssl srl plCh
    -> SParserChSym ssr srr prCh
    -> ssr sr
    -> SParserChSym (SEither ssl (STuple2 srl ssr)) (STuple2 srl srr)
        (ThenChSym plCh prCh sr)
sThenChSym plCh prCh s0r = Lam2 $ \ch -> \case
  SLeft sl ->
    case plCh @@ ch @@ sl of
      SCont sl' -> SCont $ SLeft sl'
      SDone rl  -> sThenChR rl (prCh @@ ch @@ s0r)
      SErr  el  -> SErr  $ eThenChL el
  SRight (STuple2 rl sr) -> sThenChR rl (prCh @@ ch @@ sr)

type ThenChSym
    :: ParserChSym sl rl
    -> ParserChSym sr rr
    -> sr
    -> ParserChSym (Either sl (rl, sr)) (rl, rr)
data ThenChSym plCh prCh s0r f
type instance App (ThenChSym plCh prCh s0r) f = ThenChSym1 plCh prCh s0r f

type ThenChSym1
    :: ParserChSym sl rl
    -> ParserChSym sr rr
    -> sr
    -> ParserChSym1 (Either sl (rl, sr)) (rl, rr)
data ThenChSym1 plCh prCh s0r ch s
type instance App (ThenChSym1 plCh prCh s0r ch) s = ThenCh plCh prCh s0r ch s

type family ThenEnd plEnd prEnd s0r s where
    -- | EOT during R: call R end
    ThenEnd plEnd prEnd s0r (Right '(rl, sr)) = ThenEndR rl    (prEnd @@ sr)
    -- | EOT during L: call L end, pass R end
    ThenEnd plEnd prEnd s0r (Left sl)         = ThenEndL prEnd s0r (plEnd @@ sl)

type family ThenEndR rl res where
    -- | EOT during R, R end succeeds: success
    ThenEndR rl (Right rr) = Right '(rl, rr)
    -- | EOT during R, R end fails: error
    ThenEndR rl (Left  er) = Left  (EThenEndR er)

type EThenEndR er = EIn "Then(R) end" er
eThenEndR :: SE er -> SE (EThenEndR er)
eThenEndR er = withSingE er $ singE

sThenEndR
    :: srl rl
    -> SResultEnd srr res
    -> SResultEnd (STuple2 srl srr) (ThenEndR rl res)
sThenEndR rl = \case
  SRight rr -> SRight $ STuple2 rl rr
  SLeft  er -> SLeft  $ eThenEndR er

type family ThenEndL prEnd s0r res where
    -- | EOT during L, L end succeeds: call R end on initial R state
    ThenEndL prEnd s0r (Right rl) = ThenEndR rl (prEnd @@ s0r)
    -- | EOT during L, L end fails: error
    ThenEndL prEnd s0r (Left  el) = Left (EThenEndL el)

type EThenEndL er = EIn "Then(L) end" er
eThenEndL :: SE er -> SE (EThenEndL er)
eThenEndL er = withSingE er $ singE

sThenEndSym
    :: SParserEndSym ssl srl plEnd
    -> SParserEndSym ssr srr prEnd
    -> ssr s0r
    -> SParserEndSym (SEither ssl (STuple2 srl ssr)) (STuple2 srl srr)
        (ThenEndSym plEnd prEnd s0r)
sThenEndSym plEnd prEnd s0r = Lam $ \case
  SRight (STuple2 rl sr) -> sThenEndR rl (prEnd @@ sr)
  SLeft  sl ->
    case plEnd @@ sl of
      SRight rl -> sThenEndR rl (prEnd @@ s0r)
      SLeft  el -> SLeft $ eThenEndL el

type ThenEndSym
    :: ParserEndSym sl rl
    -> ParserEndSym sr rr
    -> sr
    -> ParserEndSym (Either sl (rl, sr)) (rl, rr)
data ThenEndSym plEnd prEnd s0r s
type instance App (ThenEndSym plEnd prEnd s0r) s = ThenEnd plEnd prEnd s0r s