packages feed

hoop-0.3.0.0: src/Language/MSH/CodeGen/Inheritance.hs

module Language.MSH.CodeGen.Inheritance where

import qualified Data.Map as M

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

import Language.MSH.StateDecl
import Language.MSH.StateEnv
import Language.MSH.MethodTable
import Language.MSH.CodeGen.Shared
import Language.MSH.CodeGen.Interop

data HasMethodResult = DefResult Bool | ContResult String

class HasMethod a where
    hasMethod :: Name -> a -> Bool

instance HasMethod Dec where
    hasMethod name (SigD n _) = nameBase n == nameBase name
    hasMethod name _          = False

isOverridenEnv :: StateEnv -> StateDecl -> Name -> Q Bool
isOverridenEnv env (StateDecl {
        stateParentN = mp,
        stateBody = body
}) name = case mp of
    Nothing  -> return $ any (hasMethod name) body
    (Just p) -> isInheritedFromParent env p name

{-parentFromInfo :: Cxt -> Maybe String
parentFromInfo [] = Nothing
parentFromInfo (ClassP n _ : cs)
    | nameBase n /= "Object" = Just (nameBase n) -- TODO: REmove "Like"?
    | otherwise              = parentFromInfo cs
parentFromInfo (_ : cs) = parentFromInfo cs-}

isInheritedFromInfo :: StateEnv -> Info -> Name -> Q Bool
isInheritedFromInfo env (ClassI (ClassD cxt _ _ _ ds) _) name = error "Inheritance:isInheritedFromInfo" {-case parentFromInfo cxt of
    Nothing -> return $ any (hasMethod name) ds
    (Just p) -> fail $ show cxt -- TODO: we should search `p'-}

isInheritedFromParent :: StateEnv -> String -> Name -> Q Bool
isInheritedFromParent env p name = let pn = nameBase $ parentName $ parseType p in case M.lookup pn env of
    (Just s) -> isOverridenEnv env s name
    Nothing  -> do
        mn <- lookupTypeName (pn ++ "Like")
        case mn of
            Nothing  -> fail $ "Can't inherit from `" ++ pn ++ "': it is not in scope."
            (Just n) -> do
                i <- reify n
                isInheritedFromInfo env i name

-- | `isInherited env mp name' determines whether a method `name' is inherited from `mp'
isInherited :: StateEnv -> Maybe String -> Name -> Q Bool
isInherited env Nothing  name = return False
isInherited env (Just p) name = isInheritedFromParent env p name

-- | `isAbstract` @name decl@ determines whether @name@ is abstract in @decl@.
isAbstract :: Name -> StateDecl -> Bool
isAbstract n (StateDecl { {- stateParent = Nothing, -} stateMethods = tbl }) =
    let nb = nameBase n
    in case M.lookup (nameBase n) (methods tbl) of
        Nothing -> error $ "[isAbstract] " ++ nb ++ " does not exist"
        Just e -> abstractEntry e
-- isAbstract n (StateDecl { stateParent = Just p, stateMethods = tbl }) =
--     let nb = nameBase n
--     in case M.lookup (nameBase n) (methods tbl) of
--         Nothing -> isAbstract n p
--         Just e -> abstractEntry e
--     M.notMember (nameBase n) (methods tbl) && isAbstract n p