packages feed

symparsec-2.0.0: src/Symparsec/Parser.hs

{-# LANGUAGE UndecidableInstances #-}

module Symparsec.Parser where

import DeFun.Core
import GHC.TypeLits ( type Symbol )
import GHC.TypeNats ( type Natural )

import Singleraeh.Demote
import Data.Kind ( type Type )
import GHC.TypeLits ( type SSymbol, fromSSymbol )
import GHC.TypeNats ( type SNat, fromSNat )
import Singleraeh.List
--import Singleraeh.Symbol

-- | Parser state.
data State str n = State
  -- | Remaining input.
  { remaining :: str

  -- | Remaining permitted length.
  --
  -- Must be less than or equal to the actual length of the remaining input.
  -- Parsers must use this field when reading from input:
  --
  -- * if ==0, treat as end of input.
  -- * if  >0 but remaining input is empty, unrecoverable parser error
  --
  -- This extra bookkeeping permits much simpler parser design, specifically for
  -- parsers that act on a substring of the input.
  , length :: n

  -- | Index in the input string.
  --
  -- Overall index. Used for nicer error reporting after parse completion.
  , index :: n
  } deriving stock Show

-- | Promoted 'State'.
type PState = State Symbol Natural

-- | Singled 'State'.
data SState (s :: PState) where
    SState :: SSymbol rem -> SNat len -> SNat idx -> SState ('State rem len idx)

-- | Demote an 'SState'.
demoteSState :: SState s -> State String Natural
demoteSState (SState srem slen sidx) =
    State (fromSSymbol srem) (fromSNat slen) (fromSNat sidx)

instance Demotable SState where
    type Demote SState = State String Natural
    demote = demoteSState

{-
data Span n = Span
  { start :: n
  , end   :: n
  } deriving stock Show
-}

data Error str = Error
  { detail :: [str]
  } deriving stock Show

-- | Promoted 'Error'.
type PError = Error Symbol

-- | Singled 'Error'.
data SError (e :: PError) where
    SError :: SList SSymbol detail -> SError ('Error detail)

-- | Demote an 'SError'.
demoteSError :: SError e -> Error String
demoteSError (SError sdetail) = Error $ demoteSList fromSSymbol sdetail

instance Demotable SError where
    type Demote SError = Error String
    demote = demoteSError

-- | Parser completion: result, and final state.
--
-- TODO: megaparsec also returns a bool indicating if any input was consumed.
-- Unsure what it's used for.
data Reply str n a = Reply
  { result :: Result str n a -- ^ Parse result.
  , state  :: State str n    -- ^ Final parser state.
  } deriving stock Show

-- | Promoted 'Reply'.
type PReply = Reply Symbol Natural

-- | Singled 'Reply'.
data SReply (sa :: a -> Type) (rep :: PReply a) where
    SReply :: SResult sa result -> SState state -> SReply sa ('Reply result state)

-- | Demote an 'SReply.
demoteSReply
    :: (forall a. sa a -> da)
    -> SReply sa rep
    -> Reply String Natural da
demoteSReply demoteSA (SReply sresult sstate) =
    Reply (demoteSResult demoteSA sresult) (demoteSState sstate)

instance Demotable sa => Demotable (SReply sa) where
    type Demote (SReply sa) = Reply String Natural (Demote sa)
    demote = demoteSReply demote

-- | Parse result: a value, or an error.
data Result str n a = OK a            -- ^ Parser succeeded.
                    | Err (Error str) -- ^ Parser failed.
    deriving stock Show

-- | Promoted 'Result'.
type PResult = Result Symbol Natural

--type SState = State 
--type SResult :: _ -> Type
-- TODO ^ how to do explicit kind signature for GADT?

-- | Singled 'Result'.
data SResult (sa :: a -> Type) (res :: PResult a) where
    SOK  :: sa a     -> SResult sa (OK a)
    SErr :: SError e -> SResult sa (Err e)

-- | Demote an 'SResult'.
demoteSResult
    :: (forall a. sa a -> da)
    -> SResult sa res
    -> Result String Natural da
demoteSResult demoteSA = \case
  SOK  sa -> OK  $ demoteSA sa
  SErr se -> Err $ demoteSError se

instance Demotable sa => Demotable (SResult sa) where
    type Demote (SResult sa) = Result String Natural (Demote sa)
    demote = demoteSResult demote

-- | A parser is a function on parser state.
type Parser str n a = State str n -> Reply str n a

-- | Promoted 'Parser': a defunctionalization symbol to a function on promoted
--   parser state.
type PParser a = PState ~> PReply a

-- | Singled 'Parser'.
type SParser sa p = Lam SState (SReply sa) p
--data SParser (sa :: a -> Type) (p :: PParser a) where
 --   SParser :: Lam SState (SReply sa) (PParser a)

--class SingParser (p :: PParser a) where
--    singParser :: SParser sa p