2019-03-07 02:30:47 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Conversion for interfaces
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.Interface (convert) where
|
|
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
import Data.List (isPrefixOf)
|
2020-06-20 20:39:57 +02:00
|
|
|
import Data.Maybe (mapMaybe)
|
2020-08-12 01:14:18 +02:00
|
|
|
import Control.Monad.Writer.Strict
|
2019-03-07 02:30:47 +01:00
|
|
|
import qualified Data.Map.Strict as Map
|
|
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
import Convert.Scoper
|
2019-03-07 02:30:47 +01:00
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
data PartInfo = PartInfo
|
|
|
|
|
{ pKind :: PartKW
|
|
|
|
|
, pPorts :: [Identifier]
|
|
|
|
|
, pItems :: [ModuleItem]
|
|
|
|
|
} deriving Eq
|
|
|
|
|
type PartInfos = Map.Map Identifier PartInfo
|
|
|
|
|
|
|
|
|
|
type ModportInstances = [(Identifier, (Identifier, Identifier))]
|
|
|
|
|
type ModportBinding = (Identifier, (Expr, Expr))
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
2019-04-30 21:44:52 +02:00
|
|
|
convert =
|
2020-08-09 04:43:47 +02:00
|
|
|
traverseFiles (collectDescriptionsM collectPart)
|
|
|
|
|
(map . convertDescription)
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
-- we can only collect/map non-extern interfaces and modules
|
|
|
|
|
collectPart :: Description -> Writer PartInfos ()
|
|
|
|
|
collectPart (Part _ False kw _ name ports items) =
|
|
|
|
|
tell $ Map.singleton name $ PartInfo kw ports items
|
|
|
|
|
collectPart _ = return ()
|
|
|
|
|
|
|
|
|
|
convertDescription :: PartInfos -> Description -> Description
|
|
|
|
|
convertDescription _ (Part _ _ Interface _ name _ _) =
|
|
|
|
|
PackageItem $ Decl $ CommentDecl $ "removed interface: " ++ name
|
|
|
|
|
convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
|
|
|
|
if null $ extractModportInstances $ PartInfo Module ports items then
|
|
|
|
|
Part attrs extern Module lifetime name ports items'
|
|
|
|
|
else
|
|
|
|
|
PackageItem $ Decl $ CommentDecl $
|
|
|
|
|
"removed interface-using module: " ++ name
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
items' = evalScoper return traverseModuleItemM return return name items
|
|
|
|
|
|
|
|
|
|
convertNested =
|
|
|
|
|
scopeModuleItemT return traverseModuleItemM return return
|
|
|
|
|
|
|
|
|
|
traverseModuleItemM :: ModuleItem -> Scoper [ModportDecl] ModuleItem
|
|
|
|
|
traverseModuleItemM (Modport modportName modportDecls) =
|
|
|
|
|
insertElem modportName modportDecls >> return (Generate [])
|
|
|
|
|
traverseModuleItemM (instanceItem @ (Instance _ _ _ [] _)) =
|
|
|
|
|
if maybePartInfo == Nothing then
|
|
|
|
|
return instanceItem
|
|
|
|
|
else if partKind == Interface then
|
|
|
|
|
-- inline instantiation of an interface
|
|
|
|
|
convertNested $ Generate $ map GenModuleItem $
|
|
|
|
|
inlineInstance [] []
|
|
|
|
|
partItems instanceName paramBindings portBindings
|
|
|
|
|
else if not $ null (extractModportInstances partInfo) then do
|
|
|
|
|
modports <- embedScopes (\l () -> l) ()
|
|
|
|
|
-- inline instantiation of a module
|
|
|
|
|
convertNested $ Generate $ map GenModuleItem $
|
|
|
|
|
inlineInstance
|
|
|
|
|
(modportBindings modports)
|
|
|
|
|
(modportSubstitutions modports)
|
|
|
|
|
partItems instanceName paramBindings portBindings
|
|
|
|
|
else
|
|
|
|
|
return instanceItem
|
2020-06-20 20:39:57 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
Instance part rawParamBindings instanceName [] rawPortBindings =
|
|
|
|
|
instanceItem
|
|
|
|
|
maybePartInfo = Map.lookup part parts
|
|
|
|
|
Just partInfo = maybePartInfo
|
|
|
|
|
PartInfo partKind partPorts partItems = partInfo
|
|
|
|
|
|
|
|
|
|
partParams = parameterNames partItems
|
|
|
|
|
paramBindings = resolveBindings partParams rawParamBindings
|
|
|
|
|
portBindings = resolveBindings partPorts rawPortBindings
|
|
|
|
|
|
|
|
|
|
modportInstances = extractModportInstances partInfo
|
|
|
|
|
modportBindings modports = mapMaybe
|
|
|
|
|
(inferModportBinding modports modportInstances) portBindings
|
|
|
|
|
modportSubstitutions modports = concatMap
|
|
|
|
|
(expandModportBinding modports) (modportBindings modports)
|
|
|
|
|
|
|
|
|
|
traverseModuleItemM other = return other
|
|
|
|
|
|
|
|
|
|
-- determines the underlying modport and interface instances associated
|
|
|
|
|
-- with the given port binding, if it is a modport binding
|
|
|
|
|
inferModportBinding :: Scopes [ModportDecl] -> ModportInstances ->
|
|
|
|
|
PortBinding -> Maybe ModportBinding
|
|
|
|
|
inferModportBinding _ _ ("", _) =
|
|
|
|
|
error "internal inferModportBinding invariant violated"
|
|
|
|
|
inferModportBinding modports modportInstances (portName, expr) =
|
|
|
|
|
if bindingIsModport then
|
|
|
|
|
-- provided specific instance modport
|
|
|
|
|
foundModport expr
|
|
|
|
|
else if bindingIsBundle && portIsBundle then
|
|
|
|
|
-- bundle bound to a generic bundle
|
|
|
|
|
foundModport expr
|
|
|
|
|
else if bindingIsBundle && not portIsBundle then
|
|
|
|
|
-- given entire interface, but just bound to a modport
|
|
|
|
|
foundModport $ Dot expr modportName
|
|
|
|
|
else
|
|
|
|
|
Nothing
|
2019-03-07 03:55:27 +01:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
bindingIsModport = lookupElem modports expr /= Nothing
|
|
|
|
|
bindingIsBundle = lookupElem modports (Dot expr "") /= Nothing
|
|
|
|
|
portIsBundle = null modportName
|
|
|
|
|
modportName = case lookup portName modportInstances of
|
|
|
|
|
Just (_, x) -> x
|
|
|
|
|
Nothing -> error $ "can't deduce modport for interface "
|
|
|
|
|
++ " bound to port " ++ portName
|
|
|
|
|
|
|
|
|
|
foundModport modportE =
|
|
|
|
|
Just (portName, (instanceE, modportE))
|
|
|
|
|
where instanceE = findInstance modportE
|
|
|
|
|
findInstance :: Expr -> Expr
|
|
|
|
|
findInstance e =
|
|
|
|
|
case lookupElem modports (Dot e "") of
|
|
|
|
|
Nothing -> case e of
|
|
|
|
|
Bit e' _ -> findInstance e'
|
|
|
|
|
Dot e' _ -> findInstance e'
|
|
|
|
|
_ -> error "internal invariant violated"
|
|
|
|
|
Just (accesses, _, _) ->
|
|
|
|
|
foldl accessToExpr (Ident topName) rest
|
|
|
|
|
where Access topName Nil : rest = init accesses
|
|
|
|
|
accessToExpr :: Expr -> Access -> Expr
|
|
|
|
|
accessToExpr e (Access x Nil) = Dot e x
|
|
|
|
|
accessToExpr e (Access x i) = Bit (Dot e x) i
|
|
|
|
|
|
|
|
|
|
-- expand a modport binding into a series of expression substitutions
|
|
|
|
|
expandModportBinding :: Scopes [ModportDecl]
|
|
|
|
|
-> ModportBinding -> [(Expr, Expr)]
|
|
|
|
|
expandModportBinding modports (portName, (instanceE, modportE)) =
|
|
|
|
|
(Ident portName, instanceE) :
|
|
|
|
|
map toPortBinding modportDecls
|
2019-10-21 04:06:10 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
a = lookupElem modports modportE
|
|
|
|
|
b = lookupElem modports (Dot modportE "")
|
|
|
|
|
Just (_, replacements, modportDecls) =
|
|
|
|
|
if a == Nothing then b else a
|
|
|
|
|
toPortBinding (_, x, e) = (x', e')
|
2019-04-01 07:23:44 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
x' = Dot (Ident portName) x
|
|
|
|
|
e' = prefixExpr e
|
2020-06-04 02:18:14 +02:00
|
|
|
prefixExpr :: Expr -> Expr
|
2020-08-09 04:43:47 +02:00
|
|
|
prefixExpr (Ident x) =
|
|
|
|
|
case Map.lookup x replacements of
|
|
|
|
|
Just replacement -> replacement
|
|
|
|
|
Nothing ->
|
|
|
|
|
if "_tmp_" `isPrefixOf` x
|
|
|
|
|
then Ident x
|
|
|
|
|
else Dot instanceE x
|
|
|
|
|
prefixExpr other = traverseSinglyNestedExprs prefixExpr other
|
|
|
|
|
|
|
|
|
|
-- association list of modport instances in the given module body
|
|
|
|
|
extractModportInstances :: PartInfo -> ModportInstances
|
|
|
|
|
extractModportInstances partInfo =
|
|
|
|
|
execWriter $ mapM (collectDeclsM collectDecl) (pItems partInfo)
|
2020-06-04 02:18:14 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
collectDecl :: Decl -> Writer ModportInstances ()
|
|
|
|
|
collectDecl (Variable _ t x _ _) =
|
|
|
|
|
if maybeInfo == Nothing then
|
|
|
|
|
return ()
|
|
|
|
|
else if elem x (pPorts partInfo) then
|
|
|
|
|
tell [(x, info)]
|
|
|
|
|
else
|
|
|
|
|
error $ "Modport not in port list: " ++ show (t, x)
|
|
|
|
|
++ ". Is this an interface missing a port list?"
|
2020-06-20 20:39:57 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
maybeInfo = extractModportInfo t
|
|
|
|
|
Just info = maybeInfo
|
|
|
|
|
collectDecl _ = return ()
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
extractModportInfo :: Type -> Maybe (Identifier, Identifier)
|
|
|
|
|
extractModportInfo (InterfaceT "" Nothing []) = Just ("", "")
|
|
|
|
|
extractModportInfo (InterfaceT interfaceName (Just modportName) []) =
|
|
|
|
|
if isInterface interfaceName
|
|
|
|
|
then Just (interfaceName, modportName)
|
|
|
|
|
else Nothing
|
|
|
|
|
extractModportInfo (Alias interfaceName []) =
|
|
|
|
|
if isInterface interfaceName
|
|
|
|
|
then Just (interfaceName, "")
|
|
|
|
|
else Nothing
|
|
|
|
|
extractModportInfo _ = Nothing
|
|
|
|
|
|
|
|
|
|
isInterface :: Identifier -> Bool
|
|
|
|
|
isInterface partName =
|
|
|
|
|
case Map.lookup partName parts of
|
|
|
|
|
Nothing -> False
|
|
|
|
|
Just info -> pKind info == Interface
|
|
|
|
|
|
|
|
|
|
convertDescription _ other = other
|
|
|
|
|
|
|
|
|
|
-- produce the implicit modport decls for an interface bundle
|
|
|
|
|
impliedModport :: [ModuleItem] -> [ModportDecl]
|
|
|
|
|
impliedModport =
|
|
|
|
|
execWriter . mapM (collectNestedModuleItemsM collectModportDecls)
|
2020-06-20 21:56:01 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
collectModportDecls :: ModuleItem -> Writer [ModportDecl] ()
|
|
|
|
|
collectModportDecls (MIPackageItem (Decl (Variable d _ x _ _))) =
|
|
|
|
|
tell [(d', x, Ident x)]
|
|
|
|
|
where d' = if d == Local then Inout else d
|
|
|
|
|
collectModportDecls _ = return ()
|
|
|
|
|
|
|
|
|
|
-- convert an interface-bound module instantiation or an interface instantiation
|
|
|
|
|
-- into a series of equivalent inlined module items
|
|
|
|
|
inlineInstance :: [ModportBinding] -> [(Expr, Expr)] -> [ModuleItem]
|
|
|
|
|
-> Identifier -> [ParamBinding] -> [PortBinding] -> [ModuleItem]
|
|
|
|
|
inlineInstance modportBindings modportSubstitutions items
|
|
|
|
|
instanceName instanceParams instancePorts =
|
|
|
|
|
comment :
|
|
|
|
|
map (MIPackageItem . Decl) parameterBinds ++
|
|
|
|
|
Generate [GenBlock instanceName $ map GenModuleItem items']
|
|
|
|
|
: portBindings
|
|
|
|
|
where
|
|
|
|
|
items' = evalScoper
|
|
|
|
|
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM ""
|
|
|
|
|
$ map (traverseNestedModuleItems rewriteItem) $
|
|
|
|
|
if null modportBindings
|
|
|
|
|
then Modport "" (impliedModport items) : items
|
|
|
|
|
else items
|
|
|
|
|
|
|
|
|
|
inlineKind =
|
|
|
|
|
if null modportBindings
|
|
|
|
|
then "interface"
|
|
|
|
|
else "interface-using module"
|
2020-06-20 21:56:01 +02:00
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
comment = MIPackageItem $ Decl $ CommentDecl $
|
|
|
|
|
"expanded " ++ inlineKind ++ " instance: " ++ instanceName
|
|
|
|
|
portBindings = mapMaybe portBindingItem $
|
|
|
|
|
filter notSubstituted instancePorts
|
|
|
|
|
notSubstituted :: PortBinding -> Bool
|
|
|
|
|
notSubstituted (portName, _) =
|
|
|
|
|
lookup (portName) modportBindings == Nothing
|
|
|
|
|
|
|
|
|
|
rewriteItem :: ModuleItem -> ModuleItem
|
|
|
|
|
rewriteItem =
|
|
|
|
|
removeModportInstance .
|
|
|
|
|
removeDeclDir .
|
|
|
|
|
traverseDecls overrideParam
|
|
|
|
|
|
|
|
|
|
traverseDeclM :: Decl -> Scoper Expr Decl
|
2020-06-20 21:56:01 +02:00
|
|
|
traverseDeclM decl = do
|
2020-08-09 04:43:47 +02:00
|
|
|
decl' <- traverseDeclExprsM substituteExprM decl
|
2020-06-20 21:56:01 +02:00
|
|
|
case decl' of
|
2020-08-09 04:43:47 +02:00
|
|
|
Variable _ _ x _ _ -> insertElem x Nil
|
|
|
|
|
Param _ _ x e -> insertElem x e
|
|
|
|
|
ParamType _ x _ -> insertElem x Nil
|
2020-06-20 21:56:01 +02:00
|
|
|
CommentDecl{} -> return ()
|
|
|
|
|
return decl'
|
|
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
traverseModuleItemM :: ModuleItem -> Scoper Expr ModuleItem
|
|
|
|
|
traverseModuleItemM (item @ Modport{}) =
|
|
|
|
|
traverseExprsM substituteExprM item
|
|
|
|
|
traverseModuleItemM item =
|
|
|
|
|
traverseExprsM traverseExprM item >>=
|
|
|
|
|
traverseLHSsM traverseLHSM
|
|
|
|
|
|
|
|
|
|
traverseGenItemM :: GenItem -> Scoper Expr GenItem
|
|
|
|
|
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
|
|
|
|
|
|
|
|
|
traverseStmtM :: Stmt -> Scoper Expr Stmt
|
|
|
|
|
traverseStmtM =
|
|
|
|
|
traverseStmtExprsM traverseExprM >=>
|
|
|
|
|
traverseStmtLHSsM traverseLHSM
|
|
|
|
|
|
|
|
|
|
-- used for replacing usages of modports in the module being inlined
|
|
|
|
|
lhsReplacements = map (\(x, y) -> (toLHS x, toLHS y)) exprReplacements
|
|
|
|
|
exprReplacements = filter ((/= Nil) . snd) modportSubstitutions
|
|
|
|
|
-- LHSs are replaced using simple substitutions
|
|
|
|
|
traverseLHSM :: LHS -> Scoper Expr LHS
|
|
|
|
|
traverseLHSM lhs = do
|
|
|
|
|
lhs' <- embedScopes tagLHS lhs
|
|
|
|
|
return $ replaceLHS lhs'
|
|
|
|
|
tagLHS :: Scopes Expr -> LHS -> LHS
|
|
|
|
|
tagLHS scopes lhs =
|
|
|
|
|
if lookupElem scopes lhs /= Nothing
|
|
|
|
|
then LHSDot lhs "@"
|
|
|
|
|
else traverseSinglyNestedLHSs (tagLHS scopes) lhs
|
|
|
|
|
replaceLHS :: LHS -> LHS
|
|
|
|
|
replaceLHS (LHSDot lhs "@") = lhs
|
|
|
|
|
replaceLHS lhs =
|
|
|
|
|
case lookup lhs lhsReplacements of
|
|
|
|
|
Just lhs' -> lhs'
|
|
|
|
|
Nothing -> traverseSinglyNestedLHSs replaceLHS lhs
|
|
|
|
|
-- top-level expressions may be modports bound to other modports
|
|
|
|
|
traverseExprM :: Expr -> Scoper Expr Expr
|
|
|
|
|
traverseExprM expr = do
|
|
|
|
|
expr' <- embedScopes (tagExpr False) expr
|
|
|
|
|
return $ replaceExpr expr'
|
|
|
|
|
substituteExprM :: Expr -> Scoper Expr Expr
|
|
|
|
|
substituteExprM expr = do
|
|
|
|
|
expr' <- embedScopes (tagExpr True) expr
|
|
|
|
|
return $ replaceExpr expr'
|
|
|
|
|
tagExpr :: Bool -> Scopes Expr -> Expr -> Expr
|
|
|
|
|
tagExpr substitute scopes expr =
|
|
|
|
|
case lookupElem scopes expr of
|
|
|
|
|
Just (_, _, Nil) -> Dot expr "@"
|
|
|
|
|
Just ([_, _], replacements, expr') ->
|
|
|
|
|
if substitute && Map.null replacements
|
|
|
|
|
then Dot expr' "@"
|
|
|
|
|
else Dot expr "@"
|
|
|
|
|
Just (_, _, _) -> Dot expr "@"
|
|
|
|
|
Nothing ->
|
|
|
|
|
traverseSinglyNestedExprs (tagExpr substitute scopes) expr
|
|
|
|
|
replaceExpr :: Expr -> Expr
|
|
|
|
|
replaceExpr (Dot expr "@") = expr
|
|
|
|
|
replaceExpr (Ident x) =
|
|
|
|
|
case lookup x modportBindings of
|
|
|
|
|
Just (_, m) -> m
|
|
|
|
|
Nothing -> Ident x
|
|
|
|
|
replaceExpr expr =
|
|
|
|
|
replaceExpr' expr
|
|
|
|
|
replaceExpr' :: Expr -> Expr
|
|
|
|
|
replaceExpr' (Dot expr "@") = expr
|
|
|
|
|
replaceExpr' expr =
|
|
|
|
|
case lookup expr exprReplacements of
|
|
|
|
|
Just expr' -> expr'
|
|
|
|
|
Nothing -> traverseSinglyNestedExprs replaceExpr' expr
|
|
|
|
|
|
|
|
|
|
removeModportInstance :: ModuleItem -> ModuleItem
|
|
|
|
|
removeModportInstance (MIPackageItem (Decl (Variable d t x a e))) =
|
|
|
|
|
MIPackageItem $ Decl $
|
|
|
|
|
if lookup x modportBindings /= Nothing
|
|
|
|
|
then CommentDecl $ "removed modport instance " ++ x
|
|
|
|
|
else Variable d t x a e
|
|
|
|
|
removeModportInstance other = other
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-23 23:12:56 +02:00
|
|
|
removeDeclDir :: ModuleItem -> ModuleItem
|
2020-06-14 21:56:09 +02:00
|
|
|
removeDeclDir (MIPackageItem (Decl (Variable _ t x a e))) =
|
2020-06-20 02:32:37 +02:00
|
|
|
MIPackageItem $ Decl $ Variable Local t' x a e
|
|
|
|
|
where t' = case t of
|
|
|
|
|
Implicit Unspecified rs ->
|
|
|
|
|
IntegerVector TLogic Unspecified rs
|
|
|
|
|
_ -> t
|
2019-04-23 23:12:56 +02:00
|
|
|
removeDeclDir other = other
|
2020-08-09 04:43:47 +02:00
|
|
|
|
|
|
|
|
paramTmp = "_tmp_" ++ (shortHash (items, instanceName)) ++ "_"
|
|
|
|
|
|
|
|
|
|
parameterBinds = map makeParameterBind instanceParams
|
|
|
|
|
makeParameterBind :: ParamBinding -> Decl
|
|
|
|
|
makeParameterBind (x, Left t) =
|
|
|
|
|
ParamType Localparam (paramTmp ++ x) (Just t)
|
|
|
|
|
makeParameterBind (x, Right e) =
|
|
|
|
|
Param Localparam (TypeOf e) (paramTmp ++ x) e
|
|
|
|
|
|
2019-10-20 21:58:37 +02:00
|
|
|
overrideParam :: Decl -> Decl
|
|
|
|
|
overrideParam (Param Parameter t x e) =
|
2020-08-09 04:43:47 +02:00
|
|
|
case lookup x instanceParams of
|
|
|
|
|
Nothing -> Param Localparam t x e
|
|
|
|
|
Just (Right _) -> Param Localparam t x (Ident $ paramTmp ++ x)
|
|
|
|
|
Just (Left t') -> error $ inlineKind ++ " param " ++ x
|
|
|
|
|
++ " expected expr, found type: " ++ show t'
|
2019-10-20 21:58:37 +02:00
|
|
|
overrideParam (ParamType Parameter x mt) =
|
2020-08-09 04:43:47 +02:00
|
|
|
case lookup x instanceParams of
|
|
|
|
|
Nothing -> ParamType Localparam x mt
|
|
|
|
|
Just (Left _) ->
|
|
|
|
|
ParamType Localparam x (Just $ Alias (paramTmp ++ x) [])
|
|
|
|
|
Just (Right e') -> error $ inlineKind ++ " param " ++ x
|
|
|
|
|
++ " expected type, found expr: " ++ show e'
|
2019-10-20 21:58:37 +02:00
|
|
|
overrideParam other = other
|
|
|
|
|
|
2019-04-11 20:08:50 +02:00
|
|
|
portBindingItem :: PortBinding -> Maybe ModuleItem
|
2020-06-14 21:56:09 +02:00
|
|
|
portBindingItem (_, Nil) = Nothing
|
|
|
|
|
portBindingItem (ident, expr) =
|
2020-08-09 04:43:47 +02:00
|
|
|
if findDeclDir ident == Input
|
|
|
|
|
then bind (LHSDot (LHSIdent instanceName) ident) expr
|
|
|
|
|
else bind (toLHS expr) (Dot (Ident instanceName) ident)
|
|
|
|
|
where bind a b = Just $ Assign AssignOptionNone a b
|
2019-04-11 20:08:50 +02:00
|
|
|
|
|
|
|
|
declDirs = execWriter $
|
2020-08-09 04:43:47 +02:00
|
|
|
mapM (collectDeclsM collectDeclDir) items
|
2019-04-11 20:08:50 +02:00
|
|
|
collectDeclDir :: Decl -> Writer (Map.Map Identifier Direction) ()
|
|
|
|
|
collectDeclDir (Variable dir _ ident _ _) =
|
2020-06-20 22:41:13 +02:00
|
|
|
when (dir /= Local) $
|
|
|
|
|
tell $ Map.singleton ident dir
|
2019-04-11 20:08:50 +02:00
|
|
|
collectDeclDir _ = return ()
|
2020-08-09 04:43:47 +02:00
|
|
|
findDeclDir :: Identifier -> Direction
|
|
|
|
|
findDeclDir ident =
|
|
|
|
|
case Map.lookup ident declDirs of
|
|
|
|
|
Nothing -> error $ "could not find decl dir of " ++ ident
|
|
|
|
|
++ " among " ++ show declDirs
|
|
|
|
|
Just dir -> dir
|
2019-04-11 20:08:50 +02:00
|
|
|
|
2019-04-23 02:44:35 +02:00
|
|
|
toLHS :: Expr -> LHS
|
|
|
|
|
toLHS expr =
|
|
|
|
|
case exprToLHS expr of
|
|
|
|
|
Just lhs -> lhs
|
2020-08-09 04:43:47 +02:00
|
|
|
Nothing -> error $ "trying to bind an " ++ inlineKind
|
|
|
|
|
++ " output to " ++ show expr ++ " but that can't be an LHS"
|
|
|
|
|
|
|
|
|
|
type Binding t = (Identifier, t)
|
|
|
|
|
-- give a set of bindings explicit names
|
|
|
|
|
resolveBindings :: Show t => [Identifier] -> [Binding t] -> [Binding t]
|
|
|
|
|
resolveBindings available bindings =
|
|
|
|
|
zipWith resolveBinding bindings [0..]
|
2020-06-15 04:54:23 +02:00
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
resolveBinding ("", e) idx =
|
2020-06-15 04:54:23 +02:00
|
|
|
if idx < length available
|
|
|
|
|
then (available !! idx, e)
|
2020-08-09 04:43:47 +02:00
|
|
|
else error $ "binding " ++ show e ++ " is out of range "
|
|
|
|
|
++ show available
|
|
|
|
|
resolveBinding other _ = other
|
2020-06-15 04:54:23 +02:00
|
|
|
|
2020-08-09 04:43:47 +02:00
|
|
|
-- given a list of module items, produces the parameter names in order
|
|
|
|
|
parameterNames :: [ModuleItem] -> [Identifier]
|
|
|
|
|
parameterNames =
|
2020-06-15 04:54:23 +02:00
|
|
|
execWriter . mapM (collectNestedModuleItemsM $ collectDeclsM collectDeclM)
|
|
|
|
|
where
|
2020-08-09 04:43:47 +02:00
|
|
|
collectDeclM :: Decl -> Writer [Identifier] ()
|
|
|
|
|
collectDeclM (Param Parameter _ x _) = tell [x]
|
|
|
|
|
collectDeclM (ParamType Parameter x _) = tell [x]
|
2020-06-15 04:54:23 +02:00
|
|
|
collectDeclM _ = return ()
|