cfg-0.0.1.0: src/Cfg/Parser/ConfigParser.hs
{-# LANGUAGE UndecidableInstances #-}
module Cfg.Parser.ConfigParser where
import Cfg.Options (ConfigOptions (..), RootOptions (..))
import Cfg.Parser (ConfigParseError (..), NestedParser (..))
import Data.Kind (Type)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Tree (Tree (..))
import GHC.Generics
import Data.List
defaultParseRootConfig ::
forall a.
(Generic a, GRootConfigParser (Rep a)) =>
RootOptions ->
Tree Text ->
Either ConfigParseError a
defaultParseRootConfig opts tree = fmap to $ gParseRootConfig opts tree
class GRootConfigParser (f :: Type -> Type) where
gParseRootConfig :: RootOptions -> Tree Text -> Either ConfigParseError (f p)
instance GRootConfigParser f => GRootConfigParser (M1 D s f) where
gParseRootConfig opts tree = M1 <$> gParseRootConfig opts tree
instance (Selector s, GNestedParser f) => GRootConfigParser (M1 S s f) where
gParseRootConfig opts tree = M1 <$> gParseNestedConfig (rootOptionsFieldOptions opts) tree
instance (Constructor c, GRootConfigParser f) => GRootConfigParser (M1 C c f) where
gParseRootConfig opts t@(Node label _) =
if label == (rootOptionsLabelModifier opts . T.pack $ conName m)
then M1 <$> gParseRootConfig opts t
else Left $ MismatchedRootKey label (rootOptionsLabelModifier opts . T.pack $ conName m)
where
m :: t c f a
m = undefined
instance (GFieldParser (a :*: b)) => GRootConfigParser (a :*: b) where
gParseRootConfig opts (Node _ forest) = gParseFields (rootOptionsFieldOptions opts) forest
class FieldParser a where
parseFields :: [Tree Text] -> Either ConfigParseError a
class GFieldParser (f :: Type -> Type) where
gParseFields :: ConfigOptions -> [Tree Text] -> Either ConfigParseError (f p)
instance (Selector s, GNestedParser f) => GFieldParser (M1 S s f) where
gParseFields opts xs = case find ((==) (configOptionsLabelModifier opts . T.pack $ selName @s undefined) . rootLabel) xs of
Nothing -> Left $ MissingKeys [configOptionsLabelModifier opts . T.pack $ selName @s undefined]
Just t -> M1 <$> gParseNestedConfig opts t
instance (GFieldParser a, GFieldParser b) => GFieldParser (a :*: b) where
gParseFields opts xs = do
a <- gParseFields opts xs
b <- gParseFields opts xs
pure $ a :*: b
defaultParseNestedConfig ::
forall a.
(Generic a, GNestedParser (Rep a)) =>
ConfigOptions ->
Tree Text ->
Either ConfigParseError a
defaultParseNestedConfig opts tree = fmap to $ gParseNestedConfig opts tree
class GNestedParser (f :: Type -> Type) where
gParseNestedConfig :: ConfigOptions -> Tree Text -> Either ConfigParseError (f p)
instance NestedParser a => GNestedParser (K1 R a) where
gParseNestedConfig _ (Node label []) = Left $ MissingValue label
gParseNestedConfig _ (Node _ [val]) = K1 <$> parseNestedConfig val
gParseNestedConfig _ tree = K1 <$> parseNestedConfig tree
instance (GNestedParser f) => GNestedParser (M1 D c f) where
gParseNestedConfig opts t = M1 <$> gParseNestedConfig opts t
instance (Constructor c, GNestedParser f) => GNestedParser (M1 C c f) where
gParseNestedConfig opts t = M1 <$> gParseNestedConfig opts t
instance (Selector s, GNestedParser f) => GNestedParser (M1 S s f) where
gParseNestedConfig opts t@(Node label _) =
if label == modifiedSelectorName
then Left $ MismatchedKeyAndField label (T.pack $ selName m, modifiedSelectorName)
else M1 <$> gParseNestedConfig opts t
where
m :: t s f a
m = undefined
modifiedSelectorName :: Text
modifiedSelectorName = configOptionsLabelModifier opts . T.pack $ selName m
instance (GFieldParser (a :*: b)) => GNestedParser (a :*: b) where
gParseNestedConfig opts (Node _ forest) = gParseFields opts forest