packages feed

ddc-code-0.4.3.1: tetra/base/Control/Parsec.ds

module Control.Parsec
export  
{       parse; zero; item; satisfies;
        from; alt;
        monad_Parser;
        some; many;
}
import Class.Monad
import Data.List
import Data.Tuple
import Data.Maybe
where

data Parser (t a: Data) where
        Parser: (List t → List (Tup2 a (List t))) → Parser t a


-- | Apply a parser to a list of input tokens.
parse ((Parser p): Parser t a) (ts: List t): List (Tup2 a (List t))
 = p ts


-- Functor --------------------------------------------------------------------
functor_Parser [t: Data]: Functor (Parser t)
 = Functor parser_fmap

 where  parser_fmap [t a b: Data] (f: a → b) (parserA: Parser t a): Parser t b
         = Parser $ λts
         → for (parse parserA ts) $ λ(T2 resultA ts2)
         → T2  (f resultA) ts2


-- Applicative ----------------------------------------------------------------
applicative_Parser [t: Data]: Applicative (Parser t)
 = Applicative 
        functor_Parser
        parser_pure
        parser_ap

 where  parser_pure (x: a): Parser t' a
         = Parser $ λts → Cons (T2 x ts) Nil

        parser_ap   (parserF: Parser t' (a → b))
                    (parserA: Parser t' a)
                    : Parser t' b
         = Parser $ λts → concat
         $ for (parse parserF ts)  $ λ(T2 resultF ts2)
         → for (parse parserA ts2) $ λ(T2 resultA ts3)
         → T2 (resultF resultA) ts3


-- Monad ----------------------------------------------------------------------
monad_Parser [t: Data]: Monad (Parser t)
 = Monad applicative_Parser
         parser_return
         parser_bind

 where  parser_return (x: a): Parser t' a
         = Parser $ λts → Cons (T2 x ts) Nil

        parser_bind
                (parserA:   Parser t' a)
                (mkParserB: a → Parser t' b)
                : Parser t' b
         = Parser $ λts → concat  
         $ for (parse parserA ts)              $ λ(T2 resultA ts2)
         → for (parse (mkParserB resultA) ts2) $ λ(T2 resultB ts3)
         → T2 resultB ts3


-------------------------------------------------------------------------------
-- | Always fail, producing no possible parses.
zero: Parser t a
 = Parser $ λ_ → Nil


-- | Consume the first input token, failing if there aren't any.
item: Parser t t
 = Parser $ λts
 → case ts of
        Nil             → Nil
        Cons t ts'      → Cons (T2 t ts) Nil


-- | A parser that accepts a single token that satisfies the given predicate,
--   producing the given value if it matches.
satisfies (pred: t → Bool): Parser t t
 = Parser $ λts
 → case ts of
        Nil            → Nil
        Cons t ts
         | pred t      → Cons (T2 t ts) Nil
         | otherwise   → Nil


-- | Use the given function to check whether to accept the next token,
--   returning the result that it produces.
from (accept: t → Maybe a): Parser t a
 = Parser $ λts
 → case ts of
        Nil            → Nil
        Cons t ts'
         → case accept t of
               Nothing → Nil
               Just x  → Cons (T2 x ts') Nil


-- | Combine two argument parsers, producing a new one that accepts
--   strings parsed by either of the argument parsers.
plus (parserA parserB: Parser t a): Parser t a
 = Parser $ λts 
 → append (parse parserA ts) (parse parserB ts)


-- | Combine two argument parsers, producing a new one that accepts
--   strings parser by either of the argument parser, but not both.
--   We prefer result produced by the first parser over the second.
alt (parserA parserB: Parser t a): Parser t a
 = Parser $ λts
 → case parse parserA ts of
        Nil    → parse parserB ts
        res    → res


-- | Combine a list of argument parsers, producing a new one that
--   gives the result produced by the first matching argument parser.
alts (parsers: List (Parser t a)): Parser t a
 = case parsers of
        Nil             → zero
        Cons p ps       → alt p (alts ps)


-- | Like `alts`, accept use the given default parser if no 
--   parser from the first list succeeds.
altss (parsers: List (Parser t a)) (def: Parser t a): Parser t a
 = case parsers of
        Nil             → def
        Cons p ps       → alt p (altss ps def)


-- | Apply a parser followed by another parser,
--   producing a tuple that contains both results.
follows (parserA: Parser t a) (parserB: Parser t b): Parser t (Tup2 a b)
 = Parser $ λts → concat
 $ for (parse parserA ts)  $ λ(T2 resultA ts2)
 → for (parse parserB ts2) $ λ(T2 resultB ts3)
 → T2 (T2 resultA resultB) ts3


-- | Parse zero or more things, yielding a list of those things.
some (parserA: Parser t a): Parser t (List a)
 = alt  (bind   monad_Parser parserA        $ λx  → 
         bind   monad_Parser (some parserA) $ λxs →
         return monad_Parser (Cons x xs))
        (return monad_Parser Nil)


-- | Parse one or more things, yielding a list of those things.
many [a t: Data] (parserA: Parser t a): Parser t (List a)
 = alt  (bind   monad_Parser parserA        $ λx  →
         bind   monad_Parser (some parserA) $ λxs →
         return monad_Parser (Cons x xs))
        (bind   monad_Parser parserA        $ λx  →
         return monad_Parser (Cons x Nil))