hic-0.0.0.1: src/Language/Cimple/Hic/Inference/Raise.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Cimple.Hic.Inference.Raise
( feature
) where
import Control.Monad.State.Strict (State, modify)
import qualified Control.Monad.State.Strict as State
import Data.Fix (Fix (..), foldFix, foldFixM)
import Data.Text (Text)
import qualified Language.Cimple as C
import Language.Cimple.Hic.Ast (HicNode (..), Node, NodeF (..),
ReturnIntent (..))
import Language.Cimple.Hic.Context (Context)
import Language.Cimple.Hic.Feature (Feature (..))
feature :: Feature
feature = Feature
{ featureName = "Raise"
, featureGather = \_ ctx -> ctx
, featureInfer = infer
, featureValidate = \_ _ -> []
, featureLower = lower
}
data ErrorValueInfo = IsLiteral Text | OtherValue | IsErrorValue
infer :: Context -> FilePath -> Node (C.Lexeme Text) -> State Bool (Node (C.Lexeme Text))
infer _ctx _file = foldFixM alg
where
alg (CimpleNode (C.CompoundStmt stmts)) =
Fix . CimpleNode . C.CompoundStmt <$> inferRaise stmts
alg f = return $ Fix f
inferRaise [] = return []
inferRaise (s1 : s2 : ss)
| Just (out, val) <- matchAssign s1
, Just ret <- matchReturn s2
, isErrorValue ret = do
State.modify (const True)
let res = Fix $ HicNode $ Raise (Just out) val (ReturnError ret)
(res :) <$> inferRaise ss
inferRaise (s : ss) = (s :) <$> inferRaise ss
matchAssign :: Node (C.Lexeme Text) -> Maybe (Node (C.Lexeme Text), Node (C.Lexeme Text))
matchAssign n = case unFix n of
CimpleNode (C.ExprStmt e) -> case unFix e of
CimpleNode (C.AssignExpr lhs C.AopEq val) -> Just (lhs, val)
_ -> Nothing
_ -> Nothing
matchReturn :: Node (C.Lexeme Text) -> Maybe (Node (C.Lexeme Text))
matchReturn n = case unFix n of
CimpleNode (C.Return (Just e)) -> Just e
_ -> Nothing
isErrorValue :: Node (C.Lexeme Text) -> Bool
isErrorValue node = case foldFix alg' node of
IsErrorValue -> True
_ -> False
where
alg' (CimpleNode (C.LiteralExpr C.Int l))
| C.lexemeText l == "1" = IsErrorValue -- Could be literal 1 or error value
| C.lexemeText l == "-1" = IsErrorValue
| otherwise = IsLiteral (C.lexemeText l)
alg' (CimpleNode (C.UnaryExpr C.UopMinus inner)) =
case inner of
IsLiteral "1" -> IsErrorValue
IsErrorValue -> IsErrorValue -- Handle -1 if 1 was already IsErrorValue
_ -> OtherValue
alg' (CimpleNode (C.LiteralExpr C.ConstId l))
| C.lexemeText l == "nullptr" = IsErrorValue
alg' (CimpleNode (C.LiteralExpr C.Bool l))
| C.lexemeText l == "false" = IsErrorValue
alg' _ = OtherValue
lower :: HicNode l (C.Node l) -> Maybe (C.Node l)
lower (Raise maybeOut val ret) =
Just $ Fix $ C.Group $
maybe [] (\out -> [Fix $ C.ExprStmt (Fix $ C.AssignExpr out C.AopEq val)]) maybeOut
++ [lowerReturn ret]
where
lowerReturn ReturnVoid = Fix $ C.Return Nothing
lowerReturn (ReturnValue v) = Fix $ C.Return (Just v)
lowerReturn (ReturnError e) = Fix $ C.Return (Just e)
lower _ = Nothing