Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {-# LANGUAGE FlexibleInstances, FunctionalDependencies, TupleSections #-}
- module Parsy where
- import Control.Applicative
- import Control.Monad.Error.Class
- import RIO
- import RIO.List
- class Collection e c | c -> e where
- elemAtIndex :: c -> Word -> Maybe e
- instance Collection a [a] where
- elemAtIndex c i
- | genericLength c <= i = Nothing
- | otherwise = Just $ c `genericIndex` i
- data ParseError = NoMatch | EOD deriving (Eq, Show)
- newtype Parser c a = Parser { unParser :: c -> Word -> (Either ParseError a, Word) }
- runParser :: c -> Parser c a -> Either (ParseError, Word) a
- runParser collection parser = let (result, index) = unParser parser collection 0 in
- case result of
- Left e -> Left (e, index)
- Right a -> Right a
- instance Functor (Parser c) where
- fmap f (Parser parse) = Parser $ \c i -> let
- (e, i') = parse c i
- in (fmap f e, i')
- instance Applicative (Parser c) where
- pure a = Parser $ const (Right a,)
- (Parser f) <*> (Parser a) = Parser $ \c i -> let
- (f', fi) = f c i
- (a', ai) = a c fi
- in (f' <*> a', ai)
- instance Monad (Parser c) where
- return = pure
- (Parser a) >>= f = Parser $ \c i -> let
- (a', ai) = a c i
- in case a' of
- Left e -> (Left e, i)
- Right a -> unParser (f a) c ai
- instance MonadError ParseError (Parser c) where
- throwError e = Parser $ const (Left e,)
- catchError (Parser a) handler = Parser $ \c i -> let
- (a', ai) = a c i
- in case a' of
- Left e -> unParser (handler e) c i
- Right a -> (Right a, ai)
- instance Alternative (Parser c) where
- empty = Parser undefined
- a <|> b = catchError a $ const b
- advanceBy :: Int -> Parser c ()
- advanceBy delta = Parser $ const $ \i -> (Right (), addDelta i)
- where
- addDelta i = fromIntegral $ delta + fromIntegral i
- advance :: Parser c ()
- advance = advanceBy 1
- collection :: Parser c c
- collection = Parser $ \c i -> (Right c, i)
- index :: Parser c Word
- index = Parser $ const $ \i -> (Right i, i)
- putIndex :: Word -> Parser c ()
- putIndex = Parser . const . const . (Right (),)
- collectionWithIndex :: Parser c (c, Word)
- collectionWithIndex = Parser $ \c i -> (Right (c, i), i)
- current :: Collection a c => Parser c (Maybe a)
- current = collectionWithIndex <&> uncurry elemAtIndex
- eod :: Collection a c => Parser c ()
- eod = current >>= maybe (return ()) (const $ throwError NoMatch)
- atEOD :: Collection a c => Parser c Bool
- atEOD = isNothing <$> current
- satisfy :: Collection a c => (a -> Bool) -> Parser c a
- satisfy predicate = do
- a <- current
- case a of
- Just a -> if predicate a
- then advance >> return a
- else throwError NoMatch
- Nothing -> throwError EOD
- equals :: (Eq a, Collection a c) => a -> Parser c a
- equals a = satisfy (== a)
- many1 :: Parser c a -> Parser c [a]
- many1 parser = liftA2 (:) parser $ many parser
- many1SepBy :: Parser c a -> Parser c sep -> Parser c [a]
- many1SepBy parser sep = liftA2 (:) parser $ many (sep *> parser)
- manySepBy :: Parser c a -> Parser c sep -> Parser c [a]
- manySepBy parser sep = many1SepBy parser sep <|> pure []
- peek :: Parser c a -> Parser c ()
- peek parser = index >>= \i -> void parser >> putIndex i
- skip :: Parser c a -> Parser c ()
- skip = void
- skipMany :: Parser c a -> Parser c ()
- skipMany = void . many
- skipMany1 :: Parser c a -> Parser c ()
- skipMany1 = void . many1
- skipUntil :: Collection e c => Parser c a -> Parser c ()
- skipUntil parser = do
- err <- catchError (peek parser $> Nothing) (return . Just)
- case err of
- Nothing -> return ()
- Just EOD -> throwError EOD
- Just _ -> advance >> skipUntil parser
- skipTo :: Collection e c => Parser c a -> Parser c a
- skipTo parser = skipUntil parser >> parser
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement