shithub: MicroHs

Download patch

ref: 2e57a841206dffa9015c16471490e036e9a53551
parent: 30bbf972cec6f7ed080b42d6ccead04e110f8b98
author: Lennart Augustsson <lennart.augustsson@epicgames.com>
date: Fri Feb 2 17:23:52 EST 2024

Start of Read.

--- /dev/null
+++ b/lib/Text/ParserCombinators/ReadP.hs
@@ -1,0 +1,428 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.ParserCombinators.ReadP
+-- Copyright   :  (c) The University of Glasgow 2002
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  provisional
+-- Portability :  non-portable (local universal quantification)
+--
+-- This is a library of parser combinators, originally written by Koen Claessen.
+-- It parses all alternatives in parallel, so it never keeps hold of
+-- the beginning of the input string, a common source of space leaks with
+-- other parsers.  The @('+++')@ choice combinator is genuinely commutative;
+-- it makes no difference which branch is \"shorter\".
+
+-----------------------------------------------------------------------------
+
+module Text.ParserCombinators.ReadP
+  (
+  -- * The 'ReadP' type
+  ReadP,
+
+  -- * Primitive operations
+  get,
+  look,
+  (+++),
+  (<++),
+  gather,
+
+  -- * Other operations
+  pfail,
+  eof,
+  satisfy,
+  char,
+  string,
+  munch,
+  munch1,
+  skipSpaces,
+  choice,
+  count,
+  between,
+  option,
+  optional,
+  many,
+  many1,
+  skipMany,
+  skipMany1,
+  sepBy,
+  sepBy1,
+  endBy,
+  endBy1,
+  chainr,
+  chainl,
+  chainl1,
+  chainr1,
+  manyTill,
+
+  -- * Running a parser
+  ReadS,
+  readP_to_S,
+  readS_to_P,
+
+  -- * Properties
+  -- $properties
+  )
+ where
+
+import Control.Applicative
+import Control.Alternative
+import Control.Error
+import Control.Monad
+import Data.Bool
+import Data.Char
+import Data.Eq
+import Data.Function
+import Data.Int
+import Data.List
+import Data.Num
+import Data.Tuple
+
+infixr 5 +++, <++
+
+------------------------------------------------------------------------
+-- ReadS
+
+-- | A parser for a type @a@, represented as a function that takes a
+-- 'String' and returns a list of possible parses as @(a,'String')@ pairs.
+--
+-- Note that this kind of backtracking parser is very inefficient;
+-- reading a large structure may be quite slow (cf 'ReadP').
+type ReadS a = String -> [(a,String)]
+
+-- ---------------------------------------------------------------------------
+-- The P type
+-- is representation type -- should be kept abstract
+
+data P a
+  = Get (Char -> P a)
+  | Look (String -> P a)
+  | Fail
+  | Result a (P a)
+  | Final [(a,String)]
+--  deriving Functor -- ^ @since 4.8.0.0
+instance Functor P where
+  fmap f (Get p) = Get (\ c -> fmap f (p c))
+
+-- Monad, MonadPlus
+
+-- | @since 4.5.0.0
+instance Applicative P where
+  pure x = Result x Fail
+  (<*>) = ap
+
+-- | @since 2.01
+instance MonadPlus P
+
+-- | @since 2.01
+instance Monad P where
+  (Get f)         >>= k = Get (\c -> f c >>= k)
+  (Look f)        >>= k = Look (\s -> f s >>= k)
+  Fail            >>= _ = Fail
+  (Result x p)    >>= k = k x <|> (p >>= k)
+  (Final (r:rs))  >>= k = final [ys' | (x,s) <- (r:rs), ys' <- run (k x) s]
+
+-- | @since 4.9.0.0
+instance MonadFail P where
+  fail _ = Fail
+
+-- | @since 4.5.0.0
+instance Alternative P where
+  empty = Fail
+
+  -- most common case: two gets are combined
+  Get f1     <|> Get f2     = Get (\c -> f1 c <|> f2 c)
+
+  -- results are delivered as soon as possible
+  Result x p <|> q          = Result x (p <|> q)
+  p          <|> Result x q = Result x (p <|> q)
+
+  -- fail disappears
+  Fail       <|> p          = p
+  p          <|> Fail       = p
+
+  -- two finals are combined
+  -- final + look becomes one look and one final (=optimization)
+  -- final + sthg else becomes one look and one final
+  Final r       <|> Final t = Final (r ++ t)
+  Final (r:rs)  <|> Look f  = Look (\s -> Final (r:(rs ++ run (f s) s)))
+  Final (r:rs)  <|> p       = Look (\s -> Final (r:(rs ++ run p s)))
+  Look f        <|> Final r = Look (\s -> Final (run (f s) s ++ r))
+  p             <|> Final r = Look (\s -> Final (run p s ++ r))
+
+  -- two looks are combined (=optimization)
+  -- look + sthg else floats upwards
+  Look f     <|> Look g     = Look (\s -> f s <|> g s)
+  Look f     <|> p          = Look (\s -> f s <|> p)
+  p          <|> Look f     = Look (\s -> p <|> f s)
+
+-- ---------------------------------------------------------------------------
+-- The ReadP type
+
+newtype ReadP a = R (forall b . (a -> P b) -> P b)
+
+-- | @since 2.01
+instance Functor ReadP where
+  fmap h (R f) = R (\k -> f (k . h))
+
+-- | @since 4.6.0.0
+instance Applicative ReadP where
+    pure x = R (\k -> k x)
+    (<*>) = ap
+    -- liftA2 = liftM2
+
+-- | @since 2.01
+instance Monad ReadP where
+  R m >>= f = R (\k -> m (\a -> let { R m' = f a } in m' k))
+
+-- | @since 4.9.0.0
+instance MonadFail ReadP where
+  fail _    = R (\_ -> Fail)
+
+-- | @since 4.6.0.0
+instance Alternative ReadP where
+  empty = pfail
+  (<|>) = (+++)
+
+-- | @since 2.01
+instance MonadPlus ReadP
+
+-- ---------------------------------------------------------------------------
+-- Operations over P
+
+final :: forall a . [(a,String)] -> P a
+final [] = Fail
+final rs = Final rs
+
+run :: forall a . P a -> ReadS a
+run (Get f)         (c:s) = run (f c) s
+run (Look f)        s     = run (f s) s
+run (Result x p)    s     = (x,s) : run p s
+run (Final rs)      _     = rs
+run _               _     = []
+
+-- ---------------------------------------------------------------------------
+-- Operations over ReadP
+
+get :: ReadP Char
+-- ^ Consumes and returns the next character.
+--   Fails if there is no input left.
+get = R Get
+
+look :: ReadP String
+-- ^ Look-ahead: returns the part of the input that is left, without
+--   consuming it.
+look = R Look
+
+pfail :: forall a . ReadP a
+-- ^ Always fails.
+pfail = R (\_ -> Fail)
+
+(+++) :: forall a . ReadP a -> ReadP a -> ReadP a
+-- ^ Symmetric choice.
+R f1 +++ R f2 = R (\k -> f1 k <|> f2 k)
+
+(<++) :: forall a . ReadP a -> ReadP a -> ReadP a
+-- ^ Local, exclusive, left-biased choice: If left parser
+--   locally produces any result at all, then right parser is
+--   not used.
+R f0 <++ q =
+  do s <- look
+     probe (f0 return) s (0::Int)
+ where
+  probe (Get f)        (c:s) n = probe (f c) s (n + (1::Int))
+  probe (Look f)       s     n = probe (f s) s n
+  probe p@(Result _ _) _     n = discard n >> R (p >>=)
+  probe (Final r)      _     _ = R (Final r >>=)
+  probe _              _     _ = q
+
+  discard n = if n == 0::Int then return () else get >> discard (n - (1::Int))
+
+gather :: forall a . ReadP a -> ReadP (String, a)
+-- ^ Transforms a parser into one that does the same, but
+--   in addition returns the exact characters read.
+--   IMPORTANT NOTE: 'gather' gives a runtime error if its first argument
+--   is built using any occurrences of readS_to_P.
+gather (R m)
+  = R (\k -> gath id (m (\a -> return (\s -> k (s,a)))))
+ where
+  gath :: forall b . (String -> String) -> P (String -> P b) -> P b
+  gath l (Get f)      = Get (\c -> gath (l.(c:)) (f c))
+  gath _ Fail         = Fail
+  gath l (Look f)     = Look (\s -> gath l (f s))
+  gath l (Result k p) = k (l []) <|> gath l p
+  gath _ (Final _)    = error "do not use readS_to_P in gather!"
+
+-- ---------------------------------------------------------------------------
+-- Derived operations
+
+satisfy :: (Char -> Bool) -> ReadP Char
+-- ^ Consumes and returns the next character, if it satisfies the
+--   specified predicate.
+satisfy p = do c <- get; if p c then return c else pfail
+
+char :: Char -> ReadP Char
+-- ^ Parses and returns the specified character.
+char c = satisfy (c ==)
+
+eof :: ReadP ()
+-- ^ Succeeds iff we are at the end of input
+eof = do { s <- look
+         ; if null s then return ()
+                     else pfail }
+
+string :: String -> ReadP String
+-- ^ Parses and returns the specified string.
+string this = do s <- look; scan this s
+ where
+  scan []     _               = return this
+  scan (x:xs) (y:ys) | x == y = do _ <- get; scan xs ys
+  scan _      _               = pfail
+
+munch :: (Char -> Bool) -> ReadP String
+-- ^ Parses the first zero or more characters satisfying the predicate.
+--   Always succeeds, exactly once having consumed all the characters
+--   Hence NOT the same as (many (satisfy p))
+munch p =
+  do s <- look
+     scan s
+ where
+  scan (c:cs) | p c = do _ <- get; s <- scan cs; return (c:s)
+  scan _            = return ""
+
+munch1 :: (Char -> Bool) -> ReadP String
+-- ^ Parses the first one or more characters satisfying the predicate.
+--   Fails if none, else succeeds exactly once having consumed all the characters
+--   Hence NOT the same as (many1 (satisfy p))
+munch1 p =
+  do c <- get
+     if p c then do s <- munch p; return (c:s)
+            else pfail
+
+choice :: forall a . [ReadP a] -> ReadP a
+-- ^ Combines all parsers in the specified list.
+choice []     = pfail
+choice [p]    = p
+choice (p:ps) = p +++ choice ps
+
+skipSpaces :: ReadP ()
+-- ^ Skips all whitespace.
+skipSpaces =
+  do s <- look
+     skip s
+ where
+  skip (c:s) | isSpace c = do _ <- get; skip s
+  skip _                 = return ()
+
+count :: forall a . Int -> ReadP a -> ReadP [a]
+-- ^ @count n p@ parses @n@ occurrences of @p@ in sequence. A list of
+--   results is returned.
+count n p = sequence (replicate n p)
+
+between :: forall a open close . ReadP open -> ReadP close -> ReadP a -> ReadP a
+-- ^ @between open close p@ parses @open@, followed by @p@ and finally
+--   @close@. Only the value of @p@ is returned.
+between open close p = do _ <- open
+                          x <- p
+                          _ <- close
+                          return x
+
+option :: forall a . a -> ReadP a -> ReadP a
+-- ^ @option x p@ will either parse @p@ or return @x@ without consuming
+--   any input.
+option x p = p +++ return x
+
+optional :: forall a . ReadP a -> ReadP ()
+-- ^ @optional p@ optionally parses @p@ and always returns @()@.
+optional p = (p >> return ()) +++ return ()
+
+many :: forall a . ReadP a -> ReadP [a]
+-- ^ Parses zero or more occurrences of the given parser.
+many p = return [] +++ many1 p
+
+many1 :: forall a . ReadP a -> ReadP [a]
+-- ^ Parses one or more occurrences of the given parser.
+many1 p = liftM2 (:) p (many p)
+
+skipMany :: forall a . ReadP a -> ReadP ()
+-- ^ Like 'many', but discards the result.
+skipMany p = many p >> return ()
+
+skipMany1 :: forall a . ReadP a -> ReadP ()
+-- ^ Like 'many1', but discards the result.
+skipMany1 p = p >> skipMany p
+
+sepBy :: forall a sep . ReadP a -> ReadP sep -> ReadP [a]
+-- ^ @sepBy p sep@ parses zero or more occurrences of @p@, separated by @sep@.
+--   Returns a list of values returned by @p@.
+sepBy p sep = sepBy1 p sep +++ return []
+
+sepBy1 :: forall a sep . ReadP a -> ReadP sep -> ReadP [a]
+-- ^ @sepBy1 p sep@ parses one or more occurrences of @p@, separated by @sep@.
+--   Returns a list of values returned by @p@.
+sepBy1 p sep = liftM2 (:) p (many (sep >> p))
+
+endBy :: forall a sep . ReadP a -> ReadP sep -> ReadP [a]
+-- ^ @endBy p sep@ parses zero or more occurrences of @p@, separated and ended
+--   by @sep@.
+endBy p sep = many (do { x <- p ; _ <- sep ; return x})
+
+endBy1 :: forall a sep . ReadP a -> ReadP sep -> ReadP [a]
+-- ^ @endBy p sep@ parses one or more occurrences of @p@, separated and ended
+--   by @sep@.
+endBy1 p sep = many1 (do { x <- p ; _ <- sep ; return x})
+
+chainr :: forall a . ReadP a -> ReadP (a -> a -> a) -> a -> ReadP a
+-- ^ @chainr p op x@ parses zero or more occurrences of @p@, separated by @op@.
+--   Returns a value produced by a /right/ associative application of all
+--   functions returned by @op@. If there are no occurrences of @p@, @x@ is
+--   returned.
+chainr p op x = chainr1 p op +++ return x
+
+chainl :: forall a . ReadP a -> ReadP (a -> a -> a) -> a -> ReadP a
+-- ^ @chainl p op x@ parses zero or more occurrences of @p@, separated by @op@.
+--   Returns a value produced by a /left/ associative application of all
+--   functions returned by @op@. If there are no occurrences of @p@, @x@ is
+--   returned.
+chainl p op x = chainl1 p op +++ return x
+
+chainr1 :: forall a . ReadP a -> ReadP (a -> a -> a) -> ReadP a
+-- ^ Like 'chainr', but parses one or more occurrences of @p@.
+chainr1 p op = scan
+  where scan   = p >>= rest
+        rest x = do f <- op
+                    y <- scan
+                    return (f x y)
+                 +++ return x
+
+chainl1 :: forall a . ReadP a -> ReadP (a -> a -> a) -> ReadP a
+-- ^ Like 'chainl', but parses one or more occurrences of @p@.
+chainl1 p op = p >>= rest
+  where rest x = do f <- op
+                    y <- p
+                    rest (f x y)
+                 +++ return x
+
+manyTill :: forall a end . ReadP a -> ReadP end -> ReadP [a]
+-- ^ @manyTill p end@ parses zero or more occurrences of @p@, until @end@
+--   succeeds. Returns a list of values returned by @p@.
+manyTill p end = scan
+  where scan = (end >> return []) <++ (liftM2 (:) p scan)
+
+-- ---------------------------------------------------------------------------
+-- Converting between ReadP and Read
+
+readP_to_S :: forall a . ReadP a -> ReadS a
+-- ^ Converts a parser into a Haskell ReadS-style function.
+--   This is the main way in which you can \"run\" a 'ReadP' parser:
+--   the expanded type is
+-- @ readP_to_S :: ReadP a -> String -> [(a,String)] @
+readP_to_S (R f) = run (f return)
+
+readS_to_P :: forall a . ReadS a -> ReadP a
+-- ^ Converts a Haskell ReadS-style function into a parser.
+--   Warning: This introduces local backtracking in the resulting
+--   parser, and therefore a possible inefficiency.
+readS_to_P r =
+  R (\k -> Look (\s -> final [bs'' | (a,s') <- r s, bs'' <- run (k a) s']))
--- /dev/null
+++ b/lib/Text/ParserCombinators/ReadPrec.hs
@@ -1,0 +1,177 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.ParserCombinators.ReadPrec
+-- Copyright   :  (c) The University of Glasgow 2002
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  provisional
+-- Portability :  non-portable (uses Text.ParserCombinators.ReadP)
+--
+-- This library defines parser combinators for precedence parsing.
+
+-----------------------------------------------------------------------------
+
+module Text.ParserCombinators.ReadPrec
+  (
+  ReadPrec,
+
+  -- * Precedences
+  Prec,
+  minPrec,
+
+  -- * Precedence operations
+  lift,
+  prec,
+  step,
+  reset,
+
+  -- * Other operations
+  -- | All are based directly on their similarly-named 'ReadP' counterparts.
+  get,
+  look,
+  (+++),
+  (<++),
+  pfail,
+  choice,
+
+  -- * Converters
+  readPrec_to_P,
+  readP_to_Prec,
+  readPrec_to_S,
+  readS_to_Prec,
+  )
+ where
+
+
+import Text.ParserCombinators.ReadP
+  ( ReadP
+  , ReadS
+  , readP_to_S
+  , readS_to_P
+  )
+
+import qualified Text.ParserCombinators.ReadP as ReadP
+  ( get
+  , look
+  , (+++), (<++)
+  , pfail
+  )
+
+import Control.Applicative
+import Control.Alternative
+import Control.Monad
+import Data.Char
+import Data.Int
+import Data.List
+import Data.Num
+import Data.Ord
+
+-- ---------------------------------------------------------------------------
+-- The readPrec type
+
+newtype ReadPrec a = P (Prec -> ReadP a)
+
+-- Functor, Monad, MonadPlus
+
+-- | @since 2.01
+instance Functor ReadPrec where
+  fmap h (P f) = P (\n -> fmap h (f n))
+
+-- | @since 4.6.0.0
+instance Applicative ReadPrec where
+    pure x  = P (\_ -> pure x)
+    (<*>) = ap
+    liftA2 = liftM2
+
+-- | @since 2.01
+instance Monad ReadPrec where
+  P f >>= k = P (\n -> do {a <- f n; let {P f' = k a}; f' n})
+
+-- | @since 4.9.0.0
+instance MonadFail ReadPrec where
+  fail s    = P (\_ -> fail s)
+
+-- | @since 2.01
+instance MonadPlus ReadPrec
+
+-- | @since 4.6.0.0
+instance Alternative ReadPrec where
+  empty = pfail
+  (<|>) = (+++)
+
+-- precedences
+type Prec = Int
+
+minPrec :: Prec
+minPrec = 0
+
+-- ---------------------------------------------------------------------------
+-- Operations over ReadPrec
+
+lift :: forall a . ReadP a -> ReadPrec a
+-- ^ Lift a precedence-insensitive 'ReadP' to a 'ReadPrec'.
+lift m = P (\_ -> m)
+
+step :: forall a . ReadPrec a -> ReadPrec a
+-- ^ Increases the precedence context by one.
+step (P f) = P (\n -> f (n+1))
+
+reset :: forall a . ReadPrec a -> ReadPrec a
+-- ^ Resets the precedence context to zero.
+reset (P f) = P (\_ -> f minPrec)
+
+prec :: forall a . Prec -> ReadPrec a -> ReadPrec a
+-- ^ @(prec n p)@ checks whether the precedence context is
+--   less than or equal to @n@, and
+--
+--   * if not, fails
+--
+--   * if so, parses @p@ in context @n@.
+prec n (P f) = P (\c -> if c <= n then f n else ReadP.pfail)
+
+-- ---------------------------------------------------------------------------
+-- Derived operations
+
+get :: ReadPrec Char
+-- ^ Consumes and returns the next character.
+--   Fails if there is no input left.
+get = lift ReadP.get
+
+look :: ReadPrec String
+-- ^ Look-ahead: returns the part of the input that is left, without
+--   consuming it.
+look = lift ReadP.look
+
+(+++) :: forall a . ReadPrec a -> ReadPrec a -> ReadPrec a
+-- ^ Symmetric choice.
+P f1 +++ P f2 = P (\n -> f1 n ReadP.+++ f2 n)
+
+(<++) :: forall a . ReadPrec a -> ReadPrec a -> ReadPrec a
+-- ^ Local, exclusive, left-biased choice: If left parser
+--   locally produces any result at all, then right parser is
+--   not used.
+P f1 <++ P f2 = P (\n -> f1 n ReadP.<++ f2 n)
+
+pfail :: forall a . ReadPrec a
+-- ^ Always fails.
+pfail = lift ReadP.pfail
+
+choice :: forall a . [ReadPrec a] -> ReadPrec a
+-- ^ Combines all parsers in the specified list.
+choice ps = foldr (+++) pfail ps
+
+-- ---------------------------------------------------------------------------
+-- Converting between ReadPrec and Read
+
+readPrec_to_P :: forall a . ReadPrec a -> (Int -> ReadP a)
+readPrec_to_P (P f) = f
+
+readP_to_Prec :: forall a . (Int -> ReadP a) -> ReadPrec a
+readP_to_Prec f = P f
+
+readPrec_to_S :: forall a . ReadPrec a -> (Int -> ReadS a)
+readPrec_to_S (P f) n = readP_to_S (f n)
+
+readS_to_Prec :: forall a . (Int -> ReadS a) -> ReadPrec a
+readS_to_Prec f = P (\n -> readS_to_P (f n))
--- /dev/null
+++ b/lib/Text/Read.hs
@@ -1,0 +1,6 @@
+module Text.Read(
+  Read(..)
+  read,
+  readMaybe,
+  ReadS,
+  ) where
--