hic-0.0.0.1: src/Language/Cimple/Analysis/Refined/Inference/Translator.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Strict #-}
{-# LANGUAGE TupleSections #-}
module Language.Cimple.Analysis.Refined.Inference.Translator
( translateRegistry
, translateDescr
, translateMember
, translateType
, translateType'
, translateReturnType
, translateTemplateIdGlobal
, nodeToTypeInfo
, translateStdType
) where
import Control.Monad.State.Strict (State,
get,
gets,
modify)
import Data.Fix (Fix (..),
foldFix)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Read as TR
import Data.Word (Word32)
import Language.Cimple (Lexeme (..))
import qualified Language.Cimple as C
import Language.Cimple.Analysis.Refined.Inference.Substitution
import Language.Cimple.Analysis.Refined.Inference.Types
import Language.Cimple.Analysis.Refined.Inference.Utils
import Language.Cimple.Analysis.Refined.LatticeOp
import Language.Cimple.Analysis.Refined.Registry
import Language.Cimple.Analysis.Refined.Types
import qualified Language.Cimple.Analysis.TypeSystem as TS
translateRegistry :: TS.TypeSystem -> State TranslatorState (Registry Word32)
translateRegistry ts = do
defs <- Map.traverseWithKey (\_ d -> translateDescr d) ts
return $ Registry defs
translateDescr :: TS.TypeDescr 'TS.Global -> State TranslatorState (TypeDefinition Word32)
translateDescr = \case
TS.StructDescr name params members -> do
memberDefs <- mapM translateMember members
return $ StructDef name (map ((, Invariant) . translateTemplateIdGlobal) params) memberDefs
TS.UnionDescr name params members -> do
memberDefs <- mapM translateMember members
return $ UnionDef name (map ((, Invariant) . translateTemplateIdGlobal) params) memberDefs
TS.EnumDescr name _ ->
return $ EnumDef name []
TS.IntDescr name _ ->
return $ EnumDef name []
TS.FuncDescr name params _ _ ->
return $ StructDef name (map ((, Invariant) . translateTemplateIdGlobal) params) []
TS.AliasDescr name params _ ->
return $ StructDef name (map ((, Invariant) . translateTemplateIdGlobal) params) []
nodeToTypeInfo :: TS.TypeSystem -> C.Node (Lexeme Text) -> TS.TypeInfo 'TS.Global
nodeToTypeInfo ts (Fix node) = case node of
C.TyStd l -> TS.builtin l
C.TyPointer t -> TS.Pointer (nodeToTypeInfo ts t)
C.FunctionPrototype ret _ params ->
TS.Function (nodeToTypeInfo ts ret) (map (nodeToTypeInfo ts) params)
C.VarDecl ty _ dims ->
let baseTy = nodeToTypeInfo ts ty
in if null dims then baseTy else TS.Array (Just baseTy) (map (nodeToTypeInfo ts) dims)
C.DeclSpecArray _ mSize -> maybe TS.Unconstrained (nodeToTypeInfo ts) mSize
C.TyConst t -> TS.Const (nodeToTypeInfo ts t)
C.TyNonnull t -> TS.Nonnull (nodeToTypeInfo ts t)
C.TyNullable t -> TS.Nullable (nodeToTypeInfo ts t)
C.TyOwner t -> TS.Owner (nodeToTypeInfo ts t)
C.TyUserDefined (L _ _ t) -> case TS.lookupType t ts of
Just (TS.AliasDescr _ _ target) -> target
_ -> TS.TypeRef TS.UnresolvedRef (L (C.AlexPn 0 0 0) C.IdVar (TS.TIdName t)) []
C.TyStruct l -> TS.TypeRef TS.StructRef (fmap TS.TIdName l) []
C.TyUnion l -> TS.TypeRef TS.UnionRef (fmap TS.TIdName l) []
C.TyFunc l -> TS.TypeRef TS.FuncRef (fmap TS.TIdName l) []
C.VarExpr l -> TS.TypeRef TS.UnresolvedRef (fmap TS.TIdName l) []
C.LiteralExpr C.Int l -> TS.IntLit (fmap TS.TIdName l)
f -> TS.Unsupported (T.pack (show (Fix f)))
translateMember :: (Lexeme Text, TS.TypeInfo 'TS.Global) -> State TranslatorState (Member Word32)
translateMember (name, ty) = do
tyId <- translateType ty
return $ Member name tyId
-- | Translates a standard Cimple type to a Refined RigidNode.
translateType :: TS.TypeInfo 'TS.Global -> State TranslatorState Word32
translateType ty = do
st <- get
let ty' = TS.resolveRef (tsTypeSystem st) ty
let TS.FlatType {..} = TS.toFlat ty'
-- Check if this is a nominal type with an existential form
mExistId <- case ftStructure of
TS.TypeRefF _ name params -> do
let baseName = TS.templateIdBaseName (C.lexemeText name)
dtraceM ("translateType: checking nominal " ++ show baseName ++ " params=" ++ show (length params))
case Map.lookup baseName (tsExistentials st) of
Just existId -> do
-- If it's a generic application (all params are template vars),
-- or if it has no params, we return the existential.
let isGeneric = all isTemplateParam params
dtraceM ("translateType: found existential " ++ show existId ++ " for " ++ show baseName ++ " isGeneric=" ++ show isGeneric)
if isGeneric || null params then return (Just existId) else return Nothing
Nothing -> return Nothing
_ -> return Nothing
case mExistId of
Just existId -> return existId
Nothing -> do
let fresh = isFreshCandidate ty'
mId <- if fresh then return Nothing else gets (Map.lookup ty' . tsCache)
case mId of
Just nid -> return nid
Nothing -> do
nid <- gets tsNextId
modify $ \s -> s { tsNextId = nid + 1 }
-- Only cache non-void types to ensure freshness for void*
if not fresh then
modify $ \s -> s { tsCache = Map.insert ty' nid (tsCache s) }
else return ()
node <- translateType' ty'
dtraceM ("Registering ID " ++ show nid ++ ": " ++ show node)
modify (addNode nid node)
return nid
where
isTemplateParam (Fix (TS.TemplateF _)) = True
isTemplateParam _ = False
isFreshCandidate = foldFix (\case
TS.BuiltinTypeF TS.VoidTy -> True
TS.TemplateF (TS.FT tid _) -> case tid of
TS.TIdParam {} -> True
TS.TIdAnonymous {} -> True
_ -> False
f -> any id f)
translateType' :: TS.TypeInfo 'TS.Global -> State TranslatorState (AnyRigidNodeF TemplateId Word32)
translateType' ty = do
let TS.FlatType {..} = TS.toFlat ty
dtraceM ("translateType': ftStructure=" ++ show (fmap (const ()) ftStructure))
let quals = Quals (TS.QConst `Set.member` ftQuals)
nullability = if TS.QNonnull `Set.member` ftQuals then QNonnull'
else if TS.QNullable `Set.member` ftQuals then QNullable'
else QUnspecified
ownership = if TS.QOwner `Set.member` ftQuals then QOwned' else QNonOwned'
case ftStructure of
TS.BuiltinTypeF TS.VoidTy -> do
nid <- gets tsNextId
let tid = TIdParam PLocal nid (Just "T")
modify $ \s -> s { tsNextId = nid + 1 }
modify (addNode nid (AnyRigidNodeF (RObject (VVar tid Nothing) quals)))
return $ AnyRigidNodeF (RObject (VVar tid Nothing) quals)
TS.BuiltinTypeF bt -> case translateStdType bt of
Just sbt -> return $ AnyRigidNodeF (RObject (VBuiltin sbt) quals)
Nothing -> return $ AnyRigidNodeF (RTerminal SConflict)
TS.PointerF inner -> do
let (Fix innerF) = inner
case innerF of
TS.FunctionF ret args -> do
retId <- translateReturnType ret
argIds <- mapM translateType args
return $ AnyRigidNodeF (RReference (Ptr (TargetFunction argIds retId)) nullability ownership quals)
TS.TypeRefF TS.FuncRef name _ -> do
st <- get
case TS.lookupType (TS.templateIdBaseName (C.lexemeText name)) (tsTypeSystem st) of
Just (TS.FuncDescr _ _ ret args) -> do
retId <- translateReturnType ret
argIds <- mapM translateType args
return $ AnyRigidNodeF (RReference (Ptr (TargetFunction argIds retId)) nullability ownership quals)
_ -> do
innerId <- translateType inner
return $ AnyRigidNodeF (RReference (Ptr (TargetObject innerId)) nullability ownership quals)
TS.BuiltinTypeF TS.VoidTy -> do
varNid <- gets tsNextId
let tid = TIdParam PLocal varNid (Just "T")
modify $ \s -> s { tsNextId = varNid + 1 }
modify (addNode varNid (AnyRigidNodeF (RObject (VVar tid Nothing) (Quals False))))
return $ AnyRigidNodeF (RReference (Ptr (TargetOpaque tid)) nullability ownership quals)
_ -> do
innerId <- translateType inner
return $ AnyRigidNodeF (RReference (Ptr (TargetObject innerId)) nullability ownership quals)
TS.FunctionF ret args -> do
retId <- translateReturnType ret
argIds <- mapM translateType args
return $ AnyRigidNodeF (RFunction argIds retId)
TS.ArrayF (Just inner) dims -> do
innerId <- translateType inner
dimIds <- mapM translateType dims
return $ AnyRigidNodeF (RReference (Arr innerId dimIds) nullability ownership quals)
TS.TypeRefF _ name params -> do
paramIds <- mapM translateType params
return $ AnyRigidNodeF (RObject (VNominal (fmap translateTemplateIdGlobal name) paramIds) quals)
TS.TemplateF (TS.FT tid _) -> do
return $ AnyRigidNodeF (RObject (VVar (translateTemplateIdGlobal tid) Nothing) quals)
TS.SingletonF st val -> case translateStdType st of
Just sbt -> return $ AnyRigidNodeF (RObject (VSingleton sbt val) quals)
Nothing -> return $ AnyRigidNodeF (RTerminal SConflict)
TS.IntLitF l -> do
let t = TS.templateIdToText (C.lexemeText l)
case TR.decimal t of
Right (i, _) -> return $ AnyRigidNodeF (RObject (VSingleton S32Ty i) (Quals True))
Left _ -> return $ AnyRigidNodeF (RTerminal SConflict)
_ -> return $ AnyRigidNodeF (RTerminal SConflict)
translateReturnType :: TS.TypeInfo 'TS.Global -> State TranslatorState (ReturnType Word32)
translateReturnType (Fix (TS.BuiltinTypeF TS.VoidTy)) = return RetVoid
translateReturnType ty = RetVal <$> translateType ty
translateTemplateIdGlobal :: TS.TemplateId 'TS.Global -> TemplateId
translateTemplateIdGlobal = \case
TS.TIdName n -> TIdName n
TS.TIdParam i h -> TIdParam PGlobal (fromIntegral i) h
TS.TIdAnonymous h -> TIdName (fromMaybe "ANON" h)
TS.TIdRec i -> TIdName ("REC" <> T.pack (show i))
translateStdType :: TS.StdType -> Maybe StdType
translateStdType = \case
TS.BoolTy -> Just BoolTy
TS.CharTy -> Just CharTy
TS.U08Ty -> Just U08Ty
TS.S08Ty -> Just S08Ty
TS.U16Ty -> Just U16Ty
TS.S16Ty -> Just S16Ty
TS.U32Ty -> Just U32Ty
TS.S32Ty -> Just S32Ty
TS.U64Ty -> Just U64Ty
TS.S64Ty -> Just S64Ty
TS.SizeTy -> Just SizeTy
TS.F32Ty -> Just F32Ty
TS.F64Ty -> Just F64Ty
TS.NullPtrTy -> Just NullPtrTy
TS.VoidTy -> Nothing