content: {-# LANGUAGE CPP #-}
  -- Copyright 2019 Google LLC
  --
  -- Use of this source code is governed by a BSD-style
  -- license that can be found in the LICENSE file or at
  -- https://developers.google.com/open-source/licenses/bsd
  
  -- | This module provides combinators for constructing Haskell modules,
  -- including import and export statements.
  module GHC.SourceGen.Module
      ( -- * HsModule'
        HsModule'
      , module'
        -- * Import declarations
      , ImportDecl'
      , qualified'
      , as'
      , import'
      , exposing
      , hiding
      , source
        -- * Imported/exported things
      , IE'
      , thingAll
      , thingWith
      , moduleContents
      )  where
  
  import GHC.Hs.ImpExp
      ( IEWildcard(..), IEWrappedName(..), IE(..)
  #if MIN_VERSION_ghc(9,6,0)
      , ImportListInterpretation (EverythingBut, Exactly)
  #endif
      )
  import GHC.Hs
      ( HsModule(..)
      , ImportDecl(..)
      , simpleImportDecl
  #if MIN_VERSION_ghc(8,10,0)
      , ImportDeclQualifiedStyle(..)
  #endif
  #if MIN_VERSION_ghc(9,2,0)
      , EpAnn(..)
  #endif
  #if MIN_VERSION_ghc(9,6,0) && !MIN_VERSION_ghc(9,10,0)
      , LayoutInfo (NoLayoutInfo)
  #endif
  #if MIN_VERSION_ghc(9,6,0)
      , hsmodDeprecMessage, hsmodHaddockModHeader, hsmodAnn, XModulePs (XModulePs, hsmodLayout), noAnn, GhcPs, XImportDeclPass (XImportDeclPass, ideclAnn), SrcSpanAnnA, noExtField
  #else
      , LIEWrappedName
  #endif
      )
  #if MIN_VERSION_ghc(9,0,0) && !MIN_VERSION_ghc(9,6,0)
  import GHC.Types.SrcLoc (LayoutInfo(..))
  #endif
  #if MIN_VERSION_ghc(9,0,0)
  import GHC.Unit.Module (IsBootInterface(..))
  import GHC.Types.Name.Reader (RdrName)
  #else
  import RdrName (RdrName)
  #endif
  #if MIN_VERSION_ghc(9,4,0)
  import GHC.Types.PkgQual (RawPkgQual(..))
  #endif
  #if MIN_VERSION_ghc(9,10,0)
  import GHC.Parser.Annotation (EpLayout (..), noAnn)
  #endif
  
  
  import GHC.SourceGen.Syntax.Internal
  import GHC.SourceGen.Name.Internal
  import GHC.SourceGen.Name (unqual)
  #if MIN_VERSION_ghc(9,4,0)
  import GHC.SourceGen.Name (RdrNameStr, ModuleNameStr(unModuleNameStr), OccNameStr)
  import GHC.Types.SourceText (SourceText(NoSourceText))
  import GHC.Types.SrcLoc (GenLocated)
  #endif
  
  module'
      :: Maybe ModuleNameStr
      -> Maybe [IE'] -- ^ Exports
      -> [ImportDecl']
      -> [HsDecl']
      -> HsModule'
  module' name exports imports decls = HsModule
      { hsmodName = fmap (mkLocated . unModuleNameStr) name
      , hsmodExports = fmap (mkLocated . map mkLocated) exports
      , hsmodImports = map mkLocated imports
      , hsmodDecls = fmap mkLocated decls
  #if MIN_VERSION_ghc(9,6,0)
      , hsmodExt = XModulePs
        { hsmodAnn = noAnn
  #if MIN_VERSION_ghc(9,10,0)
        , hsmodLayout = EpNoLayout
  #else
        , hsmodLayout = NoLayoutInfo
  #endif
        , hsmodDeprecMessage = Nothing
        , hsmodHaddockModHeader = Nothing }
  #else
      , hsmodDeprecMessage = Nothing
      , hsmodHaddockModHeader = Nothing
  #  if MIN_VERSION_ghc(9,0,0)
      , hsmodLayout = NoLayoutInfo
  #  endif
  #  if MIN_VERSION_ghc(9,2,0)
      , hsmodAnn = EpAnnNotUsed
  #  endif
  #endif
      }
  
  qualified' :: ImportDecl' -> ImportDecl'
  qualified' d = d { ideclQualified =
  #if MIN_VERSION_ghc(8,10,0)
      QualifiedPre
  #else
      True
  #endif
  }
  
  as' :: ImportDecl' -> ModuleNameStr -> ImportDecl'
  as' d m = d { ideclAs = Just (mkLocated $ unModuleNameStr m) }
  
  import' :: ModuleNameStr -> ImportDecl'
  import' m = simpleImportDecl (unModuleNameStr m)
  
  exposing :: ImportDecl' -> [IE'] -> ImportDecl'
  exposing d ies = d
  #if MIN_VERSION_ghc(9,6,0)
      { ideclImportList = Just (Exactly, mkLocated $ map mkLocated ies) }
  #else
      { ideclHiding = Just (False, mkLocated $ map mkLocated ies) }
  #endif
  
  hiding :: ImportDecl' -> [IE'] -> ImportDecl'
  hiding d ies = d
  #if MIN_VERSION_ghc(9,6,0)
      { ideclImportList = Just (EverythingBut, mkLocated $ map mkLocated ies) }
  #else
      { ideclHiding = Just (True, mkLocated $ map mkLocated ies) }
  #endif
  
  -- | Adds the @{-# SOURCE #-}@ pragma to an import.
  source :: ImportDecl' -> ImportDecl'
  source d = d { ideclSource =
  #if MIN_VERSION_ghc(9,0,0)
      IsBoot
  #else
      True
  #endif
  }
  
  -- | Exports all methods and/or constructors.
  --
  -- > A(..)
  -- > =====
  -- > thingAll "A"
  thingAll :: RdrNameStr -> IE'
  #if MIN_VERSION_ghc(9,10,0)
  thingAll n = IEThingAll noAnn (wrappedName n) Nothing
  #else
  thingAll = withEpAnnNotUsed' IEThingAll . wrappedName
  #endif
  
  -- | Exports specific methods and/or constructors.
  --
  -- > A(b, C)
  -- > =====
  -- > thingWith "A" ["b", "C"]
  thingWith :: RdrNameStr -> [OccNameStr] -> IE'
  #if MIN_VERSION_ghc(9,10,0)
  thingWith n cs = IEThingWith noAnn (wrappedName n) NoIEWildcard (map (wrappedName . unqual) cs) Nothing
  #else
  thingWith n cs = withEpAnnNotUsed' IEThingWith (wrappedName n) NoIEWildcard
                      (map (wrappedName . unqual) cs)
  #if !MIN_VERSION_ghc(9,2,0)
                      -- The parsing step leaves the list of fields empty
                      -- and lumps them all together with the above list of
                      -- constructors.
                      []
  #endif
  #endif
  -- TODO: support "mixed" syntax with both ".." and explicit names.
  
  #if MIN_VERSION_ghc(9,6,0)
  wrappedName :: RdrNameStr -> GenLocated SrcSpanAnnA (IEWrappedName GhcPs)
  wrappedName rNameStr = mkLocated (IEName noExtField $ exportRdrName rNameStr)
  #else
  wrappedName :: RdrNameStr -> LIEWrappedName RdrName
  wrappedName = mkLocated . IEName . exportRdrName
  #endif
  
  -- | Exports an entire module.
  --
  -- Note: this is not valid inside of an import list.
  --
  -- > module M
  -- > =====
  -- > moduleContents "M"
  moduleContents :: ModuleNameStr -> IE'
  #if MIN_VERSION_ghc(9,10,0)
  moduleContents n = IEModuleContents noAnn (mkLocated (unModuleNameStr n))
  #else
  moduleContents = withEpAnnNotUsed' IEModuleContents . mkLocated . unModuleNameStr
  #endif
  
  #if MIN_VERSION_ghc(9,10,0)
  -- withEpAnnNotUsed' is not necessary for newer versions.
  #elif MIN_VERSION_ghc(9,8,0)
  withEpAnnNotUsed' :: ((Maybe x, EpAnn ann) -> a) -> a
  withEpAnnNotUsed' = ($ (Nothing, EpAnnNotUsed))
  #elif MIN_VERSION_ghc(9,2,0)
  withEpAnnNotUsed' :: (EpAnn ann -> a) -> a
  withEpAnnNotUsed' = withEpAnnNotUsed
  #elif MIN_VERSION_ghc(8,6,0)
  withEpAnnNotUsed' :: (NoExtField -> a) -> a
  withEpAnnNotUsed' = withEpAnnNotUsed
  #else
  withEpAnnNotUsed' :: a -> a
  withEpAnnNotUsed' = withEpAnnNotUsed
  #endif
  