mirror of https://github.com/zachjs/sv2v.git
avoid name conflicts when elaborating packages
This commit is contained in:
parent
a54be8dae6
commit
a9f00cce2a
|
|
@ -39,6 +39,7 @@
|
||||||
* Fixed conversion of casts using structs containing multi-dimensional fields
|
* Fixed conversion of casts using structs containing multi-dimensional fields
|
||||||
* Fixed incorrect name resolution conflicts raised during interface inlining
|
* Fixed incorrect name resolution conflicts raised during interface inlining
|
||||||
* Fixed handling of interface instances which shadow other declarations
|
* Fixed handling of interface instances which shadow other declarations
|
||||||
|
* Fixed names like `<pkg>_<name>` being shadowed by elaborated packages
|
||||||
|
|
||||||
## v0.0.9
|
## v0.0.9
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ module Convert.Package
|
||||||
|
|
||||||
import Control.Monad.State.Strict
|
import Control.Monad.State.Strict
|
||||||
import Control.Monad.Writer.Strict
|
import Control.Monad.Writer.Strict
|
||||||
import Data.List (insert, intercalate)
|
import Data.List (insert, intercalate, isPrefixOf)
|
||||||
import Data.Maybe (mapMaybe)
|
import Data.Maybe (mapMaybe)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
@ -74,7 +74,7 @@ inject packageItems items =
|
||||||
prefixItems :: Identifier -> [ModuleItem] -> [ModuleItem]
|
prefixItems :: Identifier -> [ModuleItem] -> [ModuleItem]
|
||||||
prefixItems prefix items =
|
prefixItems prefix items =
|
||||||
snd $ evalState (processItems "" prefix items) initialState
|
snd $ evalState (processItems "" prefix items) initialState
|
||||||
where initialState = ([], Map.empty, Map.empty)
|
where initialState = PK [] Map.empty Map.empty Set.empty
|
||||||
|
|
||||||
-- collect packages and global package items
|
-- collect packages and global package items
|
||||||
collectPackageM :: Description -> Writer (Packages, Classes, [PackageItem]) ()
|
collectPackageM :: Description -> Writer (Packages, Classes, [PackageItem]) ()
|
||||||
|
|
@ -107,13 +107,41 @@ convertPackages :: [AST] -> ([AST], Packages)
|
||||||
convertPackages files =
|
convertPackages files =
|
||||||
(files', packages')
|
(files', packages')
|
||||||
where
|
where
|
||||||
(files', ([], packages', _)) = runState op ([], packages, classes)
|
(files', PK [] packages' _ _) = runState op initialState
|
||||||
|
initialState = PK [] packages classes conflicts
|
||||||
op = mapM (traverseDescriptionsM traverseDescriptionM) files
|
op = mapM (traverseDescriptionsM traverseDescriptionM) files
|
||||||
packages = Map.insert "" (Map.empty, globalItems) realPackages
|
packages = Map.insert "" (Map.empty, globalItems) realPackages
|
||||||
(realPackages, classes, globalItems) =
|
(realPackages, classes, globalItems) =
|
||||||
execWriter $ mapM (collectDescriptionsM collectPackageM) files
|
execWriter $ mapM (collectDescriptionsM collectPackageM) files
|
||||||
|
prefixes = Set.union (Map.keysSet classes) (Map.keysSet realPackages)
|
||||||
|
conflicts =
|
||||||
|
if Set.null prefixes
|
||||||
|
then Set.empty
|
||||||
|
else execWriter $ mapM (collectIdentConflicts prefixes) files
|
||||||
|
|
||||||
type PackagesState = State ([Identifier], Packages, Classes)
|
-- write down identifiers that might conflict with the generated names for
|
||||||
|
-- injected package items
|
||||||
|
collectIdentConflicts :: Idents -> AST -> Writer Idents ()
|
||||||
|
collectIdentConflicts prefixes =
|
||||||
|
mapM_ $ collectModuleItemsM $ collectify traverseIdentsM $
|
||||||
|
collectIdent prefixes
|
||||||
|
|
||||||
|
-- write down identifiers that have a package name as a prefix
|
||||||
|
collectIdent :: Idents -> Identifier -> Writer Idents ()
|
||||||
|
collectIdent prefixes ident =
|
||||||
|
case Set.lookupLE ident prefixes of
|
||||||
|
Just prefix -> when (prefix `isPrefixOf` ident) found
|
||||||
|
where found = tell $ Set.singleton ident
|
||||||
|
Nothing -> return ()
|
||||||
|
|
||||||
|
data PK = PK
|
||||||
|
{ pkStack :: [Identifier]
|
||||||
|
, pkPackages :: Packages
|
||||||
|
, pkClasses :: Classes
|
||||||
|
, pkConflicts :: Idents
|
||||||
|
}
|
||||||
|
|
||||||
|
type PackagesState = State PK
|
||||||
|
|
||||||
traverseDescriptionM :: Description -> PackagesState Description
|
traverseDescriptionM :: Description -> PackagesState Description
|
||||||
traverseDescriptionM (PackageItem item) = do
|
traverseDescriptionM (PackageItem item) = do
|
||||||
|
|
@ -264,7 +292,7 @@ processItems topName packageName moduleItems = do
|
||||||
insertElem x Declared
|
insertElem x Declared
|
||||||
if inProcedure || null packageName
|
if inProcedure || null packageName
|
||||||
then return x
|
then return x
|
||||||
else return $ packageName ++ '_' : x
|
else lift $ makeIdent packageName x
|
||||||
|
|
||||||
-- check the global scope for declarations or imports
|
-- check the global scope for declarations or imports
|
||||||
resolveGlobalIdent :: Identifier -> Scope Identifier
|
resolveGlobalIdent :: Identifier -> Scope Identifier
|
||||||
|
|
@ -293,13 +321,13 @@ processItems topName packageName moduleItems = do
|
||||||
Just ([_, _], _, Declared) ->
|
Just ([_, _], _, Declared) ->
|
||||||
if null packageName
|
if null packageName
|
||||||
then return x
|
then return x
|
||||||
else return $ packageName ++ '_' : x
|
else lift $ makeIdent packageName x
|
||||||
Just (_, _, Declared) -> return x
|
Just (_, _, Declared) -> return x
|
||||||
Just (_, _, Imported rootPkg) ->
|
Just (_, _, Imported rootPkg) ->
|
||||||
return $ rootPkg ++ '_' : x
|
lift $ makeIdent rootPkg x
|
||||||
Just (accesses, _, Available [rootPkg]) -> do
|
Just (accesses, _, Available [rootPkg]) -> do
|
||||||
insertElem accesses $ Imported rootPkg
|
insertElem accesses $ Imported rootPkg
|
||||||
return $ rootPkg ++ '_' : x
|
lift $ makeIdent rootPkg x
|
||||||
Just (_, _, Available rootPkgs) ->
|
Just (_, _, Available rootPkgs) ->
|
||||||
error $ "identifier " ++ show x
|
error $ "identifier " ++ show x
|
||||||
++ " ambiguously refers to the definitions in any of "
|
++ " ambiguously refers to the definitions in any of "
|
||||||
|
|
@ -404,9 +432,11 @@ processItems topName packageName moduleItems = do
|
||||||
lift $ resolvePSIdent p x
|
lift $ resolvePSIdent p x
|
||||||
else do
|
else do
|
||||||
details <- lookupElemM $ Dot (Ident p) x
|
details <- lookupElemM $ Dot (Ident p) x
|
||||||
return $ case details of
|
case details of
|
||||||
Just ([_, _], _, Declared) -> p ++ '_' : x
|
Just ([_, _], _, Declared) ->
|
||||||
Just ([_, _], _, Imported rootPkg) -> rootPkg ++ '_' : x
|
lift $ makeIdent p x
|
||||||
|
Just ([_, _], _, Imported rootPkg) ->
|
||||||
|
lift $ makeIdent rootPkg x
|
||||||
_ -> error $ "package " ++ show p ++ " references"
|
_ -> error $ "package " ++ show p ++ " references"
|
||||||
++ " undeclared local \"" ++ p ++ "::" ++ x ++ "\""
|
++ " undeclared local \"" ++ p ++ "::" ++ x ++ "\""
|
||||||
|
|
||||||
|
|
@ -425,7 +455,7 @@ processItems topName packageName moduleItems = do
|
||||||
-- inject the given class item and its dependencies into the local scope
|
-- inject the given class item and its dependencies into the local scope
|
||||||
classScopeInject :: Identifier -> Identifier -> Scope ()
|
classScopeInject :: Identifier -> Identifier -> Scope ()
|
||||||
classScopeInject rootPkg fullName = do
|
classScopeInject rootPkg fullName = do
|
||||||
(_, packages, _) <- lift get
|
packages <- lift $ gets pkPackages
|
||||||
let (_, packageItems) = packages Map.! rootPkg
|
let (_, packageItems) = packages Map.! rootPkg
|
||||||
let localPIs = Map.fromList $ concatMap toPIElem packageItems
|
let localPIs = Map.fromList $ concatMap toPIElem packageItems
|
||||||
mapM_ injectIfMissing $
|
mapM_ injectIfMissing $
|
||||||
|
|
@ -451,7 +481,7 @@ processItems topName packageName moduleItems = do
|
||||||
-- locate a package by name, processing its contents if necessary
|
-- locate a package by name, processing its contents if necessary
|
||||||
findPackage :: Identifier -> PackagesState Package
|
findPackage :: Identifier -> PackagesState Package
|
||||||
findPackage packageName = do
|
findPackage packageName = do
|
||||||
(stack, packages, classes) <- get
|
PK { pkStack = stack, pkPackages = packages } <- get
|
||||||
let maybePackage = Map.lookup packageName packages
|
let maybePackage = Map.lookup packageName packages
|
||||||
assertMsg (maybePackage /= Nothing) $
|
assertMsg (maybePackage /= Nothing) $
|
||||||
"could not find package " ++ show packageName
|
"could not find package " ++ show packageName
|
||||||
|
|
@ -465,10 +495,12 @@ findPackage packageName = do
|
||||||
if Map.null exports
|
if Map.null exports
|
||||||
then do
|
then do
|
||||||
-- process and resolve this package
|
-- process and resolve this package
|
||||||
put (packageName : stack, packages, classes)
|
modify' $ \pk -> pk { pkStack = packageName : pkStack pk }
|
||||||
package' <- processPackage packageName $ snd package
|
package' <- processPackage packageName $ snd package
|
||||||
(_, packages', _) <- get
|
pk <- get
|
||||||
put (stack, Map.insert packageName package' packages', classes)
|
let stack' = tail $ pkStack pk
|
||||||
|
let packages' = Map.insert packageName package' $ pkPackages pk
|
||||||
|
put $ pk { pkStack = stack', pkPackages = packages' }
|
||||||
return package'
|
return package'
|
||||||
else return package
|
else return package
|
||||||
|
|
||||||
|
|
@ -490,11 +522,11 @@ processPackage packageName packageItems = do
|
||||||
-- resolve a package scoped identifier to its unique global name
|
-- resolve a package scoped identifier to its unique global name
|
||||||
resolvePSIdent :: Identifier -> Identifier -> PackagesState Identifier
|
resolvePSIdent :: Identifier -> Identifier -> PackagesState Identifier
|
||||||
resolvePSIdent packageName itemName = do
|
resolvePSIdent packageName itemName = do
|
||||||
(_, _, classes) <- get
|
classes <- gets pkClasses
|
||||||
case Map.lookup packageName classes of
|
case Map.lookup packageName classes of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
rootPkg <- resolveRootPackage packageName itemName
|
rootPkg <- resolveRootPackage packageName itemName
|
||||||
return $ rootPkg ++ '_' : itemName
|
makeIdent rootPkg itemName
|
||||||
Just ([], _) -> resolveCSIdent packageName [] Set.empty itemName
|
Just ([], _) -> resolveCSIdent packageName [] Set.empty itemName
|
||||||
Just _ -> error $ "reference to " ++ show itemName
|
Just _ -> error $ "reference to " ++ show itemName
|
||||||
++ " in parameterized class " ++ show packageName
|
++ " in parameterized class " ++ show packageName
|
||||||
|
|
@ -532,7 +564,7 @@ bindingsScopeKeys =
|
||||||
resolveCSIdent :: Identifier -> [ParamBinding] -> Idents -> Identifier -> PackagesState Identifier
|
resolveCSIdent :: Identifier -> [ParamBinding] -> Idents -> Identifier -> PackagesState Identifier
|
||||||
resolveCSIdent className paramBindings scopeKeys itemName = do
|
resolveCSIdent className paramBindings scopeKeys itemName = do
|
||||||
-- find the specified class
|
-- find the specified class
|
||||||
(_, _, classes) <- get
|
classes <- gets pkClasses
|
||||||
let maybeClass = Map.lookup className classes
|
let maybeClass = Map.lookup className classes
|
||||||
assertMsg (maybeClass /= Nothing) $
|
assertMsg (maybeClass /= Nothing) $
|
||||||
"could not find class " ++ show className
|
"could not find class " ++ show className
|
||||||
|
|
@ -550,13 +582,13 @@ resolveCSIdent className paramBindings scopeKeys itemName = do
|
||||||
let classItems'' = map overrider classItems'
|
let classItems'' = map overrider classItems'
|
||||||
-- add the synthetic package to the state
|
-- add the synthetic package to the state
|
||||||
let package = (exports, classItems'')
|
let package = (exports, classItems'')
|
||||||
(stack, packages, _) <- get
|
packages' <- gets $ Map.insert packageName package . pkPackages
|
||||||
put (stack, Map.insert packageName package packages, classes)
|
modify' $ \pk -> pk { pkPackages = packages' }
|
||||||
-- ensure the item actually exists
|
-- ensure the item actually exists
|
||||||
let maybeIdentState = Map.lookup itemName exports
|
let maybeIdentState = Map.lookup itemName exports
|
||||||
assertMsg (maybeIdentState /= Nothing) $
|
assertMsg (maybeIdentState /= Nothing) $
|
||||||
"could not find " ++ show itemName ++ " in class " ++ show className
|
"could not find " ++ show itemName ++ " in class " ++ show className
|
||||||
return $ packageName ++ '_' : itemName
|
makeIdent packageName itemName
|
||||||
where
|
where
|
||||||
extractParameterName :: Decl -> Maybe Identifier
|
extractParameterName :: Decl -> Maybe Identifier
|
||||||
extractParameterName (Param Parameter _ x _) = Just x
|
extractParameterName (Param Parameter _ x _) = Just x
|
||||||
|
|
@ -600,6 +632,19 @@ resolveCSIdent className paramBindings scopeKeys itemName = do
|
||||||
where x' = drop (1 + length packageName) x
|
where x' = drop (1 + length packageName) x
|
||||||
overrideParam _ _ other = other
|
overrideParam _ _ other = other
|
||||||
|
|
||||||
|
-- construct a new identifier for a package scoped identifier
|
||||||
|
makeIdent :: Identifier -> Identifier -> PackagesState Identifier
|
||||||
|
makeIdent x y = do
|
||||||
|
conflicts <- gets pkConflicts
|
||||||
|
return $ uniqueIdent conflicts $ x ++ '_' : y
|
||||||
|
|
||||||
|
-- prepend underscores until the name is unique
|
||||||
|
uniqueIdent :: Idents -> Identifier -> Identifier
|
||||||
|
uniqueIdent conflicts ident =
|
||||||
|
if Set.member ident conflicts
|
||||||
|
then uniqueIdent conflicts $ '_' : ident
|
||||||
|
else ident
|
||||||
|
|
||||||
-- errors with the given message when the check is false
|
-- errors with the given message when the check is false
|
||||||
assertMsg :: Monad m => Bool -> String -> m ()
|
assertMsg :: Monad m => Bool -> String -> m ()
|
||||||
assertMsg check msg = when (not check) $ error msg
|
assertMsg check msg = when (not check) $ error msg
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package P;
|
||||||
|
typedef logic T;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
P::T P_T;
|
||||||
|
assign P_T = 0;
|
||||||
|
initial $display("%b", P_T);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
module top;
|
||||||
|
wire P_T;
|
||||||
|
assign P_T = 0;
|
||||||
|
initial $display("%b", P_T);
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue