packages feed

Earley 0.8.2 → 0.8.3

raw patch · 4 files changed

+339/−330 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Text.Earley.Parser: instance (Eq e, Eq i) => Eq (Report e i)
- Text.Earley.Parser: instance (Ord e, Ord i) => Ord (Report e i)
- Text.Earley.Parser: instance (Read e, Read i) => Read (Report e i)
- Text.Earley.Parser: instance (Show e, Show i) => Show (Report e i)
- Text.Earley.Parser: instance Functor (Result s e i)
+ Text.Earley.Internal: [Cont] :: !Pos -> !(Args s a b) -> !(ProdR s r e t (b -> c)) -> !(Args s c d) -> !(Conts s r e t d e') -> Cont s r e t a e'
+ Text.Earley.Internal: [Conts] :: !(STRef s [Cont s r e t a c]) -> !(STRef s (Maybe (STRef s (ST s [a])))) -> Conts s r e t a c
+ Text.Earley.Internal: [Ended] :: (Report e i) -> Result s e i a
+ Text.Earley.Internal: [FinalCont] :: Args s a c -> Cont s r e t a c
+ Text.Earley.Internal: [Final] :: f -> Args s f a -> State s r e t a
+ Text.Earley.Internal: [Parsed] :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
+ Text.Earley.Internal: [Report] :: Int -> [e] -> i -> Report e i
+ Text.Earley.Internal: [Rule] :: ProdR s r e t a -> !(STRef s (Maybe [a])) -> !(STRef s (STRef s [Cont s r e t a r])) -> Rule s r e t a
+ Text.Earley.Internal: [State] :: !Pos -> !(ProdR s r e t f) -> !(Args s f b) -> !(Conts s r e t b a) -> State s r e t a
+ Text.Earley.Internal: [contsArgs] :: Conts s r e t a c -> !(STRef s (Maybe (STRef s (ST s [a]))))
+ Text.Earley.Internal: [conts] :: Conts s r e t a c -> !(STRef s [Cont s r e t a c])
+ Text.Earley.Internal: [expected] :: Report e i -> [e]
+ Text.Earley.Internal: [position] :: Report e i -> Int
+ Text.Earley.Internal: [ruleConts] :: Rule s r e t a -> !(STRef s (STRef s [Cont s r e t a r]))
+ Text.Earley.Internal: [ruleNullable] :: Rule s r e t a -> !(STRef s (Maybe [a]))
+ Text.Earley.Internal: [ruleProd] :: Rule s r e t a -> ProdR s r e t a
+ Text.Earley.Internal: [unconsumed] :: Report e i -> i
+ Text.Earley.Internal: allParses :: (forall s. ST s (Result s e i a)) -> ([(a, Int)], Report e i)
+ Text.Earley.Internal: composeArgs :: Args s a b -> Args s b c -> Args s a c
+ Text.Earley.Internal: contToState :: ST s [a] -> Cont s r e t a c -> State s r e t c
+ Text.Earley.Internal: contraMapCont :: Args s b a -> Cont s r e t a c -> Cont s r e t b c
+ Text.Earley.Internal: data Cont s r e t a b
+ Text.Earley.Internal: data Conts s r e t a c
+ Text.Earley.Internal: data Report e i
+ Text.Earley.Internal: data Result s e i a
+ Text.Earley.Internal: data Rule s r e t a
+ Text.Earley.Internal: data State s r e t a
+ Text.Earley.Internal: fullParses :: ListLike i t => (forall s. ST s (Result s e i a)) -> ([a], Report e i)
+ Text.Earley.Internal: funArg :: (f -> a) -> Args s f a
+ Text.Earley.Internal: grammar :: Grammar (Rule s r) e a -> ST s a
+ Text.Earley.Internal: impureArgs :: ST s [x] -> Args s f a -> Args s (x -> f) a
+ Text.Earley.Internal: initialState :: ProdR s a e t a -> ST s (State s a e t a)
+ Text.Earley.Internal: instance (Eq e, Eq i) => Eq (Report e i)
+ Text.Earley.Internal: instance (Ord e, Ord i) => Ord (Report e i)
+ Text.Earley.Internal: instance (Read e, Read i) => Read (Report e i)
+ Text.Earley.Internal: instance (Show e, Show i) => Show (Report e i)
+ Text.Earley.Internal: instance Functor (Result s e i)
+ Text.Earley.Internal: mapArgs :: (a -> b) -> Args s f a -> Args s f b
+ Text.Earley.Internal: newConts :: STRef s [Cont s r e t a c] -> ST s (Conts s r e t a c)
+ Text.Earley.Internal: noArgs :: Args s a a
+ Text.Earley.Internal: nullable :: Rule s r e t a -> ST s [a]
+ Text.Earley.Internal: nullableProd :: ProdR s r e t a -> ST s [a]
+ Text.Earley.Internal: parse :: ListLike i t => [State s a e t a] -> [ST s [a]] -> [State s a e t a] -> ST s () -> [e] -> Pos -> i -> ST s (Result s e i a)
+ Text.Earley.Internal: parser :: ListLike i t => (forall r. Grammar r e (Prod r e t a)) -> i -> ST s (Result s e i a)
+ Text.Earley.Internal: pureArg :: x -> Args s f a -> Args s (x -> f) a
+ Text.Earley.Internal: report :: ListLike i t => (forall s. ST s (Result s e i a)) -> Report e i
+ Text.Earley.Internal: resetConts :: Rule s r e t a -> ST s ()
+ Text.Earley.Internal: safeHead :: ListLike i t => i -> Maybe t
+ Text.Earley.Internal: safeTail :: ListLike i t => i -> i
+ Text.Earley.Internal: simplifyCont :: Conts s r e t b a -> ST s [Cont s r e t b a]
+ Text.Earley.Internal: type Args s f a = f -> ST s [a]
+ Text.Earley.Internal: type Pos = Int
+ Text.Earley.Internal: type ProdR s r e t a = Prod (Rule s r) e t a

Files

Earley.cabal view
@@ -1,5 +1,5 @@ name:                Earley-version:             0.8.2+version:             0.8.3 synopsis:            Parsing all context-free grammars using Earley's algorithm. description:         See <https://www.github.com/ollef/Earley> for more                      information and@@ -23,7 +23,13 @@   location: https://github.com/ollef/Earley.git  library-  exposed-modules:     Text.Earley.Derived, Text.Earley.Grammar, Text.Earley.Mixfix, Text.Earley.Parser Text.Earley+  exposed-modules:+                       Text.Earley,+                       Text.Earley.Derived,+                       Text.Earley.Grammar,+                       Text.Earley.Internal,+                       Text.Earley.Mixfix,+                       Text.Earley.Parser   -- other-modules:   build-depends:       base >=4.7 && <4.9, ListLike >=4.1   -- hs-source-dirs:
+ Text/Earley/Internal.hs view
@@ -0,0 +1,329 @@+{-# LANGUAGE CPP, BangPatterns, DeriveFunctor, GADTs, Rank2Types #-}+-- | This module exposes the internals of the package: its API may change independently of the PVP-compliant version number.+module Text.Earley.Internal where+import Control.Applicative+import Control.Arrow+import Control.Monad+import Control.Monad.Fix+import Control.Monad.ST+import Data.ListLike(ListLike)+import qualified Data.ListLike as ListLike+import Data.STRef+import Text.Earley.Grammar+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid+#endif++-------------------------------------------------------------------------------+-- * Concrete rules and productions+-------------------------------------------------------------------------------+-- | The concrete rule type that the parser uses+data Rule s r e t a = Rule+  { ruleProd     :: ProdR s r e t a+  , ruleNullable :: !(STRef s (Maybe [a]))+  , ruleConts    :: !(STRef s (STRef s [Cont s r e t a r]))+  }++type ProdR s r e t a = Prod (Rule s r) e t a++nullable :: Rule s r e t a -> ST s [a]+nullable r = do+  mn <- readSTRef $ ruleNullable r+  case mn of+    Just xs -> return xs+    Nothing -> do+      writeSTRef (ruleNullable r) $ Just mempty+      res <- nullableProd $ ruleProd r+      writeSTRef (ruleNullable r) $ Just res+      return res++nullableProd :: ProdR s r e t a -> ST s [a]+nullableProd (Terminal _ _)    = return mempty+nullableProd (NonTerminal r p) = do+  as <- nullable r+  concat <$> mapM (\a -> nullableProd $ fmap ($ a) p) as+nullableProd (Pure a)          = return [a]+nullableProd (Alts as p)       = (\ass fs -> fs <*> concat ass)+                              <$> mapM nullableProd as <*> nullableProd p+nullableProd (Many p q)        = do+  as <- nullableProd $ (:[]) <$> p <|> pure []+  concat <$> mapM (\a -> nullableProd $ fmap ($ a) q) as+nullableProd (Named p _)       = nullableProd p++resetConts :: Rule s r e t a -> ST s ()+resetConts r = writeSTRef (ruleConts r) =<< newSTRef []++-- | If we have something of type @f@, @'Args' s f a@ is what we need to do to+-- @f@ to produce @a@s.+type Args s f a = f -> ST s [a]++noArgs :: Args s a a+noArgs = return . pure++funArg :: (f -> a) -> Args s f a+funArg f = mapArgs f noArgs++pureArg :: x -> Args s f a -> Args s (x -> f) a+pureArg x args = args . ($ x)++impureArgs :: ST s [x] -> Args s f a -> Args s (x -> f) a+impureArgs mxs args f = fmap concat . mapM (args . f) =<< mxs++mapArgs :: (a -> b) -> Args s f a -> Args s f b+mapArgs = fmap . fmap . fmap++composeArgs :: Args s a b -> Args s b c -> Args s a c+composeArgs ab bc a = fmap concat . mapM bc =<< ab a++-------------------------------------------------------------------------------+-- * States and continuations+-------------------------------------------------------------------------------+type Pos = Int++-- | An Earley state with result type @a@.+data State s r e t a where+  State :: !Pos+        -> !(ProdR s r e t f)+        -> !(Args s f b)+        -> !(Conts s r e t b a)+        -> State s r e t a+  Final :: f -> Args s f a -> State s r e t a++-- | A continuation accepting an @a@ and producing a @b@.+data Cont s r e t a b where+  Cont      :: !Pos+            -> !(Args s a b)+            -> !(ProdR s r e t (b -> c))+            -> !(Args s c d)+            -> !(Conts s r e t d e')+            -> Cont s r e t a e'+  FinalCont :: Args s a c -> Cont s r e t a c++data Conts s r e t a c = Conts+  { conts     :: !(STRef s [Cont s r e t a c])+  , contsArgs :: !(STRef s (Maybe (STRef s (ST s [a]))))+  }++newConts :: STRef s [Cont s r e t a c] -> ST s (Conts s r e t a c)+newConts r = Conts r <$> newSTRef Nothing++contraMapCont :: Args s b a -> Cont s r e t a c -> Cont s r e t b c+contraMapCont f (Cont pos g p args cs) = Cont pos (composeArgs f g) p args cs+contraMapCont f (FinalCont args)       = FinalCont (composeArgs f args)++contToState :: ST s [a] -> Cont s r e t a c -> State s r e t c+contToState r (Cont pos g p args cs) = +  let mb = fmap concat . mapM g =<< r in+  State pos p (impureArgs mb args) cs+contToState r (FinalCont args)       = Final id (impureArgs r args)++-- | Strings of non-ambiguous continuations can be optimised by removing+--   indirections.+simplifyCont :: Conts s r e t b a -> ST s [Cont s r e t b a]+simplifyCont Conts {conts = cont} = readSTRef cont >>= go False+  where+    go !_ [Cont _ g (Pure f) args cont'] = do+      ks' <- simplifyCont cont'+      go True $ map (contraMapCont $ mapArgs f g `composeArgs` args) ks'+    go True ks = do+      writeSTRef cont ks+      return ks+    go False ks = return ks++-------------------------------------------------------------------------------+-- * Grammars+-------------------------------------------------------------------------------+-- | Interpret an abstract 'Grammar'.+grammar :: Grammar (Rule s r) e a -> ST s a+grammar g = case g of+  RuleBind p k -> do+    c  <- newSTRef =<< newSTRef mempty+    nr <- newSTRef Nothing+    grammar $ k $ NonTerminal (Rule p nr c) $ Pure id+  FixBind f k   -> do+    a <- mfix $ fmap grammar f+    grammar $ k a+  Return x      -> return x++-- | Given a grammar, construct an initial state.+initialState :: ProdR s a e t a -> ST s (State s a e t a)+initialState p = State (-1) p noArgs <$> (newConts =<< newSTRef [FinalCont noArgs])++-------------------------------------------------------------------------------+-- * Parsing+-------------------------------------------------------------------------------+-- | A parsing report, which contains fields that are useful for presenting+-- errors to the user if a parse is deemed a failure.  Note however that we get+-- a report even when we successfully parse something.+data Report e i = Report+  { position   :: Int -- ^ The final position in the input (0-based) that the+                      -- parser reached.+  , expected   :: [e] -- ^ The named productions processed at the final+                      -- position.+  , unconsumed :: i   -- ^ The part of the input string that was not consumed,+                      -- which may be empty.+  } deriving (Eq, Ord, Read, Show)++-- | The result of a parse.+data Result s e i a+  = Ended (Report e i)+    -- ^ The parser ended.+  | Parsed (ST s [a]) Int i (ST s (Result s e i a))+    -- ^ The parser parsed a number of @a@s.  These are given as a computation,+    -- @'ST' s [a]@ that constructs the 'a's when run.  We can thus save some+    -- work by ignoring this computation if we do not care about the results.+    -- The 'Int' is the position in the input where these results were+    -- obtained, the @i@ the rest of the input, and the last component is the+    -- continuation.+  deriving Functor++{-# INLINE safeHead #-}+safeHead :: ListLike i t => i -> Maybe t+safeHead ts+  | ListLike.null ts = Nothing+  | otherwise        = Just $ ListLike.head ts++{-# INLINE safeTail #-}+safeTail :: ListLike i t => i -> i+safeTail ts+  | ListLike.null ts = ts+  | otherwise        = ListLike.tail ts++{-# SPECIALISE parse :: [State s a e t a]+                     -> [ST s [a]]+                     -> [State s a e t a]+                     -> ST s ()+                     -> [e]+                     -> Pos+                     -> [t]+                     -> ST s (Result s e [t] a) #-}+-- | The internal parsing routine+parse :: ListLike i t+      => [State s a e t a] -- ^ States to process at this position+      -> [ST s [a]]        -- ^ Results ready to be reported (when this position has been processed)+      -> [State s a e t a] -- ^ States to process at the next position+      -> ST s ()           -- ^ Computation that resets the continuation refs of productions+      -> [e]               -- ^ Named productions encountered at this position+      -> Pos               -- ^ The current position in the input string+      -> i                 -- ^ The input string+      -> ST s (Result s e i a)+parse [] [] [] reset names !pos ts = do+  reset+  return $ Ended Report {position = pos, expected = names, unconsumed = ts}+parse [] [] next reset _ !pos ts = do+  reset+  parse next [] [] (return ()) [] (pos + 1) $ safeTail ts+parse [] results next reset names !pos ts = do+  reset+  return $ Parsed (concat <$> sequence results) pos ts+         $ parse [] [] next (return ()) names pos ts+parse (st:ss) results next reset names !pos ts = case st of+  Final f args -> parse ss (args f : results) next reset names pos ts+  State spos pr args scont -> case pr of+    Terminal f p -> case safeHead ts of+      Just t | f t ->+        parse ss results (State spos p (pureArg t args) scont : next) reset names pos ts+      _            -> parse ss results next reset names pos ts+    NonTerminal r p -> do+      rkref <- readSTRef $ ruleConts r+      ks    <- readSTRef rkref+      writeSTRef rkref (Cont spos noArgs p args scont : ks)+      nulls <- nullable r+      let nullStates = [State spos p (pureArg a args) scont | a <- nulls]+      if null ks then do -- The rule has not been expanded at this position.+        st' <- State pos (ruleProd r) noArgs <$> newConts rkref+        parse (st' : nullStates ++ ss)+              results+              next+              (resetConts r >> reset)+              names+              pos+              ts+      else -- The rule has already been expanded at this position.+        parse (nullStates ++ ss) results next reset names pos ts+    Pure a | spos /= pos -> do+      let argsRef = contsArgs scont+      masref  <- readSTRef argsRef+      case masref of+        Just asref -> do -- The continuation has already been followed at this position.+          modifySTRef asref (((++) <$> args a) <*>)+          parse ss results next reset names pos ts+        Nothing    -> do -- It hasn't.+          asref <- newSTRef $ args a+          writeSTRef argsRef $ Just asref+          ks  <- simplifyCont scont+          let kstates = map (contToState $ join $ readSTRef asref) ks+          parse (kstates ++ ss)+                results+                next+                (writeSTRef argsRef Nothing >> reset)+                names+                pos+                ts+           | otherwise -> parse ss results next reset names pos ts+    Alts as (Pure f) -> do+      let args' = funArg f `composeArgs` args+          sts   = [State spos a args' scont | a <- as]+      parse (sts ++ ss) results next reset names pos ts+    Alts as p -> do+      scont' <- newConts =<< newSTRef [Cont spos noArgs p args scont]+      -- State is (-1) so that nullable alts are expanded correctly+      let sts = [State (-1) a noArgs scont' | a <- as]+      parse (sts ++ ss) results next reset names pos ts+    Many p q    -> do+      c  <- newSTRef =<< newSTRef mempty+      nr <- newSTRef Nothing+      let r   = Rule (pure [] <|> (:) <$> p <*> NonTerminal r (Pure id)) nr c+          st' = State spos (NonTerminal r q) args scont+      parse (st' : ss) results next reset names pos ts+    Named pr' n -> parse (State spos pr' args scont : ss) results next reset (n : names) pos ts++{-# INLINE parser #-}+-- | Create a parser from the given grammar.+parser :: ListLike i t+       => (forall r. Grammar r e (Prod r e t a))+       -> i+       -> ST s (Result s e i a)+parser g xs = do+  s <- initialState =<< grammar g+  parse [s] [] [] (return ()) [] 0 xs++-- | Return all parses from the result of a given parser. The result may+-- contain partial parses. The 'Int's are the position at which a result was+-- produced.+allParses :: (forall s. ST s (Result s e i a)) -> ([(a, Int)], Report e i)+allParses p = runST $ p >>= go+  where+    go :: Result s e i a -> ST s ([(a, Int)], Report e i)+    go r = case r of+      Ended rep          -> return ([], rep)+      Parsed mas pos _ k -> do+        as <- mas+        fmap (first (zip as (repeat pos) ++)) $ go =<< k++{-# INLINE fullParses #-}+-- | Return all parses that reached the end of the input from the result of a+--   given parser.+fullParses :: ListLike i t => (forall s. ST s (Result s e i a)) -> ([a], Report e i)+fullParses p = runST $ p >>= go+  where+    go :: ListLike i t => Result s e i a -> ST s ([a], Report e i)+    go r = case r of+      Ended rep -> return ([], rep)+      Parsed mas _ i k+        | ListLike.null i -> do+          as <- mas+          fmap (first (as ++)) $ go =<< k+        | otherwise       -> go =<< k++{-# INLINE report #-}+-- | See e.g. how far the parser is able to parse the input string before it+-- fails.  This can be much faster than getting the parse results for highly+-- ambiguous grammars.+report :: ListLike i t => (forall s. ST s (Result s e i a)) -> Report e i+report p = runST $ p >>= go+  where+    go :: ListLike i t => Result s e i a -> ST s (Report e i)+    go r = case r of+      Ended rep      -> return rep+      Parsed _ _ _ k -> go =<< k
Text/Earley/Mixfix.hs view
@@ -18,7 +18,7 @@ -- representing the positions of its arguments. -- -- Example (commonly written "if_then_else_"):--- @['Just' "if", Nothing, 'Just' "then", Nothing, 'Just' "else", Nothing] :: 'Holey' 'String'@+-- @['Just' "if", 'Nothing', 'Just' "then", 'Nothing', 'Just' "else", 'Nothing'] :: 'Holey' 'String'@ type Holey a = [Maybe a]  -- | Create a grammar for parsing mixfix expressions.
Text/Earley/Parser.hs view
@@ -1,5 +1,4 @@ -- | Parsing.-{-# LANGUAGE CPP, BangPatterns, DeriveFunctor, GADTs, Rank2Types #-} module Text.Earley.Parser   ( Report(..)   , Result(..)@@ -8,329 +7,4 @@   , fullParses   , report   ) where-import Control.Applicative-import Control.Arrow-import Control.Monad-import Control.Monad.Fix-import Control.Monad.ST-import Data.ListLike(ListLike)-import qualified Data.ListLike as ListLike-import Data.STRef-import Text.Earley.Grammar-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid-#endif------------------------------------------------------------------------------------ * Concrete rules and productions----------------------------------------------------------------------------------- | The concrete rule type that the parser uses-data Rule s r e t a = Rule-  { ruleProd     :: ProdR s r e t a-  , ruleNullable :: !(STRef s (Maybe [a]))-  , ruleConts    :: !(STRef s (STRef s [Cont s r e t a r]))-  }--type ProdR s r e t a = Prod (Rule s r) e t a--nullable :: Rule s r e t a -> ST s [a]-nullable r = do-  mn <- readSTRef $ ruleNullable r-  case mn of-    Just xs -> return xs-    Nothing -> do-      writeSTRef (ruleNullable r) $ Just mempty-      res <- nullableProd $ ruleProd r-      writeSTRef (ruleNullable r) $ Just res-      return res--nullableProd :: ProdR s r e t a -> ST s [a]-nullableProd (Terminal _ _)    = return mempty-nullableProd (NonTerminal r p) = do-  as <- nullable r-  concat <$> mapM (\a -> nullableProd $ fmap ($ a) p) as-nullableProd (Pure a)          = return [a]-nullableProd (Alts as p)       = (\ass fs -> fs <*> concat ass)-                              <$> mapM nullableProd as <*> nullableProd p-nullableProd (Many p q)        = do-  as <- nullableProd $ (:[]) <$> p <|> pure []-  concat <$> mapM (\a -> nullableProd $ fmap ($ a) q) as-nullableProd (Named p _)       = nullableProd p--resetConts :: Rule s r e t a -> ST s ()-resetConts r = writeSTRef (ruleConts r) =<< newSTRef []---- | If we have something of type @f@, @'Args' s f a@ is what we need to do to--- @f@ to produce @a@s.-type Args s f a = f -> ST s [a]--noArgs :: Args s a a-noArgs = return . pure--funArg :: (f -> a) -> Args s f a-funArg f = mapArgs f noArgs--pureArg :: x -> Args s f a -> Args s (x -> f) a-pureArg x args = args . ($ x)--impureArgs :: ST s [x] -> Args s f a -> Args s (x -> f) a-impureArgs mxs args f = fmap concat . mapM (args . f) =<< mxs--mapArgs :: (a -> b) -> Args s f a -> Args s f b-mapArgs = fmap . fmap . fmap--composeArgs :: Args s a b -> Args s b c -> Args s a c-composeArgs ab bc a = fmap concat . mapM bc =<< ab a------------------------------------------------------------------------------------ * States and continuations---------------------------------------------------------------------------------type Pos = Int---- | An Earley state with result type @a@.-data State s r e t a where-  State :: !Pos-        -> !(ProdR s r e t f)-        -> !(Args s f b)-        -> !(Conts s r e t b a)-        -> State s r e t a-  Final :: f -> Args s f a -> State s r e t a---- | A continuation accepting an @a@ and producing a @b@.-data Cont s r e t a b where-  Cont      :: !Pos-            -> !(Args s a b)-            -> !(ProdR s r e t (b -> c))-            -> !(Args s c d)-            -> !(Conts s r e t d e')-            -> Cont s r e t a e'-  FinalCont :: Args s a c -> Cont s r e t a c--data Conts s r e t a c = Conts-  { conts     :: !(STRef s [Cont s r e t a c])-  , contsArgs :: !(STRef s (Maybe (STRef s (ST s [a]))))-  }--newConts :: STRef s [Cont s r e t a c] -> ST s (Conts s r e t a c)-newConts r = Conts r <$> newSTRef Nothing--contraMapCont :: Args s b a -> Cont s r e t a c -> Cont s r e t b c-contraMapCont f (Cont pos g p args cs) = Cont pos (composeArgs f g) p args cs-contraMapCont f (FinalCont args)       = FinalCont (composeArgs f args)--contToState :: ST s [a] -> Cont s r e t a c -> State s r e t c-contToState r (Cont pos g p args cs) = -  let mb = fmap concat . mapM g =<< r in-  State pos p (impureArgs mb args) cs-contToState r (FinalCont args)       = Final id (impureArgs r args)---- | Strings of non-ambiguous continuations can be optimised by removing---   indirections.-simplifyCont :: Conts s r e t b a -> ST s [Cont s r e t b a]-simplifyCont Conts {conts = cont} = readSTRef cont >>= go False-  where-    go !_ [Cont _ g (Pure f) args cont'] = do-      ks' <- simplifyCont cont'-      go True $ map (contraMapCont $ mapArgs f g `composeArgs` args) ks'-    go True ks = do-      writeSTRef cont ks-      return ks-    go False ks = return ks------------------------------------------------------------------------------------ * Grammars----------------------------------------------------------------------------------- | Interpret an abstract 'Grammar'.-grammar :: Grammar (Rule s r) e a -> ST s a-grammar g = case g of-  RuleBind p k -> do-    c  <- newSTRef =<< newSTRef mempty-    nr <- newSTRef Nothing-    grammar $ k $ NonTerminal (Rule p nr c) $ Pure id-  FixBind f k   -> do-    a <- mfix $ fmap grammar f-    grammar $ k a-  Return x      -> return x---- | Given a grammar, construct an initial state.-initialState :: ProdR s a e t a -> ST s (State s a e t a)-initialState p = State (-1) p noArgs <$> (newConts =<< newSTRef [FinalCont noArgs])------------------------------------------------------------------------------------ * Parsing----------------------------------------------------------------------------------- | A parsing report, which contains fields that are useful for presenting--- errors to the user if a parse is deemed a failure.  Note however that we get--- a report even when we successfully parse something.-data Report e i = Report-  { position   :: Int -- ^ The final position in the input (0-based) that the-                      -- parser reached.-  , expected   :: [e] -- ^ The named productions processed at the final-                      -- position.-  , unconsumed :: i   -- ^ The part of the input string that was not consumed,-                      -- which may be empty.-  } deriving (Eq, Ord, Read, Show)---- | The result of a parse.-data Result s e i a-  = Ended (Report e i)-    -- ^ The parser ended.-  | Parsed (ST s [a]) Int i (ST s (Result s e i a))-    -- ^ The parser parsed a number of @a@s.  These are given as a computation,-    -- @'ST' s [a]@ that constructs the 'a's when run.  We can thus save some-    -- work by ignoring this computation if we do not care about the results.-    -- The 'Int' is the position in the input where these results were-    -- obtained, the @i@ the rest of the input, and the last component is the-    -- continuation.-  deriving Functor--{-# INLINE safeHead #-}-safeHead :: ListLike i t => i -> Maybe t-safeHead ts-  | ListLike.null ts = Nothing-  | otherwise        = Just $ ListLike.head ts--{-# INLINE safeTail #-}-safeTail :: ListLike i t => i -> i-safeTail ts-  | ListLike.null ts = ts-  | otherwise        = ListLike.tail ts--{-# SPECIALISE parse :: [State s a e t a]-                     -> [ST s [a]]-                     -> [State s a e t a]-                     -> ST s ()-                     -> [e]-                     -> Pos-                     -> [t]-                     -> ST s (Result s e [t] a) #-}--- | The internal parsing routine-parse :: ListLike i t-      => [State s a e t a] -- ^ States to process at this position-      -> [ST s [a]]        -- ^ Results ready to be reported (when this position has been processed)-      -> [State s a e t a] -- ^ States to process at the next position-      -> ST s ()           -- ^ Computation that resets the continuation refs of productions-      -> [e]               -- ^ Named productions encountered at this position-      -> Pos               -- ^ The current position in the input string-      -> i                 -- ^ The input string-      -> ST s (Result s e i a)-parse [] [] [] reset names !pos ts = do-  reset-  return $ Ended Report {position = pos, expected = names, unconsumed = ts}-parse [] [] next reset _ !pos ts = do-  reset-  parse next [] [] (return ()) [] (pos + 1) $ safeTail ts-parse [] results next reset names !pos ts = do-  reset-  return $ Parsed (concat <$> sequence results) pos ts-         $ parse [] [] next (return ()) names pos ts-parse (st:ss) results next reset names !pos ts = case st of-  Final f args -> parse ss (args f : results) next reset names pos ts-  State spos pr args scont -> case pr of-    Terminal f p -> case safeHead ts of-      Just t | f t ->-        parse ss results (State spos p (pureArg t args) scont : next) reset names pos ts-      _            -> parse ss results next reset names pos ts-    NonTerminal r p -> do-      rkref <- readSTRef $ ruleConts r-      ks    <- readSTRef rkref-      writeSTRef rkref (Cont spos noArgs p args scont : ks)-      nulls <- nullable r-      let nullStates = [State spos p (pureArg a args) scont | a <- nulls]-      if null ks then do -- The rule has not been expanded at this position.-        st' <- State pos (ruleProd r) noArgs <$> newConts rkref-        parse (st' : nullStates ++ ss)-              results-              next-              (resetConts r >> reset)-              names-              pos-              ts-      else -- The rule has already been expanded at this position.-        parse (nullStates ++ ss) results next reset names pos ts-    Pure a | spos /= pos -> do-      let argsRef = contsArgs scont-      masref  <- readSTRef argsRef-      case masref of-        Just asref -> do -- The continuation has already been followed at this position.-          modifySTRef asref (((++) <$> args a) <*>)-          parse ss results next reset names pos ts-        Nothing    -> do -- It hasn't.-          asref <- newSTRef $ args a-          writeSTRef argsRef $ Just asref-          ks  <- simplifyCont scont-          let kstates = map (contToState $ join $ readSTRef asref) ks-          parse (kstates ++ ss)-                results-                next-                (writeSTRef argsRef Nothing >> reset)-                names-                pos-                ts-           | otherwise -> parse ss results next reset names pos ts-    Alts as (Pure f) -> do-      let args' = funArg f `composeArgs` args-          sts   = [State spos a args' scont | a <- as]-      parse (sts ++ ss) results next reset names pos ts-    Alts as p -> do-      scont' <- newConts =<< newSTRef [Cont spos noArgs p args scont]-      -- State is (-1) so that nullable alts are expanded correctly-      let sts = [State (-1) a noArgs scont' | a <- as]-      parse (sts ++ ss) results next reset names pos ts-    Many p q    -> do-      c  <- newSTRef =<< newSTRef mempty-      nr <- newSTRef Nothing-      let r   = Rule (pure [] <|> (:) <$> p <*> NonTerminal r (Pure id)) nr c-          st' = State spos (NonTerminal r q) args scont-      parse (st' : ss) results next reset names pos ts-    Named pr' n -> parse (State spos pr' args scont : ss) results next reset (n : names) pos ts--{-# INLINE parser #-}--- | Create a parser from the given grammar.-parser :: ListLike i t-       => (forall r. Grammar r e (Prod r e t a))-       -> i-       -> ST s (Result s e i a)-parser g xs = do-  s <- initialState =<< grammar g-  parse [s] [] [] (return ()) [] 0 xs---- | Return all parses from the result of a given parser. The result may--- contain partial parses. The 'Int's are the position at which a result was--- produced.-allParses :: (forall s. ST s (Result s e i a)) -> ([(a, Int)], Report e i)-allParses p = runST $ p >>= go-  where-    go :: Result s e i a -> ST s ([(a, Int)], Report e i)-    go r = case r of-      Ended rep          -> return ([], rep)-      Parsed mas pos _ k -> do-        as <- mas-        fmap (first (zip as (repeat pos) ++)) $ go =<< k--{-# INLINE fullParses #-}--- | Return all parses that reached the end of the input from the result of a---   given parser.-fullParses :: ListLike i t => (forall s. ST s (Result s e i a)) -> ([a], Report e i)-fullParses p = runST $ p >>= go-  where-    go :: ListLike i t => Result s e i a -> ST s ([a], Report e i)-    go r = case r of-      Ended rep -> return ([], rep)-      Parsed mas _ i k-        | ListLike.null i -> do-          as <- mas-          fmap (first (as ++)) $ go =<< k-        | otherwise       -> go =<< k--{-# INLINE report #-}--- | See e.g. how far the parser is able to parse the input string before it--- fails.  This can be much faster than getting the parse results for highly--- ambiguous grammars.-report :: ListLike i t => (forall s. ST s (Result s e i a)) -> Report e i-report p = runST $ p >>= go-  where-    go :: ListLike i t => Result s e i a -> ST s (Report e i)-    go r = case r of-      Ended rep      -> return rep-      Parsed _ _ _ k -> go =<< k+import Text.Earley.Internal