/compiler/Eta/Main/Annotations.hs

https://github.com/typelead/eta · Haskell · 133 lines · 78 code · 22 blank · 33 comment · 2 complexity · 13fb8b6fe887c2b223149833959a21fe MD5 · raw file

  1. -- |
  2. -- Support for source code annotation feature of GHC. That is the ANN pragma.
  3. --
  4. -- (c) The University of Glasgow 2006
  5. -- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
  6. --
  7. module Eta.Main.Annotations (
  8. -- * Main Annotation data types
  9. Annotation(..), AnnPayload,
  10. AnnTarget(..), CoreAnnTarget,
  11. getAnnTargetName_maybe,
  12. -- * AnnEnv for collecting and querying Annotations
  13. AnnEnv,
  14. mkAnnEnv, extendAnnEnvList, plusAnnEnv, emptyAnnEnv, findAnns,
  15. findAnnsByTypeRep, deserializeAnns
  16. ) where
  17. import Eta.Utils.Binary
  18. import Eta.BasicTypes.Module ( Module )
  19. import Eta.BasicTypes.Name
  20. import Eta.Utils.Outputable
  21. import Eta.Utils.UniqFM
  22. import Eta.BasicTypes.Unique
  23. import Eta.Serialized
  24. import Control.Monad
  25. import Data.Maybe
  26. import Data.Typeable
  27. import Data.Word ( Word8 )
  28. -- | Represents an annotation after it has been sufficiently desugared from
  29. -- it's initial form of 'HsDecls.AnnDecl'
  30. data Annotation = Annotation {
  31. ann_target :: CoreAnnTarget, -- ^ The target of the annotation
  32. ann_value :: AnnPayload
  33. }
  34. type AnnPayload = Serialized -- ^ The "payload" of an annotation
  35. -- allows recovery of its value at a given type,
  36. -- and can be persisted to an interface file
  37. -- | An annotation target
  38. data AnnTarget name
  39. = NamedTarget name -- ^ We are annotating something with a name:
  40. -- a type or identifier
  41. | ModuleTarget Module -- ^ We are annotating a particular module
  42. -- | The kind of annotation target found in the middle end of the compiler
  43. type CoreAnnTarget = AnnTarget Name
  44. instance Functor AnnTarget where
  45. fmap f (NamedTarget nm) = NamedTarget (f nm)
  46. fmap _ (ModuleTarget mod) = ModuleTarget mod
  47. -- | Get the 'name' of an annotation target if it exists.
  48. getAnnTargetName_maybe :: AnnTarget name -> Maybe name
  49. getAnnTargetName_maybe (NamedTarget nm) = Just nm
  50. getAnnTargetName_maybe _ = Nothing
  51. instance Uniquable name => Uniquable (AnnTarget name) where
  52. getUnique (NamedTarget nm) = getUnique nm
  53. getUnique (ModuleTarget mod) = deriveUnique (getUnique mod) 0
  54. -- deriveUnique prevents OccName uniques clashing with NamedTarget
  55. instance Outputable name => Outputable (AnnTarget name) where
  56. ppr (NamedTarget nm) = text "Named target" <+> ppr nm
  57. ppr (ModuleTarget mod) = text "Module target" <+> ppr mod
  58. instance Binary name => Binary (AnnTarget name) where
  59. put_ bh (NamedTarget a) = do
  60. putByte bh 0
  61. put_ bh a
  62. put_ bh (ModuleTarget a) = do
  63. putByte bh 1
  64. put_ bh a
  65. get bh = do
  66. h <- getByte bh
  67. case h of
  68. 0 -> liftM NamedTarget $ get bh
  69. _ -> liftM ModuleTarget $ get bh
  70. instance Outputable Annotation where
  71. ppr ann = ppr (ann_target ann)
  72. -- | A collection of annotations
  73. -- Can't use a type synonym or we hit bug #2412 due to source import
  74. newtype AnnEnv = MkAnnEnv (UniqFM [AnnPayload])
  75. instance Outputable AnnEnv where
  76. ppr (MkAnnEnv ann) = ppr ann
  77. -- | An empty annotation environment.
  78. emptyAnnEnv :: AnnEnv
  79. emptyAnnEnv = MkAnnEnv emptyUFM
  80. -- | Construct a new annotation environment that contains the list of
  81. -- annotations provided.
  82. mkAnnEnv :: [Annotation] -> AnnEnv
  83. mkAnnEnv = extendAnnEnvList emptyAnnEnv
  84. -- | Add the given annotation to the environment.
  85. extendAnnEnvList :: AnnEnv -> [Annotation] -> AnnEnv
  86. extendAnnEnvList (MkAnnEnv env) anns
  87. = MkAnnEnv $ addListToUFM_C (++) env $
  88. map (\ann -> (getUnique (ann_target ann), [ann_value ann])) anns
  89. -- | Union two annotation environments.
  90. plusAnnEnv :: AnnEnv -> AnnEnv -> AnnEnv
  91. plusAnnEnv (MkAnnEnv env1) (MkAnnEnv env2) = MkAnnEnv $ plusUFM_C (++) env1 env2
  92. -- | Find the annotations attached to the given target as 'Typeable'
  93. -- values of your choice. If no deserializer is specified,
  94. -- only transient annotations will be returned.
  95. findAnns :: Typeable a => ([Word8] -> a) -> AnnEnv -> CoreAnnTarget -> [a]
  96. findAnns deserialize (MkAnnEnv ann_env)
  97. = (mapMaybe (fromSerialized deserialize))
  98. . (lookupWithDefaultUFM ann_env [])
  99. -- | Find the annotations attached to the given target as 'Typeable'
  100. -- values of your choice. If no deserializer is specified,
  101. -- only transient annotations will be returned.
  102. findAnnsByTypeRep :: AnnEnv -> CoreAnnTarget -> TypeRep -> [[Word8]]
  103. findAnnsByTypeRep (MkAnnEnv ann_env) target tyrep
  104. = [ ws | Serialized tyrep' ws <- lookupWithDefaultUFM ann_env [] target
  105. , tyrep' == tyrep ]
  106. -- | Deserialize all annotations of a given type. This happens lazily, that is
  107. -- no deserialization will take place until the [a] is actually demanded and
  108. -- the [a] can also be empty (the UniqFM is not filtered).
  109. deserializeAnns :: Typeable a => ([Word8] -> a) -> AnnEnv -> UniqFM [a]
  110. deserializeAnns deserialize (MkAnnEnv ann_env)
  111. = mapUFM (mapMaybe (fromSerialized deserialize)) ann_env