module CompilerConditions
( genCompilerAssignments
, GhcAssignment
) where
import Distribution.Version
import Distribution.Compiler
import Distribution.Types.CondTree
import Distribution.Types.Condition
import Distribution.Types.GenericPackageDescription
import Data.List (nub)
import Data.Maybe (mapMaybe, maybeToList)
import GhcDatabase
type CompilerVersionRangeCondition = VersionRange
type VersionRangeConditionTruthAssignment = VersionRange
type GhcAssignment = (VersionRange, Version)
compilerConditions :: CompilerFlavor -> GenericPackageDescription -> [CompilerVersionRangeCondition]
compilerConditions comp pkgDescr = concat
[ concatMap extractCompilerConditions $ maybeToList (condLibrary pkgDescr)
, concatMap (extractCompilerConditions . snd) $ condSubLibraries pkgDescr
, concatMap (extractCompilerConditions . snd) $ condForeignLibs pkgDescr
, concatMap (extractCompilerConditions . snd) $ condExecutables pkgDescr
, concatMap (extractCompilerConditions . snd) $ condTestSuites pkgDescr
, concatMap (extractCompilerConditions . snd) $ condBenchmarks pkgDescr
]
where extractCompilerConditions :: CondTree ConfVar c a -> [CompilerVersionRangeCondition]
extractCompilerConditions =
foldMap (analyzeCond . condBranchCondition) . condTreeComponents
where analyzeCond :: Condition ConfVar -> [CompilerVersionRangeCondition]
analyzeCond (Lit _) = []
analyzeCond (Var (Impl c vr)) = [vr | c == comp]
analyzeCond (Var _) = []
analyzeCond (CNot c) = analyzeCond c
analyzeCond (COr c1 c2) = analyzeCond c1 ++ analyzeCond c2
analyzeCond (CAnd c1 c2) = analyzeCond c1 ++ analyzeCond c2
makeVersionRangeConditionTruthAssignment :: [VersionRange]
-> VersionRangeConditionTruthAssignment
makeVersionRangeConditionTruthAssignment = foldr intersectVersionRanges anyVersion
complementaryVersionRange :: VersionRange -> VersionRange
complementaryVersionRange = foldVersionRange noVersion
notThisVersion
orEarlierVersion
orLaterVersion
intersectVersionRanges
unionVersionRanges
allTruthAssignments :: [CompilerVersionRangeCondition] -> [VersionRangeConditionTruthAssignment]
allTruthAssignments vars =
let vars' = map (\v -> [v, complementaryVersionRange v]) vars
in map makeVersionRangeConditionTruthAssignment $ foldr addAssignment [[]] vars'
where addAssignment :: [CompilerVersionRangeCondition]
-> [[VersionRange]]
-> [[VersionRange]]
addAssignment alternatives assignments = do
newAssignment <- alternatives
otherAssignments <- assignments
return (newAssignment : otherAssignments)
truthAssignmentToGhcVersion :: GhcDatabase
-> VersionRangeConditionTruthAssignment
-> Maybe Version
truthAssignmentToGhcVersion db vr = fst <$> newest (filterBaseVersionIn db vr)
truthAssignmentToBaseVersionRange :: GhcDatabase
-> VersionRangeConditionTruthAssignment
-> VersionRange
truthAssignmentToBaseVersionRange db versionRangeAssignment =
let baseVersions = map (thisVersion . baseVersion . snd)
. dbToList
$ filterBaseVersionIn db versionRangeAssignment
in foldr unionVersionRanges noVersion baseVersions
truthAssignmentToGhcAssignment :: GhcDatabase
-> VersionRangeConditionTruthAssignment
-> Maybe GhcAssignment
truthAssignmentToGhcAssignment db ass = do
ghcVer <- truthAssignmentToGhcVersion db ass
let baseVerRange = truthAssignmentToBaseVersionRange db ass
return (baseVerRange, ghcVer)
ghcAssignments :: GhcDatabase
-> [CompilerVersionRangeCondition]
-> [GhcAssignment]
ghcAssignments db =
mapMaybe (truthAssignmentToGhcAssignment db)
. allTruthAssignments
. nub
{-# ANN ghcAssignments "HLint: ignore Fuse mapMaybe/map" #-}
genCompilerAssignments :: GhcDatabase
-> GenericPackageDescription
-> [GhcAssignment]
genCompilerAssignments db = ghcAssignments db
. compilerConditions GHC