mirror of https://github.com/zachjs/sv2v.git
package conversion overhaul
- full import and export support - simplify AST representation of import and export - allow package-scoped identifiers invoked as subroutines - use scoped name resolution for identifiers in packages - merge package item nesting conversion into package conversion - fix handling of colliding enum items in separate modules - fix visiting enum item exprs in types
This commit is contained in:
parent
40df902887
commit
8eb3a251f7
|
|
@ -102,8 +102,9 @@ Other:
|
||||||
## Supported Features
|
## Supported Features
|
||||||
|
|
||||||
sv2v supports most synthesizable SystemVerilog features. Current notable
|
sv2v supports most synthesizable SystemVerilog features. Current notable
|
||||||
exceptions include `export` and interface arrays. Assertions are also supported,
|
exceptions include `defparam` on interface instances and references to typedefs
|
||||||
but are simply dropped during conversion.
|
within interface instances. Assertions are also supported, but are simply
|
||||||
|
dropped during conversion.
|
||||||
|
|
||||||
If you find a bug or have a feature request, please create an issue. Preference
|
If you find a bug or have a feature request, please create an issue. Preference
|
||||||
will be given to issues which include examples or test cases.
|
will be given to issues which include examples or test cases.
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import qualified Convert.Logic
|
||||||
import qualified Convert.LogOp
|
import qualified Convert.LogOp
|
||||||
import qualified Convert.MultiplePacked
|
import qualified Convert.MultiplePacked
|
||||||
import qualified Convert.NamedBlock
|
import qualified Convert.NamedBlock
|
||||||
import qualified Convert.NestPI
|
|
||||||
import qualified Convert.Package
|
import qualified Convert.Package
|
||||||
import qualified Convert.ParamNoDefault
|
import qualified Convert.ParamNoDefault
|
||||||
import qualified Convert.ParamType
|
import qualified Convert.ParamType
|
||||||
|
|
@ -86,9 +85,7 @@ phases excludes =
|
||||||
, Convert.Unsigned.convert
|
, Convert.Unsigned.convert
|
||||||
, Convert.SignCast.convert
|
, Convert.SignCast.convert
|
||||||
, Convert.Wildcard.convert
|
, Convert.Wildcard.convert
|
||||||
, Convert.Package.convert
|
|
||||||
, Convert.Enum.convert
|
, Convert.Enum.convert
|
||||||
, Convert.NestPI.convert
|
|
||||||
, Convert.ForDecl.convert
|
, Convert.ForDecl.convert
|
||||||
, Convert.Jump.convert
|
, Convert.Jump.convert
|
||||||
, Convert.Foreach.convert
|
, Convert.Foreach.convert
|
||||||
|
|
@ -111,7 +108,7 @@ run excludes = foldr (.) id $ phases excludes
|
||||||
convert :: [Job.Exclude] -> Phase
|
convert :: [Job.Exclude] -> Phase
|
||||||
convert excludes =
|
convert excludes =
|
||||||
convert'
|
convert'
|
||||||
. Convert.NestPI.reorder
|
. Convert.Package.convert
|
||||||
. Convert.ParamNoDefault.convert
|
. Convert.ParamNoDefault.convert
|
||||||
where
|
where
|
||||||
convert' :: Phase
|
convert' :: Phase
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
-
|
-
|
||||||
- Conversion for `enum`
|
- Conversion for `enum`
|
||||||
-
|
-
|
||||||
- This conversion replaces the enum items with localparams declared at the
|
- This conversion replaces the enum items with localparams. The localparams are
|
||||||
- global scope. We leave it to the package item nesting conversion to determine
|
- explicitly sized to match the size of the converted enum type. For packages
|
||||||
- where the generated localparams are needed. The localparams are explicitly
|
- and enums used in the global scope, these localparams are inserted in place.
|
||||||
- sized to match the size of the converted enum type.
|
- For enums used within a module or interface, the localparams are injected as
|
||||||
|
- needed using a nesting procedure from the package conversion.
|
||||||
-
|
-
|
||||||
- SystemVerilog allows for enums to have any number of the items' values
|
- SystemVerilog allows for enums to have any number of the items' values
|
||||||
- specified or unspecified. If the first one is unspecified, it is 0. All other
|
- specified or unspecified. If the first one is unspecified, it is 0. All other
|
||||||
|
|
@ -24,6 +25,7 @@ import Data.List (elemIndices)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import Convert.ExprUtils
|
import Convert.ExprUtils
|
||||||
|
import Convert.Package (inject)
|
||||||
import Convert.Traverse
|
import Convert.Traverse
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
|
|
||||||
|
|
@ -36,9 +38,14 @@ convert = map $ concatMap convertDescription
|
||||||
convertDescription :: Description -> [Description]
|
convertDescription :: Description -> [Description]
|
||||||
convertDescription (Package ml name items) =
|
convertDescription (Package ml name items) =
|
||||||
[Package ml name $ concatMap convertPackageItem items]
|
[Package ml name $ concatMap convertPackageItem items]
|
||||||
convertDescription description =
|
convertDescription (description @ Part{}) =
|
||||||
(map PackageItem enumItems) ++ [description']
|
[Part attrs extern kw lifetime name ports items']
|
||||||
where (description', enumItems) = convertDescription' description
|
where
|
||||||
|
items' = inject enumItems items -- only keep what's used
|
||||||
|
Part attrs extern kw lifetime name ports items = description'
|
||||||
|
(description', enumItems) = convertDescription' description
|
||||||
|
convertDescription (PackageItem item) =
|
||||||
|
map PackageItem $ convertPackageItem item
|
||||||
|
|
||||||
-- explode a package item with its corresponding enum items
|
-- explode a package item with its corresponding enum items
|
||||||
convertPackageItem :: PackageItem -> [PackageItem]
|
convertPackageItem :: PackageItem -> [PackageItem]
|
||||||
|
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
{- sv2v
|
|
||||||
- Author: Zachary Snow <zach@zachjs.com>
|
|
||||||
-
|
|
||||||
- Conversion for moving top-level package items into modules
|
|
||||||
-}
|
|
||||||
|
|
||||||
module Convert.NestPI (convert, reorder) where
|
|
||||||
|
|
||||||
import Control.Monad.Writer.Strict
|
|
||||||
import Data.Maybe (mapMaybe)
|
|
||||||
import qualified Data.Map.Strict as Map
|
|
||||||
import qualified Data.Set as Set
|
|
||||||
|
|
||||||
import Convert.Traverse
|
|
||||||
import Language.SystemVerilog.AST
|
|
||||||
|
|
||||||
type PIs = Map.Map Identifier PackageItem
|
|
||||||
type Idents = Set.Set Identifier
|
|
||||||
|
|
||||||
convert :: [AST] -> [AST]
|
|
||||||
convert =
|
|
||||||
map (filter (not . isPI)) . nest
|
|
||||||
where
|
|
||||||
nest :: [AST] -> [AST]
|
|
||||||
nest = traverseFiles
|
|
||||||
(collectDescriptionsM collectDescriptionM)
|
|
||||||
(traverseDescriptions . convertDescription)
|
|
||||||
isPI :: Description -> Bool
|
|
||||||
isPI (PackageItem Import{}) = False
|
|
||||||
isPI (PackageItem item) = piName item /= ""
|
|
||||||
isPI _ = False
|
|
||||||
|
|
||||||
reorder :: [AST] -> [AST]
|
|
||||||
reorder = map $ traverseDescriptions reorderDescription
|
|
||||||
|
|
||||||
-- collects packages items missing
|
|
||||||
collectDescriptionM :: Description -> Writer PIs ()
|
|
||||||
collectDescriptionM (PackageItem item) = do
|
|
||||||
case piName item of
|
|
||||||
"" -> return ()
|
|
||||||
ident -> tell $ Map.singleton ident item
|
|
||||||
collectDescriptionM _ = return ()
|
|
||||||
|
|
||||||
-- nests packages items missing from modules
|
|
||||||
convertDescription :: PIs -> Description -> Description
|
|
||||||
convertDescription pis (orig @ Part{}) =
|
|
||||||
if Map.null pis
|
|
||||||
then orig
|
|
||||||
else Part attrs extern kw lifetime name ports items'
|
|
||||||
where
|
|
||||||
Part attrs extern kw lifetime name ports items = orig
|
|
||||||
items' = addItems pis Set.empty (map addUsedPIs items)
|
|
||||||
convertDescription _ other = other
|
|
||||||
|
|
||||||
-- attempt to fix simple declaration order issues
|
|
||||||
reorderDescription :: Description -> Description
|
|
||||||
reorderDescription (Part attrs extern kw lifetime name ports items) =
|
|
||||||
Part attrs extern kw lifetime name ports items'
|
|
||||||
where
|
|
||||||
items' = addItems localPIs Set.empty (map addUsedPIs items)
|
|
||||||
localPIs = Map.fromList $ mapMaybe toPIElem items
|
|
||||||
toPIElem :: ModuleItem -> Maybe (Identifier, PackageItem)
|
|
||||||
toPIElem (MIPackageItem item) = Just (piName item, item)
|
|
||||||
toPIElem _ = Nothing
|
|
||||||
reorderDescription other = other
|
|
||||||
|
|
||||||
-- iteratively inserts missing package items exactly where they are needed
|
|
||||||
addItems :: PIs -> Idents -> [(ModuleItem, Idents)] -> [ModuleItem]
|
|
||||||
addItems pis existingPIs ((item, usedPIs) : items) =
|
|
||||||
if not $ Set.disjoint existingPIs thisPI then
|
|
||||||
-- this item was re-imported earlier in the module
|
|
||||||
addItems pis existingPIs items
|
|
||||||
else if null itemsToAdd then
|
|
||||||
-- this item has no additional dependencies
|
|
||||||
item : addItems pis (Set.union existingPIs thisPI) items
|
|
||||||
else
|
|
||||||
-- this item has at least one un-met dependency
|
|
||||||
addItems pis existingPIs (addUsedPIs chosen : (item, usedPIs) : items)
|
|
||||||
where
|
|
||||||
thisPI = execWriter $ collectPIsM item
|
|
||||||
neededPIs = Set.difference (Set.difference usedPIs existingPIs) thisPI
|
|
||||||
itemsToAdd = map MIPackageItem $ Map.elems $
|
|
||||||
Map.restrictKeys pis neededPIs
|
|
||||||
chosen = head itemsToAdd
|
|
||||||
addItems _ _ [] = []
|
|
||||||
|
|
||||||
-- augment a module item with the set of identifiers it uses
|
|
||||||
addUsedPIs :: ModuleItem -> (ModuleItem, Idents)
|
|
||||||
addUsedPIs item =
|
|
||||||
(item, usedPIs)
|
|
||||||
where
|
|
||||||
usedPIs = execWriter $
|
|
||||||
traverseNestedModuleItemsM (traverseIdentsM writeIdent) item
|
|
||||||
writeIdent :: Identifier -> Writer Idents Identifier
|
|
||||||
writeIdent x = tell (Set.singleton x) >> return x
|
|
||||||
|
|
||||||
-- writes down the names of package items
|
|
||||||
collectPIsM :: ModuleItem -> Writer Idents ()
|
|
||||||
collectPIsM (MIPackageItem item) =
|
|
||||||
case piName item of
|
|
||||||
"" -> return ()
|
|
||||||
ident -> tell $ Set.singleton ident
|
|
||||||
collectPIsM _ = return ()
|
|
||||||
|
|
||||||
-- visits all identifiers in a module item
|
|
||||||
traverseIdentsM :: Monad m => MapperM m Identifier -> MapperM m ModuleItem
|
|
||||||
traverseIdentsM identMapper = traverseNodesM
|
|
||||||
(traverseExprIdentsM identMapper)
|
|
||||||
(traverseDeclIdentsM identMapper)
|
|
||||||
(traverseTypeIdentsM identMapper)
|
|
||||||
(traverseLHSIdentsM identMapper)
|
|
||||||
(traverseStmtIdentsM identMapper)
|
|
||||||
|
|
||||||
-- visits all identifiers in an expression
|
|
||||||
traverseExprIdentsM :: Monad m => MapperM m Identifier -> MapperM m Expr
|
|
||||||
traverseExprIdentsM identMapper = fullMapper
|
|
||||||
where
|
|
||||||
fullMapper = exprMapper >=> traverseSinglyNestedExprsM fullMapper
|
|
||||||
exprMapper (Call (Ident x) args) =
|
|
||||||
identMapper x >>= \x' -> return $ Call (Ident x') args
|
|
||||||
exprMapper (Ident x) = identMapper x >>= return . Ident
|
|
||||||
exprMapper other = return other
|
|
||||||
|
|
||||||
-- visits all identifiers in a type
|
|
||||||
traverseTypeIdentsM :: Monad m => MapperM m Identifier -> MapperM m Type
|
|
||||||
traverseTypeIdentsM identMapper = fullMapper
|
|
||||||
where
|
|
||||||
fullMapper = typeMapper
|
|
||||||
>=> traverseTypeExprsM (traverseExprIdentsM identMapper)
|
|
||||||
>=> traverseSinglyNestedTypesM fullMapper
|
|
||||||
typeMapper (Alias x t) = aliasHelper (Alias ) x t
|
|
||||||
typeMapper (PSAlias p x t) = aliasHelper (PSAlias p ) x t
|
|
||||||
typeMapper (CSAlias c p x t) = aliasHelper (CSAlias c p) x t
|
|
||||||
typeMapper other = return other
|
|
||||||
aliasHelper constructor x t =
|
|
||||||
identMapper x >>= \x' -> return $ constructor x' t
|
|
||||||
|
|
||||||
-- visits all identifiers in an LHS
|
|
||||||
traverseLHSIdentsM :: Monad m => MapperM m Identifier -> MapperM m LHS
|
|
||||||
traverseLHSIdentsM identMapper = fullMapper
|
|
||||||
where
|
|
||||||
fullMapper = lhsMapper
|
|
||||||
>=> traverseLHSExprsM (traverseExprIdentsM identMapper)
|
|
||||||
>=> traverseSinglyNestedLHSsM fullMapper
|
|
||||||
lhsMapper (LHSIdent x) = identMapper x >>= return . LHSIdent
|
|
||||||
lhsMapper other = return other
|
|
||||||
|
|
||||||
-- visits all identifiers in a statement
|
|
||||||
traverseStmtIdentsM :: Monad m => MapperM m Identifier -> MapperM m Stmt
|
|
||||||
traverseStmtIdentsM identMapper = fullMapper
|
|
||||||
where
|
|
||||||
fullMapper = stmtMapper
|
|
||||||
>=> traverseStmtExprsM (traverseExprIdentsM identMapper)
|
|
||||||
>=> traverseStmtLHSsM (traverseLHSIdentsM identMapper)
|
|
||||||
>=> traverseSinglyNestedStmtsM fullMapper
|
|
||||||
stmtMapper (Subroutine (Ident x) args) =
|
|
||||||
identMapper x >>= \x' -> return $ Subroutine (Ident x') args
|
|
||||||
stmtMapper other = return other
|
|
||||||
|
|
||||||
-- visits all identifiers in a declaration
|
|
||||||
traverseDeclIdentsM :: Monad m => MapperM m Identifier -> MapperM m Decl
|
|
||||||
traverseDeclIdentsM identMapper =
|
|
||||||
traverseDeclExprsM (traverseExprIdentsM identMapper) >=>
|
|
||||||
traverseDeclTypesM (traverseTypeIdentsM identMapper)
|
|
||||||
|
|
||||||
-- returns the "name" of a package item, if it has one
|
|
||||||
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 x y) = show $ Import x y
|
|
||||||
piName (Export _) = ""
|
|
||||||
piName (Directive _) = ""
|
|
||||||
|
|
@ -1,32 +1,32 @@
|
||||||
|
{-# LANGUAGE TupleSections #-}
|
||||||
{- sv2v
|
{- sv2v
|
||||||
- Author: Zachary Snow <zach@zachjs.com>
|
- Author: Zachary Snow <zach@zachjs.com>
|
||||||
-
|
-
|
||||||
- Conversion for packages, exports, and imports
|
- Conversion for packages and global declarations
|
||||||
-
|
-
|
||||||
- TODO: We do not yet handle exports.
|
- This conversion first makes a best-effort pass at resolving any simple
|
||||||
- TODO: The scoping rules are not being entirely followed yet.
|
- declaration ordering issues in the input. Many conversions require that
|
||||||
- TODO: Explicit imports may introduce name conflicts because of carried items.
|
- declarations precede their first usage.
|
||||||
-
|
-
|
||||||
- The SystemVerilog scoping rules for exports and imports are not entirely
|
- The main phase elaborates packages and resolves imported identifiers. An
|
||||||
- trivial. We do not explicitly handle the "error" scenarios detailed Table
|
- identifier (perhaps implicitly) referring to `P::X` is rewritten to `P_X`.
|
||||||
- 26-1 of Section 26-3 of IEEE 1800-2017. Users generally shouldn't be relying
|
- This conversion assumes such renaming will not cause conflicts. The full
|
||||||
- on this tool to catch and report such wild naming conflicts that are outlined
|
- semantics of imports and exports are followed.
|
||||||
- there.
|
|
||||||
-
|
-
|
||||||
- Summary:
|
- Finally, because Verilog doesn't allow declarations to exist outside of
|
||||||
- * In scopes which have a local declaration of an identifier, that identifier
|
- modules, declarations within packages and in the global scope are injected
|
||||||
- refers to that local declaration.
|
- into modules and interfaces as needed.
|
||||||
- * 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.
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Convert.Package (convert) where
|
module Convert.Package
|
||||||
|
( convert
|
||||||
|
, inject
|
||||||
|
) where
|
||||||
|
|
||||||
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.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
|
||||||
|
|
||||||
|
|
@ -34,112 +34,296 @@ import Convert.Scoper
|
||||||
import Convert.Traverse
|
import Convert.Traverse
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
|
|
||||||
type Packages = Map.Map Identifier PackageItems
|
type Packages = Map.Map Identifier Package
|
||||||
type PackageItems = [(Identifier, PackageItem)]
|
type Package = (IdentStateMap, [PackageItem])
|
||||||
type Idents = Set.Set Identifier
|
type Idents = Set.Set Identifier
|
||||||
|
type PIs = Map.Map Identifier PackageItem
|
||||||
|
|
||||||
convert :: [AST] -> [AST]
|
convert :: [AST] -> [AST]
|
||||||
convert = step
|
convert files =
|
||||||
|
map (traverseDescriptions $ convertDescription pis) files'
|
||||||
where
|
where
|
||||||
step :: [AST] -> [AST]
|
(files', packages') = convertPackages files
|
||||||
step curr =
|
pis = Map.fromList $
|
||||||
if next == curr
|
concatMap (concatMap toPackageItems . snd) $
|
||||||
then curr
|
filter (not . Map.null . fst) $
|
||||||
else step next
|
Map.elems packages'
|
||||||
|
toPackageItems :: PackageItem -> [(Identifier, PackageItem)]
|
||||||
|
toPackageItems item = map (, item) (piNames item)
|
||||||
|
|
||||||
|
-- utility for inserting package items into a set of module items as needed
|
||||||
|
inject :: [PackageItem] -> [ModuleItem] -> [ModuleItem]
|
||||||
|
inject packageItems items =
|
||||||
|
addItems localPIs Set.empty (map addUsedPIs items)
|
||||||
where
|
where
|
||||||
next = traverseFiles
|
localPIs = Map.fromList $ concatMap toPIElem packageItems
|
||||||
(collectDescriptionsM collectDescriptionM)
|
toPIElem :: PackageItem -> [(Identifier, PackageItem)]
|
||||||
convertFile curr
|
toPIElem item = map (, item) (piNames item)
|
||||||
|
|
||||||
convertFile :: Packages -> AST -> AST
|
-- collect packages and global package items
|
||||||
convertFile packages ast =
|
collectPackageM :: Description -> Writer (Packages, [PackageItem]) ()
|
||||||
(++) globalItems $
|
collectPackageM (PackageItem item) =
|
||||||
filter (not . isCollected) $
|
when (not $ null $ piNames item) $
|
||||||
concatMap (traverseDescription packages) $
|
tell (Map.empty, [item])
|
||||||
ast
|
collectPackageM (Package _ name items) =
|
||||||
|
tell (Map.singleton name (Map.empty, items), [])
|
||||||
|
collectPackageM _ = return ()
|
||||||
|
|
||||||
|
-- elaborate all packages and their usages
|
||||||
|
convertPackages :: [AST] -> ([AST], Packages)
|
||||||
|
convertPackages files =
|
||||||
|
(files', packages')
|
||||||
where
|
where
|
||||||
globalItems = map PackageItem $
|
(files', ([], packages')) = runState op ([], packages)
|
||||||
concatMap (uncurry globalPackageItems) $ Map.toList packages
|
op = mapM (traverseDescriptionsM traverseDescriptionM) files
|
||||||
isCollected :: Description -> Bool
|
packages = Map.insert "" (Map.empty, globalItems) realPackages
|
||||||
isCollected (Package _ name _) = Map.member name packages
|
(realPackages, globalItems) =
|
||||||
isCollected _ = False
|
execWriter $ mapM (collectDescriptionsM collectPackageM) files
|
||||||
|
|
||||||
globalPackageItems :: Identifier -> PackageItems -> [PackageItem]
|
type PackagesState = State ([Identifier], Packages)
|
||||||
globalPackageItems name items =
|
|
||||||
prefixPackageItems name (packageItemIdents items) (map snd items)
|
|
||||||
|
|
||||||
packageItemIdents :: PackageItems -> Idents
|
traverseDescriptionM :: Description -> PackagesState Description
|
||||||
packageItemIdents items =
|
traverseDescriptionM (PackageItem item) = do
|
||||||
Set.union
|
return $ PackageItem $ case piNames item of
|
||||||
(Set.fromList $ map fst items)
|
[] -> item
|
||||||
(Set.unions $ map (packageItemSubIdents . snd) items)
|
idents -> Decl $ CommentDecl $ "removed " ++ show idents
|
||||||
|
traverseDescriptionM (Package _ name _) =
|
||||||
|
return $ PackageItem $ Decl $ CommentDecl $ "removed package " ++ show name
|
||||||
|
traverseDescriptionM (Part attrs extern kw liftetime name ports items) = do
|
||||||
|
(_, items') <- processItems name "" items
|
||||||
|
return $ Part attrs extern kw liftetime name ports items'
|
||||||
|
|
||||||
|
data IdentState
|
||||||
|
= Available [Identifier]
|
||||||
|
| Imported Identifier
|
||||||
|
| Declared
|
||||||
|
deriving Eq
|
||||||
|
|
||||||
|
isImported :: IdentState -> Bool
|
||||||
|
isImported Imported{} = True
|
||||||
|
isImported _ = False
|
||||||
|
|
||||||
|
isDeclared :: IdentState -> Bool
|
||||||
|
isDeclared Declared{} = True
|
||||||
|
isDeclared _ = False
|
||||||
|
|
||||||
|
type IdentStateMap = Map.Map Identifier IdentState
|
||||||
|
type Scope = ScoperT IdentState PackagesState
|
||||||
|
|
||||||
|
-- produce the partial mapping for a particular export and ensure its validity
|
||||||
|
resolveExport
|
||||||
|
:: IdentStateMap -> Identifier -> Identifier -> PackagesState IdentStateMap
|
||||||
|
resolveExport mapping "" "" =
|
||||||
|
return $ Map.filter isImported mapping
|
||||||
|
resolveExport mapping pkg "" =
|
||||||
|
fmap (Map.mapMaybeWithKey checkExport . fst) (findPackage pkg)
|
||||||
where
|
where
|
||||||
packageItemSubIdents :: PackageItem -> Idents
|
checkExport :: Identifier -> IdentState -> Maybe IdentState
|
||||||
packageItemSubIdents (Typedef (Enum _ enumItems _) _) =
|
checkExport ident exportedIdentState =
|
||||||
Set.fromList $ map fst enumItems
|
if localIdentState == expectedIdentState
|
||||||
packageItemSubIdents _ = Set.empty
|
then localIdentState
|
||||||
|
else Nothing
|
||||||
|
where
|
||||||
|
localIdentState = Map.lookup ident mapping
|
||||||
|
expectedIdentState = Just $ Imported $
|
||||||
|
toRootPackage pkg exportedIdentState
|
||||||
|
resolveExport mapping pkg ident =
|
||||||
|
case Map.lookup ident mapping of
|
||||||
|
Just (Imported importedPkg) -> do
|
||||||
|
exportedPkg <- resolveRootPackage pkg ident
|
||||||
|
if importedPkg == exportedPkg
|
||||||
|
then return $ Map.singleton ident $ Imported importedPkg
|
||||||
|
else error $ "export of " ++ pkg ++ "::" ++ ident
|
||||||
|
++ " differs from import of " ++ importedPkg
|
||||||
|
++ "::" ++ ident
|
||||||
|
_ -> error $ "export of " ++ pkg ++ "::" ++ ident
|
||||||
|
++ ", but " ++ ident ++ " was never imported"
|
||||||
|
|
||||||
prefixPackageItems :: Identifier -> Idents -> [PackageItem] -> [PackageItem]
|
-- lookup the state of the identifier only within the current scope
|
||||||
prefixPackageItems packageName idents items =
|
lookupLocalIdentState :: Identifier -> Scope (Maybe IdentState)
|
||||||
map unwrap $ evalScoper
|
lookupLocalIdentState =
|
||||||
|
fmap (fmap thd3) . lookupLocalIdentM
|
||||||
|
where thd3 (_, _, c) = c
|
||||||
|
|
||||||
|
-- make a particular identifier within a package available for import
|
||||||
|
wildcardImport :: Identifier -> Identifier -> Scope ()
|
||||||
|
wildcardImport pkg ident = do
|
||||||
|
rootPkg <- lift $ resolveRootPackage pkg ident
|
||||||
|
maybeIdentState <- lookupLocalIdentState ident
|
||||||
|
insertElem ident $
|
||||||
|
case maybeIdentState of
|
||||||
|
Nothing -> Available [rootPkg]
|
||||||
|
Just Declared -> Declared
|
||||||
|
Just (Imported existingRootPkg) -> Imported existingRootPkg
|
||||||
|
Just (Available rootPkgs) ->
|
||||||
|
if elem rootPkg rootPkgs
|
||||||
|
then Available rootPkgs
|
||||||
|
else Available $ insert rootPkg rootPkgs
|
||||||
|
|
||||||
|
-- make all exported identifiers within a package available for import
|
||||||
|
wildcardImports :: Identifier -> Scope ()
|
||||||
|
wildcardImports pkg = do
|
||||||
|
(exports, _) <- lift $ findPackage pkg
|
||||||
|
_ <- mapM (wildcardImport pkg) (Map.keys exports)
|
||||||
|
return ()
|
||||||
|
|
||||||
|
-- resolve and store an explicit (non-wildcard) import
|
||||||
|
explicitImport :: Identifier -> Identifier -> Scope ()
|
||||||
|
explicitImport pkg ident = do
|
||||||
|
rootPkg <- lift $ resolveRootPackage pkg ident
|
||||||
|
maybeIdentState <- lookupLocalIdentState ident
|
||||||
|
insertElem ident $
|
||||||
|
case maybeIdentState of
|
||||||
|
Nothing -> Imported rootPkg
|
||||||
|
Just Declared ->
|
||||||
|
error $ "import of " ++ pkg ++ "::" ++ ident
|
||||||
|
++ " conflicts with prior declaration of " ++ ident
|
||||||
|
Just Available{} -> Imported rootPkg
|
||||||
|
Just (Imported otherPkg) ->
|
||||||
|
if otherPkg == rootPkg
|
||||||
|
then Imported rootPkg
|
||||||
|
else error $ "import of " ++ pkg ++ "::" ++ ident
|
||||||
|
++ " conflicts with prior import of "
|
||||||
|
++ otherPkg ++ "::" ++ ident
|
||||||
|
|
||||||
|
-- main logic responsible for translating packages, resolving imports and
|
||||||
|
-- exports, and rewriting identifiers referring to package declarations
|
||||||
|
processItems :: Identifier -> Identifier -> [ModuleItem]
|
||||||
|
-> PackagesState (IdentStateMap, [ModuleItem])
|
||||||
|
processItems topName packageName moduleItems = do
|
||||||
|
(moduleItems', scopes) <- runScoperT
|
||||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
||||||
packageName $ map (wrap . initialPrefix) items
|
topName (reorderItems moduleItems)
|
||||||
|
let rawIdents = extractMapping scopes
|
||||||
|
externalIdentMaps <- mapM (resolveExportMI rawIdents) moduleItems
|
||||||
|
let externalIdents = Map.unions externalIdentMaps
|
||||||
|
let declaredIdents = Map.filter isDeclared rawIdents
|
||||||
|
let exports = Map.union declaredIdents externalIdents
|
||||||
|
let exports' = if null packageName
|
||||||
|
then rawIdents
|
||||||
|
else exports
|
||||||
|
seq exports return (exports', moduleItems')
|
||||||
where
|
where
|
||||||
wrap :: PackageItem -> ModuleItem
|
-- produces partial mappings of exported identifiers, while also
|
||||||
wrap = MIPackageItem
|
-- checking the validity of the exports
|
||||||
unwrap :: ModuleItem -> PackageItem
|
resolveExportMI :: IdentStateMap -> ModuleItem -> PackagesState IdentStateMap
|
||||||
unwrap (MIPackageItem item) = item
|
resolveExportMI mapping (MIPackageItem (item @ (Export pkg ident))) =
|
||||||
unwrap _ = error "unwrap invariant violated"
|
if null packageName
|
||||||
|
then error $ "invalid " ++ (init $ show item)
|
||||||
|
++ " outside of package"
|
||||||
|
else resolveExport mapping pkg ident
|
||||||
|
resolveExportMI _ _ = return Map.empty
|
||||||
|
|
||||||
initialPrefix :: PackageItem -> PackageItem
|
-- declare an identifier, prefixing it if within a package
|
||||||
initialPrefix item =
|
prefixIdent :: Identifier -> Scope Identifier
|
||||||
case item of
|
prefixIdent x = do
|
||||||
Function a b x c d -> Function a b (prefix x) c d
|
inProcedure <- withinProcedureM
|
||||||
Task a x c d -> Task a (prefix x) c d
|
maybeIdentState <- lookupLocalIdentState x
|
||||||
Typedef a x -> Typedef a (prefix x)
|
case maybeIdentState of
|
||||||
Decl (Variable a b x c d) -> Decl (Variable a b (prefix x) c d)
|
Just (Imported rootPkg) -> error $ "declaration of " ++ x
|
||||||
Decl (Param a b x c ) -> Decl (Param a b (prefix x) c )
|
++ " conflicts with prior import of " ++ rootPkg
|
||||||
Decl (ParamType a x b ) -> Decl (ParamType a (prefix x) b )
|
++ "::" ++ x
|
||||||
other -> other
|
_ -> do
|
||||||
|
insertElem x Declared
|
||||||
|
if inProcedure || null packageName
|
||||||
|
then return x
|
||||||
|
else return $ packageName ++ '_' : x
|
||||||
|
|
||||||
prefix :: Identifier -> Identifier
|
-- check the global scope for declarations or imports
|
||||||
prefix x =
|
resolveGlobalIdent :: Identifier -> Scope Identifier
|
||||||
if Set.member x idents
|
resolveGlobalIdent x = do
|
||||||
then packageName ++ '_' : x
|
(exports, _) <- lift $ findPackage ""
|
||||||
else x
|
case Map.lookup x exports of
|
||||||
prefixM :: Identifier -> Scoper () Identifier
|
Nothing -> return x
|
||||||
prefixM x = do
|
Just identState -> do
|
||||||
|
-- inject the exact state outside of the module scope,
|
||||||
|
-- allowing wildcard imports to be handled correctly
|
||||||
|
insertElem [Access x Nil] identState
|
||||||
|
resolveIdent x
|
||||||
|
|
||||||
|
-- remap an identifier if needed based on declarations, explicit
|
||||||
|
-- imports, or names available for import
|
||||||
|
resolveIdent :: Identifier -> Scope Identifier
|
||||||
|
resolveIdent x = do
|
||||||
details <- lookupElemM x
|
details <- lookupElemM x
|
||||||
if details == Nothing
|
case details of
|
||||||
then return $ prefix x
|
Nothing ->
|
||||||
else return x
|
if null topName
|
||||||
|
then return x
|
||||||
|
else resolveGlobalIdent x
|
||||||
|
Just ([_, _], _, Declared) ->
|
||||||
|
if null packageName
|
||||||
|
then return x
|
||||||
|
else return $ packageName ++ '_' : x
|
||||||
|
Just (_, _, Declared) -> return x
|
||||||
|
Just (_, _, Imported rootPkg) ->
|
||||||
|
return $ rootPkg ++ '_' : x
|
||||||
|
Just (accesses, _, Available [rootPkg]) -> do
|
||||||
|
insertElem accesses $ Imported rootPkg
|
||||||
|
return $ rootPkg ++ '_' : x
|
||||||
|
Just (_, _, Available rootPkgs) ->
|
||||||
|
error $ "identifier " ++ show x
|
||||||
|
++ " ambiguously refers to the definitions in any of "
|
||||||
|
++ intercalate ", " rootPkgs
|
||||||
|
|
||||||
traverseDeclM :: Decl -> Scoper () Decl
|
traversePackageItemM :: PackageItem -> Scope PackageItem
|
||||||
|
-- TODO: fold this in with type parameters
|
||||||
|
traversePackageItemM (Typedef t x) = do
|
||||||
|
t' <- traverseTypeM t
|
||||||
|
x' <- prefixIdent x
|
||||||
|
t'' <- traverseNestedTypesM (traverseTypeExprsM traverseExprM) t'
|
||||||
|
return $ Typedef t'' x'
|
||||||
|
traversePackageItemM (orig @ (Import pkg ident)) = do
|
||||||
|
if null ident
|
||||||
|
then wildcardImports pkg
|
||||||
|
else explicitImport pkg ident
|
||||||
|
return $ Decl $ CommentDecl $ "removed " ++ show orig
|
||||||
|
traversePackageItemM (orig @ (Export pkg ident)) = do
|
||||||
|
() <- when (not (null pkg || null ident)) $ do
|
||||||
|
localName <- resolveIdent ident
|
||||||
|
rootPkg <- lift $ resolveRootPackage pkg ident
|
||||||
|
localName `seq` rootPkg `seq` return ()
|
||||||
|
return $ Decl $ CommentDecl $ "removed " ++ show orig
|
||||||
|
traversePackageItemM other = return other
|
||||||
|
|
||||||
|
traverseDeclM :: Decl -> Scope Decl
|
||||||
traverseDeclM decl = do
|
traverseDeclM decl = do
|
||||||
case decl of
|
decl' <- case decl of
|
||||||
Variable _ _ x _ _ -> insertElem x ()
|
Variable d t x a e -> declHelp x $ \x' -> Variable d t x' a e
|
||||||
Param _ _ x _ -> insertElem x ()
|
Param p t x e -> declHelp x $ \x' -> Param p t x' e
|
||||||
ParamType _ x _ -> insertElem x ()
|
ParamType p x t -> declHelp x $ \x' -> ParamType p x' t
|
||||||
CommentDecl{} -> return ()
|
CommentDecl c -> return $ CommentDecl c
|
||||||
traverseDeclTypesM traverseTypeM decl >>=
|
traverseDeclTypesM traverseTypeM decl' >>=
|
||||||
traverseDeclExprsM traverseExprM
|
traverseDeclExprsM traverseExprM
|
||||||
|
where declHelp x f = prefixIdent x >>= return . f
|
||||||
|
|
||||||
traverseTypeM :: Type -> Scoper () Type
|
traverseTypeM :: Type -> Scope Type
|
||||||
|
traverseTypeM (PSAlias p x rs) = do
|
||||||
|
x' <- lift $ resolvePSIdent p x
|
||||||
|
return $ Alias x' rs
|
||||||
traverseTypeM (Alias x rs) =
|
traverseTypeM (Alias x rs) =
|
||||||
prefixM x >>= \x' -> return $ Alias x' rs
|
resolveIdent x >>= \x' -> return $ Alias x' rs
|
||||||
traverseTypeM (Enum t enumItems rs) = do
|
traverseTypeM (Enum t enumItems rs) = do
|
||||||
enumItems' <- mapM prefixEnumItem enumItems
|
enumItems' <- mapM prefixEnumItem enumItems
|
||||||
return $ Enum t enumItems' rs
|
return $ Enum t enumItems' rs
|
||||||
where prefixEnumItem (x, e) = prefixM x >>= \x' -> return (x', e)
|
where prefixEnumItem (x, e) = prefixIdent x >>= \x' -> return (x', e)
|
||||||
traverseTypeM other = traverseSinglyNestedTypesM traverseTypeM other
|
traverseTypeM other = traverseSinglyNestedTypesM traverseTypeM other
|
||||||
|
|
||||||
traverseExprM (Ident x) = prefixM x >>= return . Ident
|
traverseExprM (PSIdent p x) = do
|
||||||
|
x' <- lift $ resolvePSIdent p x
|
||||||
|
return $ Ident x'
|
||||||
|
traverseExprM (Ident x) = resolveIdent x >>= return . Ident
|
||||||
traverseExprM other = traverseSinglyNestedExprsM traverseExprM other
|
traverseExprM other = traverseSinglyNestedExprsM traverseExprM other
|
||||||
traverseLHSM (LHSIdent x) = prefixM x >>= return . LHSIdent
|
traverseLHSM (LHSIdent x) = resolveIdent x >>= return . LHSIdent
|
||||||
traverseLHSM other = traverseSinglyNestedLHSsM traverseLHSM other
|
traverseLHSM other = traverseSinglyNestedLHSsM traverseLHSM other
|
||||||
|
|
||||||
traverseGenItemM = error "not possible"
|
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||||
traverseModuleItemM =
|
traverseModuleItemM (MIPackageItem item) = do
|
||||||
|
item' <- traversePackageItemM item
|
||||||
|
return $ MIPackageItem item'
|
||||||
|
traverseModuleItemM other =
|
||||||
|
traverseModuleItemM' other
|
||||||
|
traverseModuleItemM' =
|
||||||
traverseTypesM traverseTypeM >=>
|
traverseTypesM traverseTypeM >=>
|
||||||
traverseExprsM traverseExprM >=>
|
traverseExprsM traverseExprM >=>
|
||||||
traverseLHSsM traverseLHSM
|
traverseLHSsM traverseLHSM
|
||||||
|
|
@ -147,84 +331,200 @@ prefixPackageItems packageName idents items =
|
||||||
traverseStmtExprsM traverseExprM >=>
|
traverseStmtExprsM traverseExprM >=>
|
||||||
traverseStmtLHSsM traverseLHSM
|
traverseStmtLHSsM traverseLHSM
|
||||||
|
|
||||||
collectDescriptionM :: Description -> Writer Packages ()
|
-- locate a package by name, processing its contents if necessary
|
||||||
collectDescriptionM (Package _ name items) =
|
findPackage :: Identifier -> PackagesState Package
|
||||||
if any isImport items
|
findPackage packageName = do
|
||||||
then return ()
|
(stack, packages) <- get
|
||||||
else tell $ Map.singleton name itemList
|
let maybePackage = Map.lookup packageName packages
|
||||||
where
|
assertMsg (maybePackage /= Nothing) $
|
||||||
itemList = concatMap toPackageItems items
|
"could not find package " ++ show packageName
|
||||||
toPackageItems :: PackageItem -> PackageItems
|
-- because this conversion doesn't enforce declaration ordering of packages,
|
||||||
toPackageItems item =
|
-- it must check for dependency loops to avoid infinite recursion
|
||||||
case piName item of
|
let first : rest = reverse $ packageName : stack
|
||||||
"" -> []
|
assertMsg (not $ elem packageName stack) $
|
||||||
x -> [(x, item)]
|
"package dependency loop: " ++ show first ++ " depends on "
|
||||||
isImport :: PackageItem -> Bool
|
++ intercalate ", which depends on " (map show rest)
|
||||||
isImport (Import _ _) = True
|
let Just (package @ (exports, _))= maybePackage
|
||||||
isImport _ = False
|
if Map.null exports
|
||||||
collectDescriptionM _ = return ()
|
then do
|
||||||
|
-- process and resolve this package
|
||||||
|
put (packageName : stack, packages)
|
||||||
|
package' <- processPackage packageName $ snd package
|
||||||
|
packages' <- gets snd
|
||||||
|
put (stack, Map.insert packageName package' packages')
|
||||||
|
return package'
|
||||||
|
else return package
|
||||||
|
|
||||||
traverseDescription :: Packages -> Description -> [Description]
|
-- helper for elaborating a package when it is first referenced
|
||||||
traverseDescription packages (PackageItem (Import x y)) =
|
processPackage :: Identifier -> [PackageItem] -> PackagesState Package
|
||||||
map (\(MIPackageItem item) -> PackageItem item) items
|
processPackage packageName packageItems = do
|
||||||
|
(exports, moduleItems') <- processItems packageName packageName wrapped
|
||||||
|
let packageItems' = map unwrap moduleItems'
|
||||||
|
let package' = (exports, packageItems')
|
||||||
|
return package'
|
||||||
where
|
where
|
||||||
orig = Part [] False Module Inherit "DNE" []
|
wrapped = map wrap packageItems
|
||||||
[MIPackageItem $ Import x y]
|
wrap :: PackageItem -> ModuleItem
|
||||||
[orig'] = traverseDescription packages orig
|
wrap = MIPackageItem
|
||||||
Part [] False Module Inherit "DNE" [] items = orig'
|
unwrap :: ModuleItem -> PackageItem
|
||||||
traverseDescription packages description =
|
unwrap packageItem = item
|
||||||
[description']
|
where MIPackageItem item = packageItem
|
||||||
|
|
||||||
|
-- resolve a package scoped identifier to its unique global name
|
||||||
|
resolvePSIdent :: Identifier -> Identifier -> PackagesState Identifier
|
||||||
|
resolvePSIdent packageName itemName = do
|
||||||
|
rootPkg <- resolveRootPackage packageName itemName
|
||||||
|
return $ rootPkg ++ '_' : itemName
|
||||||
|
|
||||||
|
-- determines the root package contained the given package scoped identifier
|
||||||
|
resolveRootPackage :: Identifier -> Identifier -> PackagesState Identifier
|
||||||
|
resolveRootPackage packageName itemName = do
|
||||||
|
(exports, _) <- findPackage packageName
|
||||||
|
let maybeIdentState = Map.lookup itemName exports
|
||||||
|
assertMsg (maybeIdentState /= Nothing) $
|
||||||
|
"could not find " ++ show itemName ++ " in package " ++ show packageName
|
||||||
|
let Just identState = maybeIdentState
|
||||||
|
return $ toRootPackage packageName identState
|
||||||
|
|
||||||
|
-- errors with the given message when the check is false
|
||||||
|
assertMsg :: Monad m => Bool -> String -> m ()
|
||||||
|
assertMsg check msg = when (not check) $ error msg
|
||||||
|
|
||||||
|
-- helper for taking an ident which is either declared or exported form a
|
||||||
|
-- package and determine its true root source package
|
||||||
|
toRootPackage :: Identifier -> IdentState -> Identifier
|
||||||
|
toRootPackage sourcePackage identState =
|
||||||
|
if identState == Declared
|
||||||
|
then sourcePackage
|
||||||
|
else rootPackage
|
||||||
|
where Imported rootPackage = identState
|
||||||
|
|
||||||
|
-- nests packages items missing from modules
|
||||||
|
convertDescription :: PIs -> Description -> Description
|
||||||
|
convertDescription pis (orig @ Part{}) =
|
||||||
|
if Map.null pis
|
||||||
|
then orig
|
||||||
|
else Part attrs extern kw lifetime name ports items'
|
||||||
where
|
where
|
||||||
description' = traverseModuleItems
|
Part attrs extern kw lifetime name ports items = orig
|
||||||
(traverseModuleItem existingItemNames packages)
|
items' = addItems pis Set.empty (map addUsedPIs items)
|
||||||
description
|
convertDescription _ other = other
|
||||||
existingItemNames = execWriter $
|
|
||||||
collectModuleItemsM writePIName description
|
|
||||||
writePIName :: ModuleItem -> Writer Idents ()
|
|
||||||
writePIName (MIPackageItem (Import _ (Just x))) =
|
|
||||||
tell $ Set.singleton x
|
|
||||||
writePIName (MIPackageItem item) =
|
|
||||||
case piName item of
|
|
||||||
"" -> return ()
|
|
||||||
x -> tell $ Set.singleton x
|
|
||||||
writePIName _ = return ()
|
|
||||||
|
|
||||||
traverseModuleItem :: Idents -> Packages -> ModuleItem -> ModuleItem
|
-- attempt to fix simple declaration order issues
|
||||||
traverseModuleItem existingItemNames packages (MIPackageItem (Import x y)) =
|
reorderItems :: [ModuleItem] -> [ModuleItem]
|
||||||
if Map.member x packages
|
reorderItems items =
|
||||||
then Generate $ map (GenModuleItem . MIPackageItem) itemsRenamed
|
addItems localPIs Set.empty (map addUsedPIs items)
|
||||||
else MIPackageItem $ Import x y
|
|
||||||
where
|
where
|
||||||
packageItems = packages Map.! x
|
localPIs = Map.fromList $ concat $ mapMaybe toPIElem items
|
||||||
namesToAvoid = case y of
|
toPIElem :: ModuleItem -> Maybe [(Identifier, PackageItem)]
|
||||||
Nothing -> existingItemNames
|
toPIElem (MIPackageItem item) = Just $ map (, item) (piNames item)
|
||||||
Just ident -> Set.delete ident existingItemNames
|
toPIElem _ = Nothing
|
||||||
itemsRenamed =
|
|
||||||
prefixPackageItems x namesToAvoid
|
-- iteratively inserts missing package items exactly where they are needed
|
||||||
(map snd packageItems)
|
addItems :: PIs -> Idents -> [(ModuleItem, Idents)] -> [ModuleItem]
|
||||||
traverseModuleItem _ _ item =
|
addItems pis existingPIs ((item, usedPIs) : items) =
|
||||||
(traverseExprs $ traverseNestedExprs traverseExpr) $
|
if not $ Set.disjoint existingPIs thisPI then
|
||||||
(traverseTypes $ traverseNestedTypes traverseType) $
|
-- this item was re-imported earlier in the module
|
||||||
item
|
addItems pis existingPIs items
|
||||||
|
else if null itemsToAdd then
|
||||||
|
-- this item has no additional dependencies
|
||||||
|
item : addItems pis (Set.union existingPIs thisPI) items
|
||||||
|
else
|
||||||
|
-- this item has at least one un-met dependency
|
||||||
|
addItems pis existingPIs (addUsedPIs chosen : (item, usedPIs) : items)
|
||||||
where
|
where
|
||||||
|
thisPI = case item of
|
||||||
|
MIPackageItem packageItem ->
|
||||||
|
Set.fromList $ piNames packageItem
|
||||||
|
_ -> Set.empty
|
||||||
|
neededPIs = Set.difference (Set.difference usedPIs existingPIs) thisPI
|
||||||
|
itemsToAdd = map MIPackageItem $ Map.elems $
|
||||||
|
Map.restrictKeys pis neededPIs
|
||||||
|
chosen = head itemsToAdd
|
||||||
|
addItems _ _ [] = []
|
||||||
|
|
||||||
traverseExpr :: Expr -> Expr
|
-- augment a module item with the set of identifiers it uses
|
||||||
traverseExpr (PSIdent x y) = Ident $ x ++ "_" ++ y
|
addUsedPIs :: ModuleItem -> (ModuleItem, Idents)
|
||||||
traverseExpr other = other
|
addUsedPIs item =
|
||||||
|
(item, usedPIs)
|
||||||
|
where
|
||||||
|
usedPIs = execWriter $
|
||||||
|
traverseNestedModuleItemsM (traverseIdentsM writeIdent) item
|
||||||
|
writeIdent :: Identifier -> Writer Idents Identifier
|
||||||
|
writeIdent x = tell (Set.singleton x) >> return x
|
||||||
|
|
||||||
traverseType :: Type -> Type
|
-- visits all identifiers in a module item
|
||||||
traverseType (PSAlias ps xx rs) = Alias (ps ++ "_" ++ xx) rs
|
traverseIdentsM :: Monad m => MapperM m Identifier -> MapperM m ModuleItem
|
||||||
traverseType other = other
|
traverseIdentsM identMapper = traverseNodesM
|
||||||
|
(traverseExprIdentsM identMapper)
|
||||||
|
(traverseDeclIdentsM identMapper)
|
||||||
|
(traverseTypeIdentsM identMapper)
|
||||||
|
(traverseLHSIdentsM identMapper)
|
||||||
|
(traverseStmtIdentsM identMapper)
|
||||||
|
|
||||||
-- returns the "name" of a package item, if it has one
|
-- visits all identifiers in an expression
|
||||||
piName :: PackageItem -> Identifier
|
traverseExprIdentsM :: Monad m => MapperM m Identifier -> MapperM m Expr
|
||||||
piName (Function _ _ ident _ _) = ident
|
traverseExprIdentsM identMapper = fullMapper
|
||||||
piName (Task _ ident _ _) = ident
|
where
|
||||||
piName (Typedef _ ident ) = ident
|
fullMapper = exprMapper >=> traverseSinglyNestedExprsM fullMapper
|
||||||
piName (Decl (Variable _ _ ident _ _)) = ident
|
exprMapper (Call (Ident x) args) =
|
||||||
piName (Decl (Param _ _ ident _)) = ident
|
identMapper x >>= \x' -> return $ Call (Ident x') args
|
||||||
piName (Decl (ParamType _ ident _)) = ident
|
exprMapper (Ident x) = identMapper x >>= return . Ident
|
||||||
piName (Decl (CommentDecl _)) = ""
|
exprMapper other = return other
|
||||||
piName (Import _ _) = ""
|
|
||||||
piName (Export _) = ""
|
-- visits all identifiers in a type
|
||||||
piName (Directive _) = ""
|
traverseTypeIdentsM :: Monad m => MapperM m Identifier -> MapperM m Type
|
||||||
|
traverseTypeIdentsM identMapper = fullMapper
|
||||||
|
where
|
||||||
|
fullMapper = typeMapper
|
||||||
|
>=> traverseTypeExprsM (traverseExprIdentsM identMapper)
|
||||||
|
>=> traverseSinglyNestedTypesM fullMapper
|
||||||
|
typeMapper (Alias x t) = aliasHelper (Alias ) x t
|
||||||
|
typeMapper (PSAlias p x t) = aliasHelper (PSAlias p ) x t
|
||||||
|
typeMapper (CSAlias c p x t) = aliasHelper (CSAlias c p) x t
|
||||||
|
typeMapper other = return other
|
||||||
|
aliasHelper constructor x t =
|
||||||
|
identMapper x >>= \x' -> return $ constructor x' t
|
||||||
|
|
||||||
|
-- visits all identifiers in an LHS
|
||||||
|
traverseLHSIdentsM :: Monad m => MapperM m Identifier -> MapperM m LHS
|
||||||
|
traverseLHSIdentsM identMapper = fullMapper
|
||||||
|
where
|
||||||
|
fullMapper = lhsMapper
|
||||||
|
>=> traverseLHSExprsM (traverseExprIdentsM identMapper)
|
||||||
|
>=> traverseSinglyNestedLHSsM fullMapper
|
||||||
|
lhsMapper (LHSIdent x) = identMapper x >>= return . LHSIdent
|
||||||
|
lhsMapper other = return other
|
||||||
|
|
||||||
|
-- visits all identifiers in a statement
|
||||||
|
traverseStmtIdentsM :: Monad m => MapperM m Identifier -> MapperM m Stmt
|
||||||
|
traverseStmtIdentsM identMapper = fullMapper
|
||||||
|
where
|
||||||
|
fullMapper = stmtMapper
|
||||||
|
>=> traverseStmtExprsM (traverseExprIdentsM identMapper)
|
||||||
|
>=> traverseStmtLHSsM (traverseLHSIdentsM identMapper)
|
||||||
|
>=> traverseSinglyNestedStmtsM fullMapper
|
||||||
|
stmtMapper (Subroutine (Ident x) args) =
|
||||||
|
identMapper x >>= \x' -> return $ Subroutine (Ident x') args
|
||||||
|
stmtMapper other = return other
|
||||||
|
|
||||||
|
-- visits all identifiers in a declaration
|
||||||
|
traverseDeclIdentsM :: Monad m => MapperM m Identifier -> MapperM m Decl
|
||||||
|
traverseDeclIdentsM identMapper =
|
||||||
|
traverseDeclExprsM (traverseExprIdentsM identMapper) >=>
|
||||||
|
traverseDeclTypesM (traverseTypeIdentsM identMapper)
|
||||||
|
|
||||||
|
-- returns any names defined by a package item
|
||||||
|
piNames :: PackageItem -> [Identifier]
|
||||||
|
piNames (Function _ _ ident _ _) = [ident]
|
||||||
|
piNames (Task _ ident _ _) = [ident]
|
||||||
|
piNames (Decl (Variable _ _ ident _ _)) = [ident]
|
||||||
|
piNames (Decl (Param _ _ ident _)) = [ident]
|
||||||
|
piNames (Decl (ParamType _ ident _)) = [ident]
|
||||||
|
piNames (Decl (CommentDecl _)) = []
|
||||||
|
piNames (Import x y) = [show $ Import x y]
|
||||||
|
piNames (Export x y) = [show $ Export x y]
|
||||||
|
piNames (Directive _) = []
|
||||||
|
piNames (Typedef (Enum _ enumItems _) ident) =
|
||||||
|
ident : map fst enumItems
|
||||||
|
piNames (Typedef _ ident) = [ident]
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ module Convert.Scoper
|
||||||
, ScoperT
|
, ScoperT
|
||||||
, evalScoper
|
, evalScoper
|
||||||
, evalScoperT
|
, evalScoperT
|
||||||
|
, runScoperT
|
||||||
, partScoper
|
, partScoper
|
||||||
, partScoperT
|
, partScoperT
|
||||||
, insertElem
|
, insertElem
|
||||||
|
|
@ -36,9 +37,12 @@ module Convert.Scoper
|
||||||
, Access(..)
|
, Access(..)
|
||||||
, ScopeKey
|
, ScopeKey
|
||||||
, Scopes
|
, Scopes
|
||||||
|
, extractMapping
|
||||||
, embedScopes
|
, embedScopes
|
||||||
, withinProcedure
|
, withinProcedure
|
||||||
, withinProcedureM
|
, withinProcedureM
|
||||||
|
, lookupLocalIdent
|
||||||
|
, lookupLocalIdentM
|
||||||
, scopeModuleItemT
|
, scopeModuleItemT
|
||||||
, Replacements
|
, Replacements
|
||||||
) where
|
) where
|
||||||
|
|
@ -82,6 +86,12 @@ data Scopes a = Scopes
|
||||||
, sInjected :: [ModuleItem]
|
, sInjected :: [ModuleItem]
|
||||||
} deriving Show
|
} deriving Show
|
||||||
|
|
||||||
|
extractMapping :: Scopes a -> Map.Map Identifier a
|
||||||
|
extractMapping =
|
||||||
|
Map.mapMaybe eElement .
|
||||||
|
eMapping . snd .
|
||||||
|
Map.findMin . sMapping
|
||||||
|
|
||||||
embedScopes :: Monad m => (Scopes a -> b -> c) -> b -> ScoperT a m c
|
embedScopes :: Monad m => (Scopes a -> b -> c) -> b -> ScoperT a m c
|
||||||
embedScopes func x = do
|
embedScopes func x = do
|
||||||
scopes <- get
|
scopes <- get
|
||||||
|
|
@ -142,13 +152,26 @@ exprToAccesses (Dot e x) = do
|
||||||
Just $ accesses ++ [Access x Nil]
|
Just $ accesses ++ [Access x Nil]
|
||||||
exprToAccesses _ = Nothing
|
exprToAccesses _ = Nothing
|
||||||
|
|
||||||
insertElem :: Monad m => Identifier -> a -> ScoperT a m ()
|
class ScopePath k where
|
||||||
insertElem name element = do
|
toTiers :: Scopes a -> k -> [Tier]
|
||||||
|
|
||||||
|
instance ScopePath Identifier where
|
||||||
|
toTiers scopes name = sCurrent scopes ++ [Tier name ""]
|
||||||
|
|
||||||
|
instance ScopePath [Access] where
|
||||||
|
toTiers _ = map toTier
|
||||||
|
where
|
||||||
|
toTier :: Access -> Tier
|
||||||
|
toTier (Access x Nil) = Tier x ""
|
||||||
|
toTier (Access x iy) = Tier x y
|
||||||
|
where Ident y = iy
|
||||||
|
|
||||||
|
insertElem :: Monad m => ScopePath k => k -> a -> ScoperT a m ()
|
||||||
|
insertElem key element = do
|
||||||
s <- get
|
s <- get
|
||||||
let current = sCurrent s
|
|
||||||
let mapping = sMapping s
|
let mapping = sMapping s
|
||||||
let entry = Entry (Just element) "" Map.empty
|
let entry = Entry (Just element) "" Map.empty
|
||||||
let mapping' = setScope (current ++ [Tier name ""]) entry mapping
|
let mapping' = setScope (toTiers s key) entry mapping
|
||||||
put $ s { sMapping = mapping' }
|
put $ s { sMapping = mapping' }
|
||||||
|
|
||||||
injectItem :: Monad m => ModuleItem -> ScoperT a m ()
|
injectItem :: Monad m => ModuleItem -> ScoperT a m ()
|
||||||
|
|
@ -218,6 +241,19 @@ lookupAccesses scopes accesses = do
|
||||||
let side = resolveInScope (sMapping scopes) [] accesses
|
let side = resolveInScope (sMapping scopes) [] accesses
|
||||||
if isNothing deep then side else deep
|
if isNothing deep then side else deep
|
||||||
|
|
||||||
|
lookupLocalIdent :: Scopes a -> Identifier -> LookupResult a
|
||||||
|
lookupLocalIdent scopes ident = do
|
||||||
|
(replacements, element) <- directResolve (sMapping scopes) accesses
|
||||||
|
Just (accesses, replacements, element)
|
||||||
|
where
|
||||||
|
accesses = map toAccess (sCurrent scopes) ++ [Access ident Nil]
|
||||||
|
toAccess :: Tier -> Access
|
||||||
|
toAccess (Tier x "") = Access x Nil
|
||||||
|
toAccess (Tier x y) = Access x (Ident y)
|
||||||
|
|
||||||
|
lookupLocalIdentM :: Monad m => Identifier -> ScoperT a m (LookupResult a)
|
||||||
|
lookupLocalIdentM = embedScopes lookupLocalIdent
|
||||||
|
|
||||||
withinProcedureM :: Monad m => ScoperT a m Bool
|
withinProcedureM :: Monad m => ScoperT a m Bool
|
||||||
withinProcedureM = gets sProcedure
|
withinProcedureM = gets sProcedure
|
||||||
|
|
||||||
|
|
@ -245,8 +281,23 @@ evalScoperT
|
||||||
-> Identifier
|
-> Identifier
|
||||||
-> [ModuleItem]
|
-> [ModuleItem]
|
||||||
-> m [ModuleItem]
|
-> m [ModuleItem]
|
||||||
evalScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items =
|
evalScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items = do
|
||||||
evalStateT operation initialState
|
(items', _) <- runScoperT
|
||||||
|
declMapper moduleItemMapper genItemMapper stmtMapper
|
||||||
|
topName items
|
||||||
|
return items'
|
||||||
|
|
||||||
|
runScoperT
|
||||||
|
:: forall a m. Monad m
|
||||||
|
=> MapperM (ScoperT a m) Decl
|
||||||
|
-> MapperM (ScoperT a m) ModuleItem
|
||||||
|
-> MapperM (ScoperT a m) GenItem
|
||||||
|
-> MapperM (ScoperT a m) Stmt
|
||||||
|
-> Identifier
|
||||||
|
-> [ModuleItem]
|
||||||
|
-> m ([ModuleItem], Scopes a)
|
||||||
|
runScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items =
|
||||||
|
runStateT operation initialState
|
||||||
where
|
where
|
||||||
operation :: ScoperT a m [ModuleItem]
|
operation :: ScoperT a m [ModuleItem]
|
||||||
operation = do
|
operation = do
|
||||||
|
|
|
||||||
|
|
@ -613,8 +613,8 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper =
|
||||||
return $ MIPackageItem $ Directive c
|
return $ MIPackageItem $ Directive c
|
||||||
moduleItemMapper (MIPackageItem (Import x y)) =
|
moduleItemMapper (MIPackageItem (Import x y)) =
|
||||||
return $ MIPackageItem $ Import x y
|
return $ MIPackageItem $ Import x y
|
||||||
moduleItemMapper (MIPackageItem (Export x)) =
|
moduleItemMapper (MIPackageItem (Export x y)) =
|
||||||
return $ MIPackageItem $ Export x
|
return $ MIPackageItem $ Export x y
|
||||||
moduleItemMapper (AssertionItem (mx, a)) = do
|
moduleItemMapper (AssertionItem (mx, a)) = do
|
||||||
a' <- traverseAssertionStmtsM stmtMapper a
|
a' <- traverseAssertionStmtsM stmtMapper a
|
||||||
a'' <- traverseAssertionExprsM exprMapper a'
|
a'' <- traverseAssertionExprsM exprMapper a'
|
||||||
|
|
@ -864,6 +864,11 @@ traverseTypeExprsM exprMapper =
|
||||||
let pm' = zip (map fst pm) vals'
|
let pm' = zip (map fst pm) vals'
|
||||||
rs' <- mapM (mapBothM exprMapper) rs
|
rs' <- mapM (mapBothM exprMapper) rs
|
||||||
return $ CSAlias ps pm' xx rs'
|
return $ CSAlias ps pm' xx rs'
|
||||||
|
typeMapper (Enum t enumItems rs) = do
|
||||||
|
enumItems' <- mapM enumItemMapper enumItems
|
||||||
|
rs' <- mapM (mapBothM exprMapper) rs
|
||||||
|
return $ Enum t enumItems' rs'
|
||||||
|
where enumItemMapper (x, e) = exprMapper e >>= \e' -> return (x, e')
|
||||||
typeMapper t = do
|
typeMapper t = do
|
||||||
let (tf, rs) = typeRanges t
|
let (tf, rs) = typeRanges t
|
||||||
rs' <- mapM (mapBothM exprMapper) rs
|
rs' <- mapM (mapBothM exprMapper) rs
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ module Language.SystemVerilog.AST.Description
|
||||||
, Lifetime (..)
|
, Lifetime (..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Maybe (fromMaybe)
|
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
|
|
||||||
import Language.SystemVerilog.AST.ShowHelp
|
import Language.SystemVerilog.AST.ShowHelp
|
||||||
|
|
@ -56,8 +55,8 @@ data PackageItem
|
||||||
= Typedef Type Identifier
|
= Typedef Type Identifier
|
||||||
| Function Lifetime Type Identifier [Decl] [Stmt]
|
| Function Lifetime Type Identifier [Decl] [Stmt]
|
||||||
| Task Lifetime Identifier [Decl] [Stmt]
|
| Task Lifetime Identifier [Decl] [Stmt]
|
||||||
| Import Identifier (Maybe Identifier)
|
| Import Identifier Identifier
|
||||||
| Export (Maybe (Identifier, Maybe Identifier))
|
| Export Identifier Identifier
|
||||||
| Decl Decl
|
| Decl Decl
|
||||||
| Directive String
|
| Directive String
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
@ -70,12 +69,15 @@ instance Show PackageItem where
|
||||||
show (Task ml x i b) =
|
show (Task ml x i b) =
|
||||||
printf "task %s%s;\n%s\nendtask"
|
printf "task %s%s;\n%s\nendtask"
|
||||||
(showPad ml) x (showBlock i b)
|
(showPad ml) x (showBlock i b)
|
||||||
show (Import x y) = printf "import %s::%s;" x (fromMaybe "*" y)
|
show (Import x y) = printf "import %s::%s;" x (showWildcard y)
|
||||||
show (Export Nothing) = "export *::*";
|
show (Export x y) = printf "export %s::%s;" (showWildcard x) (showWildcard y)
|
||||||
show (Export (Just (x, y))) = printf "export %s::%s;" x (fromMaybe "*" y)
|
|
||||||
show (Decl decl) = show decl
|
show (Decl decl) = show decl
|
||||||
show (Directive str) = str
|
show (Directive str) = str
|
||||||
|
|
||||||
|
showWildcard :: Identifier -> String
|
||||||
|
showWildcard "" = "*"
|
||||||
|
showWildcard x = x
|
||||||
|
|
||||||
data PartKW
|
data PartKW
|
||||||
= Module
|
= Module
|
||||||
| Interface
|
| Interface
|
||||||
|
|
|
||||||
|
|
@ -843,8 +843,8 @@ NonDeclPackageItem :: { [PackageItem] }
|
||||||
| "function" Lifetime "void" Identifier TFItems DeclsAndStmts "endfunction" opt(Tag) { [Task $2 $4 (map defaultFuncInput $ $5 ++ fst $6) (snd $6)] }
|
| "function" Lifetime "void" Identifier TFItems DeclsAndStmts "endfunction" opt(Tag) { [Task $2 $4 (map defaultFuncInput $ $5 ++ fst $6) (snd $6)] }
|
||||||
| "task" Lifetime Identifier TFItems DeclsAndStmts "endtask" opt(Tag) { [Task $2 $3 (map defaultFuncInput $ $4 ++ fst $5) (snd $5)] }
|
| "task" Lifetime Identifier TFItems DeclsAndStmts "endtask" opt(Tag) { [Task $2 $3 (map defaultFuncInput $ $4 ++ fst $5) (snd $5)] }
|
||||||
| "import" PackageImportItems ";" { map (uncurry Import) $2 }
|
| "import" PackageImportItems ";" { map (uncurry Import) $2 }
|
||||||
| "export" PackageImportItems ";" { map (Export . Just) $2 }
|
| "export" PackageImportItems ";" { map (uncurry Export) $2 }
|
||||||
| "export" "*" "::" "*" ";" { [Export Nothing] } -- "Nothing" being no restrictions
|
| "export" "*" "::" "*" ";" { [Export "" ""] }
|
||||||
| ForwardTypedef ";" { $1 }
|
| ForwardTypedef ";" { $1 }
|
||||||
| TimeunitsDeclaration { $1 }
|
| TimeunitsDeclaration { $1 }
|
||||||
| Directive { [Directive $1] }
|
| Directive { [Directive $1] }
|
||||||
|
|
@ -872,12 +872,12 @@ DefaultNetType :: { String }
|
||||||
: NetType { show $1 }
|
: NetType { show $1 }
|
||||||
| Identifier { $1 }
|
| Identifier { $1 }
|
||||||
|
|
||||||
PackageImportItems :: { [(Identifier, Maybe Identifier)] }
|
PackageImportItems :: { [(Identifier, Identifier)] }
|
||||||
: PackageImportItem { [$1] }
|
: PackageImportItem { [$1] }
|
||||||
| PackageImportItems "," PackageImportItem { $1 ++ [$3] }
|
| PackageImportItems "," PackageImportItem { $1 ++ [$3] }
|
||||||
PackageImportItem :: { (Identifier, Maybe Identifier) }
|
PackageImportItem :: { (Identifier, Identifier) }
|
||||||
: Identifier "::" Identifier { ($1, Just $3) }
|
: Identifier "::" Identifier { ($1, $3) }
|
||||||
| Identifier "::" "*" { ($1, Nothing) }
|
| Identifier "::" "*" { ($1, "") }
|
||||||
|
|
||||||
FuncRetAndName :: { (Type, Identifier) }
|
FuncRetAndName :: { (Type, Identifier) }
|
||||||
: Type Identifier { ($1 , $2) }
|
: Type Identifier { ($1 , $2) }
|
||||||
|
|
@ -987,6 +987,8 @@ StmtAsgn :: { Stmt }
|
||||||
| IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (RawNum 1) }
|
| IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (RawNum 1) }
|
||||||
| LHS ";" { Subroutine (lhsToExpr $1) (Args [] []) }
|
| LHS ";" { Subroutine (lhsToExpr $1) (Args [] []) }
|
||||||
| LHS CallArgs ";" { Subroutine (lhsToExpr $1) $2 }
|
| LHS CallArgs ";" { Subroutine (lhsToExpr $1) $2 }
|
||||||
|
| Identifier "::" Identifier ";" { Subroutine (PSIdent $1 $3) (Args [] []) }
|
||||||
|
| Identifier "::" Identifier CallArgs ";" { Subroutine (PSIdent $1 $3) $4 }
|
||||||
StmtNonAsgn :: { Stmt }
|
StmtNonAsgn :: { Stmt }
|
||||||
: StmtBlock(BlockKWSeq, "end" ) { $1 }
|
: StmtBlock(BlockKWSeq, "end" ) { $1 }
|
||||||
| StmtBlock(BlockKWPar, "join") { $1 }
|
| StmtBlock(BlockKWPar, "join") { $1 }
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@ executable sv2v
|
||||||
Convert.LogOp
|
Convert.LogOp
|
||||||
Convert.MultiplePacked
|
Convert.MultiplePacked
|
||||||
Convert.NamedBlock
|
Convert.NamedBlock
|
||||||
Convert.NestPI
|
|
||||||
Convert.Package
|
Convert.Package
|
||||||
Convert.ParamNoDefault
|
Convert.ParamNoDefault
|
||||||
Convert.ParamType
|
Convert.ParamType
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
module ExampleA;
|
||||||
|
typedef enum logic {
|
||||||
|
A = 1,
|
||||||
|
B = 0,
|
||||||
|
C = 2
|
||||||
|
} Enum;
|
||||||
|
Enum x = A;
|
||||||
|
initial $display("ExampleA: x=%b, A=%b, B=%b", x, A, B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleB;
|
||||||
|
typedef enum logic {
|
||||||
|
A = 0,
|
||||||
|
B = 1
|
||||||
|
} Enum;
|
||||||
|
Enum x = A;
|
||||||
|
initial $display("ExampleB: x=%b, A=%b, B=%b", x, A, B);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
module ExampleA;
|
||||||
|
localparam [0:0] A = 1;
|
||||||
|
localparam [0:0] B = 0;
|
||||||
|
reg x = A;
|
||||||
|
initial $display("ExampleA: x=%b, A=%b, B=%b", x, A, B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleB;
|
||||||
|
localparam [0:0] A = 0;
|
||||||
|
localparam [0:0] B = 1;
|
||||||
|
reg x = A;
|
||||||
|
initial $display("ExampleB: x=%b, A=%b, B=%b", x, A, B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
module top;
|
||||||
|
ExampleA a();
|
||||||
|
ExampleB b();
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package Q;
|
||||||
|
localparam W = 5;
|
||||||
|
localparam unrelated = 1;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package P;
|
||||||
|
import Q::*;
|
||||||
|
export Q::W;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module Example
|
||||||
|
import P::*;
|
||||||
|
(
|
||||||
|
input logic [W - 1:0] inp
|
||||||
|
);
|
||||||
|
import Q::unrelated;
|
||||||
|
initial $display("%b %0d %0d", inp, $bits(inp), unrelated);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
module Example(inp);
|
||||||
|
localparam W = 5;
|
||||||
|
localparam unrelated = 1;
|
||||||
|
input wire [W - 1:0] inp;
|
||||||
|
initial $display("%b %0d %0d", inp, $bits(inp), unrelated);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
module top;
|
||||||
|
Example e(5'b00000);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package Pkg;
|
||||||
|
localparam integer X = func(1);
|
||||||
|
function automatic integer func;
|
||||||
|
input integer inp;
|
||||||
|
func = inp * 2;
|
||||||
|
endfunction
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
initial $display(Pkg::X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
module top;
|
||||||
|
function automatic integer func;
|
||||||
|
input integer inp;
|
||||||
|
func = inp * 2;
|
||||||
|
endfunction
|
||||||
|
localparam integer X = func(1);
|
||||||
|
initial $display(X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
localparam Y = 2;
|
||||||
|
typedef enum {
|
||||||
|
A = X,
|
||||||
|
B = Y
|
||||||
|
} Enum;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
import P::*;
|
||||||
|
initial $display("%0d %0d %0d", X, A, B);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
module top;
|
||||||
|
localparam X = 1;
|
||||||
|
localparam Y = 2;
|
||||||
|
localparam A = X;
|
||||||
|
localparam B = Y;
|
||||||
|
initial $display("%0d %0d %0d", X, A, B);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package PkgA;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
export PkgA::*;
|
||||||
|
localparam Bar = 2;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(PkgB::Bar);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
module top;
|
||||||
|
localparam Bar = 2;
|
||||||
|
initial $display(Bar);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
import P::X;
|
||||||
|
export P::*;
|
||||||
|
localparam Y = 2;
|
||||||
|
endpackage
|
||||||
|
package R;
|
||||||
|
import Q::X;
|
||||||
|
export Q::*;
|
||||||
|
localparam Z = 3;
|
||||||
|
endpackage
|
||||||
|
package S;
|
||||||
|
import P::X;
|
||||||
|
import Q::Y;
|
||||||
|
import R::Z;
|
||||||
|
export *::*;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import S::*;
|
||||||
|
initial $display(X, Y, Z);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
module top;
|
||||||
|
localparam X = 1;
|
||||||
|
localparam Y = 2;
|
||||||
|
localparam Z = 3;
|
||||||
|
initial $display(X, Y, Z);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package PkgA;
|
||||||
|
localparam X = 1;
|
||||||
|
localparam Y = 2;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
localparam X = 3;
|
||||||
|
localparam Z = 4;
|
||||||
|
endpackage
|
||||||
|
import PkgA::*;
|
||||||
|
import PkgB::*;
|
||||||
|
localparam X = 5;
|
||||||
|
module top;
|
||||||
|
initial $display(X, Y, Z);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
module top;
|
||||||
|
localparam X = 5;
|
||||||
|
localparam Y = 2;
|
||||||
|
localparam Z = 4;
|
||||||
|
initial $display(X, Y, Z);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
`define DUMP(key) initial $display(`"key %0d`", X);
|
||||||
|
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module ExampleA;
|
||||||
|
import P::*;
|
||||||
|
localparam X = 3;
|
||||||
|
`DUMP(A)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleB;
|
||||||
|
localparam X = 3;
|
||||||
|
import P::*;
|
||||||
|
`DUMP(B)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleC;
|
||||||
|
import P::*;
|
||||||
|
`DUMP(C)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleD;
|
||||||
|
import Q::*;
|
||||||
|
`DUMP(D)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleE;
|
||||||
|
import P::*;
|
||||||
|
import Q::X;
|
||||||
|
`DUMP(E)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleF;
|
||||||
|
import Q::X;
|
||||||
|
import P::*;
|
||||||
|
`DUMP(F)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleG;
|
||||||
|
import P::*;
|
||||||
|
import Q::*;
|
||||||
|
// allowed but can't reference C
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
package R;
|
||||||
|
import P::X;
|
||||||
|
export P::X;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package S;
|
||||||
|
import P::X;
|
||||||
|
export R::X; // oof but it's allowed
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module ExampleH;
|
||||||
|
import R::*;
|
||||||
|
import S::*;
|
||||||
|
`DUMP(H)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleI;
|
||||||
|
import R::X;
|
||||||
|
import S::X;
|
||||||
|
`DUMP(I)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleJ;
|
||||||
|
import R::*;
|
||||||
|
`DUMP(J)
|
||||||
|
import S::X;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleK;
|
||||||
|
import P::X;
|
||||||
|
if (1) begin : blk1
|
||||||
|
import P::X;
|
||||||
|
`DUMP(K1)
|
||||||
|
end
|
||||||
|
if (1) begin : blk2
|
||||||
|
import Q::X;
|
||||||
|
`DUMP(K2)
|
||||||
|
end
|
||||||
|
if (1) begin : blk3
|
||||||
|
localparam X = 3;
|
||||||
|
`DUMP(K3)
|
||||||
|
end
|
||||||
|
if (1) begin : blk4
|
||||||
|
import Q::*;
|
||||||
|
`DUMP(K4)
|
||||||
|
end
|
||||||
|
`DUMP(K0)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleL;
|
||||||
|
import P::X;
|
||||||
|
import R::X;
|
||||||
|
`DUMP(L)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
package T;
|
||||||
|
import P::X;
|
||||||
|
export P::*;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package U;
|
||||||
|
import P::*;
|
||||||
|
export P::X;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package V;
|
||||||
|
import P::*;
|
||||||
|
export P::*;
|
||||||
|
localparam Y = X;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package W;
|
||||||
|
import P::*;
|
||||||
|
export P::*;
|
||||||
|
task help;
|
||||||
|
$display("W::help() %0d", X);
|
||||||
|
endtask
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module ExampleM;
|
||||||
|
if (1) begin : blk1
|
||||||
|
import T::X;
|
||||||
|
`DUMP(M1)
|
||||||
|
end
|
||||||
|
if (1) begin : blk2
|
||||||
|
import U::X;
|
||||||
|
`DUMP(M2)
|
||||||
|
end
|
||||||
|
if (1) begin : blk3
|
||||||
|
import V::X;
|
||||||
|
`DUMP(M3)
|
||||||
|
end
|
||||||
|
if (1) begin : blk4
|
||||||
|
import W::X;
|
||||||
|
`DUMP(M4)
|
||||||
|
initial W::help;
|
||||||
|
initial W::help();
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleN;
|
||||||
|
import P::*;
|
||||||
|
if (1) begin : blk1
|
||||||
|
import P::X;
|
||||||
|
`DUMP(N1)
|
||||||
|
end
|
||||||
|
import Q::X;
|
||||||
|
`DUMP(N2)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ExampleO;
|
||||||
|
import P::*;
|
||||||
|
if (1) begin : blk1
|
||||||
|
import P::*;
|
||||||
|
`DUMP(O1)
|
||||||
|
end
|
||||||
|
import Q::X;
|
||||||
|
`DUMP(O2)
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
module top;
|
||||||
|
initial begin
|
||||||
|
$display("A 3");
|
||||||
|
$display("B 3");
|
||||||
|
$display("C 1");
|
||||||
|
$display("D 2");
|
||||||
|
$display("E 2");
|
||||||
|
$display("F 2");
|
||||||
|
// G doesn't print
|
||||||
|
$display("H 1");
|
||||||
|
$display("I 1");
|
||||||
|
$display("J 1");
|
||||||
|
$display("K1 1");
|
||||||
|
$display("K2 2");
|
||||||
|
$display("K3 3");
|
||||||
|
$display("K4 2");
|
||||||
|
$display("K0 1");
|
||||||
|
$display("L 1");
|
||||||
|
$display("M1 1");
|
||||||
|
$display("M2 1");
|
||||||
|
$display("M3 1");
|
||||||
|
$display("M4 1");
|
||||||
|
$display("W::help() 1");
|
||||||
|
$display("W::help() 1");
|
||||||
|
$display("N1 1");
|
||||||
|
$display("N2 2");
|
||||||
|
$display("O1 1");
|
||||||
|
$display("O2 2");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// pattern: invalid export Pkg::Foo outside of package
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
import Pkg::Foo;
|
||||||
|
export Pkg::Foo;
|
||||||
|
module top;
|
||||||
|
initial $display(Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// pattern: invalid export Pkg::Foo outside of package
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import Pkg::Foo;
|
||||||
|
export Pkg::Foo;
|
||||||
|
initial $display(Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// pattern: invalid export \*::\* outside of package
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
import Pkg::Foo;
|
||||||
|
export *::*;
|
||||||
|
module top;
|
||||||
|
initial $display(Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
// pattern: could not find package "PackageThatDoesNotExist"
|
||||||
|
module top;
|
||||||
|
import PackageThatDoesNotExist::*;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// pattern: could not find "ItemThatDoesNotExist" in package "Pkg"
|
||||||
|
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
import Pkg::ItemThatDoesNotExist;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pattern: could not find "X" in package "Q"
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
import P::*;
|
||||||
|
export P::*;
|
||||||
|
localparam Y = P::X;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(Q::X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// pattern: could not find "X" in package "Q"
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
localparam Y = 2;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
import P::*;
|
||||||
|
export *::*;
|
||||||
|
localparam Z = P::Y;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(Q::X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// pattern: export of PkgA::Bar, but Bar was never imported
|
||||||
|
package PkgA;
|
||||||
|
localparam Bar = 2;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
export PkgA::Bar;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(PkgB::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// pattern: export of Bar::Foo differs from import of Foo::Foo
|
||||||
|
package Bar;
|
||||||
|
localparam Bar = 1;
|
||||||
|
localparam Foo = 3;
|
||||||
|
endpackage
|
||||||
|
package Foo;
|
||||||
|
localparam Foo = 2;
|
||||||
|
endpackage
|
||||||
|
package Pkg;
|
||||||
|
import Foo::Foo;
|
||||||
|
import Bar::Bar;
|
||||||
|
export Bar::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(Pkg::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// pattern: could not find "Foo" in package "Bar"
|
||||||
|
package Bar;
|
||||||
|
localparam Bar = 1;
|
||||||
|
endpackage
|
||||||
|
package Pkg;
|
||||||
|
import Bar::*;
|
||||||
|
export Bar::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(Pkg::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// pattern: could not find package "PackageThatDoesNotExist"
|
||||||
|
|
||||||
|
package Wrap;
|
||||||
|
import PackageThatDoesNotExist::*;
|
||||||
|
localparam Foo = Bar;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
import Wrap::*;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// pattern: could not find "ItemThatDoesNotExist" in package "Pkg"
|
||||||
|
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
package Wrap;
|
||||||
|
localparam Foo = Pkg::ItemThatDoesNotExist;
|
||||||
|
endpackage
|
||||||
|
|
||||||
|
module top;
|
||||||
|
import Wrap::*;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pattern: package dependency loop: "PkgA" depends on "PkgB", which depends on "PkgA"
|
||||||
|
package PkgA;
|
||||||
|
import PkgB::Foo;
|
||||||
|
export PkgB::Foo;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
import PkgA::Foo;
|
||||||
|
export PkgA::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(PkgA::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// pattern: package dependency loop: "PkgA" depends on "PkgC", which depends on "PkgB", which depends on "PkgA"
|
||||||
|
package PkgA;
|
||||||
|
import PkgC::Foo;
|
||||||
|
export PkgC::Foo;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
import PkgA::Foo;
|
||||||
|
export PkgA::Foo;
|
||||||
|
endpackage
|
||||||
|
package PkgC;
|
||||||
|
import PkgB::Foo;
|
||||||
|
export PkgB::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(PkgA::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pattern: identifier "X" ambiguously refers to the definitions in any of P, Q
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::*;
|
||||||
|
import Q::*;
|
||||||
|
initial $display(X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// pattern: import of Q::X conflicts with prior import of P::X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::X;
|
||||||
|
import Q::X;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// pattern: declaration of X conflicts with prior import of P::X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::X;
|
||||||
|
localparam X = 2;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// pattern: import of P::X conflicts with prior declaration of X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
localparam X = 2;
|
||||||
|
import P::X;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pattern: import of P::X conflicts with prior import of Q::X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import Q::*;
|
||||||
|
initial $display(X); // imports Q::X
|
||||||
|
import P::X; // illegal
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// pattern: import of Q::X conflicts with prior import of P::X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
package W;
|
||||||
|
import P::*;
|
||||||
|
export P::*;
|
||||||
|
task help;
|
||||||
|
$display("W::help() %0d", X);
|
||||||
|
endtask
|
||||||
|
import Q::X;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import W::*;
|
||||||
|
initial $display(X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// pattern: import of Q::X conflicts with prior import of P::X
|
||||||
|
package P;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package Q;
|
||||||
|
localparam X = 2;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::*;
|
||||||
|
if (1) begin : blk1
|
||||||
|
// forces import of P::X at the top level
|
||||||
|
initial $display(X);
|
||||||
|
end
|
||||||
|
import Q::X; // illegal
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pattern: identifier "X" ambiguously refers to the definitions in any of PkgA, PkgB
|
||||||
|
package PkgA;
|
||||||
|
localparam X = 1;
|
||||||
|
endpackage
|
||||||
|
package PkgB;
|
||||||
|
localparam X = 3;
|
||||||
|
endpackage
|
||||||
|
import PkgA::*;
|
||||||
|
import PkgB::*;
|
||||||
|
module top;
|
||||||
|
initial $display(X);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// pattern: package dependency loop: "Pkg" depends on "Pkg"
|
||||||
|
package Pkg;
|
||||||
|
localparam Foo = 1;
|
||||||
|
export Pkg::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
initial $display(Pkg::Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// pattern: package dependency loop: "P" depends on "P"
|
||||||
|
package P;
|
||||||
|
import P::*;
|
||||||
|
localparam Foo = 1;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::*;
|
||||||
|
initial $display(Foo);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// pattern: package dependency loop: "P" depends on "P"
|
||||||
|
package P;
|
||||||
|
localparam Foo = P::Foo;
|
||||||
|
endpackage
|
||||||
|
module top;
|
||||||
|
import P::*;
|
||||||
|
initial $display(Foo);
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue