packages feed

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

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser.Literal where

import Symparsec.Parser.Common
import GHC.TypeLits hiding ( ErrorMessage(..) )
import TypeLevelShow.Utils ( ShowChar, sShowChar )
import Data.Type.Equality
import DeFun.Core
import Singleraeh.Tuple
import Singleraeh.Either
import Singleraeh.Maybe
import Singleraeh.Symbol
import Unsafe.Coerce
import TypeLevelShow.Doc

-- | Parse the given 'Symbol'.
type Literal :: Symbol -> PParser Symbol ()
type Literal str = 'PParser LiteralChSym LiteralEndSym str

sLiteral :: SSymbol str -> SParser SSymbol SUnit (Literal str)
sLiteral str = SParser sLiteralChSym sLiteralEndSym str

instance KnownSymbol str => SingParser (Literal str) where
    type PS (Literal str) = SSymbol
    type PR (Literal str) = SUnit
    singParser' = sLiteral SSymbol

type LiteralCh ch str = LiteralCh' ch (UnconsSymbol str)
type family LiteralCh' ch str where
    LiteralCh' ch (Just '(ch, str))     = Cont str
    LiteralCh' ch (Just '(chNext, str)) = Err (EWrongChar chNext ch)
    LiteralCh' ch Nothing               = Done '()

type EWrongChar chNext ch = EBase "Literal"
    (      Text "expected " :<>: Text (ShowChar chNext)
      :<>: Text    ", got " :<>: Text (ShowChar ch))

eWrongChar :: SChar chNext -> SChar ch -> SE (EWrongChar chNext ch)
eWrongChar chNext ch = SEBase symbolSing $
          SText symbolSing :$<>: SText (sShowChar chNext)
    :$<>: SText symbolSing :$<>: SText (sShowChar ch)

type LiteralChSym :: ParserChSym Symbol ()
data LiteralChSym f
type instance App LiteralChSym f = LiteralChSym1 f

type LiteralChSym1 :: ParserChSym1 Symbol ()
data LiteralChSym1 ch s
type instance App (LiteralChSym1 ch) s = LiteralCh ch s

sLiteralChSym :: SParserChSym SSymbol SUnit LiteralChSym
sLiteralChSym = Lam2 $ \ch str ->
    case sUnconsSymbol str of
      SJust (STuple2 chNext str') ->
        case testEquality ch chNext of
          Just Refl -> SCont str'
          Nothing   -> unsafeCoerce $ SErr $ eWrongChar chNext ch
      SNothing -> SDone SUnit

type LiteralEnd :: PParserEnd Symbol ()
type family LiteralEnd str where
    LiteralEnd ""  = Right '()
    LiteralEnd str = Left (EStillParsing str)

type EStillParsing str =
    EBase "Literal" (Text "still parsing literal: " :<>: Text str)

eStillParsing :: SSymbol str -> SE (EStillParsing str)
eStillParsing str = withKnownSymbol str singE

type LiteralEndSym :: ParserEndSym Symbol ()
data LiteralEndSym s
type instance App LiteralEndSym s = LiteralEnd s

sLiteralEndSym :: SParserEndSym SSymbol SUnit LiteralEndSym
sLiteralEndSym = Lam $ \str ->
    case testEquality str (SSymbol @"") of
      Just Refl -> SRight SUnit
      Nothing   -> unsafeCoerce $ SLeft $ eStillParsing str