2019-04-24 02:22:03 +02:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
2019-04-30 07:57:04 +02:00
|
|
|
- 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
|
2019-09-12 03:16:55 +02:00
|
|
|
type PackageItems = [(Identifier, PackageItem)]
|
2019-04-24 02:22:03 +02:00
|
|
|
type Idents = Set.Set Identifier
|
|
|
|
|
|
|
|
|
|
convert :: [AST] -> [AST]
|
2019-04-30 21:44:52 +02:00
|
|
|
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
|
2019-04-30 21:44:52 +02:00
|
|
|
next = traverseFiles
|
|
|
|
|
(collectDescriptionsM collectDescriptionM)
|
|
|
|
|
convertFile curr
|
2019-04-30 07:57:04 +02:00
|
|
|
|
|
|
|
|
convertFile :: Packages -> AST -> AST
|
2019-04-30 21:44:52 +02:00
|
|
|
convertFile packages ast =
|
2019-04-30 07:57:04 +02:00
|
|
|
(++) globalItems $
|
|
|
|
|
filter (not . isCollected) $
|
2020-02-16 21:43:55 +01:00
|
|
|
concatMap (traverseDescription packages) $
|
2019-04-30 07:57:04 +02:00
|
|
|
ast
|
|
|
|
|
where
|
|
|
|
|
globalItems = map PackageItem $
|
|
|
|
|
concatMap (uncurry globalPackageItems) $ Map.toList packages
|
|
|
|
|
isCollected :: Description -> Bool
|
2019-04-30 21:44:52 +02:00
|
|
|
isCollected (Package _ name _) = Map.member name packages
|
2019-04-30 07:57:04 +02:00
|
|
|
isCollected _ = False
|
2019-04-24 02:22:03 +02:00
|
|
|
|
|
|
|
|
globalPackageItems :: Identifier -> PackageItems -> [PackageItem]
|
|
|
|
|
globalPackageItems name items =
|
2019-09-12 03:16:55 +02:00
|
|
|
map (prefixPackageItem name (packageItemIdents items)) (map snd items)
|
2019-08-29 01:01:25 +02:00
|
|
|
|
|
|
|
|
packageItemIdents :: PackageItems -> Idents
|
|
|
|
|
packageItemIdents items =
|
|
|
|
|
Set.union
|
2019-09-12 03:16:55 +02:00
|
|
|
(Set.fromList $ map fst items)
|
|
|
|
|
(Set.unions $ map (packageItemSubIdents . snd) items)
|
2019-08-29 01:01:25 +02:00
|
|
|
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)
|
2019-09-07 04:29:14 +02:00
|
|
|
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
|
2019-08-28 03:32:03 +02:00
|
|
|
convertType (Alias Nothing x rs) = Alias Nothing (prefix x) rs
|
2020-06-05 02:19:21 +02:00
|
|
|
convertType (Enum t items rs) = Enum t items' rs
|
2019-08-29 01:01:25 +02:00
|
|
|
where
|
|
|
|
|
items' = map prefixItem items
|
|
|
|
|
prefixItem (x, me) = (prefix x, me)
|
2019-08-28 03:32:03 +02:00
|
|
|
convertType other = other
|
2019-04-24 02:22:03 +02:00
|
|
|
convertExpr (Ident x) = Ident $ prefix x
|
|
|
|
|
convertExpr other = other
|
2019-04-24 10:01:33 +02:00
|
|
|
convertLHS (LHSIdent x) = LHSIdent $ prefix x
|
|
|
|
|
convertLHS other = other
|
2019-04-24 02:22:03 +02:00
|
|
|
converter =
|
2019-08-28 03:32:03 +02:00
|
|
|
(traverseTypes $ traverseNestedTypes convertType) .
|
2019-04-24 10:01:33 +02:00
|
|
|
(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 ()
|
2019-09-12 03:16:55 +02:00
|
|
|
else tell $ Map.singleton name itemList
|
2019-04-24 02:22:03 +02:00
|
|
|
where
|
2019-09-12 03:16:55 +02:00
|
|
|
itemList = concatMap toPackageItems items
|
|
|
|
|
toPackageItems :: PackageItem -> PackageItems
|
|
|
|
|
toPackageItems item =
|
2019-04-24 02:22:03 +02:00
|
|
|
case piName item of
|
2019-09-12 03:16:55 +02:00
|
|
|
Nothing -> []
|
|
|
|
|
Just x -> [(x, item)]
|
2019-04-24 02:22:03 +02:00
|
|
|
isImport :: PackageItem -> Bool
|
|
|
|
|
isImport (Import _ _) = True
|
|
|
|
|
isImport _ = False
|
|
|
|
|
collectDescriptionM _ = return ()
|
|
|
|
|
|
2020-02-16 21:43:55 +01:00
|
|
|
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 =
|
2020-02-16 21:43:55 +01:00
|
|
|
[description']
|
2019-04-30 07:57:04 +02:00
|
|
|
where
|
2020-02-16 21:43:55 +01:00
|
|
|
description' = traverseModuleItems
|
|
|
|
|
(traverseModuleItem existingItemNames packages)
|
|
|
|
|
description
|
2019-04-30 07:57:04 +02:00
|
|
|
existingItemNames = execWriter $
|
|
|
|
|
collectModuleItemsM writePIName description
|
|
|
|
|
writePIName :: ModuleItem -> Writer Idents ()
|
|
|
|
|
writePIName (MIPackageItem item) =
|
|
|
|
|
case piName item of
|
|
|
|
|
Nothing -> return ()
|
|
|
|
|
Just x -> tell $ Set.singleton x
|
|
|
|
|
writePIName _ = return ()
|
2019-04-24 02:22:03 +02:00
|
|
|
|
2019-04-30 07:57:04 +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
|
2019-04-30 07:57:04 +02:00
|
|
|
filterer itemName = case y of
|
|
|
|
|
Nothing -> Set.notMember itemName existingItemNames
|
|
|
|
|
Just ident -> ident == itemName
|
2019-09-12 03:16:55 +02:00
|
|
|
items = map snd $ filter (filterer . fst) $ packageItems
|
2019-04-30 07:57:04 +02:00
|
|
|
traverseModuleItem _ _ item =
|
2019-04-24 02:22:03 +02:00
|
|
|
(traverseExprs $ traverseNestedExprs traverseExpr) $
|
2019-08-28 03:32:03 +02:00
|
|
|
(traverseTypes $ traverseNestedTypes traverseType) $
|
2019-04-24 02:22:03 +02:00
|
|
|
item
|
2019-04-24 10:01:33 +02:00
|
|
|
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
|
|
|
|
|
piName :: PackageItem -> Maybe Identifier
|
|
|
|
|
piName (Function _ _ ident _ _) = Just ident
|
|
|
|
|
piName (Task _ ident _ _) = Just ident
|
|
|
|
|
piName (Typedef _ ident ) = Just ident
|
|
|
|
|
piName (Decl (Variable _ _ ident _ _)) = Just ident
|
2019-09-07 04:29:14 +02:00
|
|
|
piName (Decl (Param _ _ ident _)) = Just ident
|
|
|
|
|
piName (Decl (ParamType _ ident _)) = Just ident
|
2020-01-31 04:17:17 +01:00
|
|
|
piName (Decl (CommentDecl _)) = Nothing
|
2019-10-11 02:53:49 +02:00
|
|
|
piName (Import _ _) = Nothing
|
|
|
|
|
piName (Export _) = Nothing
|
|
|
|
|
piName (Directive _) = Nothing
|