agda-unused-0.1.0: src/Agda/Unused/Parse.hs
{- |
Module: Agda.Unused.Parse
Parsers for roots.
-}
module Agda.Unused.Parse
( parseConfig
) where
import Agda.Unused.Types.Name
(Name(..), NamePart(..), QName(..))
import Agda.Unused.Types.Root
(Root(..), Roots, fromList)
import Agda.Unused.Utils
(mapLeft)
import Control.Monad
(void)
import Data.Char
(isSpace)
import Data.Text
(Text)
import qualified Data.Text
as T
import Data.Void
(Void)
import Text.Megaparsec
(Parsec, (<|>), between, many, parse, satisfy, some, try)
import Text.Megaparsec.Char
(char, space1)
import qualified Text.Megaparsec.Char.Lexer
as L
import Text.Megaparsec.Error
(errorBundlePretty)
-- ## Utilities
isNameChar
:: Char
-> Bool
isNameChar '.'
= False
isNameChar '('
= False
isNameChar ')'
= False
isNameChar c | isSpace c
= False
isNameChar _
= True
listMaybe
:: [a]
-> Maybe [a]
listMaybe []
= Nothing
listMaybe xs@(_ : _)
= Just xs
-- ## Parsers
type Parser
= Parsec Void Text
parseSpace
:: Parser ()
parseSpace
= L.space space1
(L.skipLineComment "--")
(L.skipBlockComment "{-" "-}")
parseDot
:: Parser ()
parseDot
= void (char '.')
parseHyphen
:: Parser ()
parseHyphen
= void (char '-')
parseParens
:: Parser a
-> Parser a
parseParens
= between (char '(') (char ')')
parseNamePart
:: Parser NamePart
parseNamePart
= Id <$> some (satisfy isNameChar)
parseName
:: Parser Name
parseName
= Name <$> some parseNamePart
parseQName
:: Parser QName
parseQName
= try (Qual <$> parseName <* parseDot <*> parseQName)
<|> QName <$> parseName
parseIgnore
:: Parser QName
parseIgnore
= parseParens (between parseSpace parseSpace parseQName)
<* parseSpace
parseRootName
:: Parser QName
parseRootName
= parseHyphen
*> parseSpace
*> parseQName
<* parseSpace
parseRootNames
:: Parser (Maybe [QName])
parseRootNames
= listMaybe <$> many parseRootName
parseRoot
:: Parser Root
parseRoot
= Root
<$> parseQName
<* parseSpace
<*> parseRootNames
parseRootEither
:: Parser (Either QName Root)
parseRootEither
= Left <$> parseIgnore
<|> Right <$> parseRoot
parseRoots
:: Parser Roots
parseRoots
= fromList <$> many parseRootEither
-- | Parse configuration, producing either an error or a collection of roots.
parseConfig
:: Text
-> Either Text Roots
parseConfig
= mapLeft T.pack
. mapLeft errorBundlePretty
. parse (parseSpace *> parseRoots) ".agda-roots"