{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE StandaloneDeriving #-} -- | 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 -- * Conversions to String , sectionArgsToString , fieldLinesToString ) where import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as B import qualified Data.Char as Char import Distribution.Compat.Prelude import Distribution.Pretty (showTokenStr) import Distribution.Utils.Generic (fromUTF8BS) import Prelude () #if MIN_VERSION_base(4,18,0) import qualified Data.Foldable1 as F1 #endif ------------------------------------------------------------------------------- -- 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) -- | @since 3.12.0.0 deriving instance Ord ann => Ord (Field ann) -- | 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.12.0.0 deriving instance Ord ann => Ord (FieldLine ann) -- | @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 = -- | identifier, or something which looks like number. Also many dot numbers, i.e. "7.6.3" SecArgName !ann !ByteString | -- | quoted string SecArgStr !ann !ByteString | -- | everything else, mm. operators (e.g. in if-section conditionals) SecArgOther !ann !ByteString deriving (Eq, Show, Functor, Foldable, Traversable) -- | @since 3.12.0.0 deriving instance Ord ann => Ord (SectionArg ann) -- | 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) -- | @since 3.12.0.0 deriving instance Ord ann => Ord (Name ann) 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 ------------------------------------------------------------------------------- -- To Strings ------------------------------------------------------------------------------- -- | -- -- @since 3.6.0.0 sectionArgsToString :: [SectionArg ann] -> String sectionArgsToString = unwords . map toStr where toStr :: SectionArg ann -> String toStr (SecArgName _ bs) = showTokenStr (fromUTF8BS bs) toStr (SecArgStr _ bs) = showTokenStr (fromUTF8BS bs) toStr (SecArgOther _ bs) = fromUTF8BS bs -- | Convert @['FieldLine']@ into String. -- -- /Note:/ this doesn't preserve indentation or empty lines, -- as the annotations (e.g. positions) are ignored. -- -- @since 3.6.0.0 fieldLinesToString :: [FieldLine ann] -> String fieldLinesToString = -- intercalate to avoid trailing newline. intercalate "\n" . map toStr where toStr (FieldLine _ bs) = fromUTF8BS bs ------------------------------------------------------------------------------- -- Foldable1 ------------------------------------------------------------------------------- #if MIN_VERSION_base(4,18,0) -- | @since 3.12.0.0 instance F1.Foldable1 Field where foldMap1 f (Field x ys) = F1.fold1 (F1.foldMap1 f x :| map (F1.foldMap1 f) ys) foldMap1 f (Section x ys zs) = F1.fold1 (F1.foldMap1 f x :| map (F1.foldMap1 f) ys ++ map (F1.foldMap1 f) zs) -- | @since 3.12.0.0 instance F1.Foldable1 FieldLine where foldMap1 = (. fieldLineAnn) -- | @since 3.12.0.0 instance F1.Foldable1 SectionArg where foldMap1 = (. sectionArgAnn) -- | @since 3.12.0.0 instance F1.Foldable1 Name where foldMap1 = (. nameAnn) #endif