Advertisement
Revolucent

A tiny toy parser combinator library

Jul 30th, 2024
530
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE FlexibleInstances, FunctionalDependencies, TupleSections #-}
  2.  
  3. module Parsy where
  4.  
  5. import Control.Applicative
  6. import Control.Monad.Error.Class
  7. import RIO
  8. import RIO.List
  9.  
  10. class Collection e c | c -> e where
  11.   elemAtIndex :: c -> Word -> Maybe e
  12.  
  13. instance Collection a [a] where
  14.   elemAtIndex c i
  15.     | genericLength c <= i = Nothing
  16.     | otherwise = Just $ c `genericIndex` i
  17.  
  18. data ParseError = NoMatch | EOD deriving (Eq, Show)
  19.  
  20. newtype Parser c a = Parser { unParser :: c -> Word -> (Either ParseError a, Word) }
  21.  
  22. runParser :: c -> Parser c a -> Either (ParseError, Word) a
  23. runParser collection parser = let (result, index) = unParser parser collection 0 in
  24.   case result of
  25.     Left e -> Left (e, index)
  26.     Right a -> Right a
  27.  
  28. instance Functor (Parser c) where
  29.   fmap f (Parser parse) = Parser $ \c i -> let
  30.       (e, i') = parse c i
  31.    in (fmap f e, i')
  32.  
  33. instance Applicative (Parser c) where
  34.   pure a = Parser $ const (Right a,)
  35.   (Parser f) <*> (Parser a) = Parser $ \c i -> let
  36.       (f', fi) = f c i
  37.      (a', ai) = a c fi
  38.     in (f' <*> a', ai)
  39.  
  40. instance Monad (Parser c) where
  41.   return = pure
  42.   (Parser a) >>= f = Parser $ \c i -> let
  43.       (a', ai) = a c i
  44.    in case a' of
  45.       Left e -> (Left e, i)
  46.       Right a -> unParser (f a) c ai
  47.  
  48. instance MonadError ParseError (Parser c) where
  49.   throwError e = Parser $ const (Left e,)
  50.   catchError (Parser a) handler = Parser $ \c i -> let
  51.       (a', ai) = a c i
  52.    in case a' of
  53.       Left e -> unParser (handler e) c i
  54.       Right a -> (Right a, ai)
  55.  
  56. instance Alternative (Parser c) where
  57.   empty = Parser undefined
  58.   a <|> b = catchError a $ const b
  59.  
  60. advanceBy :: Int -> Parser c ()
  61. advanceBy delta = Parser $ const $ \i -> (Right (), addDelta i)
  62.   where
  63.     addDelta i = fromIntegral $ delta + fromIntegral i
  64.  
  65. advance :: Parser c ()
  66. advance = advanceBy 1
  67.  
  68. collection :: Parser c c
  69. collection = Parser $ \c i -> (Right c, i)
  70.  
  71. index :: Parser c Word
  72. index = Parser $ const $ \i -> (Right i, i)
  73.  
  74. putIndex :: Word -> Parser c ()
  75. putIndex = Parser . const . const . (Right (),)
  76.  
  77. collectionWithIndex :: Parser c (c, Word)
  78. collectionWithIndex = Parser $ \c i -> (Right (c, i), i)
  79.  
  80. current :: Collection a c => Parser c (Maybe a)
  81. current = collectionWithIndex <&> uncurry elemAtIndex
  82.  
  83. eod :: Collection a c => Parser c ()
  84. eod = current >>= maybe (return ()) (const $ throwError NoMatch)
  85.  
  86. atEOD :: Collection a c => Parser c Bool
  87. atEOD = isNothing <$> current
  88.  
  89. satisfy :: Collection a c => (a -> Bool) -> Parser c a
  90. satisfy predicate = do
  91.   a <- current
  92.   case a of
  93.     Just a -> if predicate a
  94.       then advance >> return a
  95.       else throwError NoMatch
  96.     Nothing -> throwError EOD
  97.  
  98. equals :: (Eq a, Collection a c) => a -> Parser c a
  99. equals a = satisfy (== a)
  100.  
  101. many1 :: Parser c a -> Parser c [a]
  102. many1 parser = liftA2 (:) parser $ many parser
  103.  
  104. many1SepBy :: Parser c a -> Parser c sep -> Parser c [a]
  105. many1SepBy parser sep = liftA2 (:) parser $ many (sep *> parser)
  106.  
  107. manySepBy :: Parser c a -> Parser c sep -> Parser c [a]
  108. manySepBy parser sep = many1SepBy parser sep <|> pure []
  109.  
  110. peek :: Parser c a -> Parser c ()
  111. peek parser = index >>= \i -> void parser >> putIndex i
  112.  
  113. skip :: Parser c a -> Parser c ()
  114. skip = void
  115.  
  116. skipMany :: Parser c a -> Parser c ()
  117. skipMany = void . many
  118.  
  119. skipMany1 :: Parser c a -> Parser c ()
  120. skipMany1 = void . many1
  121.  
  122. skipUntil :: Collection e c => Parser c a -> Parser c ()
  123. skipUntil parser = do
  124.   err <- catchError (peek parser $> Nothing) (return . Just)
  125.   case err of
  126.     Nothing -> return ()
  127.     Just EOD -> throwError EOD
  128.     Just _ -> advance >> skipUntil parser
  129.  
  130. skipTo :: Collection e c => Parser c a -> Parser c a
  131. skipTo parser = skipUntil parser >> parser
  132.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement