cabal-install-0.5.0: Hackage/ParseUtils.hs
module Hackage.ParseUtils where
import Distribution.Compat.ReadP
( ReadP, readP_to_S, pfail, get, look, choice, (+++) )
import Distribution.Package (PackageIdentifier(..), Dependency(..))
import Distribution.ParseUtils
( Field(..), FieldDescr(..), ParseResult(..), PError
, field, liftField, readFields
, warning, lineNo, locatedErrorMsg)
import Distribution.Text
( Text(parse) )
import Distribution.Version (Version(..), VersionRange(..))
import Control.Monad (foldM, liftM)
import Data.Char (isSpace, toLower)
import Data.Maybe (listToMaybe)
import Text.PrettyPrint.HughesPJ (Doc, render, vcat, text, (<>), (<+>))
showPError :: PError -> String
showPError err = let (ml,msg) = locatedErrorMsg err
in maybe "" (\l -> "On line " ++ show l ++ ": ") ml ++ msg
readPToMaybe :: ReadP a a -> String -> Maybe a
readPToMaybe p str = listToMaybe [ r | (r,s) <- readP_to_S p str, all isSpace s ]
ignoreWarnings :: ParseResult a -> ParseResult a
ignoreWarnings (ParseOk _ x) = ParseOk [] x
ignoreWarnings r = r
parseBasicStanza :: [FieldDescr a] -> a -> String -> ParseResult a
parseBasicStanza fields empty inp =
readFields inp >>= foldM (setField fields) empty
setField :: [FieldDescr a]
-> a
-> Field
-> ParseResult a
setField fs x (F line f val) =
case lookupFieldDescr fs f of
Nothing ->
do warning ("Unrecognized field " ++ f ++ " on line " ++ show line)
return x
Just (FieldDescr _ _ set) -> set line val x
setField _ x s =
do warning ("Unrecognized stanza on line " ++ show (lineNo s))
return x
lookupFieldDescr :: [FieldDescr a] -> String -> Maybe (FieldDescr a)
lookupFieldDescr fs n = listToMaybe [f | f@(FieldDescr name _ _) <- fs, name == n]
boolField :: String -> (a -> Bool) -> (Bool -> a -> a) -> FieldDescr a
boolField name g s = liftField g s $ field name showBool readBool
where
showBool :: Bool -> Doc
showBool True = text "true"
showBool False = text "false"
readBool :: ReadP r Bool
readBool = choice [ stringNoCase "true" >> return True
, stringNoCase "false" >> return False
, stringNoCase "yes" >> return True
, stringNoCase "no" >> return False]
showFields :: [FieldDescr a] -> a -> String
showFields fs x = render $ vcat [ text name <> text ":" <+> g x | FieldDescr name g _ <- fs]
stringNoCase :: String -> ReadP r String
stringNoCase this = look >>= scan this
where
scan [] _ = return this
scan (x:xs) (y:ys) | toLower x == toLower y = get >> scan xs ys
scan _ _ = pfail
parseDependencyOrPackageId :: ReadP r Dependency
parseDependencyOrPackageId = parse +++ liftM pkgToDep parse
where pkgToDep p = case pkgVersion p of
Version [] _ -> Dependency (pkgName p) AnyVersion
version -> Dependency (pkgName p) (ThisVersion version)