summaryrefslogtreecommitdiff
path: root/DSL/BaseParsers.hs
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-02-16 23:05:24 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-02-16 23:05:24 +1300
commitb83325c4b5c324a42acfe366cf58b455f8aa941f (patch)
tree7c78add5c12970ebd3f3c50f08808a4d6a636778 /DSL/BaseParsers.hs
parentea59151d80958f14c69105ba6b40162b8e191597 (diff)
Big file-structure refactor
Diffstat (limited to 'DSL/BaseParsers.hs')
-rw-r--r--DSL/BaseParsers.hs139
1 files changed, 139 insertions, 0 deletions
diff --git a/DSL/BaseParsers.hs b/DSL/BaseParsers.hs
new file mode 100644
index 0000000..403ca42
--- /dev/null
+++ b/DSL/BaseParsers.hs
@@ -0,0 +1,139 @@
+module DSL.BaseParsers where
+
+-- Parsec is for casuals
+
+import Control.Applicative (Alternative(..), liftA2)
+import Control.Monad (MonadPlus(..), guard)
+import Data.Maybe (catMaybes)
+
+newtype Parser t a =
+ Parser { parse :: [t] -> Maybe ([t], a) }
+
+instance Semigroup a => Semigroup (Parser t a) where
+ (<>) = liftA2 (<>)
+
+instance Monoid a => Monoid (Parser t a) where
+ mempty = pure mempty
+
+instance Functor (Parser t) where
+ fmap f (Parser p) = Parser $ fmap (fmap f) . p
+
+instance Applicative (Parser t) where
+ pure = result
+
+ p <*> q = Parser $ \ inp -> do
+ (inp', f) <- parse p inp
+ parse (f <$> q) inp'
+
+instance Monad (Parser t) where
+ return = pure
+
+ p >>= f = Parser $ \ inp -> do
+ (inp', x) <- parse p inp
+ parse (f x) inp'
+
+instance Alternative (Parser t) where
+ empty = flunk
+
+ (<|>) = alt
+
+instance MonadPlus (Parser t)
+
+instance MonadFail (Parser t) where
+ fail _ = mzero
+
+-----------------------------------------------------------------------------
+
+flunk :: Parser t a
+flunk = Parser $ \ _ -> Nothing
+
+result :: a -> Parser t a
+result x = Parser $ \ inp -> Just (inp, x)
+
+peek :: Parser t a -> Parser t a
+peek p = Parser $ \ inp -> do
+ (_, x) <- parse p inp
+ return (inp, x)
+
+anyToken :: Parser t t
+anyToken = Parser $ \ inp -> case inp of
+ t:ts -> Just (ts, t)
+ _ -> Nothing
+
+eof :: Parser t ()
+eof = Parser $ \ inp -> case inp of
+ [] -> Just ([], ())
+ _ -> Nothing
+
+infixl 3 `alt`
+alt :: Parser t a -> Parser t a -> Parser t a
+alt (Parser p) (Parser q) = Parser $ \ inp -> p inp <|> q inp
+
+-----------------------------------------------------------------------------
+
+phrase :: Parser t a -> Parser t a
+phrase = (<* eof)
+
+recover :: a -> Parser t a -> Parser t a
+recover x p = p <|> pure x
+
+optional :: Parser t a -> Parser t (Maybe a)
+optional = recover Nothing . fmap Just
+
+assert :: (a -> Bool) -> Parser t a -> Parser t a
+assert f p = do
+ x <- p
+ guard $ f x
+ return x
+
+satisfy :: (t -> Bool) -> Parser t t
+satisfy f = assert f anyToken
+
+token :: Eq t => t -> Parser t t
+token t = satisfy (==t)
+
+list :: Eq t => [t] -> Parser t [t]
+list = traverse token
+
+mult :: Parser t a -> Parser t [a]
+mult = many
+
+mult1 :: Parser t a -> Parser t [a]
+mult1 = some
+
+exactly :: Int -> Parser t a -> Parser t [a]
+exactly i = sequence . replicate i
+
+atLeast :: Int -> Parser t a -> Parser t [a]
+atLeast i p = exactly i p <> mult p
+
+atMost :: Int -> Parser t a -> Parser t [a]
+atMost i = fmap catMaybes . exactly i . optional
+
+between :: Int -> Int -> Parser t a -> Parser t [a]
+between x y p = exactly (min x y) p <> atMost (abs $ x - y) p
+
+stopAt :: Parser t a -> Parser t [t]
+stopAt p = go
+ where
+ p' = ([] <$ peek p)
+ go = p' <|> liftA2 (:) anyToken go
+
+stopAfter :: Parser t a -> Parser t ([t], a)
+stopAfter p = (,) <$> stopAt p <*> p
+
+stopIf :: Parser t a -> Parser t [t]
+stopIf p = stopAt $ () <$ p <|> eof
+
+firstOf :: [Parser t a] -> Parser t a
+firstOf = foldr1 (<|>)
+
+sepBy1 :: Parser t a -> Parser t b -> Parser t [a]
+sepBy1 a b = do
+ x <- a
+ xs <- mult $ b >> a
+ return $ x:xs
+
+sepBy :: Parser t a -> Parser t b -> Parser t [a]
+sepBy a b = sepBy1 a b <|> pure []
+