packages feed

hic-0.0.0.1: test/Language/Cimple/Analysis/Refined/Inference/TranslatorSpec.hs

{-# LANGUAGE GADTs               #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Cimple.Analysis.Refined.Inference.TranslatorSpec (spec) where

import           Control.Monad.State.Strict                            (runState)
import           Data.Fix                                              (Fix (..))
import qualified Data.Map.Strict                                       as Map
import qualified Data.Set                                              as Set
import           Data.Word                                             (Word32)
import qualified Language.Cimple                                       as C
import           Language.Cimple.Analysis.Refined.Inference.Translator
import           Language.Cimple.Analysis.Refined.Inference.Types
import           Language.Cimple.Analysis.Refined.Types
import qualified Language.Cimple.Analysis.TypeSystem                   as TS
import           Test.Hspec

spec :: Spec
spec = describe "Language.Cimple.Analysis.Refined.Inference.Translator" $ do
    let emptyTS = Map.empty :: TS.TypeSystem
    let st0 = emptyTranslatorState emptyTS

    describe "translateStdType" $ do
        it "maps BoolTy correctly" $ do
            translateStdType TS.BoolTy `shouldBe` Just BoolTy
        it "maps VoidTy to Nothing" $ do
            translateStdType TS.VoidTy `shouldBe` Nothing

    describe "translateType" $ do
        it "translates int32_t to VBuiltin S32Ty" $ do
            let ty = TS.builtin (dummyL "int32_t")
            let (nid, st) = runState (translateType ty) st0
            Map.lookup nid (tsNodes st) `shouldBe` Just (AnyRigidNodeF (RObject (VBuiltin S32Ty) (Quals False)))

        it "translates pointer types" $ do
            let ty = TS.Pointer (TS.builtin (dummyL "int32_t"))
            let (nid, st) = runState (translateType ty) st0
            case Map.lookup nid (tsNodes st) of
                Just (AnyRigidNodeF (RReference (Ptr (TargetObject innerId)) _ _ _)) ->
                    Map.lookup (innerId :: Word32) (tsNodes st) `shouldBe` Just (AnyRigidNodeF (RObject (VBuiltin S32Ty) (Quals False)))
                _ -> expectationFailure "Expected nid to be a pointer to int32_t"

        it "handles void* by creating a fresh template parameter" $ do
            let ty = TS.Pointer (TS.builtin (dummyL "void"))
            let (nid1, st1) = runState (translateType ty) st0
            let (nid2, _) = runState (translateType ty) st1
            nid1 `shouldNotBe` nid2

        it "preserves const qualifiers" $ do
            let ty = TS.Const (TS.builtin (dummyL "int32_t"))
            let (nid, st) = runState (translateType ty) st0
            Map.lookup nid (tsNodes st) `shouldBe` Just (AnyRigidNodeF (RObject (VBuiltin S32Ty) (Quals True)))

        it "handles nested pointers (Recursive Translation)" $ do
            let ty = TS.Pointer (TS.Pointer (TS.builtin (dummyL "int32_t")))
            let (nid, st) = runState (translateType ty) st0
            case Map.lookup nid (tsNodes st) of
                Just (AnyRigidNodeF (RReference (Ptr (TargetObject p1)) _ _ _)) ->
                    case Map.lookup p1 (tsNodes st) of
                        Just (AnyRigidNodeF (RReference (Ptr (TargetObject p2)) _ _ _)) ->
                            Map.lookup p2 (tsNodes st) `shouldBe` Just (AnyRigidNodeF (RObject (VBuiltin S32Ty) (Quals False)))
                        _ -> expectationFailure "Expected p1 to be a pointer"
                _ -> expectationFailure "Expected nid to be a pointer"

        it "returns an existential type for a nominal type if registered" $ do
            let baseName = "My_Callback"
            let ty = TS.TypeRef TS.StructRef (dummyL (TS.TIdName baseName)) []
            let existId = 100
            let st = st0 { tsExistentials = Map.singleton baseName existId }
            let (nid, _) = runState (translateType ty) st
            nid `shouldBe` existId

        it "returns an existential type for a nominal type with generic parameters" $ do
            let baseName = "My_Callback"
            let param = TS.Template (TS.TIdParam 0 Nothing) Nothing
            let ty = TS.TypeRef TS.StructRef (dummyL (TS.TIdName baseName)) [param]
            let existId = 100
            let st = st0 { tsExistentials = Map.singleton baseName existId }
            let (nid, _) = runState (translateType ty) st
            nid `shouldBe` existId

    describe "translateTemplateIdGlobal" $ do
        it "maps TIdName" $ do
            translateTemplateIdGlobal (TS.TIdName "foo") `shouldBe` TIdName "foo"
        it "maps TIdParam" $ do
            translateTemplateIdGlobal (TS.TIdParam 5 (Just "T")) `shouldBe` TIdParam PGlobal 5 (Just "T")

dummyL :: t -> C.Lexeme t
dummyL = C.L (C.AlexPn 0 0 0) C.IdSueType