packages feed

g2-0.1.0.0: src/G2/Liquid/Annotations.hs

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}

module G2.Liquid.Annotations ( AnnotMap
                                       , getAnnotations
                                       , lookupAnnot
                                       , lookupAnnotAtLoc) where

import G2.Language
import G2.Language.Monad
import G2.Liquid.Conversion
import G2.Liquid.Types

import Language.Haskell.Liquid.Liquid()
import Language.Haskell.Liquid.Constraint.Types hiding (ghcI)
import Language.Haskell.Liquid.Types hiding (Loc, names)
import Language.Haskell.Liquid.Types.RefType

import G2.Translation.Haskell

import qualified Data.HashMap.Lazy as HM
import Data.Hashable
import Data.List
import qualified Data.Map as M
import Data.Maybe
import qualified Data.Text as T

import SrcLoc

import Debug.Trace

lookupAnnot :: Name -> AnnotMap -> Maybe [(Maybe T.Text, Expr)]
lookupAnnot (Name _ _ _ (Just s)) =
    HM.lookup s . unAnnotMap
lookupAnnot _ = const Nothing

lookupAnnotAtLoc :: Name -> AnnotMap -> Maybe [(Maybe T.Text, Expr)]
lookupAnnotAtLoc (Name _ _ _ (Just (Span {start = l}))) =
    Just . concatMap snd . find (\(Span {start = l'}, _) -> l == l') . HM.toList . unAnnotMap
lookupAnnotAtLoc _ = const Nothing

getAnnotations :: [LHOutput] -> LHStateM ()
getAnnotations ghci_cg = do
    locM <- return . locLookup =<< exprEnv

    let anna = map lhCleanAnnotMaps ghci_cg
    mapM_ (annotMapToExpr locM) anna

annotMapToExpr :: M.Map Loc Name -> AnnInfo SpecType ->  LHStateM ()
annotMapToExpr locM (AI st) = mapM_ (uncurry (valToExpr locM)) (HM.toList st)

valToExpr :: M.Map Loc Name -> SrcSpan -> [(Maybe T.Text, SpecType)] -> LHStateM ()
valToExpr locM srcspn =
    case mkSpan srcspn of
        Just spn -> mapM_ (valToExpr' locM spn)
        Nothing -> return . const ()

valToExpr' :: M.Map Loc Name -> Span -> (Maybe T.Text, SpecType) -> LHStateM ()
valToExpr' locM spn@(Span {start = stloc}) (n, ast) = do
    e <- case M.lookup stloc locM of
            Just n' -> lookupE n'
            Nothing -> return Nothing

    t <- specTypeToType ast

    case (e, t) of
        (Just e', Just t') -> do
            let i = Id (Name "ret" Nothing 0 Nothing) t'
            let ai = leadingLamUsesIds e'
            dm <- dictMapFromIds (map snd ai)

            ce <- convertSpecType dm M.empty (map snd ai) (Just i) ast
            let ce' = addIds ce (ai ++ [(TermL, i)])

            insertAnnotM spn n ce'
        _ -> return ()

lhCleanAnnotMaps :: LHOutput -> AnnInfo SpecType
lhCleanAnnotMaps (LHOutput {cgI = cgi, solution = sol}) =
    applySolution sol $ closeAnnots $ annotMap cgi

addIds :: Expr -> [(LamUse, Id)] -> Expr
addIds e ((u, i):is) = Lam u i $ addIds e is
-- addIds e@(Lam _ ei _) ((u, i):is) = if i == ei then e else Lam u i $ addIds e is
addIds e _ = e

-- modeled after Language.Haskell.Liquid.UX.Annotate
closeAnnots :: AnnInfo (Annot SpecType) -> AnnInfo SpecType
closeAnnots = closeA . filterA . collapseA

closeA :: AnnInfo (Annot b) -> AnnInfo b
closeA a@(AI m)   = cf <$> a
  where
    cf (AnnLoc l)  = case m `mlookup` l of
                      [(_, AnnUse t)] -> t
                      [(_, AnnDef t)] -> t
                      [(_, AnnRDf t)] -> t
                      _               -> error $ "malformed AnnInfo: " ++ show l
    cf (AnnUse t) = t
    cf (AnnDef t) = t
    cf (AnnRDf t) = t

mlookup    :: (Eq k, Show k, Hashable k) => HM.HashMap k v -> k -> v
mlookup m k = fromMaybe err $ HM.lookup k m
  where
    err     = error $ "mlookup: unknown key " ++ show k

filterA :: AnnInfo (Annot t) -> AnnInfo (Annot t)
filterA (AI m) = AI (HM.filter ff m)
  where
    ff [(_, AnnLoc l)] = l `HM.member` m
    ff _               = True

collapseA :: AnnInfo (Annot t) -> AnnInfo (Annot t)
collapseA (AI m) = AI (fmap pickOneA m)

pickOneA :: [(t, Annot t1)] -> [(t, Annot t1)]
pickOneA xas = case (rs, ds, ls, us) of
                 (x:_, _, _, _) -> [x]
                 (_, x:_, _, _) -> [x]
                 (_, _, _:_, _) -> trace ("Loc") []
                 (_, _, _, x:_) -> [x]

                 -- (_, x:_, _, _) -> [x]
                 -- (_, _, x:_, _) -> [x]
                 -- (_, _, _, x:_) -> [x]
                 (_, _, _, _  ) -> [ ]
  where
    rs = [x | x@(_, AnnRDf _) <- xas]
    ds = [x | x@(_, AnnDef _) <- xas]
    ls = [x | x@(_, AnnLoc _) <- xas]
    us = [x | x@(_, AnnUse _) <- xas]