packages feed

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

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser.Then.VoidLeft where

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

type SPThenVL ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r =
    SParser
        (SEither ssl ssr)
        srr
        (ThenVL' plCh plEnd s0l prCh prEnd s0r)

sThenVL
    :: SParser   ssl srl ('PParser plCh plEnd s0l)
    -> SParser   ssr srr ('PParser prCh prEnd s0r)
    -> SPThenVL  ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r
sThenVL (SParser plCh plEnd s0l) (SParser prCh prEnd s0r) =
    SParser (sThenVLChSym plCh prCh s0r) (sThenVLEndSym plEnd prEnd s0r) (SLeft s0l)

instance
  ( pl ~ 'PParser plCh plEnd s0l
  , pr ~ 'PParser prCh prEnd s0r
  , SingParser pl
  , SingParser pr
  ) => SingParser (ThenVL' plCh plEnd s0l prCh prEnd s0r) where
    type PS (ThenVL' plCh plEnd s0l prCh prEnd s0r) =
        SEither
            (PS ('PParser plCh plEnd s0l))
            (PS ('PParser prCh prEnd s0r))
    type PR (ThenVL' plCh plEnd s0l prCh prEnd s0r) =
        PR ('PParser prCh prEnd s0r)
    singParser' = sThenVL (singParser @pl) (singParser @pr)

-- | Sequence two parsers, running left then right, and discard the return value
--   of the left parser.
infixl 4 :*>:
type (:*>:)
    :: PParser sl rl
    -> PParser sr rr
    -> PParser (Either sl sr) rr
type family pl :*>: pr where
    'PParser plCh plEnd s0l :*>: 'PParser prCh prEnd s0r =
        ThenVL' plCh plEnd s0l prCh prEnd s0r

type ThenVL'
    :: ParserChSym  sl rl
    -> ParserEndSym sl rl
    -> sl
    -> ParserChSym  sr rr
    -> ParserEndSym sr rr
    -> sr
    -> PParser (Either sl sr) rr
type ThenVL' plCh plEnd s0l prCh prEnd s0r =
    'PParser (ThenVLChSym plCh prCh s0r) (ThenVLEndSym plEnd prEnd s0r) (Left s0l)

type ThenVLCh
    :: ParserChSym sl rl
    -> ParserChSym sr rr
    -> sr
    -> PParserCh (Either sl sr) rr
type family ThenVLCh plCh prCh s0r ch s where
    ThenVLCh plCh prCh s0r ch (Left  sl) =
        ThenVLChL prCh s0r ch (plCh @@ ch @@ sl)
    ThenVLCh plCh prCh s0r ch (Right sr) =
        ThenVLChR (prCh @@ ch @@ sr)

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

type EThenVLChL el = EIn "ThenVL(L)" el
eThenVLChL :: SE el -> SE (EThenVLChL el)
eThenVLChL el = withSingE el $ singE

type family ThenVLChR resr where
    ThenVLChR (Cont sr) = Cont (Right sr)
    ThenVLChR (Done rr) = Done rr
    ThenVLChR (Err  er) = Err  (EThenVLChR er)

type EThenVLChR er = EIn "ThenVL(R)" er
eThenVLChR :: SE er -> SE (EThenVLChR er)
eThenVLChR er = withSingE er $ singE

sThenVLChR
    :: SResult ssr srr resr
    -> SResult (SEither ssl ssr) srr (ThenVLChR resr)
sThenVLChR = \case
  SCont sr -> SCont $ SRight sr
  SDone rr -> SDone rr
  SErr  er -> SErr  $ eThenVLChR er

sThenVLChSym
    :: SParserChSym ssl srl plCh
    -> SParserChSym ssr srr prCh
    -> ssr sr
    -> SParserChSym (SEither ssl ssr) srr
        (ThenVLChSym plCh prCh sr)
sThenVLChSym plCh prCh s0r = Lam2 $ \ch -> \case
  SLeft  sl ->
    case plCh @@ ch @@ sl of
      SCont  sl' -> SCont $ SLeft sl'
      SDone _rl  -> sThenVLChR (prCh @@ ch @@ s0r)
      SErr   el  -> SErr  $ eThenVLChL el
  SRight sr -> sThenVLChR (prCh @@ ch @@ sr)

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

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

type family ThenVLEnd plEnd prEnd s0r s where
    -- | EOT during R: call R end
    ThenVLEnd plEnd prEnd s0r (Right sr) = ThenVLEndR           (prEnd @@ sr)
    -- | EOT during L: call L end, pass R end
    ThenVLEnd plEnd prEnd s0r (Left  sl) = ThenVLEndL prEnd s0r (plEnd @@ sl)

type family ThenVLEndR res where
    -- | EOT during R, R end succeeds: success
    ThenVLEndR (Right rr) = Right rr
    -- | EOT during R, R end fails: error
    ThenVLEndR (Left  er) = Left  (EThenVLEndR er)

type EThenVLEndR er = EIn "ThenVL(R) end" er
eThenVLEndR :: SE er -> SE (EThenVLEndR er)
eThenVLEndR er = withSingE er $ singE

sThenVLEndR
    :: SResultEnd srr res
    -> SResultEnd srr (ThenVLEndR res)
sThenVLEndR = \case
  SRight rr -> SRight rr
  SLeft  er -> SLeft  $ eThenVLEndR er

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

type EThenVLEndL er = EIn "ThenVL(L) end" er
eThenVLEndL :: SE er -> SE (EThenVLEndL er)
eThenVLEndL er = withSingE er $ singE

sThenVLEndSym
    :: SParserEndSym ssl srl plEnd
    -> SParserEndSym ssr srr prEnd
    -> ssr s0r
    -> SParserEndSym (SEither ssl ssr) srr
        (ThenVLEndSym plEnd prEnd s0r)
sThenVLEndSym plEnd prEnd s0r = Lam $ \case
  SRight sr -> sThenVLEndR (prEnd @@ sr)
  SLeft  sl ->
    case plEnd @@ sl of
      SRight _rl -> sThenVLEndR (prEnd @@ s0r)
      SLeft   el -> SLeft $ eThenVLEndL el

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