packages feed

HaskellAnalysisProgram-0.1.0: src/MetaHS/DataModel/MetaModel.hs

{-|
Module      : MetaHS.DataModel.MetaModel
Description : The MetaHS metamodel
Copyright   : Copyright (C) 2017-2019 H.H.R.F. Vos, S. Kamps
License     : -- This file is distributed under the  terms of the Apache License 2.0.
              For more information, see the file "LICENSE", which is included in the distribution.
Stability   : experimental
MetaHS metamodel
-}

{-# OPTIONS_GHC -funbox-strict-fields #-}

module MetaHS.DataModel.MetaModel
    ( Element(..)
    , Pair
    , Relation
    , MetaModel(..)
    , pPrint
    ) where

import qualified Data.Set as Set
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Text.PrettyPrint
import Text.PrettyPrint.HughesPJClass
import Prelude hiding ((<>))

-- | The various elements that can be used in the metamodel.
data Element
    = Program
        { name :: !String
        -- ^ The name of the program.
        }
    -- ^ Top level program
    | Module
        { name :: !String
        -- ^ The qualified name of the module.
        }
    -- ^ Represents a module
    | ModuleHead
        { name :: !String
        -- ^ The qualified name of the module.
        }
    -- ^ Represents a module head
    | ModuleImport
        { name :: !String
        -- ^ The qualified name of the imported module.
        }
    -- ^ Represents a module import
    | ModuleExport
        { name :: !String
        -- ^ The qualified name of the exported module.
        }
    -- ^ Represents a module export
    | Function
        { name :: !String
        -- ^ The qualified name of the function.
        }
    -- ^ Represents a function
    | DataType
        { name :: !String
        -- ^ The qualified name of the data declaration.
        }
    -- ^ Represents a datatype declaration.
    | TypeSynonym
        { name :: !String
        -- ^ The qualified name of the type synonym.
        }
    -- ^ Represents a type synonym.
    | TypeSignature
        { name :: !String
        -- ^ The qualified name of the type signature.
        }
        -- ^ Represents a type signature.
    | TypeClass
        { name :: !String
        -- ^ The qualified name of the type instance.
        }
        -- ^ Represents a type instance.
    | Instance
        { name :: !String
        -- ^ The qualified name of the type instance.
        }
    | Pragma
        { name :: !String
        -- ^ The qualified name of the inline Pragma.
        }
        -- ^ Represents an inline Pragma.
    | UnknownType
        { name :: !String
        -- ^ The "?" qualified name of the unknown type.
        }
    -- ^ Represents a type which is unknown.
    | Location
        { locationPath        :: !String
        -- ^ The path to the file containing the source code.
        , locationStartLine   :: !Int
        -- ^ The start line.
        , locationStartColumn :: !Int
        -- ^ The start column.
        , locationEndLine     :: !Int
        -- ^ The end line.
        , locationEndColumn   :: !Int
        -- ^ The end column.
        }
    -- ^ Represents a source code location.
    | StringValue
        { stringValue :: !String
        -- ^ The String value.
        }
    -- ^ Contains a generic String value.
    | IntValue
        { intValue :: !Int
        -- ^ The Int value.
        }
    -- ^ Contains a generic Int value.
    deriving (Show, Read, Eq, Ord)

-- | A Pair is defined as a tuple of Elements
type Pair = (Element,Element)

-- | A relation is defined as a set of Pair types.
--   E.g., _contains, _source, _uses, LCOM
type Relation = Set.Set (Element,Element)

-- | A metamodel is implemented as a mapping between a String and Relation.
--   The key string will denote the type of relation between the pairs in the
--   value relation.
type MetaModelImpl = Map.Map String Relation

-- | The MetaModel type.
newtype MetaModel = MetaModel { getMetaModelImpl :: MetaModelImpl }
    deriving (Read,Show)

-- | Pretty print instance for Elements.
instance Pretty Element where
    pPrint Program { name = n } = text "Program" <+> qt n
    pPrint Module { name = n } = text "Module" <+> qt n
    pPrint ModuleHead { name = n } = text "ModuleHead" <+> qt n
    pPrint ModuleImport { name = n } = text "ModuleImport" <+> qt n
    pPrint ModuleExport { name = n } = text "ModuleExport" <+> qt n
    pPrint Function { name = n } = text "Function" <+> qt n
    pPrint DataType { name = n } = text "DataType" <+> qt n
    pPrint TypeSynonym { name = n } = text "TypeSynonym" <+> qt n
    pPrint TypeSignature { name = n } = text "TypeSignature" <+> qt n
    pPrint TypeClass { name = n } = text "TypeClass" <+> qt n
    pPrint Instance { name = n } = text "Instance" <+> qt n
    pPrint Pragma { name = n } = text "Pragma" <+> qt n
    pPrint UnknownType { name = n } = text "UnknownType" <+> qt n
    pPrint Location { locationPath = p
                    , locationStartLine = sl
                    , locationStartColumn = sc
                    , locationEndLine = el
                    , locationEndColumn = ec
                    } = text "Location" <+> qt p <+> int sl <+> int sc
                        <+> int el <+> int ec
    pPrint StringValue { stringValue = v } = text "StringValue" <+> qt v
    pPrint IntValue { intValue = v } = text "IntValue" <+> qt (show v)

-- | Pretty print instance for the MetaModel.
instance Pretty MetaModel where
    pPrint metaModel =
        if null metaModelMap
        then
            text "MetaModel"
        else
            text "MetaModel" $$
            vcat ( map f (Map.keys metaModelMap) ) $$
            text ""
        where
            metaModelMap = getMetaModelImpl metaModel

            f :: String -> Doc
            f key = -- function f iterates through the keys
                text "  " <> text (show key) <> char ':' $$
                g ( fromMaybe Set.empty $ Map.lookup key metaModelMap)

            g :: Relation -> Doc
            g relation =
                if null relation
                then
                    text ""
                else
                    vcat . map (docLine "    ") $ Set.elems relation
                where
                    docLine prefix v = text prefix <> pPrint v

-- | Returns the provided String as a quoted Doc
qt :: String -> Doc
qt t = char '"' <> text t <> char '"'