Distribution/Fields/Field.hs

    {-# LANGUAGE DeriveFunctor #-}
    {-# LANGUAGE DeriveFoldable #-}
    {-# LANGUAGE DeriveTraversable #-}
    -- | Cabal-like file AST types: 'Field', 'Section' etc
    --
    -- These types are parametrized by an annotation.
    module Distribution.Fields.Field (
        -- * Cabal file
        Field (..),
        fieldName,
        fieldAnn,
        fieldUniverse,
        FieldLine (..),
        fieldLineAnn,
        fieldLineBS,
        SectionArg (..),
        sectionArgAnn,
        -- * Name
        FieldName,
        Name (..),
        mkName,
        getName,
        nameAnn,
        ) where

    import           Prelude ()
    import           Distribution.Compat.Prelude
    import           Data.ByteString             (ByteString)
    import qualified Data.ByteString.Char8       as B
    import qualified Data.Char                   as Char

    -------------------------------------------------------------------------------
    -- Cabal file
    -------------------------------------------------------------------------------

    -- | A Cabal-like file consists of a series of fields (@foo: bar@) and sections (@library ...@).
    data Field ann
        = Field   !(Name ann) [FieldLine ann]
        | Section !(Name ann) [SectionArg ann] [Field ann]
      deriving (Eq, Show, Functor, Foldable, Traversable)

    -- | Section of field name
    fieldName :: Field ann -> Name ann
    fieldName (Field n _ )    = n
    fieldName (Section n _ _) = n

    fieldAnn :: Field ann -> ann
    fieldAnn = nameAnn . fieldName

    -- | All transitive descendants of 'Field', including itself.
    --
    -- /Note:/ the resulting list is never empty.
    --
    fieldUniverse :: Field ann -> [Field ann]
    fieldUniverse f@(Section _ _ fs) = f : concatMap fieldUniverse fs
    fieldUniverse f@(Field _ _)      = [f]

    -- | A line of text representing the value of a field from a Cabal file.
    -- A field may contain multiple lines.
    --
    -- /Invariant:/ 'ByteString' has no newlines.
    data FieldLine ann  = FieldLine  !ann !ByteString
      deriving (Eq, Show, Functor, Foldable, Traversable)

    -- | @since 3.0.0.0
    fieldLineAnn :: FieldLine ann -> ann
    fieldLineAnn (FieldLine ann _) = ann

    -- | @since 3.0.0.0
    fieldLineBS :: FieldLine ann -> ByteString
    fieldLineBS (FieldLine _ bs) = bs

    -- | Section arguments, e.g. name of the library
    data SectionArg ann
        = SecArgName  !ann !ByteString
          -- ^ identifier, or something which looks like number. Also many dot numbers, i.e. "7.6.3"
        | SecArgStr   !ann !ByteString
          -- ^ quoted string
        | SecArgOther !ann !ByteString
          -- ^ everything else, mm. operators (e.g. in if-section conditionals)
      deriving (Eq, Show, Functor, Foldable, Traversable)

    -- | Extract annotation from 'SectionArg'.
    sectionArgAnn :: SectionArg ann -> ann
    sectionArgAnn (SecArgName ann _)  = ann
    sectionArgAnn (SecArgStr ann _)   = ann
    sectionArgAnn (SecArgOther ann _) = ann

    -------------------------------------------------------------------------------
    -- Name
    -------------------------------------------------------------------------------

    type FieldName = ByteString

    -- | A field name.
    --
    -- /Invariant/: 'ByteString' is lower-case ASCII.
    data Name ann  = Name       !ann !FieldName
      deriving (Eq, Show, Functor, Foldable, Traversable)

    mkName :: ann -> FieldName -> Name ann
    mkName ann bs = Name ann (B.map Char.toLower bs)

    getName :: Name ann -> FieldName
    getName (Name _ bs) = bs

    nameAnn :: Name ann -> ann
    nameAnn (Name ann _) = ann