2020-07-11 01:45:36 +02:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
2019-09-11 09:27:18 +02:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Conversion for `parameter type` in module instantiations
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.ParamType (convert) where
|
|
|
|
|
|
2020-08-12 01:14:18 +02:00
|
|
|
import Control.Monad.Writer.Strict
|
2019-09-11 09:27:18 +02:00
|
|
|
import Data.Either (isLeft)
|
|
|
|
|
import Data.Maybe (isJust, isNothing, fromJust)
|
|
|
|
|
import qualified Data.Map.Strict as Map
|
2019-09-11 17:58:03 +02:00
|
|
|
import qualified Data.Set as Set
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2020-07-12 23:06:27 +02:00
|
|
|
import Convert.ExprUtils
|
2019-09-11 09:27:18 +02:00
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
|
|
|
|
type MaybeTypeMap = Map.Map Identifier (Maybe Type)
|
|
|
|
|
type Info = Map.Map Identifier ([Identifier], MaybeTypeMap)
|
|
|
|
|
|
2020-07-11 01:45:36 +02:00
|
|
|
type Instance = Map.Map Identifier (Type, IdentSet)
|
2020-04-05 19:09:52 +02:00
|
|
|
type Instances = Set.Set (Identifier, Instance)
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
type IdentSet = Set.Set Identifier
|
|
|
|
|
type UsageMap = [(Identifier, Set.Set Identifier)]
|
|
|
|
|
|
2019-09-11 09:27:18 +02:00
|
|
|
convert :: [AST] -> [AST]
|
|
|
|
|
convert files =
|
2019-09-11 17:58:03 +02:00
|
|
|
files'''
|
2019-09-11 09:27:18 +02:00
|
|
|
where
|
|
|
|
|
info = execWriter $
|
|
|
|
|
mapM (collectDescriptionsM collectDescriptionM) files
|
|
|
|
|
(files', instancesRaw) = runWriter $ mapM
|
2019-09-11 17:58:03 +02:00
|
|
|
(mapM $ traverseModuleItemsM $ convertModuleItemM info) files
|
2020-04-05 19:09:52 +02:00
|
|
|
instances = Set.toList instancesRaw
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- add type parameter instantiations
|
|
|
|
|
files'' = map (concatMap explodeDescription) files'
|
2019-09-11 09:27:18 +02:00
|
|
|
explodeDescription :: Description -> [Description]
|
2019-09-16 05:17:14 +02:00
|
|
|
explodeDescription (part @ (Part _ _ _ _ name _ _)) =
|
2019-09-11 17:58:03 +02:00
|
|
|
if null theseInstances then
|
|
|
|
|
[part]
|
|
|
|
|
else
|
|
|
|
|
(:) part $
|
|
|
|
|
filter (not . alreadyExists) $
|
|
|
|
|
filter isNonDefault $
|
|
|
|
|
map (rewriteModule part) theseInstances
|
|
|
|
|
where
|
|
|
|
|
theseInstances = map snd $ filter ((== name) . fst) instances
|
|
|
|
|
isNonDefault = (name /=) . moduleName
|
|
|
|
|
alreadyExists = (flip Map.member info) . moduleName
|
|
|
|
|
moduleName :: Description -> Identifier
|
2019-09-16 05:17:14 +02:00
|
|
|
moduleName (Part _ _ _ _ x _ _) = x
|
2019-09-11 17:58:03 +02:00
|
|
|
moduleName _ = error "not possible"
|
2019-09-11 09:27:18 +02:00
|
|
|
explodeDescription other = [other]
|
|
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- remove or rewrite source modules that are no longer needed
|
2020-02-09 17:04:11 +01:00
|
|
|
files''' = map (\a -> concatMap (replaceDefault a) a) files''
|
2019-09-11 17:58:03 +02:00
|
|
|
(usageMapRaw, usedTypedModulesRaw) =
|
|
|
|
|
execWriter $ mapM (mapM collectUsageInfoM) files''
|
|
|
|
|
usageMap = Map.unionsWith Set.union $ map (uncurry Map.singleton)
|
|
|
|
|
usageMapRaw
|
|
|
|
|
usedTypedModules = Map.unionsWith Set.union $ map (uncurry
|
|
|
|
|
Map.singleton) usedTypedModulesRaw
|
|
|
|
|
collectUsageInfoM :: Description -> Writer (UsageMap, UsageMap) ()
|
2019-09-16 05:17:14 +02:00
|
|
|
collectUsageInfoM (part @ (Part _ _ _ _ name _ _)) =
|
2019-09-11 17:58:03 +02:00
|
|
|
tell (makeList used, makeList usedTyped)
|
|
|
|
|
where
|
|
|
|
|
makeList s = zip (Set.toList s) (repeat $ Set.singleton name)
|
|
|
|
|
(usedUntyped, usedTyped) =
|
|
|
|
|
execWriter $ (collectModuleItemsM collectModuleItemM) part
|
|
|
|
|
used = Set.union usedUntyped usedTyped
|
|
|
|
|
collectUsageInfoM _ = return ()
|
|
|
|
|
collectModuleItemM :: ModuleItem -> Writer (IdentSet, IdentSet) ()
|
|
|
|
|
collectModuleItemM (Instance m bindings _ _ _) = do
|
|
|
|
|
case Map.lookup m info of
|
|
|
|
|
Nothing -> tell (Set.singleton m, Set.empty)
|
|
|
|
|
Just (_, maybeTypeMap) ->
|
|
|
|
|
if any (flip Map.member maybeTypeMap) $ map fst bindings
|
|
|
|
|
then tell (Set.empty, Set.singleton m)
|
|
|
|
|
else tell (Set.singleton m, Set.empty)
|
|
|
|
|
collectModuleItemM _ = return ()
|
2020-02-09 17:04:11 +01:00
|
|
|
replaceDefault :: [Description] -> Description -> [Description]
|
|
|
|
|
replaceDefault existing (part @ (Part _ _ _ _ name _ _)) =
|
2019-09-11 17:58:03 +02:00
|
|
|
if Map.notMember name info then
|
|
|
|
|
[part]
|
|
|
|
|
else if Map.null maybeTypeMap then
|
|
|
|
|
[part]
|
|
|
|
|
else if Map.member name usedTypedModules && isUsed name then
|
|
|
|
|
[part]
|
|
|
|
|
else if all isNothing maybeTypeMap then
|
|
|
|
|
[]
|
|
|
|
|
else
|
2020-06-01 03:29:37 +02:00
|
|
|
filter (not . alreadyExists) $
|
2019-09-11 17:58:03 +02:00
|
|
|
(:) (removeDefaultTypeParams part) $
|
|
|
|
|
if isNothing typeMap
|
|
|
|
|
then []
|
|
|
|
|
else [rewriteModule part $ fromJust typeMap]
|
|
|
|
|
where
|
|
|
|
|
maybeTypeMap = snd $ info Map.! name
|
|
|
|
|
typeMap = defaultInstance maybeTypeMap
|
2020-06-14 21:56:09 +02:00
|
|
|
existingNames = map moduleName existing
|
|
|
|
|
alreadyExists = (flip elem existingNames) . moduleName
|
|
|
|
|
moduleName :: Description -> Identifier
|
|
|
|
|
moduleName (Part _ _ _ _ x _ _) = x
|
|
|
|
|
moduleName _ = ""
|
2020-02-09 17:04:11 +01:00
|
|
|
replaceDefault _ other = [other]
|
2019-09-11 17:58:03 +02:00
|
|
|
|
|
|
|
|
removeDefaultTypeParams :: Description -> Description
|
2019-09-16 05:17:14 +02:00
|
|
|
removeDefaultTypeParams (part @ Part{}) =
|
|
|
|
|
Part attrs extern kw ml (moduleDefaultName name) p items
|
2019-09-11 17:58:03 +02:00
|
|
|
where
|
2019-09-16 05:17:14 +02:00
|
|
|
Part attrs extern kw ml name p items =
|
2019-09-11 17:58:03 +02:00
|
|
|
traverseModuleItems (traverseDecls rewriteDecl) part
|
|
|
|
|
rewriteDecl :: Decl -> Decl
|
|
|
|
|
rewriteDecl (ParamType Parameter x _) =
|
2021-01-24 17:55:03 +01:00
|
|
|
ParamType Parameter x UnknownType
|
2019-09-11 17:58:03 +02:00
|
|
|
rewriteDecl other = other
|
|
|
|
|
removeDefaultTypeParams _ = error "not possible"
|
|
|
|
|
|
|
|
|
|
isUsed :: Identifier -> Bool
|
|
|
|
|
isUsed name =
|
|
|
|
|
any (flip Map.notMember usedTypedModules) used
|
|
|
|
|
where
|
|
|
|
|
used = usageSet $ expandSet name
|
|
|
|
|
expandSet :: Identifier -> IdentSet
|
|
|
|
|
expandSet ident =
|
|
|
|
|
case ( Map.lookup ident usedTypedModules
|
|
|
|
|
, Map.lookup name usageMap) of
|
|
|
|
|
(Just x, _) -> x
|
|
|
|
|
(Nothing, Just x) -> x
|
|
|
|
|
_ -> Set.empty
|
|
|
|
|
usageSet :: IdentSet -> IdentSet
|
|
|
|
|
usageSet names =
|
|
|
|
|
if names' == names
|
|
|
|
|
then names
|
|
|
|
|
else usageSet names'
|
|
|
|
|
where names' =
|
|
|
|
|
Set.union names $
|
|
|
|
|
Set.unions $
|
|
|
|
|
Set.map expandSet names
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- substitute in a particular instance's parameter types
|
2019-09-11 09:27:18 +02:00
|
|
|
rewriteModule :: Description -> Instance -> Description
|
|
|
|
|
rewriteModule part typeMap =
|
2020-07-09 02:56:41 +02:00
|
|
|
Part attrs extern kw ml m' p (additionalParamItems ++ items')
|
2019-09-11 09:27:18 +02:00
|
|
|
where
|
2019-09-16 05:17:14 +02:00
|
|
|
Part attrs extern kw ml m p items = part
|
2019-09-11 17:58:03 +02:00
|
|
|
m' = moduleInstanceName m typeMap
|
2021-04-13 22:44:22 +02:00
|
|
|
items' = map rewriteModuleItem items
|
|
|
|
|
rewriteModuleItem = traverseDecls rewriteDecl .
|
|
|
|
|
traverseNestedModuleItems
|
|
|
|
|
(traverseExprs rewriteExpr . traverseLHSs rewriteLHS)
|
2020-07-09 03:34:49 +02:00
|
|
|
rewriteDecl :: Decl -> Decl
|
|
|
|
|
rewriteDecl (ParamType Parameter x _) =
|
2021-01-24 17:55:03 +01:00
|
|
|
ParamType Localparam x (fst $ typeMap Map.! x)
|
2019-09-11 09:27:18 +02:00
|
|
|
rewriteDecl other = other
|
2020-07-09 02:56:41 +02:00
|
|
|
additionalParamItems = concatMap makeAddedParams $
|
2020-07-11 01:45:36 +02:00
|
|
|
Map.toList $ Map.map snd typeMap
|
2021-02-21 23:07:50 +01:00
|
|
|
rewriteExpr :: Expr -> Expr
|
|
|
|
|
rewriteExpr (orig @ (Dot (Ident x) y)) =
|
|
|
|
|
if x == m
|
|
|
|
|
then Dot (Ident m') y
|
|
|
|
|
else orig
|
|
|
|
|
rewriteExpr other =
|
|
|
|
|
traverseExprTypes rewriteType $
|
|
|
|
|
traverseSinglyNestedExprs rewriteExpr other
|
2021-04-13 22:44:22 +02:00
|
|
|
rewriteLHS :: LHS -> LHS
|
|
|
|
|
rewriteLHS (orig @ (LHSDot (LHSIdent x) y)) =
|
|
|
|
|
if x == m
|
|
|
|
|
then LHSDot (LHSIdent m') y
|
|
|
|
|
else orig
|
|
|
|
|
rewriteLHS other =
|
|
|
|
|
traverseLHSExprs rewriteExpr $
|
|
|
|
|
traverseSinglyNestedLHSs rewriteLHS other
|
2021-02-21 23:07:50 +01:00
|
|
|
rewriteType :: Type -> Type
|
|
|
|
|
rewriteType =
|
|
|
|
|
traverseNestedTypes $ traverseTypeExprs rewriteExpr
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2020-07-09 02:56:41 +02:00
|
|
|
makeAddedParams :: (Identifier, IdentSet) -> [ModuleItem]
|
|
|
|
|
makeAddedParams (paramName, identSet) =
|
|
|
|
|
map (MIPackageItem . Decl) $
|
|
|
|
|
map toTypeParam idents ++ map toParam idents
|
|
|
|
|
where
|
|
|
|
|
idents = Set.toList identSet
|
|
|
|
|
toParam :: Identifier -> Decl
|
|
|
|
|
toParam ident =
|
2020-07-12 23:06:27 +02:00
|
|
|
Param Parameter typ name (RawNum 0)
|
2020-07-09 02:56:41 +02:00
|
|
|
where
|
|
|
|
|
typ = Alias (addedParamTypeName paramName ident) []
|
|
|
|
|
name = addedParamName paramName ident
|
|
|
|
|
toTypeParam :: Identifier -> Decl
|
2021-01-24 17:55:03 +01:00
|
|
|
toTypeParam ident = ParamType Parameter name UnknownType
|
2020-07-09 02:56:41 +02:00
|
|
|
where name = addedParamTypeName paramName ident
|
|
|
|
|
|
2019-09-11 09:27:18 +02:00
|
|
|
-- write down module parameter names and type parameters
|
|
|
|
|
collectDescriptionM :: Description -> Writer Info ()
|
2019-09-16 05:17:14 +02:00
|
|
|
collectDescriptionM (part @ (Part _ _ _ _ name _ _)) =
|
2019-09-11 09:27:18 +02:00
|
|
|
tell $ Map.singleton name (paramNames, maybeTypeMap)
|
|
|
|
|
where
|
|
|
|
|
params = execWriter $
|
|
|
|
|
collectModuleItemsM (collectDeclsM collectDeclM) part
|
|
|
|
|
paramNames = map fst params
|
|
|
|
|
maybeTypeMap = Map.fromList $
|
|
|
|
|
map (\(x, y) -> (x, fromJust y)) $
|
|
|
|
|
filter (isJust . snd) params
|
|
|
|
|
collectDeclM :: Decl -> Writer [(Identifier, Maybe (Maybe Type))] ()
|
|
|
|
|
collectDeclM (Param Parameter _ x _) = tell [(x, Nothing)]
|
2021-01-24 17:55:03 +01:00
|
|
|
collectDeclM (ParamType Parameter x v) =
|
|
|
|
|
if v == UnknownType
|
|
|
|
|
then tell [(x, Just Nothing)]
|
|
|
|
|
else tell [(x, Just $ Just v)]
|
2019-09-11 09:27:18 +02:00
|
|
|
collectDeclM _ = return ()
|
|
|
|
|
collectDescriptionM _ = return ()
|
|
|
|
|
|
|
|
|
|
-- produces the default type mapping of a module, if there is one
|
|
|
|
|
defaultInstance :: MaybeTypeMap -> Maybe Instance
|
|
|
|
|
defaultInstance maybeTypeMap =
|
|
|
|
|
if any isNothing maybeTypeMap
|
|
|
|
|
then Nothing
|
2020-07-11 01:45:36 +02:00
|
|
|
else Just $ Map.map ((, Set.empty) . fromJust) maybeTypeMap
|
2019-09-11 09:27:18 +02:00
|
|
|
|
|
|
|
|
-- generate a "unique" name for a particular module type instance
|
2019-09-11 17:58:03 +02:00
|
|
|
moduleInstanceName :: Identifier -> Instance -> Identifier
|
|
|
|
|
moduleInstanceName m inst = m ++ "_" ++ shortHash (m, inst)
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- name for the module without any default type parameters
|
|
|
|
|
moduleDefaultName :: Identifier -> Identifier
|
|
|
|
|
moduleDefaultName m = m ++ defaultTag
|
|
|
|
|
isDefaultName :: Identifier -> Bool
|
|
|
|
|
isDefaultName m =
|
|
|
|
|
defaultTag == (reverse $ (take $ length defaultTag) $ reverse m)
|
|
|
|
|
defaultTag :: Identifier
|
|
|
|
|
defaultTag = "_sv2v_default"
|
2019-09-11 09:27:18 +02:00
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- attempt to convert an expression to syntactically equivalent type
|
|
|
|
|
exprToType :: Expr -> Maybe Type
|
2020-07-10 05:01:18 +02:00
|
|
|
exprToType (Ident x) = Just $ Alias x []
|
|
|
|
|
exprToType (PSIdent y x) = Just $ PSAlias y x []
|
|
|
|
|
exprToType (CSIdent y p x) = Just $ CSAlias y p x []
|
2019-09-11 17:58:03 +02:00
|
|
|
exprToType (Range e NonIndexed r) =
|
|
|
|
|
case exprToType e of
|
|
|
|
|
Nothing -> Nothing
|
|
|
|
|
Just t -> Just $ tf (rs ++ [r])
|
|
|
|
|
where (tf, rs) = typeRanges t
|
|
|
|
|
exprToType (Bit e i) =
|
|
|
|
|
case exprToType e of
|
|
|
|
|
Nothing -> Nothing
|
|
|
|
|
Just t -> Just $ tf (rs ++ [r])
|
|
|
|
|
where
|
|
|
|
|
(tf, rs) = typeRanges t
|
2020-07-12 23:06:27 +02:00
|
|
|
r = (simplify $ BinOp Sub i (RawNum 1), RawNum 0)
|
2019-09-11 17:58:03 +02:00
|
|
|
exprToType _ = Nothing
|
|
|
|
|
|
|
|
|
|
-- checks where a type is sufficiently resolved to be substituted
|
|
|
|
|
isSimpleType :: Type -> Bool
|
2020-06-25 05:49:59 +02:00
|
|
|
isSimpleType typ =
|
2021-02-21 23:07:50 +01:00
|
|
|
(not $ typeIsUnresolved typ) &&
|
2020-06-25 05:49:59 +02:00
|
|
|
case typ of
|
|
|
|
|
IntegerVector{} -> True
|
|
|
|
|
IntegerAtom {} -> True
|
|
|
|
|
NonInteger {} -> True
|
|
|
|
|
Net {} -> True
|
2020-07-10 05:00:23 +02:00
|
|
|
Implicit {} -> True
|
2020-06-25 05:49:59 +02:00
|
|
|
Struct _ fields _ -> all (isSimpleType . fst) fields
|
|
|
|
|
Union _ fields _ -> all (isSimpleType . fst) fields
|
|
|
|
|
_ -> False
|
|
|
|
|
|
2021-02-21 23:07:50 +01:00
|
|
|
-- returns whether a top-level type contains any dimension queries or
|
|
|
|
|
-- hierarchical references
|
|
|
|
|
typeIsUnresolved :: Type -> Bool
|
|
|
|
|
typeIsUnresolved =
|
|
|
|
|
getAny . execWriter . collectTypeExprsM
|
2020-06-25 05:49:59 +02:00
|
|
|
(collectNestedExprsM collectUnresolvedExprM)
|
|
|
|
|
where
|
2021-02-21 23:07:50 +01:00
|
|
|
collectUnresolvedExprM :: Expr -> Writer Any ()
|
|
|
|
|
collectUnresolvedExprM PSIdent{} = tell $ Any True
|
|
|
|
|
collectUnresolvedExprM CSIdent{} = tell $ Any True
|
|
|
|
|
collectUnresolvedExprM DimsFn {} = tell $ Any True
|
|
|
|
|
collectUnresolvedExprM DimFn {} = tell $ Any True
|
|
|
|
|
collectUnresolvedExprM Dot {} = tell $ Any True
|
2020-06-25 05:49:59 +02:00
|
|
|
collectUnresolvedExprM _ = return ()
|
2019-09-11 17:58:03 +02:00
|
|
|
|
2020-07-09 02:56:41 +02:00
|
|
|
prepareTypeIdents :: Identifier -> Type -> (Type, IdentSet)
|
2020-07-16 02:44:57 +02:00
|
|
|
prepareTypeIdents prefix =
|
|
|
|
|
runWriter . traverseNestedTypesM
|
|
|
|
|
(traverseTypeExprsM $ traverseNestedExprsM prepareExprIdents)
|
2020-07-09 02:56:41 +02:00
|
|
|
where
|
|
|
|
|
prepareExprIdents :: Expr -> Writer IdentSet Expr
|
|
|
|
|
prepareExprIdents (Ident x) = do
|
|
|
|
|
tell $ Set.singleton x
|
|
|
|
|
return $ Ident $ prefix ++ '_' : x
|
|
|
|
|
prepareExprIdents other = return other
|
|
|
|
|
|
|
|
|
|
addedParamName :: Identifier -> Identifier -> Identifier
|
|
|
|
|
addedParamName paramName var = paramName ++ '_' : var
|
|
|
|
|
|
|
|
|
|
addedParamTypeName :: Identifier -> Identifier -> Identifier
|
|
|
|
|
addedParamTypeName paramName var = paramName ++ '_' : var ++ "_type"
|
|
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
-- attempt to rewrite instantiations with type parameters
|
|
|
|
|
convertModuleItemM :: Info -> ModuleItem -> Writer Instances ModuleItem
|
|
|
|
|
convertModuleItemM info (orig @ (Instance m bindings x r p)) =
|
2019-09-11 09:27:18 +02:00
|
|
|
if Map.notMember m info then
|
|
|
|
|
return orig
|
2019-09-11 17:58:03 +02:00
|
|
|
else if Map.null maybeTypeMap then
|
2020-06-14 15:20:30 +02:00
|
|
|
return orig
|
2019-09-11 09:27:18 +02:00
|
|
|
else if any (isLeft . snd) bindings' then
|
|
|
|
|
error $ "param type resolution left type params: " ++ show orig
|
|
|
|
|
++ " converted to: " ++ show bindings'
|
2020-07-11 01:45:36 +02:00
|
|
|
else if any (not . isSimpleType . fst) resolvedTypes then do
|
|
|
|
|
let defaults = Map.map (Left . fst) resolvedTypes
|
2019-09-11 17:58:03 +02:00
|
|
|
let bindingsDefaulted = Map.toList $ Map.union bindingsMap defaults
|
2020-06-01 03:29:37 +02:00
|
|
|
if isDefaultName m || bindingsDefaulted == Map.toList bindingsMap
|
2019-09-11 17:58:03 +02:00
|
|
|
then return $ Instance m bindingsNamed x r p
|
|
|
|
|
else return $ Instance (moduleDefaultName m) bindingsDefaulted x r p
|
2019-09-11 09:27:18 +02:00
|
|
|
else do
|
2020-04-05 19:09:52 +02:00
|
|
|
tell $ Set.singleton (m, resolvedTypes)
|
2019-09-11 17:58:03 +02:00
|
|
|
let m' = moduleInstanceName m resolvedTypes
|
2020-07-09 02:56:41 +02:00
|
|
|
return $ Instance m' (additionalBindings ++ bindings') x r p
|
2019-09-11 09:27:18 +02:00
|
|
|
where
|
|
|
|
|
(paramNames, maybeTypeMap) = info Map.! m
|
|
|
|
|
-- attach names to unnamed parameters
|
|
|
|
|
bindingsNamed =
|
|
|
|
|
if all (== "") (map fst bindings) then
|
|
|
|
|
zip paramNames (map snd bindings)
|
|
|
|
|
else if any (== "") (map fst bindings) then
|
|
|
|
|
error $ "instance has a mix of named and unnamed params: "
|
|
|
|
|
++ show orig
|
|
|
|
|
else bindings
|
|
|
|
|
-- determine the types corresponding to each type parameter
|
|
|
|
|
bindingsMap = Map.fromList bindingsNamed
|
|
|
|
|
resolvedTypes = Map.mapWithKey resolveType maybeTypeMap
|
2020-07-11 01:45:36 +02:00
|
|
|
resolveType :: Identifier -> Maybe Type -> (Type, IdentSet)
|
2019-09-11 09:27:18 +02:00
|
|
|
resolveType paramName defaultType =
|
|
|
|
|
case (Map.lookup paramName bindingsMap, defaultType) of
|
2020-07-11 01:45:36 +02:00
|
|
|
(Nothing, Just t) -> (t, Set.empty)
|
2019-09-11 09:27:18 +02:00
|
|
|
(Nothing, Nothing) ->
|
|
|
|
|
error $ "instantiation " ++ show orig ++
|
|
|
|
|
" is missing a type parameter: " ++ paramName
|
2020-07-11 01:45:36 +02:00
|
|
|
(Just (Left t), _) -> prepareTypeIdents paramName t
|
2019-09-11 09:27:18 +02:00
|
|
|
(Just (Right e), _) ->
|
2019-09-11 17:58:03 +02:00
|
|
|
-- Some types are parsed as expressions because of the
|
|
|
|
|
-- ambiguities of defined type names.
|
|
|
|
|
case exprToType e of
|
2020-07-11 01:45:36 +02:00
|
|
|
Just t -> prepareTypeIdents paramName t
|
2019-09-11 17:58:03 +02:00
|
|
|
Nothing ->
|
|
|
|
|
error $ "instantiation " ++ show orig
|
|
|
|
|
++ " has expr " ++ show e
|
|
|
|
|
++ " for type param: " ++ paramName
|
|
|
|
|
|
2019-09-11 09:27:18 +02:00
|
|
|
-- leave only the normal expression params behind
|
|
|
|
|
isParamType = flip Map.member maybeTypeMap
|
|
|
|
|
bindings' = filter (not . isParamType . fst) bindingsNamed
|
2020-07-09 02:56:41 +02:00
|
|
|
|
|
|
|
|
-- create additional parameters needed to specify existing type params
|
|
|
|
|
additionalBindings = concatMap makeAddedParams $
|
2020-07-11 01:45:36 +02:00
|
|
|
Map.toList $ Map.map snd resolvedTypes
|
2020-07-09 02:56:41 +02:00
|
|
|
makeAddedParams :: (Identifier, IdentSet) -> [ParamBinding]
|
|
|
|
|
makeAddedParams (paramName, identSet) =
|
|
|
|
|
map toTypeParam idents ++ map toParam idents
|
|
|
|
|
where
|
|
|
|
|
idents = Set.toList identSet
|
|
|
|
|
toParam :: Identifier -> ParamBinding
|
|
|
|
|
toParam ident =
|
|
|
|
|
(addedParamName paramName ident, Right $ Ident ident)
|
|
|
|
|
toTypeParam :: Identifier -> ParamBinding
|
|
|
|
|
toTypeParam ident =
|
|
|
|
|
(addedParamTypeName paramName ident, Left $ TypeOf $ Ident ident)
|
|
|
|
|
|
2019-09-11 17:58:03 +02:00
|
|
|
convertModuleItemM _ other = return other
|