From 62aa7bb8ba54c2a0f480e122c46d967f2102dac5 Mon Sep 17 00:00:00 2001 From: defanor Date: Tue, 19 Dec 2017 07:58:16 +0300 Subject: Reorganize the modules --- Coalpit.hs | 470 +------------------------------------------------------------ 1 file changed, 4 insertions(+), 466 deletions(-) (limited to 'Coalpit.hs') diff --git a/Coalpit.hs b/Coalpit.hs index a0a7ac2..27df1bb 100644 --- a/Coalpit.hs +++ b/Coalpit.hs @@ -57,471 +57,9 @@ Then, in a shell: -} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE DefaultSignatures #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE ScopedTypeVariables #-} +module Coalpit ( module Coalpit.Core + , module Coalpit.DSV + ) where -module Coalpit ( - -- * Core class - Coalpit(..) - -- * Utility functions - , fromArgs - , usage - , showDSV - , readDSV - -- * Options - , Options(..) - , defOpt - ) where - -import GHC.Generics -import Text.Megaparsec -import Text.Megaparsec.Char -import Data.Char (toLower) -import Data.Proxy (Proxy(..)) -import qualified Data.List.NonEmpty as NE -import Data.Word (Word8, Word16, Word32, Word64) -import Numeric.Natural (Natural) -import Data.Int (Int8, Int16, Int32, Int64) -import Data.Time.Clock (DiffTime, NominalDiffTime, UniversalTime, UTCTime) -import Data.Time.Format ( TimeLocale, formatTime - , iso8601DateFormat, defaultTimeLocale) -import Data.Time.Calendar (Day) -import Data.Time.LocalTime (TimeOfDay, LocalTime, ZonedTime) -import Data.Scientific (Scientific, FPFormat(..), formatScientific, scientificP) -import Text.ParserCombinators.ReadP (readP_to_S) -import Data.Complex (Complex) -import Data.Version (Version, parseVersion, showVersion) -import System.Exit (ExitCode) -import Network.URI (URI, parseURIReference, uriToString) - -import Coalpit.Parsing +import Coalpit.Core import Coalpit.DSV - - --- | Printing and parsing options. -data Options = Options { fieldSeparator :: Char - -- ^ DSV field separator ('showDSV', - -- 'readDSV'). - , conNameMod :: String -> String - -- ^ Constructor name modifier. - , selNameMod :: String -> String - -- ^ Record selector name modifier. - , alwaysUseSelName :: Bool - -- ^ Add record selector name always, not just - -- for optional arguments. - , omitNamedOptions :: Bool - -- ^ Omit named Maybe values to indicate - -- 'Nothing'. - , timeLocale :: TimeLocale - , dateFormat :: String - -- ^ See "Data.Time.Format". - , timeFormat :: String - , dateTimeFormat :: String - , scientificFormat :: FPFormat - , scientificDecimals :: Maybe Int - , uriUserInfo :: String -> String - -- ^ Used to map userinfo parts of URIs. - } - --- | Default options. -defOpt :: Options -defOpt = Options ' ' (map toLower) (("--" ++) . map toLower) False True - defaultTimeLocale (iso8601DateFormat Nothing) "%H:%M:%S" - (iso8601DateFormat (Just "%H:%M:%S")) Generic Nothing id - --- | Coalpit class: parsing, printing, usage strings. -class Coalpit a where - argParser :: Options -> Parser a - default argParser :: (Generic a, GCoalpit (Rep a)) => Options -> Parser a - argParser opt = to <$> gArgParser opt - - toArgs :: Options -> a -> [String] - default toArgs :: (Generic a, GCoalpit (Rep a)) => Options -> a -> [String] - toArgs opt a = gToArgs opt (from a) - - argHelper :: Options -> [String] -> Proxy a -> String - default argHelper :: (GCoalpit (Rep a)) - => Options -> [String] -> Proxy a -> String - argHelper opt path Proxy = gArgHelper opt path (Proxy :: Proxy (Rep a p)) - -class GCoalpit a where - gArgParser :: Options -> Parser (a p) - gToArgs :: Options -> a p -> [String] - gArgHelper :: Options -> [String] -> Proxy (a p) -> String - --- | Parses arguments. -fromArgs :: Coalpit a => Options -> [String] -> Either String a -fromArgs opt args = case parse (argParser opt) "arguments" (map CLArg args) of - Left err -> Left $ parseErrorPretty err - Right x -> Right x - --- | Composes a usage string. -usage :: Coalpit a => Options -> Proxy a -> String -usage opt = argHelper opt [] - --- | Shows values in DSV format. -showDSV :: Coalpit a => Options -> [a] -> String -showDSV opt = composeDSV (fieldSeparator opt) . map (toArgs opt) - --- | Reads values from DSV format. -readDSV :: Coalpit a => Options -> String -> [Either String a] -readDSV opt = map (>>= fromArgs opt) . parseDSV (fieldSeparator opt) - - --- Units -instance GCoalpit U1 where - gArgParser _ = pure U1 - gToArgs _ U1 = [] - gArgHelper _ _ (Proxy :: Proxy (U1 f)) = "" - - --- Products -instance (GCoalpit a, GCoalpit b) => GCoalpit (a :*: b) where - gArgParser opt = (:*:) <$> gArgParser opt <*> gArgParser opt - gToArgs opt (x :*: y) = gToArgs opt x ++ gToArgs opt y - gArgHelper opt path (Proxy :: Proxy ((a :*: b) p)) = - concat [ gArgHelper opt path (Proxy :: Proxy (a p)) - , " " - , gArgHelper opt path (Proxy :: Proxy (b p))] - - --- Sums - --- | Handles recursive constructors. -handleRecCon :: GCoalpit a - => String - -- ^ Constructor name - -> Options - -> [String] - -> Proxy (a p) - -> String -handleRecCon nameA opt path (Proxy :: Proxy (a p)) = conNameMod opt nameA - ++ if nameA `elem` path - then "..." - else case gArgHelper opt (nameA : path) (Proxy :: Proxy (a p)) of - "" -> "" - s -> ' ' : s - -instance (Constructor conA, GCoalpit a, GCoalpit (b :+: c)) => - GCoalpit ((b :+: c) :+: C1 conA a) where - gArgParser opt = - L1 <$> gArgParser opt - <|> - R1 <$> (pS (string (conNameMod opt $ conName (undefined :: C1 conA a p))) - *> gArgParser opt) - gToArgs opt (L1 x) = gToArgs opt x - gToArgs opt (R1 x) = conNameMod opt (conName x) : gToArgs opt x - gArgHelper opt path (Proxy :: Proxy (((b :+: c) :+: C1 conA a) p)) = - let nameA = conName (undefined :: C1 conA f p) - in concat [ "(" - , gArgHelper opt path (Proxy :: Proxy ((b :+: c) p)) - , " | " - , handleRecCon nameA opt path (Proxy :: Proxy (a p)) - , ")"] - -instance (Constructor conA, GCoalpit a, GCoalpit (b :+: c)) => - GCoalpit (C1 conA a :+: (b :+: c)) where - gArgParser opt = - L1 <$> (pS (string (conNameMod opt $ conName (undefined :: C1 conA a p))) - *> gArgParser opt) - <|> - R1 <$> gArgParser opt - gToArgs opt (L1 x) = conNameMod opt (conName x) : gToArgs opt x - gToArgs opt (R1 x) = gToArgs opt x - gArgHelper opt path (Proxy :: Proxy ((C1 conA a :+: (b :+: c)) p)) = - let nameA = conName (undefined :: C1 conA a p) - in concat [ "(" - , handleRecCon nameA opt path (Proxy :: Proxy (a p)) - , " | " - , gArgHelper opt path (Proxy :: Proxy ((b :+: c) p)) - , ")"] - -instance (Constructor conA, Constructor conB, GCoalpit a, GCoalpit b) => - GCoalpit (C1 conA a :+: C1 conB b) where - gArgParser opt = - L1 <$> (pS (string (conNameMod opt $ - conName (undefined :: C1 conA a p))) - *> gArgParser opt) - <|> - R1 <$> (pS (string (conNameMod opt $ - conName (undefined :: C1 conB b p))) - *> gArgParser opt) - gToArgs opt (L1 x) = conNameMod opt (conName x) : gToArgs opt x - gToArgs opt (R1 x) = conNameMod opt (conName x) : gToArgs opt x - gArgHelper opt path (Proxy :: Proxy ((C1 conA a :+: C1 conB b) p)) = - let nameA = conName (undefined :: C1 conA a p) - nameB = conName (undefined :: C1 conB b p) - in concat [ "(" - , handleRecCon nameA opt path (Proxy :: Proxy (a p)) - , " | " - , handleRecCon nameB opt path (Proxy :: Proxy (b p)) - , ")"] - - --- Record Selectors - -parseS1 :: (GCoalpit a) => String -> Options -> Parser (S1 selA a p) -parseS1 nameA opt = - let sName = case (nameA, alwaysUseSelName opt) of - ("", _) -> pure () - (_, False) -> pure () - (_, True) -> pS (string (selNameMod opt nameA)) >> pure () - in M1 <$> (sName *> gArgParser opt) - -printS1 :: (GCoalpit a, Selector selA) => Options -> S1 selA a p -> [String] -printS1 opt sel@(M1 x) = case (selName sel, alwaysUseSelName opt) of - ("", _) -> gToArgs opt x - (_, False) -> gToArgs opt x - (name, True) -> selNameMod opt name : gToArgs opt x - -helpS1 :: (GCoalpit a) - => String -> Options -> [String] -> Proxy (S1 selA a p) -> String -helpS1 nameA opt path (Proxy :: Proxy (S1 selA a p)) = - case (nameA, alwaysUseSelName opt) of - ("", _) -> gArgHelper opt path (Proxy :: Proxy (a p)) - (_, False) -> gArgHelper opt path (Proxy :: Proxy (a p)) - (_, True) -> concat [ selNameMod opt nameA - , " " - , gArgHelper opt path (Proxy :: Proxy (a p))] - -instance (GCoalpit a, Selector selA) => GCoalpit (S1 selA a) where - gArgParser = parseS1 (selName (undefined :: S1 selA a p)) - gToArgs = printS1 - gArgHelper = helpS1 (selName (undefined :: S1 selA a p)) - --- Optional arguments -instance {-#OVERLAPPING#-} - (Coalpit a, Selector selA) => GCoalpit (S1 selA (Rec0 (Maybe a))) where - gArgParser opt = - let nameA = selName (undefined :: S1 selA (Rec0 (Maybe a)) p) - in case (omitNamedOptions opt, null nameA) of - (True, True) -> M1 <$> gArgParser opt - (True, False) -> - M1 . K1 - <$> optional (pS (string (selNameMod opt nameA)) *> argParser opt) - _ -> parseS1 nameA opt - gToArgs opt sel@(M1 (K1 x)) - | omitNamedOptions opt = case (selName sel, x) of - ("", _) -> toArgs opt x - (_, Nothing) -> [] - (nameA, Just x') -> selNameMod opt nameA : toArgs opt x' - | otherwise = printS1 opt sel - gArgHelper opt path (Proxy :: Proxy (S1 selA (Rec0 (Maybe a)) p)) = - let nameA = selName (undefined :: S1 selA (Rec0 (Maybe a)) p) - in case (omitNamedOptions opt, null nameA) of - (True, True) -> gArgHelper opt path (Proxy :: Proxy (Rec0 (Maybe a) p)) - (True, False) -> concat [ "[" - , selNameMod opt nameA - , " " - , gArgHelper opt path (Proxy :: Proxy (Rec0 a p)) - , "]"] - _ -> helpS1 nameA opt path (Proxy :: Proxy (S1 selA (Rec0 (Maybe a)) p)) - - --- Constructors - -instance (GCoalpit a) => GCoalpit (C1 conA a) where - gArgParser = fmap M1 . gArgParser - gToArgs opt (M1 x) = gToArgs opt x - gArgHelper opt path (Proxy :: Proxy (C1 conA a p)) = - gArgHelper opt path (Proxy :: Proxy (a p)) - --- Data types -instance (GCoalpit a) => GCoalpit (D1 conA a) where - gArgParser = fmap M1 . gArgParser - gToArgs opt (M1 x) = gToArgs opt x - gArgHelper opt path (Proxy :: Proxy (D1 conA a p)) = - gArgHelper opt path (Proxy :: Proxy (a p)) - --- Constraints and such -instance (Coalpit a) => GCoalpit (K1 i a) where - gArgParser = fmap K1 . argParser - gToArgs opt (K1 x) = toArgs opt x - gArgHelper opt path (Proxy :: Proxy (K1 x a p)) = - argHelper opt path (Proxy :: Proxy a) - - --- Common types - -instance Coalpit Int where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INT" - -instance Coalpit Integer where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INTEGER" - -instance Coalpit Word8 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "WORD8" - -instance Coalpit Word16 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "WORD16" - -instance Coalpit Word32 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "WORD32" - -instance Coalpit Word64 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "WORD64" - -instance Coalpit Int8 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INT8" - -instance Coalpit Int16 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INT16" - -instance Coalpit Int32 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INT32" - -instance Coalpit Int64 where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "INT64" - -instance Coalpit Natural where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "NATURAL" - -instance Coalpit Rational where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "RATIONAL" - -instance Coalpit Double where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "DOUBLE" - -instance Coalpit Float where - argParser _ = readArg - toArgs _ i = [show i] - argHelper _ _ _ = "FLOAT" - -instance Coalpit Char where - argParser _ = readArg - toArgs _ c = [show c] - argHelper _ _ _ = "CHAR" - -instance {-#OVERLAPPING#-} Coalpit String where - argParser _ = token (Right . unArg) Nothing - toArgs _ i = [i] - argHelper _ _ _ = "STRING" - --- | A dot ("."). -instance Coalpit () where - argParser _ = pS (char '.') *> pure () - toArgs _ () = ["."] - argHelper _ _ _ = "." - -instance Coalpit Scientific where - argParser _ = try $ do - x <- token (Right . unArg) Nothing - case reverse $ readP_to_S scientificP x of - (n, ""):_ -> pure n - _ -> fail $ "Failed to read a scientific number: " ++ x - toArgs opt n = [formatScientific - (scientificFormat opt) (scientificDecimals opt) n] - argHelper _ _ _ = "SCIENTIFIC" - -instance Coalpit Version where - argParser _ = try $ do - x <- token (Right . unArg) Nothing - case reverse $ readP_to_S parseVersion x of - (v, ""):_ -> pure v - _ -> fail $ "Failed to read a version: " ++ x - toArgs _ v = [showVersion v] - argHelper _ _ _ = "VERSION" - --- | An URI reference (absolute or relative). -instance Coalpit URI where - argParser _ = try $ do - x <- token (Right . unArg) Nothing - maybe (fail $ "Failed to parse URI: " ++ x) pure (parseURIReference x) - toArgs opt u = [uriToString (uriUserInfo opt) u ""] - argHelper _ _ _ = "URI" - - --- | Uses 'dateTimeFormat'. -instance Coalpit UTCTime where - argParser opt = pTime (timeLocale opt) (dateTimeFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (dateTimeFormat opt) t] - argHelper _ _ _ = "UTC_TIME" - --- | Uses 'dateTimeFormat'. -instance Coalpit ZonedTime where - argParser opt = pTime (timeLocale opt) (dateTimeFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (dateTimeFormat opt) t] - argHelper _ _ _ = "ZONED_TIME" - --- | Uses 'dateTimeFormat'. -instance Coalpit LocalTime where - argParser opt = pTime (timeLocale opt) (dateTimeFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (dateTimeFormat opt) t] - argHelper _ _ _ = "LOCAL_TIME" - --- | Uses 'dateTimeFormat'. -instance Coalpit UniversalTime where - argParser opt = pTime (timeLocale opt) (dateTimeFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (dateTimeFormat opt) t] - argHelper _ _ _ = "UNIVERSAL_TIME" - --- | Uses 'timeFormat'. -instance Coalpit TimeOfDay where - argParser opt = pTime (timeLocale opt) (timeFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (timeFormat opt) t] - argHelper _ _ _ = "TIME_OF_DAY" - --- | Uses 'dateFormat'. -instance Coalpit Day where - argParser opt = pTime (timeLocale opt) (dateFormat opt) - toArgs opt t = [formatTime (timeLocale opt) (dateFormat opt) t] - argHelper _ _ _ = "DAY" - --- | Converts to/from 'Scientific'. -instance Coalpit NominalDiffTime where - argParser opt = fromRational . toRational - <$> (argParser opt :: Parser Scientific) - toArgs opt = toArgs opt . - (fromRational . toRational :: NominalDiffTime -> Scientific) - argHelper _ _ _ = "NOMINAL_DIFF_TIME" - --- | Converts to/from 'Scientific'. -instance Coalpit DiffTime where - argParser opt = fromRational . toRational - <$> (argParser opt :: Parser Scientific) - toArgs opt = toArgs opt . - (fromRational . toRational :: DiffTime -> Scientific) - argHelper _ _ _ = "DIFF_TIME" - - -instance Coalpit Bool -instance Coalpit Ordering -instance Coalpit ExitCode -instance Coalpit a => Coalpit (Complex a) -instance Coalpit a => Coalpit (Maybe a) -instance Coalpit a => Coalpit [a] -instance Coalpit a => Coalpit (NE.NonEmpty a) -instance (Coalpit a, Coalpit b) => Coalpit (Either a b) -instance (Coalpit a, Coalpit b) => Coalpit (a, b) -instance (Coalpit a, Coalpit b, Coalpit c) => Coalpit (a, b, c) -instance (Coalpit a, Coalpit b, Coalpit c, Coalpit d) => Coalpit (a, b, c, d) -- cgit v1.2.3