Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace cabal project parsing with Parsec #8889

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
82c243d
Replace cabal project parsing with Parsec
jgotoh May 31, 2024
e3373be
Replace haddock-lib with haddock-resources-dir
jgotoh May 31, 2024
ebd6c9f
Add parsing of ClientInstallFlags
jgotoh May 31, 2024
e5cbba4
Add parsing of InstallDirs
jgotoh May 31, 2024
24440c9
Add missing constraintKinds
jgotoh May 31, 2024
2ed99c1
Update docs and remove comment
jgotoh Jun 14, 2024
06455e1
Extract testInstallDirs into separate test
jgotoh Jun 14, 2024
63aee4e
Add RemoteRepos and LocalNoIndexRepos test stubs
jgotoh Jun 14, 2024
6f34619
Add RemoteRepos test
jgotoh Jun 14, 2024
e92f951
Add LocalNoIndexRepos Test
jgotoh Jun 14, 2024
c1f8071
Update only compare parsed values of repositories
jgotoh Jun 14, 2024
9ceadbc
Add Distribution.Client.Utils.Newtypes module
jgotoh Jul 12, 2024
f3f2a02
Add RemoteRepo Lenses
jgotoh Jul 12, 2024
8a1abbc
Add RemoteRepo FieldGrammar
jgotoh Jul 12, 2024
ce0a82d
Add parsing of repository sections
jgotoh Jul 26, 2024
dbab8c4
Fix RemoteRepo test
jgotoh Jul 26, 2024
7b22c88
Improve stateConfig lense usage
jgotoh Jul 26, 2024
bb6f939
Add filtering fields to parseProgramArgs/Paths
jgotoh Jul 26, 2024
a0f82c0
Fix imports of test
jgotoh Aug 11, 2024
37d592c
Add parsing of profiling-shared and use-unicode
jgotoh Aug 11, 2024
b727bd0
Add changelog
jgotoh Aug 13, 2024
55d5765
Migrate ParserTests to cabal-install/parser-tests
jgotoh Aug 22, 2024
5959feb
Add monoidal parsing of AllowNewer and AllowOlder
jgotoh Aug 22, 2024
32de2a3
Fix order of programArgs parsing
jgotoh Aug 24, 2024
b5e69e3
Fix parsing of commas in programArgs
jgotoh Aug 24, 2024
7e5df6a
Add quotes in programOptions test
jgotoh Sep 12, 2024
5cb80ad
Update programArgs parser to allow Quotes
jgotoh Sep 13, 2024
6919f72
Fix order of imports
jgotoh Sep 13, 2024
7d25cbd
Update PackageDBNT to use PackageDBCWD
jgotoh Sep 13, 2024
d9c616a
Fix ParserTests to use PackageDBX
jgotoh Sep 13, 2024
146d907
Fix TOCTOU
jgotoh Sep 13, 2024
e2d6e2d
Add library-coverage test
jgotoh Nov 1, 2024
051d2e5
Add parsing of haddock-all flag
jgotoh Nov 1, 2024
0df3041
Renamed LiftParseResult, pure composition
jgotoh Nov 1, 2024
91f6317
Fix intToOptimisationLevel dynamic bounds
jgotoh Nov 4, 2024
1265975
Add cabal-install:parser-tests to cabal-validate
jgotoh Nov 4, 2024
5b0c35a
Fix maxLevel comparison
jgotoh Nov 4, 2024
7d7707f
Fix regression test and issue url
jgotoh Jan 7, 2025
b641acd
Fix exports in ProjectConfig
jgotoh Jan 7, 2025
462a345
Add Parsec Subsection Warning to test
jgotoh Jan 10, 2025
eededa4
Fix T5213 cabal.out warning order
jgotoh Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cabal-syntax/src/Distribution/FieldGrammar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ x ^^^ f = f x
data PS ann = PS (Fields ann) [Section ann] [[Section ann]]

-- | Partition field list into field map and groups of sections.
-- Groups sections between fields. This means that the following snippet contains
-- two section groups:
--
-- @
-- -- first group
-- some-section
-- field: value
-- another-section
-- field: value
-- foo: bar
-- -- second group
-- yet-another-section
-- field: value
-- @
partitionFields :: [Field ann] -> (Fields ann, [[Section ann]])
partitionFields = finalize . foldl' f (PS mempty mempty mempty)
where
Expand Down
12 changes: 12 additions & 0 deletions Cabal-syntax/src/Distribution/Fields/ParseResult.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Distribution.Fields.ParseResult
, getCabalSpecVersion
, setCabalSpecVersion
, withoutWarnings
, liftParseResult
) where

import Distribution.Compat.Prelude
Expand Down Expand Up @@ -62,6 +63,17 @@ runParseResult pr = unPR pr emptyPRState failure success
-- If there are any errors, don't return the result
success (PRState warns (err : errs) v) _ = (warns, Left (v, err :| errs))

-- | Chain parsing operations that involve 'IO' actions.
liftParseResult :: (a -> IO (ParseResult b)) -> ParseResult a -> IO (ParseResult b)
liftParseResult f pr = unPR pr emptyPRState failure success
where
failure s = return $ PR $ \s' failure' _ -> failure' (concatPRState s s')
success s a = do
pr' <- f a
return $ PR $ \s' failure' success' -> unPR pr' (concatPRState s s') failure' success'
concatPRState (PRState warnings errors version) (PRState warnings' errors' version') =
(PRState (warnings ++ warnings') (toList errors ++ errors') (version <|> version'))

instance Functor ParseResult where
fmap f (PR pr) = PR $ \ !s failure success ->
pr s failure $ \ !s' a ->
Expand Down
59 changes: 50 additions & 9 deletions Cabal/src/Distribution/Simple/Compiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ module Distribution.Simple.Compiler
, interpretPackageDBStack
, coercePackageDB
, coercePackageDBStack
, readPackageDb

-- * Support for optimisation levels
, OptimisationLevel (..)
Expand Down Expand Up @@ -92,7 +93,9 @@ module Distribution.Simple.Compiler
, showProfDetailLevel
) where

import Distribution.Compat.CharParsing
import Distribution.Compat.Prelude
import Distribution.Parsec
import Distribution.Pretty
import Prelude ()

Expand All @@ -103,6 +106,7 @@ import Distribution.Version

import Language.Haskell.Extension

import Data.Bool (bool)
import qualified Data.Map as Map (lookup)
import System.Directory (canonicalizePath)

Expand Down Expand Up @@ -202,6 +206,15 @@ data PackageDBX fp
instance Binary fp => Binary (PackageDBX fp)
instance Structured fp => Structured (PackageDBX fp)

-- | Parse a PackageDB stack entry
--
-- @since 3.7.0.0
readPackageDb :: String -> Maybe PackageDB
readPackageDb "clear" = Nothing
readPackageDb "global" = Just GlobalPackageDB
readPackageDb "user" = Just UserPackageDB
readPackageDb other = Just (SpecificPackageDB (makeSymbolicPath other))

-- | We typically get packages from several databases, and stack them
-- together. This type lets us be explicit about that stacking. For example
-- typical stacks include:
Expand Down Expand Up @@ -293,20 +306,36 @@ data OptimisationLevel
instance Binary OptimisationLevel
instance Structured OptimisationLevel

instance Parsec OptimisationLevel where
parsec = parsecOptimisationLevel

parsecOptimisationLevel :: CabalParsing m => m OptimisationLevel
parsecOptimisationLevel = boolParser <|> intParser
where
boolParser = (bool NoOptimisation NormalOptimisation) <$> parsec
intParser = intToOptimisationLevel <$> integral

flagToOptimisationLevel :: Maybe String -> OptimisationLevel
flagToOptimisationLevel Nothing = NormalOptimisation
flagToOptimisationLevel (Just s) = case reads s of
[(i, "")]
| i >= fromEnum (minBound :: OptimisationLevel)
&& i <= fromEnum (maxBound :: OptimisationLevel) ->
toEnum i
| otherwise ->
error $
"Bad optimisation level: "
++ show i
++ ". Valid values are 0..2"
[(i, "")] -> intToOptimisationLevel i
_ -> error $ "Can't parse optimisation level " ++ s

intToOptimisationLevel :: Int -> OptimisationLevel
intToOptimisationLevel i
| i >= minLevel && i <= maxLevel = toEnum i
| otherwise =
error $
"Bad optimisation level: "
++ show i
++ ". Valid values are "
++ show minLevel
++ ".."
++ show maxLevel
where
minLevel = fromEnum (minBound :: OptimisationLevel)
maxLevel = fromEnum (maxBound :: OptimisationLevel)

-- ------------------------------------------------------------

-- * Debug info levels
Expand All @@ -326,6 +355,12 @@ data DebugInfoLevel
instance Binary DebugInfoLevel
instance Structured DebugInfoLevel

instance Parsec DebugInfoLevel where
parsec = parsecDebugInfoLevel

parsecDebugInfoLevel :: CabalParsing m => m DebugInfoLevel
parsecDebugInfoLevel = flagToDebugInfoLevel . pure <$> parsecToken

flagToDebugInfoLevel :: Maybe String -> DebugInfoLevel
flagToDebugInfoLevel Nothing = NormalDebugInfo
flagToDebugInfoLevel (Just s) = case reads s of
Expand Down Expand Up @@ -563,6 +598,12 @@ data ProfDetailLevel
instance Binary ProfDetailLevel
instance Structured ProfDetailLevel

instance Parsec ProfDetailLevel where
parsec = parsecProfDetailLevel

parsecProfDetailLevel :: CabalParsing m => m ProfDetailLevel
parsecProfDetailLevel = flagToProfDetailLevel <$> parsecToken

flagToProfDetailLevel :: String -> ProfDetailLevel
flagToProfDetailLevel "" = ProfDetailDefault
flagToProfDetailLevel s =
Expand Down
7 changes: 7 additions & 0 deletions Cabal/src/Distribution/Simple/Flag.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module Distribution.Simple.Flag

import Distribution.Compat.Prelude hiding (get)
import Distribution.Compat.Stack
import Distribution.Parsec
import Prelude ()

-- ------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +100,12 @@ instance Enum a => Enum (Flag a) where
enumFromThenTo (Flag a) (Flag b) (Flag c) = toFlag `map` enumFromThenTo a b c
enumFromThenTo _ _ _ = []

instance Parsec a => Parsec (Flag a) where
parsec = parsecFlag

parsecFlag :: (Parsec a, CabalParsing m) => m (Flag a)
parsecFlag = (Flag <$> parsec) <|> pure mempty

-- | Wraps a value in 'Flag'.
toFlag :: a -> Flag a
toFlag = Flag
Expand Down
90 changes: 90 additions & 0 deletions Cabal/src/Distribution/Simple/InstallDirs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}

-----------------------------------------------------------------------------
Expand Down Expand Up @@ -44,16 +45,21 @@ module Distribution.Simple.InstallDirs
, compilerTemplateEnv
, packageTemplateEnv
, abiTemplateEnv
, installDirsGrammar
, installDirsTemplateEnv
) where

import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Compat.Environment (lookupEnv)
import Distribution.Compat.Lens (Lens')
import Distribution.Compiler
import Distribution.FieldGrammar
import Distribution.Package
import Distribution.Parsec
import Distribution.Pretty
import Distribution.Simple.Flag
import Distribution.Simple.InstallDirs.Internal
import Distribution.System

Expand Down Expand Up @@ -506,6 +512,12 @@ instance Read PathTemplate where
, (template, "") <- reads path
]

instance Parsec PathTemplate where
parsec = parsecPathTemplate

parsecPathTemplate :: CabalParsing m => m PathTemplate
parsecPathTemplate = parsecFilePath >>= return . toPathTemplate

-- ---------------------------------------------------------------------------
-- Internal utilities

Expand Down Expand Up @@ -552,3 +564,81 @@ foreign import CALLCONV unsafe "shlobj.h SHGetFolderPathW"
-> Prelude.IO CInt
#endif
{- FOURMOLU_ENABLE -}

-- ---------------------------------------------------------------------------
-- FieldGrammar

installDirsGrammar :: ParsecFieldGrammar' (InstallDirs (Flag PathTemplate))
installDirsGrammar =
InstallDirs
<$> optionalFieldDef "prefix" installDirsPrefixLens mempty
<*> optionalFieldDef "bindir" installDirsBindirLens mempty
<*> optionalFieldDef "libdir" installDirsLibdirLens mempty
<*> optionalFieldDef "libsubdir" installDirsLibsubdirLens mempty
<*> optionalFieldDef "dynlibdir" installDirsDynlibdirLens mempty
<*> (pure NoFlag) -- flibdir
<*> optionalFieldDef "libexecdir" installDirsLibexecdirLens mempty
<*> optionalFieldDef "libexecsubdir" installDirsLibexecsubdirLens mempty
<*> (pure NoFlag) -- includedir
<*> optionalFieldDef "datadir" installDirsDatadirLens mempty
<*> optionalFieldDef "datasubdir" installDirsDatasubdirLens mempty
<*> optionalFieldDef "docdir" installDirsDocdirLens mempty
<*> (pure NoFlag) -- mandir
<*> optionalFieldDef "htmldir" installDirsHtmldirLens mempty
<*> optionalFieldDef "haddockdir" installDirsHaddockdirLens mempty
<*> optionalFieldDef "sysconfdir" installDirsSysconfdirLens mempty

-- ---------------------------------------------------------------------------
-- Lenses

installDirsPrefixLens :: Lens' (InstallDirs a) a
installDirsPrefixLens f c = fmap (\x -> c{prefix = x}) (f (prefix c))
{-# INLINEABLE installDirsPrefixLens #-}

installDirsBindirLens :: Lens' (InstallDirs a) a
installDirsBindirLens f c = fmap (\x -> c{bindir = x}) (f (bindir c))
{-# INLINEABLE installDirsBindirLens #-}

installDirsLibdirLens :: Lens' (InstallDirs a) a
installDirsLibdirLens f c = fmap (\x -> c{libdir = x}) (f (libdir c))
{-# INLINEABLE installDirsLibdirLens #-}

installDirsLibsubdirLens :: Lens' (InstallDirs a) a
installDirsLibsubdirLens f c = fmap (\x -> c{libsubdir = x}) (f (libsubdir c))
{-# INLINEABLE installDirsLibsubdirLens #-}

installDirsDynlibdirLens :: Lens' (InstallDirs a) a
installDirsDynlibdirLens f c = fmap (\x -> c{dynlibdir = x}) (f (dynlibdir c))
{-# INLINEABLE installDirsDynlibdirLens #-}

installDirsLibexecdirLens :: Lens' (InstallDirs a) a
installDirsLibexecdirLens f c = fmap (\x -> c{libexecdir = x}) (f (libexecdir c))
{-# INLINEABLE installDirsLibexecdirLens #-}

installDirsLibexecsubdirLens :: Lens' (InstallDirs a) a
installDirsLibexecsubdirLens f c = fmap (\x -> c{libexecsubdir = x}) (f (libexecsubdir c))
{-# INLINEABLE installDirsLibexecsubdirLens #-}

installDirsDatadirLens :: Lens' (InstallDirs a) a
installDirsDatadirLens f c = fmap (\x -> c{datadir = x}) (f (datadir c))
{-# INLINEABLE installDirsDatadirLens #-}

installDirsDatasubdirLens :: Lens' (InstallDirs a) a
installDirsDatasubdirLens f c = fmap (\x -> c{datasubdir = x}) (f (datasubdir c))
{-# INLINEABLE installDirsDatasubdirLens #-}

installDirsDocdirLens :: Lens' (InstallDirs a) a
installDirsDocdirLens f c = fmap (\x -> c{docdir = x}) (f (docdir c))
{-# INLINEABLE installDirsDocdirLens #-}

installDirsHtmldirLens :: Lens' (InstallDirs a) a
installDirsHtmldirLens f c = fmap (\x -> c{htmldir = x}) (f (htmldir c))
{-# INLINEABLE installDirsHtmldirLens #-}

installDirsHaddockdirLens :: Lens' (InstallDirs a) a
installDirsHaddockdirLens f c = fmap (\x -> c{haddockdir = x}) (f (haddockdir c))
{-# INLINEABLE installDirsHaddockdirLens #-}

installDirsSysconfdirLens :: Lens' (InstallDirs a) a
installDirsSysconfdirLens f c = fmap (\x -> c{sysconfdir = x}) (f (sysconfdir c))
{-# INLINEABLE installDirsSysconfdirLens #-}
2 changes: 2 additions & 0 deletions Cabal/src/Distribution/Simple/PackageDescription.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module Distribution.Simple.PackageDescription

-- * Utility Parsing function
, parseString
, readAndParseFile
, flattenDups
) where

import Distribution.Compat.Prelude
Expand Down
9 changes: 0 additions & 9 deletions Cabal/src/Distribution/Simple/Setup/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -897,15 +897,6 @@ configureOptions showOrParseArgs =
readPackageDbList :: String -> [Maybe PackageDB]
readPackageDbList str = [readPackageDb str]

-- | Parse a PackageDB stack entry
--
-- @since 3.7.0.0
readPackageDb :: String -> Maybe PackageDB
readPackageDb "clear" = Nothing
readPackageDb "global" = Just GlobalPackageDB
readPackageDb "user" = Just UserPackageDB
readPackageDb other = Just (SpecificPackageDB (makeSymbolicPath other))

showPackageDbList :: [Maybe PackageDB] -> [String]
showPackageDbList = map showPackageDb

Expand Down
12 changes: 12 additions & 0 deletions Cabal/src/Distribution/Types/DumpBuildInfo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Distribution.Types.DumpBuildInfo
) where

import Distribution.Compat.Prelude
import Distribution.Parsec

data DumpBuildInfo
= NoDumpBuildInfo
Expand All @@ -13,3 +14,14 @@ data DumpBuildInfo

instance Binary DumpBuildInfo
instance Structured DumpBuildInfo

instance Parsec DumpBuildInfo where
parsec = parsecDumpBuildInfo

parsecDumpBuildInfo :: CabalParsing m => m DumpBuildInfo
parsecDumpBuildInfo = boolToDumpBuildInfo <$> parsec

boolToDumpBuildInfo :: Bool -> DumpBuildInfo
boolToDumpBuildInfo bool = case bool of
True -> DumpBuildInfo
_ -> NoDumpBuildInfo
23 changes: 23 additions & 0 deletions cabal-install-solver/src/Distribution/Solver/Types/Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,26 @@ instance Parsec OnlyConstrained where
, P.string "none" >> return OnlyConstrainedNone
]

instance Parsec ReorderGoals where
parsec = ReorderGoals <$> parsec

instance Parsec CountConflicts where
parsec = CountConflicts <$> parsec

instance Parsec FineGrainedConflicts where
parsec = FineGrainedConflicts <$> parsec

instance Parsec MinimizeConflictSet where
parsec = MinimizeConflictSet <$> parsec

instance Parsec StrongFlags where
parsec = StrongFlags <$> parsec

instance Parsec AllowBootLibInstalls where
parsec = AllowBootLibInstalls <$> parsec

instance Parsec PreferOldest where
parsec = PreferOldest <$> parsec

instance Parsec IndependentGoals where
parsec = IndependentGoals <$> parsec
Loading
Loading