packages feed

coformat 0.2.1.0 → 0.3.0.0

raw patch · 25 files changed

+820/−741 lines, 25 filesdep +commandPVP ok

version bump matches the API change (PVP)

Dependencies added: command

API changes (from Hackage documentation)

- Clang.Coformat.Formatter: FormatterInfo :: String -> [ConfigItemT 'Supported] -> [Text] -> FormatterInfo
- Clang.Coformat.Formatter: [baseStyles] :: FormatterInfo -> [Text]
- Clang.Coformat.Formatter: [executableName] :: FormatterInfo -> String
- Clang.Coformat.Formatter: [knownOptions] :: FormatterInfo -> [ConfigItemT 'Supported]
- Clang.Coformat.Formatter: class Formatter fmt
- Clang.Coformat.Formatter: data FormatterInfo
- Clang.Coformat.Formatter: formatFile :: (Formatter fmt, MonadIO m) => proxy fmt -> Text -> [ConfigItemT 'Value] -> FilePath -> m ByteString
- Clang.Coformat.Formatter: formatterInfo :: Formatter fmt => proxy fmt -> FormatterInfo
- Clang.Coformat.Formatter: instance GHC.Show.Show Clang.Coformat.Formatter.FormatterInfo
- Clang.Coformat.Optimization: FmtEnv :: Text -> [PreparedFile] -> [ConfigItemT 'Value] -> FmtEnv
- Clang.Coformat.Optimization: OptEnv :: [IxedCategoricalVariable] -> [IxedIntegralVariable] -> Natural -> OptEnv
- Clang.Coformat.Optimization: OptState :: [ConfigItemT 'Value] -> Score -> OptState
- Clang.Coformat.Optimization: [baseStyle] :: FmtEnv -> Text
- Clang.Coformat.Optimization: [categoricalVariables] :: OptEnv -> [IxedCategoricalVariable]
- Clang.Coformat.Optimization: [constantOpts] :: FmtEnv -> [ConfigItemT 'Value]
- Clang.Coformat.Optimization: [currentOpts] :: OptState -> [ConfigItemT 'Value]
- Clang.Coformat.Optimization: [currentScore] :: OptState -> Score
- Clang.Coformat.Optimization: [integralVariables] :: OptEnv -> [IxedIntegralVariable]
- Clang.Coformat.Optimization: [maxSubsetSize] :: OptEnv -> Natural
- Clang.Coformat.Optimization: [preparedFiles] :: FmtEnv -> [PreparedFile]
- Clang.Coformat.Optimization: chooseBaseStyle :: (MonadError String m, MonadLoggerIO m) => [Text] -> [ConfigItemT 'Value] -> [PreparedFile] -> m (Text, Score)
- Clang.Coformat.Optimization: chooseBestSubset :: (OptMonad err r m, Has OptState r, Has TaskGroup r) => Natural -> [SomeIxedVariable] -> m (Maybe ([ConfigItemT 'Value], Score))
- Clang.Coformat.Optimization: data FmtEnv
- Clang.Coformat.Optimization: data OptEnv
- Clang.Coformat.Optimization: data OptState
- Clang.Coformat.Optimization: dropExpectedFailures :: OptMonad err r m => (forall err' r' m'. (OptMonad err' r' m', CoHas ExpectedFailure err') => m' Score) -> m Score
- Clang.Coformat.Optimization: fixGD :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m, err ~ UnexpectedFailure) => Maybe Int -> Natural -> m ()
- Clang.Coformat.Optimization: initOptState :: [ConfigItemT 'Value] -> Score -> OptState
- Clang.Coformat.Optimization: instance GHC.Show.Show Clang.Coformat.Optimization.OptState
- Clang.Coformat.Optimization: runClangFormat :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m, MonadLogger m) => PreparedFile -> String -> ByteString -> m Score
- Clang.Coformat.Optimization: runClangFormatFiles :: (OptMonad err r m, CoHas ExpectedFailure err) => [ConfigItemT 'Value] -> String -> m Score
- Clang.Coformat.Optimization: showVariated :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> String
- Clang.Coformat.Optimization: stepGDGeneric :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m) => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()
- Clang.Coformat.Optimization: stepGDGeneric' :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m) => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()
- Clang.Coformat.Optimization: type OptMonad err r m = (MonadLoggerIO m, MonadError err m, CoHas UnexpectedFailure err, MonadReader r m, Has FmtEnv r)
- Clang.Coformat.Optimization: variateAt :: forall a. (Variate a, Foldable (VariateResult a)) => Proxy a -> Int -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]
- Clang.Coformat.Optimization: variateSubset :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]
- Clang.Coformat.Pipeline: PipelineOpts :: Maybe Natural -> Maybe FilePath -> NonEmpty FilePath -> TaskGroup -> [String] -> PipelineOpts
- Clang.Coformat.Pipeline: [forceStrs] :: PipelineOpts -> [String]
- Clang.Coformat.Pipeline: [input] :: PipelineOpts -> NonEmpty FilePath
- Clang.Coformat.Pipeline: [maxSubsetSize] :: PipelineOpts -> Maybe Natural
- Clang.Coformat.Pipeline: [resumePath] :: PipelineOpts -> Maybe FilePath
- Clang.Coformat.Pipeline: [taskGroup] :: PipelineOpts -> TaskGroup
- Clang.Coformat.Pipeline: data PipelineOpts
- Clang.Coformat.Pipeline: runOptPipeline :: (MonadError String m, MonadLoggerIO m) => PipelineOpts -> m ByteString
- Clang.Coformat.Score: calcScore :: PreparedFile -> ByteString -> Score
- Clang.Coformat.Score: data PreparedFile
- Clang.Coformat.Score: data Score
- Clang.Coformat.Score: filename :: PreparedFile -> FilePath
- Clang.Coformat.Score: instance GHC.Base.Monoid Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Base.Semigroup Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Classes.Eq Clang.Coformat.Score.PreparedFile
- Clang.Coformat.Score: instance GHC.Classes.Eq Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Classes.Ord Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Enum.Bounded Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Generics.Generic Clang.Coformat.Score.Score
- Clang.Coformat.Score: instance GHC.Show.Show Clang.Coformat.Score.Score
- Clang.Coformat.Score: prepareFile :: MonadIO m => FilePath -> m PreparedFile
- Clang.Coformat.StyOpts: StyOpts :: Text -> [ConfigItemT 'Value] -> StyOpts
- Clang.Coformat.StyOpts: [additionalOpts] :: StyOpts -> [ConfigItemT 'Value]
- Clang.Coformat.StyOpts: [basedOnStyle] :: StyOpts -> Text
- Clang.Coformat.StyOpts: data StyOpts
- Clang.Coformat.StyOpts: formatStyArg :: StyOpts -> ByteString
- Clang.Coformat.StyOpts: instance Data.Aeson.Types.ToJSON.ToJSON Clang.Coformat.StyOpts.StyOpts
- Clang.Coformat.Util: ExpectedFailure :: ExpectedFailure -> Failure
- Clang.Coformat.Util: FormatterFailure :: Int -> Text -> UnexpectedFailure
- Clang.Coformat.Util: FormatterSegfaulted :: Text -> ExpectedFailure
- Clang.Coformat.Util: UnexpectedFailure :: UnexpectedFailure -> Failure
- Clang.Coformat.Util: [errorCode] :: UnexpectedFailure -> Int
- Clang.Coformat.Util: [errorOutput] :: UnexpectedFailure -> Text
- Clang.Coformat.Util: checked :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m) => IO (ExitCode, Text, Text) -> m Text
- Clang.Coformat.Util: convert :: MonadError e' m => (e -> e') -> ExceptT e m a -> m a
- Clang.Coformat.Util: data ExpectedFailure
- Clang.Coformat.Util: data Failure
- Clang.Coformat.Util: data UnexpectedFailure
- Clang.Coformat.Util: failuresAreUnexpected :: Failure -> UnexpectedFailure
- Clang.Coformat.Util: forConcurrently' :: (MonadLoggerIO m, MonadError e m) => [a] -> (forall m'. (MonadLoggerIO m', MonadError e m') => a -> m' b) -> m [b]
- Clang.Coformat.Util: forConcurrentlyPooled :: (MonadLoggerIO m, MonadError e m, MonadReader r m, Has TaskGroup r) => [a] -> (forall m'. (MonadLoggerIO m', MonadReader r m', MonadError e m') => a -> m' b) -> m [b]
- Clang.Coformat.Util: instance Control.Monad.Except.CoHas.CoHas Clang.Coformat.Util.ExpectedFailure Clang.Coformat.Util.Failure
- Clang.Coformat.Util: instance Control.Monad.Except.CoHas.CoHas Clang.Coformat.Util.UnexpectedFailure Clang.Coformat.Util.Failure
- Clang.Coformat.Util: instance GHC.Classes.Eq Clang.Coformat.Util.ExpectedFailure
- Clang.Coformat.Util: instance GHC.Classes.Eq Clang.Coformat.Util.Failure
- Clang.Coformat.Util: instance GHC.Classes.Eq Clang.Coformat.Util.UnexpectedFailure
- Clang.Coformat.Util: instance GHC.Generics.Generic Clang.Coformat.Util.Failure
- Clang.Coformat.Util: instance GHC.Show.Show Clang.Coformat.Util.ExpectedFailure
- Clang.Coformat.Util: instance GHC.Show.Show Clang.Coformat.Util.Failure
- Clang.Coformat.Util: instance GHC.Show.Show Clang.Coformat.Util.UnexpectedFailure
- Clang.Coformat.Util: subsetsN :: Natural -> [a] -> [[a]]
- Clang.Coformat.Util: update :: Int -> (a -> a) -> [a] -> [a]
- Clang.Coformat.Variables: Categorical :: KnownVariateType
- Clang.Coformat.Variables: Integral :: KnownVariateType
- Clang.Coformat.Variables: IxedVariable :: Variable varTy -> Int -> IxedVariable varTy
- Clang.Coformat.Variables: [MkDV] :: (Variate a, VariateType a ~ varTy, Foldable (VariateResult a)) => a -> Variable varTy
- Clang.Coformat.Variables: [SomeIxedVariable] :: IxedVariable varTy -> SomeIxedVariable
- Clang.Coformat.Variables: [discreteVar] :: IxedVariable varTy -> Variable varTy
- Clang.Coformat.Variables: [varIdx] :: IxedVariable varTy -> Int
- Clang.Coformat.Variables: asSome :: [IxedVariable varTy] -> [SomeIxedVariable]
- Clang.Coformat.Variables: class Variate a where {
- Clang.Coformat.Variables: data IxedVariable varTy
- Clang.Coformat.Variables: data KnownVariateType
- Clang.Coformat.Variables: data SomeIxedVariable :: Type
- Clang.Coformat.Variables: data Variable varTy
- Clang.Coformat.Variables: instance Clang.Coformat.Variables.Variate Clang.Coformat.Variables.EnumVar
- Clang.Coformat.Variables: instance Clang.Coformat.Variables.Variate GHC.Natural.Natural
- Clang.Coformat.Variables: instance Clang.Coformat.Variables.Variate GHC.Types.Bool
- Clang.Coformat.Variables: instance Clang.Coformat.Variables.Variate GHC.Types.Int
- Clang.Coformat.Variables: searchSpace :: Show a => Integral a => a -> [a]
- Clang.Coformat.Variables: typToDV :: ConfigTypeT 'Value -> Maybe CategoricalVariable
- Clang.Coformat.Variables: typToIV :: ConfigTypeT 'Value -> Maybe IntegralVariable
- Clang.Coformat.Variables: type CategoricalVariable = Variable 'Categorical
- Clang.Coformat.Variables: type CategoricalVariate a = (Variate a, VariateType a ~ 'Categorical)
- Clang.Coformat.Variables: type EnumVar = ([Text], Text)
- Clang.Coformat.Variables: type IntegralVariable = Variable 'Integral
- Clang.Coformat.Variables: type IntegralVariate a = (Variate a, VariateType a ~ 'Integral)
- Clang.Coformat.Variables: type IxedCategoricalVariable = IxedVariable 'Categorical
- Clang.Coformat.Variables: type IxedIntegralVariable = IxedVariable 'Integral
- Clang.Coformat.Variables: type family VariateType a :: KnownVariateType;
- Clang.Coformat.Variables: varPrism :: Variate a => Prism' (ConfigTypeT 'Value) a
- Clang.Coformat.Variables: variate :: Variate a => a -> VariateResult a a
- Clang.Coformat.Variables: }
- Clang.Format.Descr: CTBool :: CTData f Bool -> ConfigTypeT f
- Clang.Format.Descr: CTEnum :: [Text] -> CTData f Text -> ConfigTypeT f
- Clang.Format.Descr: CTIncludeCats :: CTData f Void -> ConfigTypeT f
- Clang.Format.Descr: CTInt :: CTData f Int -> ConfigTypeT f
- Clang.Format.Descr: CTRawStringFormats :: CTData f Void -> ConfigTypeT f
- Clang.Format.Descr: CTString :: CTData f Void -> ConfigTypeT f
- Clang.Format.Descr: CTStringVec :: CTData f Void -> ConfigTypeT f
- Clang.Format.Descr: CTUnsigned :: CTData f Natural -> ConfigTypeT f
- Clang.Format.Descr: ConfigItem :: [Text] -> ConfigTypeT f -> ConfigItemT f
- Clang.Format.Descr: Parsed :: Stage
- Clang.Format.Descr: Supported :: Stage
- Clang.Format.Descr: Value :: Stage
- Clang.Format.Descr: [enumValue] :: ConfigTypeT f -> CTData f Text
- Clang.Format.Descr: [name] :: ConfigItemT f -> [Text]
- Clang.Format.Descr: [value] :: ConfigItemT f -> ConfigTypeT f
- Clang.Format.Descr: [variants] :: ConfigTypeT f -> [Text]
- Clang.Format.Descr: data ConfigItemT f
- Clang.Format.Descr: data ConfigTypeT f
- Clang.Format.Descr: data Stage
- Clang.Format.Descr: instance GHC.Classes.Eq (Clang.Format.Descr.ConfigTypeT 'Clang.Format.Descr.Value)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigItemT 'Clang.Format.Descr.Parsed)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigItemT 'Clang.Format.Descr.Supported)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigItemT 'Clang.Format.Descr.Value)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigTypeT 'Clang.Format.Descr.Parsed)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigTypeT 'Clang.Format.Descr.Supported)
- Clang.Format.Descr: instance GHC.Show.Show (Clang.Format.Descr.ConfigTypeT 'Clang.Format.Descr.Value)
- Clang.Format.Descr: type family CTData f ty
- Clang.Format.Descr.Operations: filterParsedItems :: [ConfigItemT 'Parsed] -> [ConfigItemT 'Supported]
- Clang.Format.Descr.Operations: parseConfigValue :: (MonadError String m, ParseableConfigState f) => ConfigItemT f -> String -> m (ConfigItemT 'Value)
- Clang.Format.Descr.Operations: replaceItemsWith :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]
- Clang.Format.Descr.Operations: subtractMatching :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]
- Clang.Format.Descr.Operations: type ParseableConfigState f = (CTData f Void ~ Void, Show (ConfigTypeT f))
- Clang.Format.DescrParser: parseFile :: FilePath -> IO (Either String [ConfigItemT 'Parsed])
+ Clang.Format.Formatter: clangFormatter :: Formatter
+ Clang.Format.StyOpts: StyOpts :: Text -> [ConfigItemT 'Value] -> StyOpts
+ Clang.Format.StyOpts: [additionalOpts] :: StyOpts -> [ConfigItemT 'Value]
+ Clang.Format.StyOpts: [basedOnStyle] :: StyOpts -> Text
+ Clang.Format.StyOpts: data StyOpts
+ Clang.Format.StyOpts: formatStyArg :: StyOpts -> ByteString
+ Clang.Format.StyOpts: instance Data.Aeson.Types.ToJSON.ToJSON Clang.Format.StyOpts.StyOpts
+ Language.Coformat.Descr: CTBool :: CTData f Bool -> ConfigTypeT f
+ Language.Coformat.Descr: CTEnum :: [Text] -> CTData f Text -> ConfigTypeT f
+ Language.Coformat.Descr: CTIncludeCats :: CTData f Void -> ConfigTypeT f
+ Language.Coformat.Descr: CTInt :: CTData f Int -> ConfigTypeT f
+ Language.Coformat.Descr: CTRawStringFormats :: CTData f Void -> ConfigTypeT f
+ Language.Coformat.Descr: CTString :: CTData f Void -> ConfigTypeT f
+ Language.Coformat.Descr: CTStringVec :: CTData f Void -> ConfigTypeT f
+ Language.Coformat.Descr: CTUnsigned :: CTData f Natural -> ConfigTypeT f
+ Language.Coformat.Descr: ConfigItem :: [Text] -> ConfigTypeT f -> ConfigItemT f
+ Language.Coformat.Descr: Parsed :: Stage
+ Language.Coformat.Descr: Supported :: Stage
+ Language.Coformat.Descr: Value :: Stage
+ Language.Coformat.Descr: [enumValue] :: ConfigTypeT f -> CTData f Text
+ Language.Coformat.Descr: [name] :: ConfigItemT f -> [Text]
+ Language.Coformat.Descr: [value] :: ConfigItemT f -> ConfigTypeT f
+ Language.Coformat.Descr: [variants] :: ConfigTypeT f -> [Text]
+ Language.Coformat.Descr: data ConfigItemT f
+ Language.Coformat.Descr: data ConfigTypeT f
+ Language.Coformat.Descr: data Stage
+ Language.Coformat.Descr: instance GHC.Classes.Eq (Language.Coformat.Descr.ConfigTypeT 'Language.Coformat.Descr.Value)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigItemT 'Language.Coformat.Descr.Parsed)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigItemT 'Language.Coformat.Descr.Supported)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigItemT 'Language.Coformat.Descr.Value)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigTypeT 'Language.Coformat.Descr.Parsed)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigTypeT 'Language.Coformat.Descr.Supported)
+ Language.Coformat.Descr: instance GHC.Show.Show (Language.Coformat.Descr.ConfigTypeT 'Language.Coformat.Descr.Value)
+ Language.Coformat.Descr: type family CTData f ty
+ Language.Coformat.Descr.Operations: filterParsedItems :: [ConfigItemT 'Parsed] -> [ConfigItemT 'Supported]
+ Language.Coformat.Descr.Operations: parseConfigValue :: (MonadError String m, ParseableConfigState f) => ConfigItemT f -> String -> m (ConfigItemT 'Value)
+ Language.Coformat.Descr.Operations: replaceItemsWith :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]
+ Language.Coformat.Descr.Operations: subtractMatching :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]
+ Language.Coformat.Descr.Operations: type ParseableConfigState f = (CTData f Void ~ Void, Show (ConfigTypeT f))
+ Language.Coformat.Formatter: CmdArgs :: [ByteString] -> CmdArgs
+ Language.Coformat.Formatter: FormatterInfo :: String -> OptsSource (OptsDescription 'Supported) -> [ConfigItemT 'Value] -> (Text -> [ConfigItemT 'Supported] -> [ConfigItemT 'Value] -> OptsSource [ConfigItemT 'Value]) -> (Text -> [ConfigItemT 'Value] -> FilePath -> CmdArgs) -> (Text -> [ConfigItemT 'Value] -> ByteString) -> FormatterInfo
+ Language.Coformat.Formatter: OptsDescription :: [ConfigItemT stage] -> [Text] -> OptsDescription stage
+ Language.Coformat.Formatter: OptsFromCmd :: CmdArgs -> (ByteString -> Either String opts) -> OptsSource opts
+ Language.Coformat.Formatter: OptsFromFile :: FilePath -> (ByteString -> Either String opts) -> OptsSource opts
+ Language.Coformat.Formatter: StaticOpts :: opts -> OptsSource opts
+ Language.Coformat.Formatter: [Formatter] :: forall resumeObj. {formatterInfo :: FormatterInfo, parseResumeObject :: ByteString -> Either String resumeObj, parseResumeOptions :: [ConfigItemT 'Supported] -> resumeObj -> Either String (Text, [ConfigItemT 'Value])} -> Formatter
+ Language.Coformat.Formatter: [args] :: CmdArgs -> [ByteString]
+ Language.Coformat.Formatter: [baseStyles] :: OptsDescription stage -> [Text]
+ Language.Coformat.Formatter: [defaultStyleOpts] :: FormatterInfo -> Text -> [ConfigItemT 'Supported] -> [ConfigItemT 'Value] -> OptsSource [ConfigItemT 'Value]
+ Language.Coformat.Formatter: [execName] :: FormatterInfo -> String
+ Language.Coformat.Formatter: [formatFile] :: FormatterInfo -> Text -> [ConfigItemT 'Value] -> FilePath -> CmdArgs
+ Language.Coformat.Formatter: [formatterOpts] :: FormatterInfo -> OptsSource (OptsDescription 'Supported)
+ Language.Coformat.Formatter: [hardcodedOpts] :: FormatterInfo -> [ConfigItemT 'Value]
+ Language.Coformat.Formatter: [knownOpts] :: OptsDescription stage -> [ConfigItemT stage]
+ Language.Coformat.Formatter: [serializeOptions] :: FormatterInfo -> Text -> [ConfigItemT 'Value] -> ByteString
+ Language.Coformat.Formatter: data Formatter
+ Language.Coformat.Formatter: data FormatterInfo
+ Language.Coformat.Formatter: data OptsDescription stage
+ Language.Coformat.Formatter: data OptsSource opts
+ Language.Coformat.Formatter: instance GHC.Show.Show Language.Coformat.Formatter.CmdArgs
+ Language.Coformat.Formatter: newtype CmdArgs
+ Language.Coformat.Formatter: parseOpts :: (MonadIO m, MonadError String m) => String -> OptsSource opts -> m opts
+ Language.Coformat.Formatter: runCommand :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m) => String -> CmdArgs -> m ByteString
+ Language.Coformat.Formatter.Failure: ExpectedFailure :: ExpectedFailure -> Failure
+ Language.Coformat.Formatter.Failure: FormatterFailure :: Int -> Text -> UnexpectedFailure
+ Language.Coformat.Formatter.Failure: FormatterSegfaulted :: Text -> ExpectedFailure
+ Language.Coformat.Formatter.Failure: UnexpectedFailure :: UnexpectedFailure -> Failure
+ Language.Coformat.Formatter.Failure: [errorCode] :: UnexpectedFailure -> Int
+ Language.Coformat.Formatter.Failure: [errorOutput] :: UnexpectedFailure -> Text
+ Language.Coformat.Formatter.Failure: data ExpectedFailure
+ Language.Coformat.Formatter.Failure: data Failure
+ Language.Coformat.Formatter.Failure: data UnexpectedFailure
+ Language.Coformat.Formatter.Failure: failuresAreUnexpected :: Failure -> UnexpectedFailure
+ Language.Coformat.Formatter.Failure: instance Control.Monad.Except.CoHas.CoHas Language.Coformat.Formatter.Failure.ExpectedFailure Language.Coformat.Formatter.Failure.Failure
+ Language.Coformat.Formatter.Failure: instance Control.Monad.Except.CoHas.CoHas Language.Coformat.Formatter.Failure.UnexpectedFailure Language.Coformat.Formatter.Failure.Failure
+ Language.Coformat.Formatter.Failure: instance GHC.Classes.Eq Language.Coformat.Formatter.Failure.ExpectedFailure
+ Language.Coformat.Formatter.Failure: instance GHC.Classes.Eq Language.Coformat.Formatter.Failure.Failure
+ Language.Coformat.Formatter.Failure: instance GHC.Classes.Eq Language.Coformat.Formatter.Failure.UnexpectedFailure
+ Language.Coformat.Formatter.Failure: instance GHC.Generics.Generic Language.Coformat.Formatter.Failure.Failure
+ Language.Coformat.Formatter.Failure: instance GHC.Show.Show Language.Coformat.Formatter.Failure.ExpectedFailure
+ Language.Coformat.Formatter.Failure: instance GHC.Show.Show Language.Coformat.Formatter.Failure.Failure
+ Language.Coformat.Formatter.Failure: instance GHC.Show.Show Language.Coformat.Formatter.Failure.UnexpectedFailure
+ Language.Coformat.Optimization: FmtEnv :: Text -> [PreparedFile] -> [ConfigItemT 'Value] -> FormatterInfo -> FmtEnv
+ Language.Coformat.Optimization: OptEnv :: [IxedCategoricalVariable] -> [IxedIntegralVariable] -> Natural -> OptEnv
+ Language.Coformat.Optimization: OptState :: [ConfigItemT 'Value] -> Score -> OptState
+ Language.Coformat.Optimization: [baseStyle] :: FmtEnv -> Text
+ Language.Coformat.Optimization: [categoricalVariables] :: OptEnv -> [IxedCategoricalVariable]
+ Language.Coformat.Optimization: [constantOpts] :: FmtEnv -> [ConfigItemT 'Value]
+ Language.Coformat.Optimization: [currentOpts] :: OptState -> [ConfigItemT 'Value]
+ Language.Coformat.Optimization: [currentScore] :: OptState -> Score
+ Language.Coformat.Optimization: [formatterInfo] :: FmtEnv -> FormatterInfo
+ Language.Coformat.Optimization: [integralVariables] :: OptEnv -> [IxedIntegralVariable]
+ Language.Coformat.Optimization: [maxSubsetSize] :: OptEnv -> Natural
+ Language.Coformat.Optimization: [preparedFiles] :: FmtEnv -> [PreparedFile]
+ Language.Coformat.Optimization: chooseBaseStyle :: (MonadError String m, MonadLoggerIO m) => FormatterInfo -> [Text] -> [ConfigItemT 'Value] -> [PreparedFile] -> m (Text, Score)
+ Language.Coformat.Optimization: chooseBestSubset :: (OptMonad err r m, Has OptState r, Has TaskGroup r) => Natural -> [SomeIxedVariable] -> m (Maybe ([ConfigItemT 'Value], Score))
+ Language.Coformat.Optimization: data FmtEnv
+ Language.Coformat.Optimization: data OptEnv
+ Language.Coformat.Optimization: data OptState
+ Language.Coformat.Optimization: dropExpectedFailures :: OptMonad err r m => (forall err' r' m'. (OptMonad err' r' m', CoHas ExpectedFailure err') => m' Score) -> m Score
+ Language.Coformat.Optimization: fixGD :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m, err ~ UnexpectedFailure) => Maybe Int -> Natural -> m ()
+ Language.Coformat.Optimization: initOptState :: [ConfigItemT 'Value] -> Score -> OptState
+ Language.Coformat.Optimization: instance GHC.Show.Show Language.Coformat.Optimization.OptState
+ Language.Coformat.Optimization: runFormat :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m, MonadLogger m) => FormatterInfo -> PreparedFile -> String -> Text -> [ConfigItemT 'Value] -> m Score
+ Language.Coformat.Optimization: runFormatFiles :: (OptMonad err r m, CoHas ExpectedFailure err) => [ConfigItemT 'Value] -> String -> m Score
+ Language.Coformat.Optimization: showVariated :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> String
+ Language.Coformat.Optimization: stepGDGeneric :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m) => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()
+ Language.Coformat.Optimization: stepGDGeneric' :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m) => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()
+ Language.Coformat.Optimization: type OptMonad err r m = (MonadLoggerIO m, MonadError err m, CoHas UnexpectedFailure err, MonadReader r m, Has FmtEnv r)
+ Language.Coformat.Optimization: variateAt :: forall a. (Variate a, Foldable (VariateResult a)) => Proxy a -> Int -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]
+ Language.Coformat.Optimization: variateSubset :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]
+ Language.Coformat.Pipeline: PipelineOpts :: Maybe Natural -> Maybe FilePath -> NonEmpty FilePath -> TaskGroup -> [String] -> Formatter -> PipelineOpts
+ Language.Coformat.Pipeline: [forceStrs] :: PipelineOpts -> [String]
+ Language.Coformat.Pipeline: [formatter] :: PipelineOpts -> Formatter
+ Language.Coformat.Pipeline: [input] :: PipelineOpts -> NonEmpty FilePath
+ Language.Coformat.Pipeline: [maxSubsetSize] :: PipelineOpts -> Maybe Natural
+ Language.Coformat.Pipeline: [resumePath] :: PipelineOpts -> Maybe FilePath
+ Language.Coformat.Pipeline: [taskGroup] :: PipelineOpts -> TaskGroup
+ Language.Coformat.Pipeline: data PipelineOpts
+ Language.Coformat.Pipeline: runOptPipeline :: (MonadError String m, MonadLoggerIO m) => PipelineOpts -> m ByteString
+ Language.Coformat.Score: calcScore :: PreparedFile -> ByteString -> Score
+ Language.Coformat.Score: data PreparedFile
+ Language.Coformat.Score: data Score
+ Language.Coformat.Score: filename :: PreparedFile -> FilePath
+ Language.Coformat.Score: instance GHC.Base.Monoid Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Base.Semigroup Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Classes.Eq Language.Coformat.Score.PreparedFile
+ Language.Coformat.Score: instance GHC.Classes.Eq Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Classes.Ord Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Enum.Bounded Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Generics.Generic Language.Coformat.Score.Score
+ Language.Coformat.Score: instance GHC.Show.Show Language.Coformat.Score.Score
+ Language.Coformat.Score: prepareFile :: MonadIO m => FilePath -> m PreparedFile
+ Language.Coformat.Util: convert :: MonadError e' m => (e -> e') -> ExceptT e m a -> m a
+ Language.Coformat.Util: forConcurrently' :: (MonadLoggerIO m, MonadError e m) => [a] -> (forall m'. (MonadLoggerIO m', MonadError e m') => a -> m' b) -> m [b]
+ Language.Coformat.Util: forConcurrentlyPooled :: (MonadLoggerIO m, MonadError e m, MonadReader r m, Has TaskGroup r) => [a] -> (forall m'. (MonadLoggerIO m', MonadReader r m', MonadError e m') => a -> m' b) -> m [b]
+ Language.Coformat.Util: subsetsN :: Natural -> [a] -> [[a]]
+ Language.Coformat.Util: update :: Int -> (a -> a) -> [a] -> [a]
+ Language.Coformat.Variables: Categorical :: KnownVariateType
+ Language.Coformat.Variables: Integral :: KnownVariateType
+ Language.Coformat.Variables: IxedVariable :: Variable varTy -> Int -> IxedVariable varTy
+ Language.Coformat.Variables: [MkDV] :: (Variate a, VariateType a ~ varTy, Foldable (VariateResult a)) => a -> Variable varTy
+ Language.Coformat.Variables: [SomeIxedVariable] :: IxedVariable varTy -> SomeIxedVariable
+ Language.Coformat.Variables: [discreteVar] :: IxedVariable varTy -> Variable varTy
+ Language.Coformat.Variables: [varIdx] :: IxedVariable varTy -> Int
+ Language.Coformat.Variables: asSome :: [IxedVariable varTy] -> [SomeIxedVariable]
+ Language.Coformat.Variables: class Variate a where {
+ Language.Coformat.Variables: data IxedVariable varTy
+ Language.Coformat.Variables: data KnownVariateType
+ Language.Coformat.Variables: data SomeIxedVariable :: Type
+ Language.Coformat.Variables: data Variable varTy
+ Language.Coformat.Variables: instance Language.Coformat.Variables.Variate GHC.Natural.Natural
+ Language.Coformat.Variables: instance Language.Coformat.Variables.Variate GHC.Types.Bool
+ Language.Coformat.Variables: instance Language.Coformat.Variables.Variate GHC.Types.Int
+ Language.Coformat.Variables: instance Language.Coformat.Variables.Variate Language.Coformat.Variables.EnumVar
+ Language.Coformat.Variables: searchSpace :: Show a => Integral a => a -> [a]
+ Language.Coformat.Variables: typToDV :: ConfigTypeT 'Value -> Maybe CategoricalVariable
+ Language.Coformat.Variables: typToIV :: ConfigTypeT 'Value -> Maybe IntegralVariable
+ Language.Coformat.Variables: type CategoricalVariable = Variable 'Categorical
+ Language.Coformat.Variables: type CategoricalVariate a = (Variate a, VariateType a ~ 'Categorical)
+ Language.Coformat.Variables: type EnumVar = ([Text], Text)
+ Language.Coformat.Variables: type IntegralVariable = Variable 'Integral
+ Language.Coformat.Variables: type IntegralVariate a = (Variate a, VariateType a ~ 'Integral)
+ Language.Coformat.Variables: type IxedCategoricalVariable = IxedVariable 'Categorical
+ Language.Coformat.Variables: type IxedIntegralVariable = IxedVariable 'Integral
+ Language.Coformat.Variables: type family VariateType a :: KnownVariateType;
+ Language.Coformat.Variables: varPrism :: Variate a => Prism' (ConfigTypeT 'Value) a
+ Language.Coformat.Variables: variate :: Variate a => a -> VariateResult a a
+ Language.Coformat.Variables: }

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for coformat +## v0.3.0.0++* A fairly major refactoring: isolated the description of the formatters.+* Change the casing of flags to be more in line with the common lisp-style.+ ## v0.2.1.0  * Allow the user to force-set formatter options.
app/Main.hs view
@@ -17,7 +17,8 @@ import System.IO(IOMode(..), Handle, stderr, withFile) import System.Log.FastLogger -import Clang.Coformat.Pipeline+import Clang.Format.Formatter+import Language.Coformat.Pipeline  data Options w = Options   { parallelism :: w ::: Maybe Natural <?> "Max parallel threads of heavy-duty computations (defaults to NCPUs - 1)"@@ -29,7 +30,8 @@   , output :: w ::: FilePath <?> "Where to save the resulting configuration file"   } deriving (Generic) -instance ParseRecord (Options Wrapped)+instance ParseRecord (Options Wrapped) where+  parseRecord = parseRecordWithModifiers lispCaseModifiers  logOutput :: Maybe Handle           -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()@@ -53,7 +55,11 @@    res <- withDebugLog $ \maybeLogHandle ->          withTaskGroup tgSize $ \taskGroup ->-         (`runLoggingT` logOutput maybeLogHandle) $ runExceptT $ runOptPipeline PipelineOpts { forceStrs = forceOption, .. }+         (`runLoggingT` logOutput maybeLogHandle) $ runExceptT $ runOptPipeline PipelineOpts+                                                                                { forceStrs = forceOption+                                                                                , formatter = clangFormatter+                                                                                , ..+                                                                                }   case res of        Left err -> putStrLn err        Right bs -> BS.writeFile output bs
coformat.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: ea70ef65978e2e5237ba446709fed08a5dcdef26609680601b4b7a02afdbdc95+-- hash: 842fc70286283a152b2bed20670e1262702c1b7efa574a215ebab64b09049761  name:           coformat-version:        0.2.1.0+version:        0.3.0.0 synopsis:       Generate clang-format config based on some existing code base description:    Please see the README on GitHub at <https://github.com/0xd34df00d/coformat#readme> category:       Language@@ -29,17 +29,19 @@  library   exposed-modules:-      Clang.Coformat.Formatter-      Clang.Coformat.Optimization-      Clang.Coformat.Pipeline-      Clang.Coformat.Score-      Clang.Coformat.StyOpts-      Clang.Coformat.Util-      Clang.Coformat.Variables-      Clang.Format.Descr-      Clang.Format.Descr.Operations       Clang.Format.DescrParser+      Clang.Format.Formatter+      Clang.Format.StyOpts       Clang.Format.YamlConversions+      Language.Coformat.Descr+      Language.Coformat.Descr.Operations+      Language.Coformat.Formatter+      Language.Coformat.Formatter.Failure+      Language.Coformat.Optimization+      Language.Coformat.Pipeline+      Language.Coformat.Score+      Language.Coformat.Util+      Language.Coformat.Variables   other-modules:       Paths_coformat   hs-source-dirs:@@ -52,6 +54,7 @@     , base >=4.7 && <5     , bytestring     , can-i-haz+    , command     , command-qq     , containers     , dom-selector@@ -89,6 +92,7 @@     , bytestring     , can-i-haz     , coformat+    , command     , command-qq     , containers     , dom-selector@@ -127,6 +131,7 @@     , bytestring     , can-i-haz     , coformat+    , command     , command-qq     , containers     , dom-selector
− src/Clang/Coformat/Formatter.hs
@@ -1,19 +0,0 @@-{-# LANGUAGE DataKinds #-}--module Clang.Coformat.Formatter where--import qualified Data.ByteString.Char8 as BS-import qualified Data.Text as T-import Control.Monad.IO.Class--import Clang.Format.Descr--data FormatterInfo = FormatterInfo-  { executableName :: String-  , knownOptions :: [ConfigItemT 'Supported]-  , baseStyles :: [T.Text]-  } deriving (Show)--class Formatter fmt where-  formatterInfo :: proxy fmt -> FormatterInfo-  formatFile :: MonadIO m => proxy fmt -> T.Text -> [ConfigItemT 'Value] -> FilePath -> m BS.ByteString
− src/Clang/Coformat/Optimization.hs
@@ -1,164 +0,0 @@-{-# LANGUAGE GADTs, DataKinds, TypeApplications, RankNTypes, ScopedTypeVariables, ConstraintKinds #-}-{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}-{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}-{-# LANGUAGE QuasiQuotes, RecordWildCards, TupleSections, LambdaCase #-}--module Clang.Coformat.Optimization where--import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T-import qualified Data.Text.Lazy.Encoding as TL-import Control.Concurrent.Async.Pool-import Control.Lens-import Control.Monad.Except.CoHas-import Control.Monad.Extra-import Control.Monad.Logger-import Control.Monad.Reader.Has hiding(update)-import Control.Monad.State.Strict-import Data.Foldable-import Data.List-import Data.Ord-import Data.Proxy-import Data.String.Interpolate.IsString-import Numeric.Natural-import System.Command.QQ--import Clang.Coformat.Score-import Clang.Coformat.StyOpts-import Clang.Coformat.Util-import Clang.Coformat.Variables-import Clang.Format.Descr--data FmtEnv = FmtEnv-  { baseStyle :: T.Text-  , preparedFiles :: [PreparedFile]-  , constantOpts :: [ConfigItemT 'Value]-  }--data OptEnv = OptEnv-  { categoricalVariables :: [IxedCategoricalVariable]-  , integralVariables :: [IxedIntegralVariable]-  , maxSubsetSize :: Natural-  }--runClangFormat :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m, MonadLogger m)-               => PreparedFile -> String -> BSL.ByteString -> m Score-runClangFormat prepared logStr formattedSty = do-  stdout <- checked [sh|clang-format --style='#{unpackedSty}' #{path}|]-  let dist = calcScore prepared $ BSL.toStrict $ TL.encodeUtf8 stdout-  logDebugN [i|#{logStr}: #{dist}|]-  pure dist-  where-    path = filename prepared-    unpackedSty = BSL.unpack formattedSty--type OptMonad err r m = (MonadLoggerIO m, MonadError err m, CoHas UnexpectedFailure err, MonadReader r m, Has FmtEnv r)--runClangFormatFiles :: (OptMonad err r m, CoHas ExpectedFailure err)-                    => [ConfigItemT 'Value] -> String -> m Score-runClangFormatFiles varOpts logStr = do-  FmtEnv { .. } <- ask-  let sty = StyOpts { basedOnStyle = baseStyle, additionalOpts = constantOpts <> varOpts }-  let formattedSty = formatStyArg sty-  fmap mconcat $ forM preparedFiles $ \prepared -> runClangFormat prepared [i|#{logStr} at #{filename prepared}|] formattedSty--chooseBaseStyle :: (MonadError String m, MonadLoggerIO m) => [T.Text] -> [ConfigItemT 'Value] -> [PreparedFile] -> m (T.Text, Score)-chooseBaseStyle baseStyles predefinedOpts files = do-  sty2dists <- forConcurrently' ((,) <$> baseStyles <*> files) $ \(sty, file) -> do-    let formattedArg = formatStyArg StyOpts { basedOnStyle = sty, additionalOpts = predefinedOpts }-    convert (show @(Either ExpectedFailure UnexpectedFailure)) $ (sty,) <$> runClangFormat file [i|Initial guess for #{sty} at #{filename file}|] formattedArg-  let accumulated = HM.toList $ HM.fromListWith (<>) sty2dists-  forM_ accumulated $ \(sty, acc) -> logInfoN [i|Initial accumulated guess for #{sty}: #{acc}|]-  pure $ minimumBy (comparing snd) accumulated--variateAt :: forall a. (Variate a, Foldable (VariateResult a))-          => Proxy a -> Int -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]-variateAt _ idx opts = [ update idx (updater v') opts | v' <- toList variated ]-  where-    thePrism :: Prism' (ConfigTypeT 'Value) a-    thePrism = varPrism-    variated = variate $ value (opts !! idx) ^?! thePrism-    updater v cfg = cfg { value = value cfg & thePrism .~ v }--data OptState = OptState-  { currentOpts :: [ConfigItemT 'Value]-  , currentScore :: Score-  } deriving (Show)--initOptState :: [ConfigItemT 'Value] -> Score -> OptState-initOptState currentOpts currentScore = OptState { .. }--dropExpectedFailures :: OptMonad err r m-                     => (forall err' r' m'. (OptMonad err' r' m', CoHas ExpectedFailure err') => m' Score)-                     -> m Score-dropExpectedFailures act = do-  res <- runExceptT act-  case res of-       Left (UnexpectedFailure failure) -> throwError failure-       Left (ExpectedFailure failure) -> do-         logErrorN [i|Unable to run the formatter: #{show failure}|]-         pure maxBound-       Right sc -> pure sc--variateSubset :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]-variateSubset [] opts = [opts]-variateSubset (SomeIxedVariable (IxedVariable (MkDV (_ :: a)) idx) : rest) opts = concatMap (variateSubset rest) $ variateAt @a Proxy idx opts--showVariated :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> String-showVariated vars opts = intercalate ", " [showVar var | var <- vars]-  where-    showVar (SomeIxedVariable (IxedVariable _ idx)) = [i|#{name $ opts !! idx} -> #{value $ opts !! idx}|]--chooseBestSubset :: (OptMonad err r m, Has OptState r, Has TaskGroup r)-                 => Natural -> [SomeIxedVariable] -> m (Maybe ([ConfigItemT 'Value], Score))-chooseBestSubset subsetSize ixedVariables = do-  OptState { .. } <- ask-  partialResults <- forConcurrentlyPooled (subsetsN subsetSize ixedVariables) $ \someVarsSubset -> do-    opt2scores <- forM (variateSubset someVarsSubset currentOpts) $ \opts' ->-      fmap (opts',) $ dropExpectedFailures $ runClangFormatFiles opts' $ showVariated someVarsSubset opts'-    let (bestOpts, bestScore) = minimumBy (comparing snd) opt2scores-    when (bestScore < currentScore) $-      logInfoN [i|Total dist for #{showVariated someVarsSubset bestOpts}: #{currentScore} -> #{bestScore}|]-    pure (bestOpts, bestScore, someVarsSubset)-  let (bestOpts, bestScore, bestVarsSubset) = minimumBy (comparing (^. _2)) partialResults-  if bestScore < currentScore-    then do-      logInfoN [i|Choosing #{showVariated bestVarsSubset bestOpts}|]-      pure $ Just (bestOpts, bestScore)-    else pure Nothing--stepGDGeneric' :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m)-               => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()-stepGDGeneric' subsetSize varGetters = do-  current <- get-  fmtEnv@FmtEnv { .. } <- ask-  optEnv <- ask-  tg :: TaskGroup <- ask-  runReaderT (chooseBestSubset subsetSize $ concatMap ($ optEnv) varGetters) (current, fmtEnv, tg) >>=-    \case Nothing -> pure ()-          Just (opts', score') -> do-            logInfoN [i|Total score after optimization on all files: #{score'}|]-            put OptState { currentOpts = opts', currentScore = score' }--stepGDGeneric :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m)-              => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()-stepGDGeneric subsetSize varGetters = whenM ((> mempty) <$> gets currentScore) $ stepGDGeneric' subsetSize varGetters--fixGD :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m, err ~ UnexpectedFailure)-      => Maybe Int -> Natural -> m ()-fixGD (Just 0) _ = pure ()-fixGD counter curSubsetSize = do-  maxSubsetSize' <- asks maxSubsetSize-  if curSubsetSize > maxSubsetSize'-    then logInfoN [i|Done optimizing|]-    else do-      startScore <- gets currentScore-      stepGDGeneric curSubsetSize [asSome . categoricalVariables, asSome . integralVariables]-      endScore <- gets currentScore-      logInfoN [i|Full optimization step done, went from #{startScore} to #{endScore}|]-      if startScore /= endScore-        then fixGD (subtract 1 <$> counter) 1-        else do-          logInfoN [i|Done optimizing with subset size #{curSubsetSize}, stopped at score #{endScore}|]-          fixGD (subtract 1 <$> counter) (curSubsetSize + 1)
− src/Clang/Coformat/Pipeline.hs
@@ -1,148 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE DataKinds, GADTs #-}-{-# LANGUAGE TypeApplications, OverloadedStrings, RecordWildCards, QuasiQuotes #-}--module Clang.Coformat.Pipeline-( runOptPipeline-, PipelineOpts(..)-) where--import qualified Control.Monad.Except.CoHas as EC-import qualified Data.ByteString.Char8 as BS-import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T-import qualified Data.Text.Lazy.Encoding as TL-import Control.Concurrent.Async.Pool-import Control.Lens hiding (Wrapped, Unwrapped)-import Control.Monad.Except-import Control.Monad.Logger-import Control.Monad.Reader-import Control.Monad.State.Strict-import Data.Aeson.Lens-import Data.Bifunctor-import Data.Foldable-import Data.List.NonEmpty(NonEmpty)-import Data.Maybe-import Data.String.Interpolate.IsString-import Data.Traversable-import Numeric.Natural-import System.Command.QQ--import Clang.Coformat.Optimization-import Clang.Coformat.Score-import Clang.Coformat.StyOpts-import Clang.Coformat.Util-import Clang.Coformat.Variables-import Clang.Format.Descr-import Clang.Format.Descr.Operations-import Clang.Format.DescrParser-import Clang.Format.YamlConversions--liftEither' :: (MonadError String m, Show e) => String -> Either e a -> m a-liftEither' context = liftEither . first ((context <>) . show)--parseOptsDescription :: (MonadError String m, MonadIO m) => FilePath -> m ([T.Text], [ConfigItemT 'Supported])-parseOptsDescription path = do-  parseResult <- liftIO $ parseFile path-  supportedOptions <- filterParsedItems <$> liftEither' "Unable to parse the file: " parseResult-  baseStyles <- case find ((== bosKey) . name) supportedOptions of-                     Nothing -> throwError "No `BasedOnStyle` option"-                     Just stys -> pure stys-  let varyingOptions = filter ((/= bosKey) . name) supportedOptions-  case value baseStyles of-       CTEnum { .. } -> pure (variants, varyingOptions)-       _ -> throwError [i|Unknown type for the `BaseStyles` option: #{value baseStyles}|]-  where-    bosKey = ["BasedOnStyle"]--hardcodedOpts :: [ConfigItemT 'Value]-hardcodedOpts = [ ConfigItem { name = ["Language"], value = CTEnum ["Cpp"] "Cpp" }-                , ConfigItem { name = ["BreakBeforeBraces"], value = CTEnum ["Custom"] "Custom" }-                , ConfigItem { name = ["DisableFormat"], value = CTBool False }-                , ConfigItem { name = ["SortIncludes"], value = CTBool False }-                ]--data InitializeOptionsResult = InitializeOptionsResult-  { baseStyle :: T.Text-  , baseScore :: Score-  , baseOptions :: [ConfigItemT 'Value]-  , filledOptions :: [ConfigItemT 'Value]-  , userForcedOpts :: [ConfigItemT 'Value]-  }--initializeOptions :: (MonadError String m, MonadLoggerIO m)-                  => [PreparedFile] -> Maybe FilePath -> [String] -> m InitializeOptionsResult-initializeOptions preparedFiles maybeResumePath forceStrs = do-  (baseStyles, allOptions) <- parseOptsDescription "data/ClangFormatStyleOptions-9.html"-  let varyingOptions = filter (not . (`elem` hardcodedOptsNames) . name) allOptions-  userForcedOpts <- parseUserOpts forceStrs allOptions--  maybeResumeObj <- for maybeResumePath $ liftIO . BS.readFile-                                      >=> convert (show @FillError) . preprocessYaml PartialConfig-  maybeResumeOptions <- for maybeResumeObj $ convert (show @FillError) . collectConfigItems varyingOptions--  let allFixedOpts = hardcodedOpts <> userForcedOpts--  (baseStyle, baseScore) <--      case maybeResumeObj of-           Nothing -> chooseBaseStyle baseStyles allFixedOpts preparedFiles-           Just resumeObj -> do-              baseStyle <- EC.liftMaybe ("Unable to find `BasedOnStyle` key in the resume file" :: String)-                        $ HM.lookup "BasedOnStyle" resumeObj ^? _Just . _String-              constantOpts <- convert (show @FillError) $ collectConfigItems varyingOptions resumeObj-              score <- convert (show @Failure) $ flip runReaderT FmtEnv { .. } $ runClangFormatFiles allFixedOpts [i|Calculating the score of the resumed-from style|]-              pure (baseStyle, score)--  logInfoN [i|Using initial style: #{baseStyle} with score of #{baseScore}|]-  let formattedBaseSty = BSL.unpack $ formatStyArg $ StyOpts { basedOnStyle = baseStyle, additionalOpts = allFixedOpts }-  stdout <- convert (show @Failure) $ checked [sh|clang-format --style='#{formattedBaseSty}' --dump-config|]-  baseOptions <- convert (show @FillError) $ fillConfigItems varyingOptions $ BSL.toStrict $ TL.encodeUtf8 stdout--  let filledOptions | Just resumeOptions <- maybeResumeOptions = baseOptions `replaceItemsWith` resumeOptions-                    | otherwise = baseOptions--  pure InitializeOptionsResult { .. }-  where-    hardcodedOptsNames = name <$> hardcodedOpts--parseUserOpts :: (MonadError String m, ParseableConfigState f) => [String] -> [ConfigItemT f] -> m [ConfigItemT 'Value]-parseUserOpts opts baseOpts = forM opts $ splitStr >=> findBaseOpt >=> uncurry parseConfigValue-  where-    splitStr str | (name, _:valStr) <- break (== ':') str = pure (T.splitOn "." $ T.pack name, valStr)-                 | otherwise = throwError [i|Unable to parse `#{str}`: it should have the form of `name:value`|]-    findBaseOpt (name, valStr) | Just item <- HM.lookup name baseOptsMap = pure (item, valStr)-                               | otherwise = throwError [i|Unable to find option `#{name}`|]--    baseOptsMap = HM.fromList [ (name item, item) | item <- baseOpts]--data PipelineOpts = PipelineOpts-  { maxSubsetSize :: Maybe Natural-  , resumePath :: Maybe FilePath-  , input :: NonEmpty FilePath-  , taskGroup :: TaskGroup-  , forceStrs :: [String]-  }--runOptPipeline :: (MonadError String m, MonadLoggerIO m)-               => PipelineOpts -> m BS.ByteString-runOptPipeline PipelineOpts { .. } = do-  preparedFiles <- mapM prepareFile $ toList input--  InitializeOptionsResult { .. } <- initializeOptions preparedFiles resumePath forceStrs--  let categoricalVariables = [ IxedVariable dv idx-                             | (Just dv, idx) <- zip (typToDV . value <$> filledOptions) [0..]-                             ]-  let integralVariables = [ IxedVariable dv idx-                          | (Just dv, idx) <- zip (typToIV . value <$> filledOptions) [0..]-                          ]-  let constantOpts = hardcodedOpts <> userForcedOpts-  let fmtEnv = FmtEnv { .. }-  let optEnv = OptEnv { maxSubsetSize = fromMaybe 1 maxSubsetSize, .. }-  let optState = initOptState filledOptions baseScore-  finalOptState <- convert (show @UnexpectedFailure) $ flip runReaderT (fmtEnv, optEnv, taskGroup) $ execStateT (fixGD Nothing 1) optState-  let finalStyOpts = StyOpts { basedOnStyle = baseStyle-                             , additionalOpts = constantOpts <> currentOpts finalOptState `subtractMatching` baseOptions-                             }-  pure $ formatClangFormat finalStyOpts
− src/Clang/Coformat/Score.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE DeriveGeneric, DerivingVia #-}-{-# LANGUAGE RecordWildCards, QuasiQuotes #-}--module Clang.Coformat.Score-( Score-, calcScore--, PreparedFile-, filename-, prepareFile-) where--import qualified Data.ByteString.Char8 as BS-import qualified Data.IntMap.Strict as IM-import Control.Monad.IO.Class-import Data.Char-import Data.Monoid-import Data.String.Interpolate-import GHC.Generics-import Generic.Data--type CharsHist = IM.IntMap Int--data PreparedFile = PreparedFile-  { filename :: FilePath-  , contents :: BS.ByteString-  , charsHist :: CharsHist-  } deriving (Eq)--prepareFile :: MonadIO m => FilePath -> m PreparedFile-prepareFile filename = do-  contents <- liftIO $ BS.readFile filename-  let charsHist = calcCharsHist contents-  pure $ PreparedFile { .. }--data Score = Score-  { significantLettersCountsDiff :: Sum Int-  , spacesMisalignment :: Sum Int-  } deriving (Eq, Ord, Bounded, Generic)-    deriving (Semigroup, Monoid) via (Generically Score)--instance Show Score where-  show Score { .. } = [i|Score { #{getSum significantLettersCountsDiff} / #{getSum spacesMisalignment} }|]--calcScore :: PreparedFile -> BS.ByteString -> Score-calcScore prepared str = Score { .. }-  where-    significantLettersCountsDiff = Sum $ calcCharsDiff (charsHist prepared) (calcCharsHist str)-    spacesMisalignment | significantLettersCountsDiff /= 0 = 0-                       | otherwise = Sum $ alignSpaces (contents prepared) str--calcCharsDiff :: CharsHist -> CharsHist -> Int-calcCharsDiff hm1 hm2 = sum $ IM.elems $ IM.unionWith (\v1 v2 -> abs $ v1 - v2) hm1 hm2--calcCharsHist :: BS.ByteString -> CharsHist-calcCharsHist = BS.foldl' ins mempty-  where-    ins hm ch | isSpace ch = hm-              | otherwise = IM.insertWith (+) (ord ch) 1 hm--alignSpaces :: BS.ByteString -> BS.ByteString -> Int-alignSpaces bs1 bs2 = go (BS.unpack bs1) (BS.unpack bs2)-  where-    go s1 [] = length s1-    go [] s2 = length s2-    go (c1:s1) (c2:s2) | c1 == c2 = go s1 s2-                       | isSpace c1 && isSpace c2 = 2 + go s1 s2-                       | isSpace c1 = 1 + go s1 (c2:s2)-                       | isSpace c2 = 1 + go (c1:s1) s2-                       | otherwise = 2 + length s1 + length s2
− src/Clang/Coformat/StyOpts.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts, GADTs #-}-{-# LANGUAGE RecordWildCards, OverloadedStrings #-}--module Clang.Coformat.StyOpts where--import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T-import Control.Lens-import Data.Aeson-import Data.Aeson.Lens(_Object)-import Data.List-import Data.Maybe-import Data.Void--import Clang.Format.Descr--data StyOpts = StyOpts-  { basedOnStyle :: T.Text-  , additionalOpts :: [ConfigItemT 'Value]-  }--instance ToJSON StyOpts where-  toJSON StyOpts { .. } = Object $ foldl' f (HM.singleton "BasedOnStyle" $ String basedOnStyle) additionalOpts-    where-      f hm ConfigItem { .. } = updateRec value name hm--      updateRec value [key] = HM.insert key (toJson value)-      updateRec value (key:rest) = HM.alter (Just . Object . updateRec value rest . getObj) key-      updateRec _ [] = id-      getObj = fromMaybe mempty . ((^? _Object) =<<)--      toJson (CTInt n) = Number $ fromIntegral n-      toJson (CTUnsigned n) = Number $ fromIntegral n-      toJson (CTString v) = absurd v-      toJson (CTStringVec v) = absurd v-      toJson (CTRawStringFormats v) = absurd v-      toJson (CTIncludeCats v) = absurd v-      toJson (CTBool b) = Bool b-      toJson (CTEnum _ opt) = String opt--formatStyArg :: StyOpts -> BSL.ByteString-formatStyArg = encode
− src/Clang/Coformat/Util.hs
@@ -1,78 +0,0 @@-{-# LANGUAGE FlexibleContexts, RankNTypes #-}-{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}--module Clang.Coformat.Util where--import qualified Control.Concurrent.Async as A-import qualified Control.Concurrent.Async.Pool as A.P-import qualified Control.Monad.Except as E-import qualified Control.Monad.Reader as R-import qualified Data.Text.Lazy as TL-import Control.Monad.Except.CoHas-import Control.Monad.Logger-import Control.Monad.Reader.Has-import Data.Bifunctor-import GHC.Generics-import Numeric.Natural-import System.Exit--data ExpectedFailure = FormatterSegfaulted TL.Text   -- kek-  deriving (Eq, Show)--data UnexpectedFailure = FormatterFailure-  { errorCode :: Int-  , errorOutput :: TL.Text-  } deriving (Eq, Show)--data Failure = ExpectedFailure ExpectedFailure-             | UnexpectedFailure UnexpectedFailure-             deriving (Eq, Show, Generic, CoHas ExpectedFailure, CoHas UnexpectedFailure)--failuresAreUnexpected :: Failure -> UnexpectedFailure-failuresAreUnexpected (UnexpectedFailure err) = err-failuresAreUnexpected (ExpectedFailure (FormatterSegfaulted out)) = FormatterFailure 0 out--checked :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m)-        => IO (ExitCode, TL.Text, TL.Text) -> m TL.Text-checked act = do-  (ec, stdout, stderr) <- liftIO act-  case ec of ExitSuccess -> pure stdout-             ExitFailure n | n == cfCrashRetCode -> throwError $ FormatterSegfaulted stderr-                           | otherwise -> throwError $ FormatterFailure n stderr-  where-    cfCrashRetCode = -8--update :: Int -> (a -> a) -> [a] -> [a]-update idx f = zipWith z [0..]-  where z idx' val = if idx' == idx then f val else val--forConcurrently' :: (MonadLoggerIO m, MonadError e m)-                 => [a]-                 -> (forall m'. (MonadLoggerIO m', MonadError e m') => a -> m' b)-                 -> m [b]-forConcurrently' lst act = do-  logger <- askLoggerIO-  result <- liftIO $ A.forConcurrently lst $ \elt -> flip runLoggingT logger $ runExceptT $ act elt-  E.liftEither $ sequence result--forConcurrentlyPooled :: (MonadLoggerIO m, MonadError e m, MonadReader r m, Has A.P.TaskGroup r)-                      => [a]-                      -> (forall m'. (MonadLoggerIO m', MonadReader r m', MonadError e m') => a -> m' b)-                      -> m [b]-forConcurrentlyPooled lst act = do-  logger <- askLoggerIO-  tg <- ask-  env <- R.ask-  result <- liftIO $ flip (A.P.mapConcurrently tg) lst $ \elt -> flip runLoggingT logger $ runExceptT $ flip runReaderT env $ act elt-  E.liftEither $ sequence result--convert :: MonadError e' m-        => (e -> e')-        -> ExceptT e m a-        -> m a-convert cvt act = runExceptT act >>= (E.liftEither . first cvt)--subsetsN :: Natural -> [a] -> [[a]]-subsetsN _ [] = []-subsetsN 1 xs = pure <$> xs-subsetsN n (x:xs) = ((x:) <$> subsetsN (n - 1) xs) <> subsetsN n xs
− src/Clang/Coformat/Variables.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE GADTs, TypeFamilies, DataKinds, TypeApplications, ConstraintKinds #-}-{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# OPTIONS_GHC -Wno-type-defaults #-}--module Clang.Coformat.Variables where--import qualified Data.Text as T-import Control.Lens-import Control.Monad-import Data.Kind-import Numeric.Natural--import Clang.Format.Descr--data KnownVariateType = Categorical | Integral--class Variate a where-  type VariateResult a :: Type -> Type-  type VariateType a :: KnownVariateType-  variate :: a -> VariateResult a a-  varPrism :: Prism' (ConfigTypeT 'Value) a--data Variable varTy where-  -- TODO proxy should be enough-  MkDV :: (Variate a, VariateType a ~ varTy, Foldable (VariateResult a)) => a -> Variable varTy--data IxedVariable varTy = IxedVariable-  { discreteVar :: Variable varTy-  , varIdx :: Int-  }--type CategoricalVariate a = (Variate a, VariateType a ~ 'Categorical)-type CategoricalVariable = Variable 'Categorical-type IxedCategoricalVariable = IxedVariable 'Categorical---instance Variate Bool where-  type VariateResult Bool = []-  type VariateType Bool = 'Categorical-  variate b = [not b]-  varPrism = prism' CTBool $ \case CTBool b -> Just b-                                   _ -> Nothing--type EnumVar = ([T.Text], T.Text)--instance Variate EnumVar where-  type VariateResult EnumVar = []-  type VariateType EnumVar = 'Categorical-  variate (vars, cur) = [(vars, next) | next <- vars, next /= cur]-  varPrism = prism' (uncurry CTEnum) $ \case CTEnum vars cur -> Just (vars, cur)-                                             _ -> Nothing--typToDV :: ConfigTypeT 'Value -> Maybe CategoricalVariable-typToDV val = msum [ MkDV <$> val ^? varPrism @Bool-                   , MkDV <$> val ^? varPrism @([T.Text], T.Text)-                   ]--searchSpace :: Show a => Integral a => a -> [a]-searchSpace n = [ 2 ^ k | k <- [ 0 .. maxK ] ]-  where-    nBase = round $ logBase 2 $ fromIntegral n-    maxK | n > 100 = nBase + 1-         | otherwise = 2 * nBase--instance Variate Int where-  type VariateResult Int = []-  type VariateType Int = 'Integral-  variate n = n - 1 : n + 1 : searchSpace n <> map negate (searchSpace n)-  varPrism = prism' CTInt $ \case CTInt n -> Just n-                                  _ -> Nothing--instance Variate Natural where-  type VariateResult Natural = []-  type VariateType Natural = 'Integral-  variate n | n > 0 = n - 1 : n + 1 : searchSpace n-            | otherwise = n + 1 : searchSpace n-  varPrism = prism' CTUnsigned $ \case CTUnsigned n -> Just n-                                       _ -> Nothing--type IntegralVariate a = (Variate a, VariateType a ~ 'Integral)-type IntegralVariable = Variable 'Integral-type IxedIntegralVariable = IxedVariable 'Integral--typToIV :: ConfigTypeT 'Value -> Maybe IntegralVariable-typToIV val = msum [ MkDV <$> val ^? varPrism @Int-                   , MkDV <$> val ^? varPrism @Natural-                   ]--data SomeIxedVariable :: Type where-  SomeIxedVariable :: IxedVariable varTy -> SomeIxedVariable--asSome :: [IxedVariable varTy] -> [SomeIxedVariable]-asSome = fmap SomeIxedVariable
− src/Clang/Format/Descr.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE DataKinds, TypeFamilies #-}-{-# LANGUAGE StandaloneDeriving, FlexibleInstances #-}-{-# LANGUAGE Strict #-}--module Clang.Format.Descr where--import qualified Data.Text as T-import Data.Void-import Numeric.Natural--data Stage = Parsed | Supported | Value--type family CTData f ty where-  CTData 'Parsed _ = ()-  CTData 'Supported Void = Void-  CTData 'Supported _ = ()-  CTData 'Value ty = ty--data ConfigTypeT f-  = CTInt (CTData f Int)-  | CTUnsigned (CTData f Natural)-  | CTBool (CTData f Bool)-  | CTString (CTData f Void)-  | CTStringVec (CTData f Void)-  | CTRawStringFormats (CTData f Void)-  | CTIncludeCats (CTData f Void)-  | CTEnum { variants :: [T.Text], enumValue :: CTData f T.Text }--deriving instance Show (ConfigTypeT 'Parsed)-deriving instance Show (ConfigTypeT 'Supported)-deriving instance Show (ConfigTypeT 'Value)-deriving instance Eq (ConfigTypeT 'Value)--data ConfigItemT f = ConfigItem-  { name :: [T.Text]-  , value :: ConfigTypeT f-  }--deriving instance Show (ConfigItemT 'Parsed)-deriving instance Show (ConfigItemT 'Supported)-deriving instance Show (ConfigItemT 'Value)
− src/Clang/Format/Descr/Operations.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE DataKinds, GADTs, ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}-{-# LANGUAGE RecordWildCards, LambdaCase, QuasiQuotes, OverloadedStrings #-}--module Clang.Format.Descr.Operations where--import qualified Data.HashMap.Strict as HM-import qualified Data.Map.Strict as M-import qualified Data.Text as T-import Control.Monad.Except-import Data.Bifunctor-import Data.Maybe-import Data.String.Interpolate.IsString-import Data.Typeable-import Data.Void-import Text.Read--import Clang.Format.Descr--filterParsedItems :: [ConfigItemT 'Parsed] -> [ConfigItemT 'Supported]-filterParsedItems = mapMaybe $ \ConfigItem { .. } -> ConfigItem name <$> filterType value-  where-    filterType = \case-                    CTInt () -> Just $ CTInt ()-                    CTUnsigned () -> Just $ CTUnsigned ()-                    CTBool () -> Just $ CTBool ()-                    CTString () -> Nothing-                    CTStringVec () -> Nothing-                    CTRawStringFormats () -> Nothing-                    CTIncludeCats () -> Nothing-                    CTEnum vars () -> Just $ CTEnum vars ()--replaceItemsWith :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]-replaceItemsWith l1 l2 = M.elems $ toMap l2 <> toMap l1-  where-    toMap lst = M.fromList [ (name item, item) | item <- lst ]--subtractMatching :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]-subtractMatching minuend subtrahend = filter f minuend-  where-    f ConfigItem { .. } = (/= Just value) $ HM.lookup name subMap-    subMap = HM.fromList [ (name, value) | ConfigItem { .. } <- subtrahend]--type ParseableConfigState f = (CTData f Void ~ Void, Show (ConfigTypeT f))--parseConfigValue :: (MonadError String m, ParseableConfigState f) => ConfigItemT f -> String -> m (ConfigItemT 'Value)-parseConfigValue cfg str = liftEither $ (\parsed -> ConfigItem { name = name cfg, value = parsed }) <$> eitherParsed-  where-    eitherParsed = case value cfg of-                        CTInt _ -> CTInt <$> readEither'-                        CTUnsigned _ -> CTUnsigned <$> readEither'-                        CTBool _ -> CTBool <$> readEither'-                        CTString val -> absurd val-                        CTStringVec val -> absurd val-                        CTRawStringFormats val -> absurd val-                        CTIncludeCats val -> absurd val-                        CTEnum variants _ | var `elem` variants -> pure $ CTEnum variants var-                                          | otherwise -> throwError [i|Unsupported option `#{var}`, supported ones are `#{T.intercalate "`, `" variants}`|]-                            where var = T.pack str-    readEither' :: forall a. (Typeable a, Read a) => Either String a-    readEither' = first (\err -> [i|Error parsing #{str} as #{typeRep (Proxy :: Proxy a)}: #{err}, expected type: #{value cfg}|]) $ readEither str
src/Clang/Format/DescrParser.hs view
@@ -2,8 +2,7 @@ {-# LANGUAGE DataKinds, GADTs #-}  module Clang.Format.DescrParser-( parseFile-, parseDescr+( parseDescr ) where  import qualified Data.ByteString.Lazy.Char8 as LBS@@ -19,10 +18,7 @@ import Text.XML.Selector.TH import Text.XML.Selector.Types -import Clang.Format.Descr--parseFile :: FilePath -> IO (Either String [ConfigItemT 'Parsed])-parseFile = fmap parseDescr . LBS.readFile+import Language.Coformat.Descr  parseDescr :: LBS.ByteString -> Either String [ConfigItemT 'Parsed] parseDescr = parseCursor . fromDocument . parseLBS
+ src/Clang/Format/Formatter.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE GADTs, TypeApplications, DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards, QuasiQuotes, OverloadedStrings #-}++module Clang.Format.Formatter(clangFormatter) where++import qualified Control.Monad.Except.CoHas as EC+import qualified Data.ByteString.Char8 as BS+import qualified Data.ByteString.Lazy.Char8 as LBS+import qualified Data.HashMap.Strict as HM+import Control.Lens+import Control.Monad.Except+import Data.Aeson.Lens+import Data.Bifunctor+import Data.List+import Data.String.Interpolate++import Clang.Format.DescrParser+import Clang.Format.StyOpts+import Clang.Format.YamlConversions+import Language.Coformat.Descr+import Language.Coformat.Descr.Operations+import Language.Coformat.Formatter+import Language.Coformat.Util++clangFormatter :: Formatter+clangFormatter = Formatter { .. }+  where+    formatterInfo = FormatterInfo { .. }+      where+        execName = "clang-format"+        formatterOpts = OptsFromFile "data/ClangFormatStyleOptions-9.html" parseOptsDescription+        hardcodedOpts = [ ConfigItem { name = ["Language"], value = CTEnum ["Cpp"] "Cpp" }+                        , ConfigItem { name = ["BreakBeforeBraces"], value = CTEnum ["Custom"] "Custom" }+                        , ConfigItem { name = ["DisableFormat"], value = CTBool False }+                        , ConfigItem { name = ["SortIncludes"], value = CTBool False }+                        ]+        defaultStyleOpts sty supported allFixedOpts = OptsFromCmd (CmdArgs args) parser+          where+            args = [ "--style=" <> formattedBaseSty, "--dump-config" ]+            parser = convert (show @FillError) . fillConfigItems supported+            formattedBaseSty = formatStyArg $ StyOpts { basedOnStyle = sty, additionalOpts = allFixedOpts }++        formatFile baseSty opts path = CmdArgs { args = [ "--style=" <> formattedBaseSty, BS.pack path ] }+          where+            formattedBaseSty = formatStyArg $ StyOpts { basedOnStyle = baseSty, additionalOpts = opts }++        serializeOptions baseSty opts = formatClangFormat StyOpts { basedOnStyle = baseSty, additionalOpts = opts }++    parseResumeObject = convert (show @FillError) . preprocessYaml PartialConfig+    parseResumeOptions knownOpts resumeObj = do+      baseStyle <- EC.liftMaybe ("Unable to find `BasedOnStyle` key in the resume file" :: String)+                $ HM.lookup "BasedOnStyle" resumeObj ^? _Just . _String+      opts <- convert (show @FillError) $ collectConfigItems knownOpts resumeObj+      pure (baseStyle, opts)++liftEither' :: (MonadError String m, Show e) => String -> Either e a -> m a+liftEither' context = liftEither . first ((context <>) . show)++parseOptsDescription :: LBS.ByteString -> Either String (OptsDescription 'Supported)+parseOptsDescription contents = do+  parseResult <- liftEither' "Unable to parse the file: " $ parseDescr contents+  let supportedOptions = filterParsedItems parseResult+  baseStyles <- case find ((== bosKey) . name) supportedOptions of+                     Nothing -> throwError "No `BasedOnStyle` option"+                     Just stys -> pure stys+  let varyingOptions = filter ((/= bosKey) . name) supportedOptions+  case value baseStyles of+       CTEnum { .. } -> pure $ OptsDescription { baseStyles = variants, knownOpts = varyingOptions }+       _ -> throwError [i|Unknown type for the `BaseStyles` option: #{value baseStyles}|]+  where+    bosKey = ["BasedOnStyle"]
+ src/Clang/Format/StyOpts.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts, GADTs #-}+{-# LANGUAGE RecordWildCards, OverloadedStrings #-}++module Clang.Format.StyOpts where++import qualified Data.ByteString.Char8 as BS+import qualified Data.ByteString.Lazy.Char8 as BSL+import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T+import Control.Lens+import Data.Aeson+import Data.Aeson.Lens(_Object)+import Data.List+import Data.Maybe+import Data.Void++import Language.Coformat.Descr++data StyOpts = StyOpts+  { basedOnStyle :: T.Text+  , additionalOpts :: [ConfigItemT 'Value]+  }++instance ToJSON StyOpts where+  toJSON StyOpts { .. } = Object $ foldl' f (HM.singleton "BasedOnStyle" $ String basedOnStyle) additionalOpts+    where+      f hm ConfigItem { .. } = updateRec value name hm++      updateRec value [key] = HM.insert key (toJson value)+      updateRec value (key:rest) = HM.alter (Just . Object . updateRec value rest . getObj) key+      updateRec _ [] = id+      getObj = fromMaybe mempty . ((^? _Object) =<<)++      toJson (CTInt n) = Number $ fromIntegral n+      toJson (CTUnsigned n) = Number $ fromIntegral n+      toJson (CTString v) = absurd v+      toJson (CTStringVec v) = absurd v+      toJson (CTRawStringFormats v) = absurd v+      toJson (CTIncludeCats v) = absurd v+      toJson (CTBool b) = Bool b+      toJson (CTEnum _ opt) = String opt++formatStyArg :: StyOpts -> BS.ByteString+formatStyArg = BSL.toStrict . encode
src/Clang/Format/YamlConversions.hs view
@@ -25,8 +25,8 @@ import Data.Yaml.Pretty import GHC.Generics -import Clang.Format.Descr-import Clang.Coformat.StyOpts+import Clang.Format.StyOpts+import Language.Coformat.Descr  data FillError   = YamlParseError ParseException
+ src/Language/Coformat/Descr.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DataKinds, TypeFamilies #-}+{-# LANGUAGE StandaloneDeriving, FlexibleInstances #-}+{-# LANGUAGE Strict #-}++module Language.Coformat.Descr where++import qualified Data.Text as T+import Data.Void+import Numeric.Natural++data Stage = Parsed | Supported | Value++type family CTData f ty where+  CTData 'Parsed _ = ()+  CTData 'Supported Void = Void+  CTData 'Supported _ = ()+  CTData 'Value ty = ty++data ConfigTypeT f+  = CTInt (CTData f Int)+  | CTUnsigned (CTData f Natural)+  | CTBool (CTData f Bool)+  | CTString (CTData f Void)+  | CTStringVec (CTData f Void)+  | CTRawStringFormats (CTData f Void)+  | CTIncludeCats (CTData f Void)+  | CTEnum { variants :: [T.Text], enumValue :: CTData f T.Text }++deriving instance Show (ConfigTypeT 'Parsed)+deriving instance Show (ConfigTypeT 'Supported)+deriving instance Show (ConfigTypeT 'Value)+deriving instance Eq (ConfigTypeT 'Value)++data ConfigItemT f = ConfigItem+  { name :: [T.Text]+  , value :: ConfigTypeT f+  }++deriving instance Show (ConfigItemT 'Parsed)+deriving instance Show (ConfigItemT 'Supported)+deriving instance Show (ConfigItemT 'Value)
+ src/Language/Coformat/Descr/Operations.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE DataKinds, GADTs, ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}+{-# LANGUAGE RecordWildCards, LambdaCase, QuasiQuotes, OverloadedStrings #-}++module Language.Coformat.Descr.Operations where++import qualified Data.HashMap.Strict as HM+import qualified Data.Map.Strict as M+import qualified Data.Text as T+import Control.Monad.Except+import Data.Bifunctor+import Data.Maybe+import Data.String.Interpolate.IsString+import Data.Typeable+import Data.Void+import Text.Read++import Language.Coformat.Descr++filterParsedItems :: [ConfigItemT 'Parsed] -> [ConfigItemT 'Supported]+filterParsedItems = mapMaybe $ \ConfigItem { .. } -> ConfigItem name <$> filterType value+  where+    filterType = \case+                    CTInt () -> Just $ CTInt ()+                    CTUnsigned () -> Just $ CTUnsigned ()+                    CTBool () -> Just $ CTBool ()+                    CTString () -> Nothing+                    CTStringVec () -> Nothing+                    CTRawStringFormats () -> Nothing+                    CTIncludeCats () -> Nothing+                    CTEnum vars () -> Just $ CTEnum vars ()++replaceItemsWith :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]+replaceItemsWith l1 l2 = M.elems $ toMap l2 <> toMap l1+  where+    toMap lst = M.fromList [ (name item, item) | item <- lst ]++subtractMatching :: [ConfigItemT 'Value] -> [ConfigItemT 'Value] -> [ConfigItemT 'Value]+subtractMatching minuend subtrahend = filter f minuend+  where+    f ConfigItem { .. } = (/= Just value) $ HM.lookup name subMap+    subMap = HM.fromList [ (name, value) | ConfigItem { .. } <- subtrahend]++type ParseableConfigState f = (CTData f Void ~ Void, Show (ConfigTypeT f))++parseConfigValue :: (MonadError String m, ParseableConfigState f) => ConfigItemT f -> String -> m (ConfigItemT 'Value)+parseConfigValue cfg str = liftEither $ (\parsed -> ConfigItem { name = name cfg, value = parsed }) <$> eitherParsed+  where+    eitherParsed = case value cfg of+                        CTInt _ -> CTInt <$> readEither'+                        CTUnsigned _ -> CTUnsigned <$> readEither'+                        CTBool _ -> CTBool <$> readEither'+                        CTString val -> absurd val+                        CTStringVec val -> absurd val+                        CTRawStringFormats val -> absurd val+                        CTIncludeCats val -> absurd val+                        CTEnum variants _ | var `elem` variants -> pure $ CTEnum variants var+                                          | otherwise -> throwError [i|Unsupported option `#{var}`, supported ones are `#{T.intercalate "`, `" variants}`|]+                            where var = T.pack str+    readEither' :: forall a. (Typeable a, Read a) => Either String a+    readEither' = first (\err -> [i|Error parsing #{str} as #{typeRep (Proxy :: Proxy a)}: #{err}, expected type: #{value cfg}|]) $ readEither str
+ src/Language/Coformat/Formatter.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE DataKinds, GADTs, RankNTypes, TypeApplications #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}++module Language.Coformat.Formatter where++import qualified Data.ByteString.Char8 as BS+import qualified Data.ByteString.Lazy.Char8 as LBS+import qualified Data.Text as T+import Control.Monad.Except.CoHas+import System.Command hiding(cmd)+import System.Exit++import Language.Coformat.Descr+import Language.Coformat.Formatter.Failure+import Language.Coformat.Util++data OptsDescription stage = OptsDescription+  { knownOpts :: [ConfigItemT stage]+  , baseStyles :: [T.Text]+  }++data OptsSource opts+  = StaticOpts opts+  | OptsFromFile FilePath (LBS.ByteString -> Either String opts)+  | OptsFromCmd CmdArgs (BS.ByteString -> Either String opts)++parseOpts :: (MonadIO m, MonadError String m) => String -> OptsSource opts -> m opts+parseOpts _     (StaticOpts d) = pure d+parseOpts _     (OptsFromFile path parser) = parser <$> liftIO (LBS.readFile path) >>= liftEither+parseOpts exec  (OptsFromCmd args parser) = convert (show @Failure) (runCommand exec args) >>= liftEither . parser++data FormatterInfo = FormatterInfo+  { execName :: String++  , formatterOpts :: OptsSource (OptsDescription 'Supported)+  , hardcodedOpts :: [ConfigItemT 'Value]+  , defaultStyleOpts :: T.Text -> [ConfigItemT 'Supported] -> [ConfigItemT 'Value] -> OptsSource [ConfigItemT 'Value]++  , formatFile :: T.Text -> [ConfigItemT 'Value] -> FilePath -> CmdArgs++  , serializeOptions :: T.Text -> [ConfigItemT 'Value] -> BS.ByteString+  }++newtype CmdArgs = CmdArgs+  { args :: [BS.ByteString]+  } deriving (Show)++runCommand :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m)+           => String -> CmdArgs -> m BS.ByteString+runCommand exec (CmdArgs args) = do+  (ec, stdout, stderr) <- liftIO $ command [] exec $ BS.unpack <$> args+  case ec of ExitSuccess -> pure $ BS.pack $ fromStdout stdout+             ExitFailure n | n == cfCrashRetCode -> throwError $ FormatterSegfaulted $ T.pack $ fromStderr stderr+                           | otherwise -> throwError $ FormatterFailure n $ T.pack $ fromStderr stderr+  where+    cfCrashRetCode = -8++data Formatter where+  Formatter :: forall resumeObj.+               { formatterInfo :: FormatterInfo+               , parseResumeObject :: BS.ByteString -> Either String resumeObj+               , parseResumeOptions :: [ConfigItemT 'Supported] -> resumeObj -> Either String (T.Text, [ConfigItemT 'Value])+               } -> Formatter
+ src/Language/Coformat/Formatter/Failure.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}++module Language.Coformat.Formatter.Failure where++import qualified Data.Text as T+import Control.Monad.Except.CoHas+import GHC.Generics++data ExpectedFailure = FormatterSegfaulted T.Text   -- kek+  deriving (Eq, Show)++data UnexpectedFailure = FormatterFailure+  { errorCode :: Int+  , errorOutput :: T.Text+  } deriving (Eq, Show)++data Failure = ExpectedFailure ExpectedFailure+             | UnexpectedFailure UnexpectedFailure+             deriving (Eq, Show, Generic, CoHas ExpectedFailure, CoHas UnexpectedFailure)++failuresAreUnexpected :: Failure -> UnexpectedFailure+failuresAreUnexpected (UnexpectedFailure err) = err+failuresAreUnexpected (ExpectedFailure (FormatterSegfaulted out)) = FormatterFailure 0 out
+ src/Language/Coformat/Optimization.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE GADTs, DataKinds, TypeApplications, RankNTypes, ScopedTypeVariables, ConstraintKinds #-}+{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}+{-# LANGUAGE QuasiQuotes, RecordWildCards, TupleSections, LambdaCase, OverloadedStrings #-}++module Language.Coformat.Optimization where++import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T+import Control.Concurrent.Async.Pool+import Control.Lens+import Control.Monad.Except.CoHas+import Control.Monad.Extra+import Control.Monad.Logger+import Control.Monad.Reader.Has hiding(update)+import Control.Monad.State.Strict+import Data.Foldable+import Data.List+import Data.Ord+import Data.Proxy+import Data.String.Interpolate.IsString+import Numeric.Natural++import Language.Coformat.Descr+import Language.Coformat.Formatter+import Language.Coformat.Formatter.Failure+import Language.Coformat.Score+import Language.Coformat.Util+import Language.Coformat.Variables++data FmtEnv = FmtEnv+  { baseStyle :: T.Text+  , preparedFiles :: [PreparedFile]+  , constantOpts :: [ConfigItemT 'Value]+  , formatterInfo :: FormatterInfo+  }++data OptEnv = OptEnv+  { categoricalVariables :: [IxedCategoricalVariable]+  , integralVariables :: [IxedIntegralVariable]+  , maxSubsetSize :: Natural+  }++runFormat :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m, MonadLogger m)+          => FormatterInfo -> PreparedFile -> String -> T.Text -> [ConfigItemT 'Value] -> m Score+runFormat FormatterInfo { .. } prepared logStr baseSty opts = do+  stdout <- runCommand execName $ formatFile baseSty opts $ filename prepared+  let dist = calcScore prepared stdout+  logDebugN [i|#{logStr}: #{dist}|]+  pure dist++type OptMonad err r m = (MonadLoggerIO m, MonadError err m, CoHas UnexpectedFailure err, MonadReader r m, Has FmtEnv r)++runFormatFiles :: (OptMonad err r m, CoHas ExpectedFailure err)+               => [ConfigItemT 'Value] -> String -> m Score+runFormatFiles varOpts logStr = do+  FmtEnv { .. } <- ask+  fmap mconcat $ forM preparedFiles $ \prepared -> runFormat formatterInfo prepared [i|#{logStr} at #{filename prepared}|] baseStyle $ constantOpts <> varOpts++chooseBaseStyle :: (MonadError String m, MonadLoggerIO m)+                => FormatterInfo -> [T.Text] -> [ConfigItemT 'Value] -> [PreparedFile] -> m (T.Text, Score)+chooseBaseStyle formatter baseStyles predefinedOpts files = do+  sty2dists <- forConcurrently' ((,) <$> baseStyles <*> files) $ \(sty, file) ->+    convert (show @(Either ExpectedFailure UnexpectedFailure)) $ (sty,) <$> runFormat formatter file [i|Initial guess for #{sty} at #{filename file}|] sty predefinedOpts+  let accumulated = HM.toList $ HM.fromListWith (<>) sty2dists+  forM_ accumulated $ \(sty, acc) -> logInfoN [i|Initial accumulated guess for #{sty}: #{acc}|]+  pure $ minimumBy (comparing snd) accumulated++variateAt :: forall a. (Variate a, Foldable (VariateResult a))+          => Proxy a -> Int -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]+variateAt _ idx opts = [ update idx (updater v') opts | v' <- toList variated ]+  where+    thePrism :: Prism' (ConfigTypeT 'Value) a+    thePrism = varPrism+    variated = variate $ value (opts !! idx) ^?! thePrism+    updater v cfg = cfg { value = value cfg & thePrism .~ v }++data OptState = OptState+  { currentOpts :: [ConfigItemT 'Value]+  , currentScore :: Score+  } deriving (Show)++initOptState :: [ConfigItemT 'Value] -> Score -> OptState+initOptState currentOpts currentScore = OptState { .. }++dropExpectedFailures :: OptMonad err r m+                     => (forall err' r' m'. (OptMonad err' r' m', CoHas ExpectedFailure err') => m' Score)+                     -> m Score+dropExpectedFailures act = do+  res <- runExceptT act+  case res of+       Left (UnexpectedFailure failure) -> throwError failure+       Left (ExpectedFailure failure) -> do+         logErrorN [i|Unable to run the formatter: #{show failure}|]+         pure maxBound+       Right sc -> pure sc++variateSubset :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> [[ConfigItemT 'Value]]+variateSubset [] opts = [opts]+variateSubset (SomeIxedVariable (IxedVariable (MkDV (_ :: a)) idx) : rest) opts = concatMap (variateSubset rest) $ variateAt @a Proxy idx opts++showVariated :: [SomeIxedVariable] -> [ConfigItemT 'Value] -> String+showVariated vars opts = intercalate ", " [showVar var | var <- vars]+  where+    showVar (SomeIxedVariable (IxedVariable _ idx)) = [i|#{name $ opts !! idx} -> #{value $ opts !! idx}|]++chooseBestSubset :: (OptMonad err r m, Has OptState r, Has TaskGroup r)+                 => Natural -> [SomeIxedVariable] -> m (Maybe ([ConfigItemT 'Value], Score))+chooseBestSubset subsetSize ixedVariables = do+  OptState { .. } <- ask+  FmtEnv { .. } <- ask+  partialResults <- forConcurrentlyPooled (subsetsN subsetSize ixedVariables) $ \someVarsSubset -> do+    opt2scores <- forM (variateSubset someVarsSubset currentOpts) $ \opts' ->+      fmap (opts',) $ dropExpectedFailures $ runFormatFiles opts' $ showVariated someVarsSubset opts'+    let (bestOpts, bestScore) = minimumBy (comparing snd) opt2scores+    when (bestScore < currentScore) $+      logInfoN [i|Total dist for #{showVariated someVarsSubset bestOpts}: #{currentScore} -> #{bestScore}|]+    pure (bestOpts, bestScore, someVarsSubset)+  let (bestOpts, bestScore, bestVarsSubset) = minimumBy (comparing (^. _2)) partialResults+  if bestScore < currentScore+    then do+      logInfoN [i|Choosing #{showVariated bestVarsSubset bestOpts}|]+      pure $ Just (bestOpts, bestScore)+    else pure Nothing++stepGDGeneric' :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m)+               => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()+stepGDGeneric' subsetSize varGetters = do+  current <- get+  fmtEnv@FmtEnv { .. } <- ask+  optEnv <- ask+  tg :: TaskGroup <- ask+  runReaderT (chooseBestSubset subsetSize $ concatMap ($ optEnv) varGetters) (current, fmtEnv, tg) >>=+    \case Nothing -> pure ()+          Just (opts', score') -> do+            logInfoN [i|Total score after optimization on all files: #{score'}|]+            put OptState { currentOpts = opts', currentScore = score' }++stepGDGeneric :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m)+              => Natural -> [OptEnv -> [SomeIxedVariable]] -> m ()+stepGDGeneric subsetSize varGetters = whenM ((> mempty) <$> gets currentScore) $ stepGDGeneric' subsetSize varGetters++fixGD :: (OptMonad err r m, Has TaskGroup r, Has OptEnv r, MonadState OptState m, err ~ UnexpectedFailure)+      => Maybe Int -> Natural -> m ()+fixGD (Just 0) _ = pure ()+fixGD counter curSubsetSize = do+  maxSubsetSize' <- asks maxSubsetSize+  if curSubsetSize > maxSubsetSize'+    then logInfoN [i|Done optimizing|]+    else do+      startScore <- gets currentScore+      stepGDGeneric curSubsetSize [asSome . categoricalVariables, asSome . integralVariables]+      endScore <- gets currentScore+      logInfoN [i|Full optimization step done, went from #{startScore} to #{endScore}|]+      if startScore /= endScore+        then fixGD (subtract 1 <$> counter) 1+        else do+          logInfoN [i|Done optimizing with subset size #{curSubsetSize}, stopped at score #{endScore}|]+          fixGD (subtract 1 <$> counter) (curSubsetSize + 1)
+ src/Language/Coformat/Pipeline.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds, GADTs #-}+{-# LANGUAGE TypeApplications, OverloadedStrings, RecordWildCards, QuasiQuotes #-}++module Language.Coformat.Pipeline+( runOptPipeline+, PipelineOpts(..)+) where++import qualified Data.ByteString.Char8 as BS+import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T+import Control.Concurrent.Async.Pool+import Control.Monad.Except+import Control.Monad.Logger+import Control.Monad.Reader+import Control.Monad.State.Strict+import Data.Foldable+import Data.List.NonEmpty(NonEmpty)+import Data.Maybe+import Data.String.Interpolate.IsString+import Data.Traversable+import Numeric.Natural++import Language.Coformat.Descr+import Language.Coformat.Descr.Operations+import Language.Coformat.Formatter+import Language.Coformat.Formatter.Failure+import Language.Coformat.Optimization+import Language.Coformat.Score+import Language.Coformat.Util+import Language.Coformat.Variables++data InitializeOptionsResult = InitializeOptionsResult+  { baseStyle :: T.Text+  , baseScore :: Score+  , baseOptions :: [ConfigItemT 'Value]+  , filledOptions :: [ConfigItemT 'Value]+  , userForcedOpts :: [ConfigItemT 'Value]+  }++initializeOptions :: (MonadError String m, MonadLoggerIO m)+                  => Formatter -> [PreparedFile] -> Maybe FilePath -> [String] -> m InitializeOptionsResult+initializeOptions Formatter { formatterInfo = formatterInfo@FormatterInfo { .. }, .. } preparedFiles maybeResumePath forceStrs = do+  OptsDescription { .. } <- parseOpts execName formatterOpts+  let varyingOptions = filter (not . (`elem` hardcodedOptsNames) . name) knownOpts+  userForcedOpts <- parseUserOpts forceStrs knownOpts++  let allFixedOpts = hardcodedOpts <> userForcedOpts++  maybeResumeObj <- for maybeResumePath $ liftIO . BS.readFile >=> liftEither . parseResumeObject+  maybeResumeOptions <- for maybeResumeObj $ liftEither . parseResumeOptions varyingOptions++  (baseStyle, baseScore) <-+      case maybeResumeOptions of+           Nothing -> chooseBaseStyle formatterInfo baseStyles allFixedOpts preparedFiles+           Just (baseStyle, constantOpts) -> do+              let fmtAct = runFormatFiles allFixedOpts [i|Calculating the score of the resumed-from style|]+              score <- convert (show @Failure) $ runReaderT fmtAct FmtEnv { .. }+              pure (baseStyle, score)++  logInfoN [i|Using initial style: #{baseStyle} with score of #{baseScore}|]+  baseOptions <- parseOpts execName $ defaultStyleOpts baseStyle varyingOptions allFixedOpts++  let filledOptions | Just (_, resumeOptions) <- maybeResumeOptions = baseOptions `replaceItemsWith` resumeOptions+                    | otherwise = baseOptions++  pure InitializeOptionsResult { .. }+  where+    hardcodedOptsNames = name <$> hardcodedOpts++parseUserOpts :: (MonadError String m, ParseableConfigState f) => [String] -> [ConfigItemT f] -> m [ConfigItemT 'Value]+parseUserOpts opts baseOpts = forM opts $ splitStr >=> findBaseOpt >=> uncurry parseConfigValue+  where+    splitStr str | (name, _:valStr) <- break (== ':') str = pure (T.splitOn "." $ T.pack name, valStr)+                 | otherwise = throwError [i|Unable to parse `#{str}`: it should have the form of `name:value`|]+    findBaseOpt (name, valStr) | Just item <- HM.lookup name baseOptsMap = pure (item, valStr)+                               | otherwise = throwError [i|Unable to find option `#{name}`|]++    baseOptsMap = HM.fromList [ (name item, item) | item <- baseOpts]++data PipelineOpts = PipelineOpts+  { maxSubsetSize :: Maybe Natural+  , resumePath :: Maybe FilePath+  , input :: NonEmpty FilePath+  , taskGroup :: TaskGroup+  , forceStrs :: [String]+  , formatter :: Formatter+  }++runOptPipeline :: (MonadError String m, MonadLoggerIO m)+               => PipelineOpts -> m BS.ByteString+runOptPipeline PipelineOpts { formatter = formatter@Formatter { .. }, .. } = do+  preparedFiles <- mapM prepareFile $ toList input++  InitializeOptionsResult { .. } <- initializeOptions formatter preparedFiles resumePath forceStrs++  let categoricalVariables = [ IxedVariable dv idx+                             | (Just dv, idx) <- zip (typToDV . value <$> filledOptions) [0..]+                             ]+  let integralVariables = [ IxedVariable dv idx+                          | (Just dv, idx) <- zip (typToIV . value <$> filledOptions) [0..]+                          ]+  let constantOpts = hardcodedOpts formatterInfo <> userForcedOpts+  let fmtEnv = FmtEnv { .. }+  let optEnv = OptEnv { maxSubsetSize = fromMaybe 1 maxSubsetSize, .. }+  let optState = initOptState filledOptions baseScore+  finalOptState <- convert (show @UnexpectedFailure) $ flip runReaderT (fmtEnv, optEnv, taskGroup) $ execStateT (fixGD Nothing 1) optState+  pure $ serializeOptions formatterInfo baseStyle $ constantOpts <> currentOpts finalOptState `subtractMatching` baseOptions
+ src/Language/Coformat/Score.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE DeriveGeneric, DerivingVia #-}+{-# LANGUAGE RecordWildCards, QuasiQuotes #-}++module Language.Coformat.Score+( Score+, calcScore++, PreparedFile+, filename+, prepareFile+) where++import qualified Data.ByteString.Char8 as BS+import qualified Data.IntMap.Strict as IM+import Control.Monad.IO.Class+import Data.Char+import Data.Monoid+import Data.String.Interpolate+import GHC.Generics+import Generic.Data++type CharsHist = IM.IntMap Int++data PreparedFile = PreparedFile+  { filename :: FilePath+  , contents :: BS.ByteString+  , charsHist :: CharsHist+  } deriving (Eq)++prepareFile :: MonadIO m => FilePath -> m PreparedFile+prepareFile filename = do+  contents <- liftIO $ BS.readFile filename+  let charsHist = calcCharsHist contents+  pure $ PreparedFile { .. }++data Score = Score+  { significantLettersCountsDiff :: Sum Int+  , spacesMisalignment :: Sum Int+  } deriving (Eq, Ord, Bounded, Generic)+    deriving (Semigroup, Monoid) via (Generically Score)++instance Show Score where+  show Score { .. } = [i|Score { #{getSum significantLettersCountsDiff} / #{getSum spacesMisalignment} }|]++calcScore :: PreparedFile -> BS.ByteString -> Score+calcScore prepared str = Score { .. }+  where+    significantLettersCountsDiff = Sum $ calcCharsDiff (charsHist prepared) (calcCharsHist str)+    spacesMisalignment | significantLettersCountsDiff /= 0 = 0+                       | otherwise = Sum $ alignSpaces (contents prepared) str++calcCharsDiff :: CharsHist -> CharsHist -> Int+calcCharsDiff hm1 hm2 = sum $ IM.elems $ IM.unionWith (\v1 v2 -> abs $ v1 - v2) hm1 hm2++calcCharsHist :: BS.ByteString -> CharsHist+calcCharsHist = BS.foldl' ins mempty+  where+    ins hm ch | isSpace ch = hm+              | otherwise = IM.insertWith (+) (ord ch) 1 hm++alignSpaces :: BS.ByteString -> BS.ByteString -> Int+alignSpaces bs1 bs2 = go (BS.unpack bs1) (BS.unpack bs2)+  where+    go s1 [] = length s1+    go [] s2 = length s2+    go (c1:s1) (c2:s2) | c1 == c2 = go s1 s2+                       | isSpace c1 && isSpace c2 = 2 + go s1 s2+                       | isSpace c1 = 1 + go s1 (c2:s2)+                       | isSpace c2 = 1 + go (c1:s1) s2+                       | otherwise = 2 + length s1 + length s2
+ src/Language/Coformat/Util.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE FlexibleContexts, RankNTypes #-}++module Language.Coformat.Util where++import qualified Control.Concurrent.Async as A+import qualified Control.Concurrent.Async.Pool as A.P+import qualified Control.Monad.Except as E+import qualified Control.Monad.Reader as R+import Control.Monad.Except.CoHas+import Control.Monad.Logger+import Control.Monad.Reader.Has+import Data.Bifunctor+import Numeric.Natural++update :: Int -> (a -> a) -> [a] -> [a]+update idx f = zipWith z [0..]+  where z idx' val = if idx' == idx then f val else val++forConcurrently' :: (MonadLoggerIO m, MonadError e m)+                 => [a]+                 -> (forall m'. (MonadLoggerIO m', MonadError e m') => a -> m' b)+                 -> m [b]+forConcurrently' lst act = do+  logger <- askLoggerIO+  result <- liftIO $ A.forConcurrently lst $ \elt -> flip runLoggingT logger $ runExceptT $ act elt+  E.liftEither $ sequence result++forConcurrentlyPooled :: (MonadLoggerIO m, MonadError e m, MonadReader r m, Has A.P.TaskGroup r)+                      => [a]+                      -> (forall m'. (MonadLoggerIO m', MonadReader r m', MonadError e m') => a -> m' b)+                      -> m [b]+forConcurrentlyPooled lst act = do+  logger <- askLoggerIO+  tg <- ask+  env <- R.ask+  result <- liftIO $ flip (A.P.mapConcurrently tg) lst $ \elt -> flip runLoggingT logger $ runExceptT $ flip runReaderT env $ act elt+  E.liftEither $ sequence result++convert :: MonadError e' m+        => (e -> e')+        -> ExceptT e m a+        -> m a+convert cvt act = runExceptT act >>= (E.liftEither . first cvt)++subsetsN :: Natural -> [a] -> [[a]]+subsetsN _ [] = []+subsetsN 1 xs = pure <$> xs+subsetsN n (x:xs) = ((x:) <$> subsetsN (n - 1) xs) <> subsetsN n xs
+ src/Language/Coformat/Variables.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE GADTs, TypeFamilies, DataKinds, TypeApplications, ConstraintKinds #-}+{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# OPTIONS_GHC -Wno-type-defaults #-}++module Language.Coformat.Variables where++import qualified Data.Text as T+import Control.Lens+import Control.Monad+import Data.Kind+import Numeric.Natural++import Language.Coformat.Descr++data KnownVariateType = Categorical | Integral++class Variate a where+  type VariateResult a :: Type -> Type+  type VariateType a :: KnownVariateType+  variate :: a -> VariateResult a a+  varPrism :: Prism' (ConfigTypeT 'Value) a++data Variable varTy where+  -- TODO proxy should be enough+  MkDV :: (Variate a, VariateType a ~ varTy, Foldable (VariateResult a)) => a -> Variable varTy++data IxedVariable varTy = IxedVariable+  { discreteVar :: Variable varTy+  , varIdx :: Int+  }++type CategoricalVariate a = (Variate a, VariateType a ~ 'Categorical)+type CategoricalVariable = Variable 'Categorical+type IxedCategoricalVariable = IxedVariable 'Categorical+++instance Variate Bool where+  type VariateResult Bool = []+  type VariateType Bool = 'Categorical+  variate b = [not b]+  varPrism = prism' CTBool $ \case CTBool b -> Just b+                                   _ -> Nothing++type EnumVar = ([T.Text], T.Text)++instance Variate EnumVar where+  type VariateResult EnumVar = []+  type VariateType EnumVar = 'Categorical+  variate (vars, cur) = [(vars, next) | next <- vars, next /= cur]+  varPrism = prism' (uncurry CTEnum) $ \case CTEnum vars cur -> Just (vars, cur)+                                             _ -> Nothing++typToDV :: ConfigTypeT 'Value -> Maybe CategoricalVariable+typToDV val = msum [ MkDV <$> val ^? varPrism @Bool+                   , MkDV <$> val ^? varPrism @([T.Text], T.Text)+                   ]++searchSpace :: Show a => Integral a => a -> [a]+searchSpace n = [ 2 ^ k | k <- [ 0 .. maxK ] ]+  where+    nBase = round $ logBase 2 $ fromIntegral n+    maxK | n > 100 = nBase + 1+         | otherwise = 2 * nBase++instance Variate Int where+  type VariateResult Int = []+  type VariateType Int = 'Integral+  variate n = n - 1 : n + 1 : searchSpace n <> map negate (searchSpace n)+  varPrism = prism' CTInt $ \case CTInt n -> Just n+                                  _ -> Nothing++instance Variate Natural where+  type VariateResult Natural = []+  type VariateType Natural = 'Integral+  variate n | n > 0 = n - 1 : n + 1 : searchSpace n+            | otherwise = n + 1 : searchSpace n+  varPrism = prism' CTUnsigned $ \case CTUnsigned n -> Just n+                                       _ -> Nothing++type IntegralVariate a = (Variate a, VariateType a ~ 'Integral)+type IntegralVariable = Variable 'Integral+type IxedIntegralVariable = IxedVariable 'Integral++typToIV :: ConfigTypeT 'Value -> Maybe IntegralVariable+typToIV val = msum [ MkDV <$> val ^? varPrism @Int+                   , MkDV <$> val ^? varPrism @Natural+                   ]++data SomeIxedVariable :: Type where+  SomeIxedVariable :: IxedVariable varTy -> SomeIxedVariable++asSome :: [IxedVariable varTy] -> [SomeIxedVariable]+asSome = fmap SomeIxedVariable