{- | Module : Camfort.Specification.Stencils.Annotation Description : Annotation with stencil information. Copyright : (c) 2017, Dominic Orchard, Andrew Rice, Mistral Contrastin, Matthew Danish License : Apache-2.0 Maintainer : dom.orchard@gmail.com Stability : experimental Defines the 'StencilAnnotation' datatype, which is used for annotating a 'ProgramFile' with stencil information. -} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module Camfort.Specification.Stencils.Annotation ( StencilAnnotation , SA , mkStencilAnnotation -- ** Specification Annotation Helpers , getAstSpec , getParseSpec , getRegionSpec , getStencilBlock , giveAstSpec , giveParseSpec , giveRegionSpec -- ** Base Annotation , getBaseAnnotation , modifyBaseAnnotation ) where import Data.Data (Data) import qualified Language.Fortran.AST as F import qualified Language.Fortran.Analysis as FA import qualified Camfort.Analysis.Annotations as Ann import Camfort.Analysis.CommentAnnotator import qualified Camfort.Specification.Stencils.Parser.Types as Gram import qualified Camfort.Specification.Stencils.Syntax as Syn -- | Specification annotation. data SpecAnnotation -- | Unprocessed syntax tree. = ParserSpec Gram.Specification -- | Region definition. | RegionDecl Syn.RegionDecl -- | Normalised AST specification. | ASTSpec Syn.SpecDecls deriving (Eq, Show, Data) data StencilAnnotation a = StencilAnnotation { prevAnnotation :: a -- | Assocatated specification. , stencilSpec :: Maybe SpecAnnotation -- | Associated assignment. , stencilBlock :: Maybe (F.Block (FA.Analysis (StencilAnnotation a))) } deriving (Show, Eq, Data) -- | Create a new stencil annotation. mkStencilAnnotation :: a -> StencilAnnotation a mkStencilAnnotation a = StencilAnnotation { prevAnnotation = a , stencilSpec = Nothing , stencilBlock = Nothing } -- | Convenience name for common annotation type. type SA = FA.Analysis (StencilAnnotation Ann.A) modifyBaseAnnotation :: (Ann.A -> Ann.A) -> SA -> SA modifyBaseAnnotation f = Ann.onPrev (\ann -> ann { prevAnnotation = f (prevAnnotation ann) }) -- | Retrieve the underlying (base) annotation from a stencil annotation. getBaseAnnotation :: SA -> Ann.A getBaseAnnotation = prevAnnotation . FA.prevAnnotation setSpec :: SpecAnnotation -> SA -> SA setSpec s = Ann.onPrev (\ann -> ann { stencilSpec = Just s }) -- | Set the annotation's stencil specification to a parsed specification. giveParseSpec :: Gram.Specification -> SA -> SA giveParseSpec spec = setSpec (ParserSpec spec) -- | Set the annotation's stencil specification to a region alias. giveRegionSpec :: Syn.RegionDecl -> SA -> SA giveRegionSpec spec = setSpec (RegionDecl spec) -- | Set the annotation's stencil specification to a normalized specification. giveAstSpec :: Syn.SpecDecls -> SA -> SA giveAstSpec spec = setSpec (ASTSpec spec) getSA :: SA -> StencilAnnotation Ann.A getSA = FA.prevAnnotation getSpec :: SA -> Maybe SpecAnnotation getSpec = stencilSpec . getSA -- | Retrieve a parsed specification from an annotation. getParseSpec :: SA -> Maybe Gram.Specification getParseSpec s = case getSpec s of (Just (ParserSpec spec)) -> Just spec _ -> Nothing -- | Retrieve a region environment from an annotation. getRegionSpec :: SA -> Maybe Syn.RegionDecl getRegionSpec s = case getSpec s of (Just (RegionDecl renv)) -> Just renv _ -> Nothing -- | Retrieve a normalized specification from an annotation. getAstSpec :: SA -> Maybe Syn.SpecDecls getAstSpec s = case getSpec s of (Just (ASTSpec ast)) -> Just ast _ -> Nothing getStencilBlock :: SA -> Maybe (F.Block SA) getStencilBlock = stencilBlock . getSA {- *** Routines for associating annotations to ASTs -} -- Instances for embedding parsed specifications into the AST instance ASTEmbeddable SA Gram.Specification where annotateWithAST ann ast = Ann.onPrev (\ann' -> ann' { stencilSpec = Just $ ParserSpec ast }) ann instance Linkable SA where link ann b@F.BlDo{} = Ann.onPrev (\ann' -> ann' { stencilBlock = Just b }) ann link ann (b@(F.BlStatement _ _ _ F.StExpressionAssign{})) = Ann.onPrev (\ann' -> ann' { stencilBlock = Just b }) ann link ann _ = ann linkPU ann _ = ann