sv2v/src/Convert/Package.hs

191 lines
7.1 KiB
Haskell
Raw Normal View History

2019-04-24 02:22:03 +02:00
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for packages, exports, and imports
-
- TODO: We do not yet handle exports.
- TODO: The scoping rules are not being entirely followed yet.
- TODO: Explicit imports may introduce name conflicts because of carried items.
-
- The SystemVerilog scoping rules for exports and imports are not entirely
- trivial. We do not explicitly handle the "error" scenarios detailed Table
- 26-1 of Section 26-3 of IEEE 1800-2017. Users generally shouldn't be relying
- on this tool to catch and report such wild naming conflicts that are outlined
- there.
-
- Summary:
- * In scopes which have a local declaration of an identifier, that identifier
- refers to that local declaration.
- * If there is no local declaration, the identifier refers to the imported
- declaration.
- * If there is an explicit import of that identifier, the identifier refers to
- the imported declaration.
- * Usages of conflicting wildcard imports are not allowed.
2019-04-24 02:22:03 +02:00
-}
module Convert.Package (convert) where
import Control.Monad.Writer
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Convert.Traverse
import Language.SystemVerilog.AST
type Packages = Map.Map Identifier PackageItems
type PackageItems = [(Identifier, PackageItem)]
2019-04-24 02:22:03 +02:00
type Idents = Set.Set Identifier
convert :: [AST] -> [AST]
convert = step
2019-04-24 02:22:03 +02:00
where
step :: [AST] -> [AST]
step curr =
if next == curr
then curr
else step next
where
next = traverseFiles
(collectDescriptionsM collectDescriptionM)
convertFile curr
convertFile :: Packages -> AST -> AST
convertFile packages ast =
(++) globalItems $
filter (not . isCollected) $
concatMap (traverseDescription packages) $
ast
where
globalItems = map PackageItem $
concatMap (uncurry globalPackageItems) $ Map.toList packages
isCollected :: Description -> Bool
isCollected (Package _ name _) = Map.member name packages
isCollected _ = False
2019-04-24 02:22:03 +02:00
globalPackageItems :: Identifier -> PackageItems -> [PackageItem]
globalPackageItems name items =
map (prefixPackageItem name (packageItemIdents items)) (map snd items)
packageItemIdents :: PackageItems -> Idents
packageItemIdents items =
Set.union
(Set.fromList $ map fst items)
(Set.unions $ map (packageItemSubIdents . snd) items)
where
packageItemSubIdents :: PackageItem -> Idents
packageItemSubIdents (Typedef (Enum _ enumItems _) _) =
Set.fromList $ map fst enumItems
packageItemSubIdents _ = Set.empty
2019-04-24 02:22:03 +02:00
prefixPackageItem :: Identifier -> Idents -> PackageItem -> PackageItem
prefixPackageItem packageName idents item =
item''
where
prefix :: Identifier -> Identifier
prefix x =
if Set.member x idents
2020-02-22 03:17:47 +01:00
then packageName ++ '_' : x
2019-04-24 02:22:03 +02:00
else x
item' = case item of
Function a b x c d -> Function a b (prefix x) c d
Task a x c d -> Task a (prefix x) c d
Typedef a x -> Typedef a (prefix x)
Decl (Variable a b x c d) -> Decl (Variable a b (prefix x) c d)
Decl (Param a b x c ) -> Decl (Param a b (prefix x) c )
Decl (ParamType a x b ) -> Decl (ParamType a (prefix x) b )
2019-04-24 02:22:03 +02:00
other -> other
convertType (Alias Nothing x rs) = Alias Nothing (prefix x) rs
convertType (Enum t items rs) = Enum t items' rs
where
items' = map prefixItem items
2020-06-14 21:56:09 +02:00
prefixItem (x, e) = (prefix x, e)
convertType other = other
2019-04-24 02:22:03 +02:00
convertExpr (Ident x) = Ident $ prefix x
convertExpr other = other
convertLHS (LHSIdent x) = LHSIdent $ prefix x
convertLHS other = other
2019-04-24 02:22:03 +02:00
converter =
(traverseTypes $ traverseNestedTypes convertType) .
(traverseExprs $ traverseNestedExprs convertExpr) .
(traverseLHSs $ traverseNestedLHSs convertLHS )
2019-04-24 02:22:03 +02:00
MIPackageItem item'' = converter $ MIPackageItem item'
collectDescriptionM :: Description -> Writer Packages ()
collectDescriptionM (Package _ name items) =
if any isImport items
then return ()
else tell $ Map.singleton name itemList
2019-04-24 02:22:03 +02:00
where
itemList = concatMap toPackageItems items
toPackageItems :: PackageItem -> PackageItems
toPackageItems item =
2019-04-24 02:22:03 +02:00
case piName item of
2020-06-14 21:56:09 +02:00
"" -> []
x -> [(x, item)]
2019-04-24 02:22:03 +02:00
isImport :: PackageItem -> Bool
isImport (Import _ _) = True
isImport _ = False
collectDescriptionM _ = return ()
traverseDescription :: Packages -> Description -> [Description]
traverseDescription packages (PackageItem (Import x y)) =
map (\(MIPackageItem item) -> PackageItem item) items
where
orig = Part [] False Module Inherit "DNE" []
[MIPackageItem $ Import x y]
[orig'] = traverseDescription packages orig
Part [] False Module Inherit "DNE" [] items = orig'
2019-04-24 02:22:03 +02:00
traverseDescription packages description =
[description']
where
description' = traverseModuleItems
(traverseModuleItem existingItemNames packages)
description
existingItemNames = execWriter $
collectModuleItemsM writePIName description
writePIName :: ModuleItem -> Writer Idents ()
writePIName (MIPackageItem item) =
case piName item of
2020-06-14 21:56:09 +02:00
"" -> return ()
x -> tell $ Set.singleton x
writePIName _ = return ()
2019-04-24 02:22:03 +02:00
traverseModuleItem :: Idents -> Packages -> ModuleItem -> ModuleItem
traverseModuleItem existingItemNames packages (MIPackageItem (Import x y)) =
2019-04-24 02:22:03 +02:00
if Map.member x packages
then Generate $ map (GenModuleItem . MIPackageItem) items
else MIPackageItem $ Import x y
where
packageItems = packages Map.! x
filterer itemName = case y of
Nothing -> Set.notMember itemName existingItemNames
Just ident -> ident == itemName
items = map snd $ filter (filterer . fst) $ packageItems
traverseModuleItem _ _ item =
2019-04-24 02:22:03 +02:00
(traverseExprs $ traverseNestedExprs traverseExpr) $
(traverseTypes $ traverseNestedTypes traverseType) $
2019-04-24 02:22:03 +02:00
item
where
traverseExpr :: Expr -> Expr
traverseExpr (PSIdent x y) = Ident $ x ++ "_" ++ y
traverseExpr other = other
traverseType :: Type -> Type
traverseType (Alias (Just ps) xx rs) =
Alias Nothing (ps ++ "_" ++ xx) rs
traverseType other = other
2019-04-24 02:22:03 +02:00
-- returns the "name" of a package item, if it has one
2020-06-14 21:56:09 +02:00
piName :: PackageItem -> Identifier
piName (Function _ _ ident _ _) = ident
piName (Task _ ident _ _) = ident
piName (Typedef _ ident ) = ident
piName (Decl (Variable _ _ ident _ _)) = ident
piName (Decl (Param _ _ ident _)) = ident
piName (Decl (ParamType _ ident _)) = ident
piName (Decl (CommentDecl _)) = ""
piName (Import _ _) = ""
piName (Export _) = ""
piName (Directive _) = ""