diff --git a/cabal-install/Distribution/Client/ParseUtils.hs b/cabal-install/Distribution/Client/ParseUtils.hs
index 56eebf37569056330757acbe3ca099c5cca5c72c..23d5e32b12126a65bed2aaa322af3fe6b4272f42 100644
--- a/cabal-install/Distribution/Client/ParseUtils.hs
+++ b/cabal-install/Distribution/Client/ParseUtils.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ExistentialQuantification, NamedFieldPuns #-}
+{-# LANGUAGE ExistentialQuantification, NamedFieldPuns, RankNTypes #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -24,6 +24,9 @@ module Distribution.Client.ParseUtils (
     SectionDescr(..),
     liftSection,
 
+    -- * FieldGrammar sections
+    FGSectionDescr(..),
+
     -- * Parsing and printing flat config
     parseFields,
     ppFields,
@@ -39,6 +42,9 @@ module Distribution.Client.ParseUtils (
   )
        where
 
+import Distribution.Client.Compat.Prelude hiding (empty, get)
+import Prelude ()
+
 import Distribution.Deprecated.ParseUtils
          ( FieldDescr(..), ParseResult(..), warning, LineNo, lineNo
          , Field(..), liftField, readFieldsFlat )
@@ -48,12 +54,22 @@ import Distribution.Deprecated.ViewAsFieldDescr
 import Distribution.Simple.Command
          ( OptionField  )
 
-import Control.Monad    ( foldM )
 import Text.PrettyPrint ( (<+>), ($+$) )
 import qualified Data.Map as Map
 import qualified Text.PrettyPrint as Disp
          ( (<>), Doc, text, colon, vcat, empty, isEmpty, nest )
 
+-- For new parser stuff
+import Distribution.CabalSpecVersion (cabalSpecLatest)
+import Distribution.FieldGrammar (FieldGrammar, partitionFields, parseFieldGrammar)
+import Distribution.Fields.ParseResult (runParseResult)
+import Distribution.Parsec.Error (showPError)
+import Distribution.Parsec.Position (Position (..))
+import Distribution.Parsec.Warning (showPWarning)
+import Distribution.Simple.Utils (fromUTF8BS, toUTF8BS)
+import qualified Distribution.Fields as F
+import qualified Distribution.FieldGrammar as FG
+
 
 -------------------------
 -- FieldDescr utilities
@@ -107,6 +123,15 @@ data SectionDescr a = forall b. SectionDescr {
        sectionEmpty       :: b
      }
 
+-- | 'FieldGrammar' section description
+data FGSectionDescr a = forall s. FGSectionDescr
+    { fgSectionName    :: String
+    , fgSectionGrammar :: forall g. (FieldGrammar g, Applicative (g s)) => g s s
+    -- todo: add subsections?
+    , fgSectionGet     :: a -> [(String, s)]
+    , fgSectionSet     :: LineNo -> String -> s -> a -> ParseResult a
+    }
+
 -- | To help construction of config file descriptions in a modular way it is
 -- useful to define fields and sections on local types and then hoist them
 -- into the parent types when combining them in bigger descriptions.
@@ -191,13 +216,18 @@ ppSection name arg fields def cur
 -- | Much like 'parseFields' but it also allows subsections. The permitted
 -- subsections are given by a list of 'SectionDescr's.
 --
-parseFieldsAndSections :: [FieldDescr a] -> [SectionDescr a] -> a
-                       -> [Field] -> ParseResult a
-parseFieldsAndSections fieldDescrs sectionDescrs =
+parseFieldsAndSections
+    :: [FieldDescr a]      -- ^ field
+    -> [SectionDescr a]    -- ^ legacy sections
+    -> [FGSectionDescr a]  -- ^ FieldGrammar sections
+    -> a
+    -> [Field] -> ParseResult a
+parseFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs =
     foldM setField
   where
-    fieldMap   = Map.fromList [ (fieldName   f, f) | f <- fieldDescrs   ]
-    sectionMap = Map.fromList [ (sectionName s, s) | s <- sectionDescrs ]
+    fieldMap     = Map.fromList [ (fieldName     f, f) | f <- fieldDescrs     ]
+    sectionMap   = Map.fromList [ (sectionName   s, s) | s <- sectionDescrs   ]
+    fgSectionMap = Map.fromList [ (fgSectionName s, s) | s <- fgSectionDescrs ]
 
     setField a (F line name value) =
       case Map.lookup name fieldMap of
@@ -208,10 +238,25 @@ parseFieldsAndSections fieldDescrs sectionDescrs =
           return a
 
     setField a (Section line name param fields) =
-      case Map.lookup name sectionMap of
-        Just (SectionDescr _ fieldDescrs' sectionDescrs' _ set sectionEmpty) -> do
-          b <- parseFieldsAndSections fieldDescrs' sectionDescrs' sectionEmpty fields
+      case Left <$> Map.lookup name sectionMap <|> Right <$> Map.lookup name fgSectionMap of
+        Just (Left (SectionDescr _ fieldDescrs' sectionDescrs' _ set sectionEmpty)) -> do
+          b <- parseFieldsAndSections fieldDescrs' sectionDescrs' [] sectionEmpty fields
           set line param b a
+        Just (Right (FGSectionDescr _ grammar _getter setter)) -> do
+          let fields1 = mapMaybe convertField fields
+              (fields2, sections) = partitionFields fields1
+          -- TODO: recurse into sections
+          for_ (concat sections) $ \(FG.MkSection (F.Name (Position line' _) name') _ _) ->
+            warning $ "Unrecognized section '" ++ fromUTF8BS name'
+              ++ "' on line " ++ show line'
+          case runParseResult $ parseFieldGrammar cabalSpecLatest fields2 grammar of
+            (warnings, Right b) -> do
+              for_ warnings $ \w -> warning $ showPWarning "???" w
+              setter line param b a
+            (warnings, Left (_, errs)) -> do
+              for_ warnings $ \w -> warning $ showPWarning "???" w
+              case errs of
+                err :| _errs -> fail $ showPError "???" err
         Nothing -> do
           warning $ "Unrecognized section '" ++ name
                  ++ "' on line " ++ show line
@@ -221,17 +266,31 @@ parseFieldsAndSections fieldDescrs sectionDescrs =
       warning $ "Unrecognized stanza on line " ++ show (lineNo block)
       return accum
 
+convertField :: Field -> Maybe (F.Field Position)
+convertField (F line name str) = Just $
+    F.Field (F.Name pos (toUTF8BS name)) [ F.FieldLine pos $ toUTF8BS str ]
+  where
+    pos = Position line 0
+-- arguments omitted
+convertField (Section line name _arg fields) = Just $
+    F.Section (F.Name pos (toUTF8BS name)) [] (mapMaybe convertField fields)
+  where
+    pos = Position line 0
+-- silently omitted.
+convertField IfBlock {} = Nothing
+
+
 -- | Much like 'ppFields' but also pretty prints any subsections. Subsection
 -- are only shown if they are non-empty.
 --
 -- Note that unlike 'ppFields', at present it does not support printing
 -- default values. If needed, adding such support would be quite reasonable.
 --
-ppFieldsAndSections :: [FieldDescr a] -> [SectionDescr a] -> a -> Disp.Doc
-ppFieldsAndSections fieldDescrs sectionDescrs val =
+ppFieldsAndSections :: [FieldDescr a] -> [SectionDescr a] -> [FGSectionDescr a] -> a -> Disp.Doc
+ppFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs val =
     ppFields fieldDescrs Nothing val
       $+$
-    Disp.vcat
+    Disp.vcat (
       [ Disp.text "" $+$ sectionDoc
       | SectionDescr {
           sectionName, sectionGet,
@@ -240,24 +299,57 @@ ppFieldsAndSections fieldDescrs sectionDescrs val =
       , (param, x) <- sectionGet val
       , let sectionDoc = ppSectionAndSubsections
                            sectionName param
-                           sectionFields sectionSubsections x
+                           sectionFields sectionSubsections [] x
+      , not (Disp.isEmpty sectionDoc)
+      ] ++
+      [ Disp.text "" $+$ sectionDoc
+      | FGSectionDescr { fgSectionName, fgSectionGrammar, fgSectionGet } <- fgSectionDescrs
+      , (param, x) <- fgSectionGet val
+      , let sectionDoc = ppFgSection fgSectionName param fgSectionGrammar x
       , not (Disp.isEmpty sectionDoc)
-      ]
+      ])
 
 -- | Unlike 'ppSection' which has to be called directly, this gets used via
 -- 'ppFieldsAndSections' and so does not need to be exported.
 --
 ppSectionAndSubsections :: String -> String
-                        -> [FieldDescr a] -> [SectionDescr a] -> a -> Disp.Doc
-ppSectionAndSubsections name arg fields sections cur
+                        -> [FieldDescr a] -> [SectionDescr a] -> [FGSectionDescr a] -> a -> Disp.Doc
+ppSectionAndSubsections name arg fields sections fgSections cur
   | Disp.isEmpty fieldsDoc = Disp.empty
   | otherwise              = Disp.text name <+> argDoc
                              $+$ (Disp.nest 2 fieldsDoc)
   where
-    fieldsDoc = showConfig fields sections cur
+    fieldsDoc = showConfig fields sections fgSections cur
     argDoc | arg == "" = Disp.empty
            | otherwise = Disp.text arg
 
+-- |
+--
+-- TODO: subsections
+-- TODO: this should simply build 'PrettyField'
+ppFgSection
+    :: String  -- ^ section name
+    -> String  -- ^ parameter
+    -> FG.PrettyFieldGrammar a a
+    -> a
+    -> Disp.Doc
+ppFgSection secName arg grammar x
+    | null prettyFields = Disp.empty
+    | otherwise         =
+        Disp.text secName <+> argDoc
+        $+$ (Disp.nest 2 fieldsDoc)
+  where
+    prettyFields = FG.prettyFieldGrammar cabalSpecLatest grammar x
+
+    argDoc | arg == "" = Disp.empty
+           | otherwise = Disp.text arg
+
+    fieldsDoc = Disp.vcat
+        [ Disp.text fname' <<>> Disp.colon <<>> doc
+        | F.PrettyField _ fname doc <- prettyFields -- TODO: this skips sections
+        , let fname' = fromUTF8BS fname
+        ]
+
 
 -----------------------------------------------
 -- Top level config file parsing and printing
@@ -268,15 +360,15 @@ ppSectionAndSubsections name arg fields sections cur
 --
 -- It accumulates the result on top of a given initial (typically empty) value.
 --
-parseConfig :: [FieldDescr a] -> [SectionDescr a] -> a
+parseConfig :: [FieldDescr a] -> [SectionDescr a] -> [FGSectionDescr a] -> a
             -> String -> ParseResult a
-parseConfig fieldDescrs sectionDescrs empty str =
-      parseFieldsAndSections fieldDescrs sectionDescrs empty
+parseConfig fieldDescrs sectionDescrs fgSectionDescrs empty str =
+      parseFieldsAndSections fieldDescrs sectionDescrs fgSectionDescrs empty
   =<< readFieldsFlat str
 
 -- | Render a value in the config file syntax, based on a description of the
 -- configuration file in terms of its fields and sections.
 --
-showConfig :: [FieldDescr a] -> [SectionDescr a] -> a -> Disp.Doc
+showConfig :: [FieldDescr a] -> [SectionDescr a] -> [FGSectionDescr a] -> a -> Disp.Doc
 showConfig = ppFieldsAndSections
 
diff --git a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs
index 4aa68231cace9d98b0815bac801c57387d8d1b8d..865305a0873e8b7d2f715403561b71fed8c51dee 100644
--- a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs
+++ b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs
@@ -43,8 +43,7 @@ import Distribution.Package
 import Distribution.PackageDescription
          ( SourceRepo(..), RepoKind(..)
          , dispFlagAssignment )
-import Distribution.Client.SourceRepoParse
-         ( sourceRepoFieldDescrs )
+import Distribution.PackageDescription.FieldGrammar (sourceRepoFieldGrammar)
 import Distribution.Simple.Compiler
          ( OptimisationLevel(..), DebugInfoLevel(..) )
 import Distribution.Simple.InstallDirs ( CopyDest (NoCopyDest) )
@@ -812,6 +811,7 @@ parseLegacyProjectConfig :: String -> ParseResult LegacyProjectConfig
 parseLegacyProjectConfig =
     parseConfig legacyProjectConfigFieldDescrs
                 legacyPackageConfigSectionDescrs
+                legacyPackageConfigFGSectionDescrs
                 mempty
 
 showLegacyProjectConfig :: LegacyProjectConfig -> String
@@ -819,6 +819,7 @@ showLegacyProjectConfig config =
     Disp.render $
     showConfig  legacyProjectConfigFieldDescrs
                 legacyPackageConfigSectionDescrs
+                legacyPackageConfigFGSectionDescrs
                 config
   $+$
     Disp.text ""
@@ -1166,10 +1167,14 @@ legacyPackageConfigFieldDescrs =
                     | otherwise = "test-" ++ name
 
 
+legacyPackageConfigFGSectionDescrs :: [FGSectionDescr LegacyProjectConfig]
+legacyPackageConfigFGSectionDescrs =
+    [ packageRepoSectionDescr
+    ]
+
 legacyPackageConfigSectionDescrs :: [SectionDescr LegacyProjectConfig]
 legacyPackageConfigSectionDescrs =
-    [ packageRepoSectionDescr
-    , packageSpecificOptionsSectionDescr
+    [ packageSpecificOptionsSectionDescr
     , liftSection
         legacyLocalConfig
         (\flags conf -> conf { legacyLocalConfig = flags })
@@ -1187,31 +1192,19 @@ legacyPackageConfigSectionDescrs =
         remoteRepoSectionDescr
     ]
 
-packageRepoSectionDescr :: SectionDescr LegacyProjectConfig
-packageRepoSectionDescr =
-    SectionDescr {
-      sectionName        = "source-repository-package",
-      sectionFields      = sourceRepoFieldDescrs,
-      sectionSubsections = [],
-      sectionGet         = map (\x->("", x))
-                         . legacyPackagesRepo,
-      sectionSet         =
+packageRepoSectionDescr :: FGSectionDescr LegacyProjectConfig
+packageRepoSectionDescr = FGSectionDescr
+  { fgSectionName        = "source-repository-package"
+  , fgSectionGrammar     = sourceRepoFieldGrammar (RepoKindUnknown "unused")
+  , fgSectionGet         = map (\x->("", x)) . legacyPackagesRepo
+  , fgSectionSet         =
         \lineno unused pkgrepo projconf -> do
           unless (null unused) $
             syntaxError lineno "the section 'source-repository-package' takes no arguments"
           return projconf {
             legacyPackagesRepo = legacyPackagesRepo projconf ++ [pkgrepo]
-          },
-      sectionEmpty       = SourceRepo {
-                             repoKind     = RepoThis, -- hopefully unused
-                             repoType     = Nothing,
-                             repoLocation = Nothing,
-                             repoModule   = Nothing,
-                             repoBranch   = Nothing,
-                             repoTag      = Nothing,
-                             repoSubdir   = Nothing
-                           }
-    }
+          }
+  }
 
 -- | The definitions of all the fields that can appear in the @package pkgfoo@
 -- and @package *@ sections of the @cabal.project@-format files.
diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
index 360b9f5533f950803580412d7ad4a14172e41803..f8c4969d2e7b2dca23781e6cdf4c500db9f97b0f 100644
--- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
+++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
@@ -763,14 +763,16 @@ instance Arbitrary TestShowDetails where
     arbitrary = arbitraryBoundedEnum
 
 instance Arbitrary SourceRepo where
-    arbitrary = (SourceRepo RepoThis
+    arbitrary = (SourceRepo kind
                            <$> arbitrary
                            <*> (fmap getShortToken <$> arbitrary)
                            <*> (fmap getShortToken <$> arbitrary)
                            <*> (fmap getShortToken <$> arbitrary)
                            <*> (fmap getShortToken <$> arbitrary)
                            <*> (fmap getShortToken <$> arbitrary))
-                `suchThat` (/= emptySourceRepo RepoThis)
+                `suchThat` (/= emptySourceRepo kind)
+      where
+        kind = RepoKindUnknown "unused"
 
     shrink (SourceRepo _ x1 x2 x3 x4 x5 x6) =
       [ repo