module ReadArgs where
import Control.Arrow (first)
import Data.Maybe
import Data.List
import Data.Typeable
import Data.Text (Text, pack)
import Filesystem.Path (FilePath)
import Filesystem.Path.CurrentOS (fromText)
import Prelude hiding (FilePath)
import System.Environment
import System.Exit
import System.IO hiding (FilePath)
readArgs :: ArgumentTuple a => IO a
readArgs = getArgs >>= readArgsFrom
readArgsFrom :: ArgumentTuple a => [String] -> IO a
readArgsFrom ss =
let ma@(~(Just a)) = parseArgsFrom ss
in case ma of
Nothing -> do
progName <- getProgName
hPutStrLn stderr $ "usage: " ++ progName ++ usageFor a
exitFailure
_ -> return a
class Arguable a where
parse :: String -> Maybe a
name :: a -> String
instance (Typeable t, Read t) => Arguable t where
parse s = case reads s of
[(i,"")] -> Just i
_ -> Nothing
name t = showsTypeRep (typeOf t) ""
instance Arguable String where
parse = Just
name _ = "String"
instance Arguable Text where
parse = Just . pack
name _ = "Text"
instance Arguable FilePath where
parse = Just . fromText . pack
name _ = "FilePath"
instance Arguable Char where
parse [x] = Just x
parse _ = Nothing
name _ = "Char"
class Argument a where
parseArg :: [String] -> [(a, [String])]
argName :: a -> String
instance Arguable a => Argument a where
parseArg [] = []
parseArg (s:ss) = do
a <- maybeToList $ parse s
return (a, ss)
argName = name
instance Arguable a => Argument (Maybe a) where
argName ~(Just x) = "["++name x++"]"
parseArg [] = [(Nothing, [])]
parseArg ss'@(s:ss) = case parse s of
Nothing -> [(Nothing, ss')]
justA -> [(justA, ss),(Nothing,ss')]
instance Arguable a => Argument [a] where
argName ~(x:_) = "["++name x ++"...]"
parseArg ss = reverse $ inits ss' `zip` tails ss
where ss' = map fromJust . takeWhile isJust $ map parse ss
newtype NonGreedy m a = NonGreedy { unNonGreedy :: m a } deriving (Show, Eq)
instance Argument (m a) => Argument (NonGreedy m a) where
argName ~(NonGreedy m) = argName m
parseArg = map (first NonGreedy) . reverse . parseArg
instance Argument String where
parseArg [] = []
parseArg (s:ss) = do
a <- maybeToList $ parse s
return (a, ss)
argName = name
class ArgumentTuple a where
parseArgsFrom :: [String] -> Maybe a
usageFor :: a -> String
instance ArgumentTuple () where
parseArgsFrom [] = Just ()
parseArgsFrom _ = Nothing
usageFor = const ""
data a :& b = a :& b deriving (Show, Eq)
infixr 5 :&
instance (Argument a, ArgumentTuple y) => ArgumentTuple (a :& y) where
parseArgsFrom ss = listToMaybe $ do
(a, ss') <- parseArg ss
y <- maybeToList $ parseArgsFrom ss'
return $ a :& y
usageFor ~(a :& y) = " " ++ argName a ++ usageFor y
instance (Argument a) => ArgumentTuple a where
parseArgsFrom ss = do
a :& () <- parseArgsFrom ss
return a
usageFor a = usageFor (a :& ())
instance (Argument b, Argument a) => ArgumentTuple (b,a) where
parseArgsFrom ss = do
b :& a :& () <- parseArgsFrom ss
return (b,a)
usageFor ~(b,a) = usageFor (b :& a :& ())
instance (Argument c, Argument b, Argument a) => ArgumentTuple (c,b,a) where
parseArgsFrom ss = do
c :& b :& a :& () <- parseArgsFrom ss
return (c,b,a)
usageFor ~(c,b,a) = usageFor (c :& b :& a :& ())
instance (Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (d,c,b,a) where
parseArgsFrom ss = do
d :& c :& b :& a :& () <- parseArgsFrom ss
return (d,c,b,a)
usageFor ~(d,c,b,a) = usageFor (d :& c :& b :& a :& ())
instance (Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (e,d,c,b,a) where
parseArgsFrom ss = do
e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (e,d,c,b,a)
usageFor ~(e,d,c,b,a) = usageFor (e :& d :& c :& b :& a :& ())
instance (Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (f,e,d,c,b,a) where
parseArgsFrom ss = do
f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (f,e,d,c,b,a)
usageFor ~(f,e,d,c,b,a) = usageFor (f :& e :& d :& c :& b :& a :& ())
instance (Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (g,f,e,d,c,b,a) where
parseArgsFrom ss = do
g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (g,f,e,d,c,b,a)
usageFor ~(g,f,e,d,c,b,a) = usageFor (g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (h,g,f,e,d,c,b,a)
usageFor ~(h,g,f,e,d,c,b,a) = usageFor (h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (i,h,g,f,e,d,c,b,a)
usageFor ~(i,h,g,f,e,d,c,b,a) = usageFor (i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (j,i,h,g,f,e,d,c,b,a)
usageFor ~(j,i,h,g,f,e,d,c,b,a) = usageFor (j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument k, Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (k,j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (k,j,i,h,g,f,e,d,c,b,a)
usageFor ~(k,j,i,h,g,f,e,d,c,b,a) = usageFor (k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument l, Argument k, Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (l,k,j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (l,k,j,i,h,g,f,e,d,c,b,a)
usageFor ~(l,k,j,i,h,g,f,e,d,c,b,a) = usageFor (l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument m, Argument l, Argument k, Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (m,l,k,j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (m,l,k,j,i,h,g,f,e,d,c,b,a)
usageFor ~(m,l,k,j,i,h,g,f,e,d,c,b,a) = usageFor (m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument n, Argument m, Argument l, Argument k, Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (n,m,l,k,j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
n :& m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (n,m,l,k,j,i,h,g,f,e,d,c,b,a)
usageFor ~(n,m,l,k,j,i,h,g,f,e,d,c,b,a) = usageFor (n :& m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())
instance (Argument o, Argument n, Argument m, Argument l, Argument k, Argument j, Argument i, Argument h, Argument g, Argument f, Argument e, Argument d, Argument c, Argument b, Argument a) => ArgumentTuple (o,n,m,l,k,j,i,h,g,f,e,d,c,b,a) where
parseArgsFrom ss = do
o :& n :& m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& () <- parseArgsFrom ss
return (o,n,m,l,k,j,i,h,g,f,e,d,c,b,a)
usageFor ~(o,n,m,l,k,j,i,h,g,f,e,d,c,b,a) = usageFor (o :& n :& m :& l :& k :& j :& i :& h :& g :& f :& e :& d :& c :& b :& a :& ())