2020-07-03 02:50:26 +02:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2020-07-15 06:22:41 +02:00
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2020-07-03 02:50:26 +02:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Standardized scope traversal utilities
|
|
|
|
|
-
|
|
|
|
|
- This module provides a series of "scopers" which track the scope of blocks,
|
|
|
|
|
- generate loops, tasks, and functions, and provides the ability to insert and
|
2020-07-02 01:25:33 +02:00
|
|
|
- lookup elements in a scope-aware way. It also provides the ability to check
|
|
|
|
|
- whether the current node is within a procedural context.
|
2020-07-03 02:50:26 +02:00
|
|
|
-
|
|
|
|
|
- The interfaces take in a mappers for each of: Decl, ModuleItem, GenItem, and
|
|
|
|
|
- Stmt. Note that Function, Task, Always, Initial, and Final are NOT passed
|
|
|
|
|
- through the ModuleItem mapper as those constructs only provide Stmts and
|
|
|
|
|
- Decls. For the same reason, Decl ModuleItems are not passed through the
|
|
|
|
|
- ModuleItem mapper.
|
|
|
|
|
-
|
|
|
|
|
- All of the mappers should not recursively traverse any of the items captured
|
|
|
|
|
- by any of the other mappers. Scope resolution enforces data declaration
|
|
|
|
|
- ordering.
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.Scoper
|
|
|
|
|
( Scoper
|
|
|
|
|
, ScoperT
|
|
|
|
|
, evalScoper
|
|
|
|
|
, evalScoperT
|
2021-02-10 18:43:59 +01:00
|
|
|
, runScoper
|
2021-01-24 00:50:06 +01:00
|
|
|
, runScoperT
|
2020-07-03 02:50:26 +02:00
|
|
|
, partScoper
|
2021-09-17 05:35:16 +02:00
|
|
|
, scopeModuleItem
|
|
|
|
|
, scopeModuleItems
|
|
|
|
|
, scopePart
|
|
|
|
|
, scopeModule
|
2021-02-10 18:43:59 +01:00
|
|
|
, accessesToExpr
|
|
|
|
|
, replaceInType
|
|
|
|
|
, replaceInExpr
|
2021-02-22 20:13:37 +01:00
|
|
|
, scopeExpr
|
|
|
|
|
, scopeType
|
2020-07-03 02:50:26 +02:00
|
|
|
, insertElem
|
2021-07-24 01:59:26 +02:00
|
|
|
, removeElem
|
2020-07-15 04:04:47 +02:00
|
|
|
, injectItem
|
2021-07-18 04:56:14 +02:00
|
|
|
, injectTopItem
|
2021-02-03 22:12:05 +01:00
|
|
|
, injectDecl
|
2020-07-15 06:22:41 +02:00
|
|
|
, lookupElem
|
|
|
|
|
, lookupElemM
|
2021-07-14 03:25:09 +02:00
|
|
|
, localAccesses
|
|
|
|
|
, localAccessesM
|
2020-07-02 01:25:33 +02:00
|
|
|
, Access(..)
|
2020-07-15 06:22:41 +02:00
|
|
|
, ScopeKey
|
2020-07-03 02:50:26 +02:00
|
|
|
, Scopes
|
2021-01-24 00:50:06 +01:00
|
|
|
, extractMapping
|
2020-07-03 02:50:26 +02:00
|
|
|
, embedScopes
|
2020-07-02 01:25:33 +02:00
|
|
|
, withinProcedure
|
|
|
|
|
, withinProcedureM
|
2021-06-19 20:46:00 +02:00
|
|
|
, procedureLoc
|
|
|
|
|
, procedureLocM
|
2021-10-07 06:17:41 +02:00
|
|
|
, scopedError
|
|
|
|
|
, scopedErrorM
|
2021-02-22 05:17:47 +01:00
|
|
|
, isLoopVar
|
|
|
|
|
, isLoopVarM
|
2021-07-28 01:17:03 +02:00
|
|
|
, loopVarDepth
|
|
|
|
|
, loopVarDepthM
|
2021-01-24 00:50:06 +01:00
|
|
|
, lookupLocalIdent
|
|
|
|
|
, lookupLocalIdentM
|
2020-09-29 05:42:46 +02:00
|
|
|
, Replacements
|
2021-04-18 05:16:25 +02:00
|
|
|
, LookupResult
|
2020-07-03 02:50:26 +02:00
|
|
|
) where
|
|
|
|
|
|
2020-08-12 01:14:18 +02:00
|
|
|
import Control.Monad.State.Strict
|
2021-10-07 06:17:41 +02:00
|
|
|
import Data.List (findIndices, intercalate, isPrefixOf, partition)
|
2020-07-16 02:44:36 +02:00
|
|
|
import Data.Maybe (isNothing)
|
2020-07-03 02:50:26 +02:00
|
|
|
import qualified Data.Map.Strict as Map
|
|
|
|
|
|
|
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
|
|
|
|
-- user monad aliases
|
|
|
|
|
type Scoper a = State (Scopes a)
|
|
|
|
|
type ScoperT a m = StateT (Scopes a) m
|
|
|
|
|
|
|
|
|
|
-- one tier of scope construction
|
|
|
|
|
data Tier = Tier
|
|
|
|
|
{ tierName :: Identifier
|
|
|
|
|
, tierIndex :: Identifier
|
|
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
|
|
|
|
|
-- one layer of scope inspection
|
|
|
|
|
data Access = Access
|
|
|
|
|
{ accessName :: Identifier
|
|
|
|
|
, accessIndex :: Expr
|
|
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
|
|
|
|
|
type Mapping a = Map.Map Identifier (Entry a)
|
|
|
|
|
|
|
|
|
|
data Entry a = Entry
|
|
|
|
|
{ eElement :: Maybe a
|
|
|
|
|
, eIndex :: Identifier
|
|
|
|
|
, eMapping :: Mapping a
|
|
|
|
|
} deriving Show
|
|
|
|
|
|
|
|
|
|
data Scopes a = Scopes
|
|
|
|
|
{ sCurrent :: [Tier]
|
|
|
|
|
, sMapping :: Mapping a
|
2021-06-19 20:46:00 +02:00
|
|
|
, sProcedureLoc :: [Access]
|
2021-07-18 04:56:14 +02:00
|
|
|
, sInjectedItems :: [(Bool, ModuleItem)]
|
2021-02-03 22:12:05 +01:00
|
|
|
, sInjectedDecls :: [Decl]
|
2021-10-07 06:17:41 +02:00
|
|
|
, sLatestTrace :: String
|
2020-07-03 02:50:26 +02:00
|
|
|
} deriving Show
|
|
|
|
|
|
2021-01-24 00:50:06 +01:00
|
|
|
extractMapping :: Scopes a -> Map.Map Identifier a
|
|
|
|
|
extractMapping =
|
|
|
|
|
Map.mapMaybe eElement .
|
|
|
|
|
eMapping . snd .
|
|
|
|
|
Map.findMin . sMapping
|
|
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
embedScopes :: Monad m => (Scopes a -> b -> c) -> b -> ScoperT a m c
|
|
|
|
|
embedScopes func x = do
|
|
|
|
|
scopes <- get
|
|
|
|
|
return $ func scopes x
|
|
|
|
|
|
|
|
|
|
setScope :: [Tier] -> Entry a -> Mapping a -> Mapping a
|
|
|
|
|
setScope [] _ = error "setScope invariant violated"
|
|
|
|
|
setScope [Tier name _] newEntry =
|
|
|
|
|
Map.insert name newEntry
|
|
|
|
|
setScope (Tier name _ : tiers) newEntry =
|
|
|
|
|
Map.adjust adjustment name
|
|
|
|
|
where
|
|
|
|
|
adjustment entry =
|
|
|
|
|
entry { eMapping = setScope tiers newEntry (eMapping entry) }
|
|
|
|
|
|
|
|
|
|
enterScope :: Monad m => Identifier -> Identifier -> ScoperT a m ()
|
|
|
|
|
enterScope name index = do
|
2020-07-15 04:04:47 +02:00
|
|
|
s <- get
|
|
|
|
|
let current' = sCurrent s ++ [Tier name index]
|
2021-02-11 23:22:01 +01:00
|
|
|
let existingResult = lookupLocalIdent s name
|
2020-07-03 02:50:26 +02:00
|
|
|
let existingElement = fmap thd3 existingResult
|
|
|
|
|
let entry = Entry existingElement index Map.empty
|
2020-07-15 04:04:47 +02:00
|
|
|
let mapping' = setScope current' entry $ sMapping s
|
|
|
|
|
put $ s { sCurrent = current', sMapping = mapping'}
|
2020-07-03 02:50:26 +02:00
|
|
|
where thd3 (_, _, c) = c
|
|
|
|
|
|
2021-02-11 23:22:01 +01:00
|
|
|
exitScope :: Monad m => ScoperT a m ()
|
|
|
|
|
exitScope = modify' $ \s -> s { sCurrent = init $ sCurrent s }
|
2020-07-02 01:25:33 +02:00
|
|
|
|
|
|
|
|
enterProcedure :: Monad m => ScoperT a m ()
|
2021-06-19 20:46:00 +02:00
|
|
|
enterProcedure = modify' $ \s -> s { sProcedureLoc = map toAccess (sCurrent s) }
|
2020-07-02 01:25:33 +02:00
|
|
|
|
|
|
|
|
exitProcedure :: Monad m => ScoperT a m ()
|
2021-06-19 20:46:00 +02:00
|
|
|
exitProcedure = modify' $ \s -> s { sProcedureLoc = [] }
|
2021-02-11 23:22:01 +01:00
|
|
|
|
|
|
|
|
exprToAccesses :: [Access] -> Expr -> Maybe [Access]
|
|
|
|
|
exprToAccesses accesses (Ident x) =
|
|
|
|
|
Just $ Access x Nil : accesses
|
|
|
|
|
exprToAccesses accesses (Bit (Ident x) y) =
|
|
|
|
|
Just $ Access x y : accesses
|
|
|
|
|
exprToAccesses accesses (Bit (Dot e x) y) =
|
|
|
|
|
exprToAccesses (Access x y : accesses) e
|
|
|
|
|
exprToAccesses accesses (Dot e x) =
|
|
|
|
|
exprToAccesses (Access x Nil : accesses) e
|
|
|
|
|
exprToAccesses _ _ = Nothing
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2021-02-10 18:43:59 +01:00
|
|
|
accessesToExpr :: [Access] -> Expr
|
|
|
|
|
accessesToExpr accesses =
|
|
|
|
|
foldl accessToExpr (Ident topName) rest
|
|
|
|
|
where Access topName Nil : rest = accesses
|
|
|
|
|
|
|
|
|
|
accessToExpr :: Expr -> Access -> Expr
|
|
|
|
|
accessToExpr e (Access x Nil) = Dot e x
|
|
|
|
|
accessToExpr e (Access x i) = Bit (Dot e x) i
|
|
|
|
|
|
|
|
|
|
replaceInType :: Replacements -> Type -> Type
|
|
|
|
|
replaceInType replacements =
|
|
|
|
|
if Map.null replacements
|
|
|
|
|
then id
|
2021-02-11 22:50:13 +01:00
|
|
|
else replaceInType' replacements
|
|
|
|
|
|
|
|
|
|
replaceInType' :: Replacements -> Type -> Type
|
|
|
|
|
replaceInType' replacements =
|
|
|
|
|
traverseNestedTypes $ traverseTypeExprs $ replaceInExpr' replacements
|
2021-02-10 18:43:59 +01:00
|
|
|
|
|
|
|
|
replaceInExpr :: Replacements -> Expr -> Expr
|
|
|
|
|
replaceInExpr replacements =
|
|
|
|
|
if Map.null replacements
|
|
|
|
|
then id
|
|
|
|
|
else replaceInExpr' replacements
|
|
|
|
|
|
|
|
|
|
replaceInExpr' :: Replacements -> Expr -> Expr
|
|
|
|
|
replaceInExpr' replacements (Ident x) =
|
|
|
|
|
Map.findWithDefault (Ident x) x replacements
|
|
|
|
|
replaceInExpr' replacements other =
|
2021-02-11 22:50:13 +01:00
|
|
|
traverseExprTypes (replaceInType' replacements) $
|
|
|
|
|
traverseSinglyNestedExprs (replaceInExpr' replacements) other
|
2021-02-10 18:43:59 +01:00
|
|
|
|
2021-02-22 20:13:37 +01:00
|
|
|
-- rewrite an expression so that any identifiers it contains unambiguously refer
|
|
|
|
|
-- refer to currently visible declarations so it can be substituted elsewhere
|
|
|
|
|
scopeExpr :: Monad m => Expr -> ScoperT a m Expr
|
|
|
|
|
scopeExpr expr = do
|
|
|
|
|
expr' <- traverseSinglyNestedExprsM scopeExpr expr
|
|
|
|
|
>>= traverseExprTypesM scopeType
|
|
|
|
|
details <- lookupElemM expr'
|
|
|
|
|
case details of
|
|
|
|
|
Just (accesses, _, _) -> return $ accessesToExpr accesses
|
|
|
|
|
_ -> return expr'
|
|
|
|
|
scopeType :: Monad m => Type -> ScoperT a m Type
|
|
|
|
|
scopeType = traverseNestedTypesM $ traverseTypeExprsM scopeExpr
|
|
|
|
|
|
|
|
|
|
{-# INLINABLE scopeExpr #-}
|
|
|
|
|
{-# INLINABLE scopeType #-}
|
|
|
|
|
|
2021-01-24 00:50:06 +01:00
|
|
|
class ScopePath k where
|
|
|
|
|
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 ()
|
2021-07-24 01:59:26 +02:00
|
|
|
insertElem key = setElem key . Just
|
|
|
|
|
|
|
|
|
|
removeElem :: Monad m => ScopePath k => k -> ScoperT a m ()
|
|
|
|
|
removeElem key = setElem key Nothing
|
|
|
|
|
|
|
|
|
|
setElem :: Monad m => ScopePath k => k -> Maybe a -> ScoperT a m ()
|
|
|
|
|
setElem key maybeElement = do
|
2020-07-15 04:04:47 +02:00
|
|
|
s <- get
|
|
|
|
|
let mapping = sMapping s
|
2021-07-24 01:59:26 +02:00
|
|
|
let entry = Entry maybeElement "" Map.empty
|
2021-01-24 00:50:06 +01:00
|
|
|
let mapping' = setScope (toTiers s key) entry mapping
|
2020-07-15 04:04:47 +02:00
|
|
|
put $ s { sMapping = mapping' }
|
|
|
|
|
|
|
|
|
|
injectItem :: Monad m => ModuleItem -> ScoperT a m ()
|
|
|
|
|
injectItem item =
|
2021-07-18 04:56:14 +02:00
|
|
|
modify' $ \s -> s { sInjectedItems = (True, item) : sInjectedItems s }
|
|
|
|
|
|
|
|
|
|
injectTopItem :: Monad m => ModuleItem -> ScoperT a m ()
|
|
|
|
|
injectTopItem item =
|
|
|
|
|
modify' $ \s -> s { sInjectedItems = (False, item) : sInjectedItems s }
|
2021-02-03 22:12:05 +01:00
|
|
|
|
|
|
|
|
injectDecl :: Monad m => Decl -> ScoperT a m ()
|
|
|
|
|
injectDecl decl =
|
|
|
|
|
modify' $ \s -> s { sInjectedDecls = decl : sInjectedDecls s }
|
|
|
|
|
|
|
|
|
|
consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem]
|
|
|
|
|
consumeInjectedItems = do
|
2021-07-18 04:56:14 +02:00
|
|
|
-- only pull out top items if in the top scope
|
|
|
|
|
inTopLevelScope <- gets $ (== 1) . length . sCurrent
|
|
|
|
|
let op = if inTopLevelScope then const True else fst
|
|
|
|
|
(injected, remaining) <- gets $ partition op . sInjectedItems
|
2021-02-03 22:12:05 +01:00
|
|
|
when (not $ null injected) $
|
2021-07-18 04:56:14 +02:00
|
|
|
modify' $ \s -> s { sInjectedItems = remaining }
|
|
|
|
|
return $ reverse $ map snd $ injected
|
2021-02-03 22:12:05 +01:00
|
|
|
|
|
|
|
|
consumeInjectedDecls :: Monad m => ScoperT a m [Decl]
|
|
|
|
|
consumeInjectedDecls = do
|
|
|
|
|
injected <- gets sInjectedDecls
|
|
|
|
|
when (not $ null injected) $
|
|
|
|
|
modify' $ \s -> s { sInjectedDecls = [] }
|
|
|
|
|
return $ reverse injected
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
type Replacements = Map.Map Identifier Expr
|
|
|
|
|
|
2020-07-16 02:44:36 +02:00
|
|
|
-- lookup accesses by direct match (no search)
|
|
|
|
|
directResolve :: Mapping a -> [Access] -> Maybe (Replacements, a)
|
|
|
|
|
directResolve _ [] = Nothing
|
|
|
|
|
directResolve mapping [Access x Nil] = do
|
|
|
|
|
Entry maybeElement _ _ <- Map.lookup x mapping
|
|
|
|
|
fmap (Map.empty, ) maybeElement
|
|
|
|
|
directResolve _ [_] = Nothing
|
|
|
|
|
directResolve mapping (Access x Nil : rest) = do
|
|
|
|
|
Entry _ "" subMapping <- Map.lookup x mapping
|
|
|
|
|
directResolve subMapping rest
|
|
|
|
|
directResolve mapping (Access x e : rest) = do
|
2021-08-13 00:13:12 +02:00
|
|
|
Entry _ index@(_ : _) subMapping <- Map.lookup x mapping
|
2020-07-16 02:44:36 +02:00
|
|
|
(replacements, element) <- directResolve subMapping rest
|
|
|
|
|
let replacements' = Map.insert index e replacements
|
|
|
|
|
Just (replacements', element)
|
|
|
|
|
|
|
|
|
|
-- lookup accesses given a current scope prefix
|
|
|
|
|
resolveInScope :: Mapping a -> [Tier] -> [Access] -> LookupResult a
|
|
|
|
|
resolveInScope mapping [] accesses = do
|
|
|
|
|
(replacements, element) <- directResolve mapping accesses
|
|
|
|
|
Just (accesses, replacements, element)
|
|
|
|
|
resolveInScope mapping (Tier x y : rest) accesses = do
|
|
|
|
|
Entry _ _ subMapping <- Map.lookup x mapping
|
|
|
|
|
let deep = resolveInScope subMapping rest accesses
|
|
|
|
|
let side = resolveInScope subMapping [] accesses
|
|
|
|
|
let chosen = if isNothing deep then side else deep
|
|
|
|
|
(accesses', replacements, element) <- chosen
|
|
|
|
|
if null y
|
|
|
|
|
then Just (Access x Nil : accesses', replacements, element)
|
|
|
|
|
else do
|
|
|
|
|
let replacements' = Map.insert y (Ident y) replacements
|
|
|
|
|
Just (Access x (Ident y) : accesses', replacements', element)
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
type LookupResult a = Maybe ([Access], Replacements, a)
|
|
|
|
|
|
2020-07-15 06:22:41 +02:00
|
|
|
class ScopeKey k where
|
|
|
|
|
lookupElem :: Scopes a -> k -> LookupResult a
|
|
|
|
|
lookupElemM :: Monad m => k -> ScoperT a m (LookupResult a)
|
|
|
|
|
lookupElemM = embedScopes lookupElem
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2020-07-15 06:22:41 +02:00
|
|
|
instance ScopeKey Expr where
|
2021-02-11 23:22:01 +01:00
|
|
|
lookupElem scopes = join . fmap (lookupAccesses scopes) . exprToAccesses []
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2020-07-15 06:22:41 +02:00
|
|
|
instance ScopeKey LHS where
|
|
|
|
|
lookupElem scopes = lookupElem scopes . lhsToExpr
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2020-07-15 06:22:41 +02:00
|
|
|
instance ScopeKey Identifier where
|
|
|
|
|
lookupElem scopes ident = lookupAccesses scopes [Access ident Nil]
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
lookupAccesses :: Scopes a -> [Access] -> LookupResult a
|
|
|
|
|
lookupAccesses scopes accesses = do
|
2020-07-16 02:44:36 +02:00
|
|
|
let deep = resolveInScope (sMapping scopes) (sCurrent scopes) accesses
|
|
|
|
|
let side = resolveInScope (sMapping scopes) [] accesses
|
|
|
|
|
if isNothing deep then side else deep
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2021-07-14 03:25:09 +02:00
|
|
|
localAccesses :: Scopes a -> Identifier -> [Access]
|
|
|
|
|
localAccesses scopes ident =
|
|
|
|
|
foldr ((:) . toAccess) [Access ident Nil] (sCurrent scopes)
|
|
|
|
|
|
|
|
|
|
localAccessesM :: Monad m => Identifier -> ScoperT a m [Access]
|
|
|
|
|
localAccessesM = embedScopes localAccesses
|
|
|
|
|
|
2021-01-24 00:50:06 +01:00
|
|
|
lookupLocalIdent :: Scopes a -> Identifier -> LookupResult a
|
|
|
|
|
lookupLocalIdent scopes ident = do
|
|
|
|
|
(replacements, element) <- directResolve (sMapping scopes) accesses
|
|
|
|
|
Just (accesses, replacements, element)
|
2021-07-14 03:25:09 +02:00
|
|
|
where accesses = localAccesses scopes ident
|
2021-06-19 20:46:00 +02:00
|
|
|
|
|
|
|
|
toAccess :: Tier -> Access
|
|
|
|
|
toAccess (Tier x "") = Access x Nil
|
|
|
|
|
toAccess (Tier x y) = Access x (Ident y)
|
2021-01-24 00:50:06 +01:00
|
|
|
|
|
|
|
|
lookupLocalIdentM :: Monad m => Identifier -> ScoperT a m (LookupResult a)
|
|
|
|
|
lookupLocalIdentM = embedScopes lookupLocalIdent
|
|
|
|
|
|
2020-07-02 01:25:33 +02:00
|
|
|
withinProcedureM :: Monad m => ScoperT a m Bool
|
2021-06-19 20:46:00 +02:00
|
|
|
withinProcedureM = gets withinProcedure
|
2020-07-02 01:25:33 +02:00
|
|
|
|
|
|
|
|
withinProcedure :: Scopes a -> Bool
|
2021-06-19 20:46:00 +02:00
|
|
|
withinProcedure = not . null . sProcedureLoc
|
|
|
|
|
|
|
|
|
|
procedureLocM :: Monad m => ScoperT a m [Access]
|
|
|
|
|
procedureLocM = gets procedureLoc
|
|
|
|
|
|
|
|
|
|
procedureLoc :: Scopes a -> [Access]
|
|
|
|
|
procedureLoc = sProcedureLoc
|
2020-07-02 01:25:33 +02:00
|
|
|
|
2021-10-07 06:17:41 +02:00
|
|
|
debugLocation :: Scopes a -> String
|
|
|
|
|
debugLocation s =
|
|
|
|
|
hierarchy ++
|
|
|
|
|
if null latestTrace
|
|
|
|
|
then " (use -v to get approximate source location)"
|
|
|
|
|
else ", near " ++ latestTrace
|
|
|
|
|
where
|
|
|
|
|
hierarchy = intercalate "." $ map tierToStr $ sCurrent s
|
|
|
|
|
latestTrace = sLatestTrace s
|
|
|
|
|
tierToStr :: Tier -> String
|
|
|
|
|
tierToStr (Tier "" _) = "<unnamed_block>"
|
|
|
|
|
tierToStr (Tier x "") = x
|
|
|
|
|
tierToStr (Tier x y) = x ++ '[' : y ++ "]"
|
|
|
|
|
|
|
|
|
|
scopedErrorM :: Monad m => String -> ScoperT a m x
|
|
|
|
|
scopedErrorM msg = get >>= flip scopedError msg
|
|
|
|
|
|
|
|
|
|
scopedError :: Scopes a -> String -> x
|
|
|
|
|
scopedError scopes = error . (++ ", within scope " ++ debugLocation scopes)
|
|
|
|
|
|
2021-02-22 05:17:47 +01:00
|
|
|
isLoopVar :: Scopes a -> Identifier -> Bool
|
|
|
|
|
isLoopVar scopes x = any matches $ sCurrent scopes
|
|
|
|
|
where matches = (== x) . tierIndex
|
|
|
|
|
|
|
|
|
|
isLoopVarM :: Monad m => Identifier -> ScoperT a m Bool
|
|
|
|
|
isLoopVarM = embedScopes isLoopVar
|
|
|
|
|
|
2021-07-28 01:17:03 +02:00
|
|
|
loopVarDepth :: Scopes a -> Identifier -> Maybe Int
|
|
|
|
|
loopVarDepth scopes x =
|
|
|
|
|
case findIndices matches $ sCurrent scopes of
|
|
|
|
|
[] -> Nothing
|
|
|
|
|
indices -> Just $ last indices
|
|
|
|
|
where matches = (== x) . tierIndex
|
|
|
|
|
|
|
|
|
|
loopVarDepthM :: Monad m => Identifier -> ScoperT a m (Maybe Int)
|
|
|
|
|
loopVarDepthM = embedScopes loopVarDepth
|
|
|
|
|
|
2021-09-17 05:35:16 +02:00
|
|
|
scopeModuleItems
|
|
|
|
|
:: Monad m
|
|
|
|
|
=> MapperM (ScoperT a m) ModuleItem
|
2020-07-03 02:50:26 +02:00
|
|
|
-> Identifier
|
2021-09-17 05:35:16 +02:00
|
|
|
-> MapperM (ScoperT a m) [ModuleItem]
|
|
|
|
|
scopeModuleItems moduleItemMapper topName items = do
|
|
|
|
|
enterScope topName ""
|
|
|
|
|
items' <- mapM moduleItemMapper items
|
|
|
|
|
exitScope
|
2021-01-24 00:50:06 +01:00
|
|
|
return items'
|
|
|
|
|
|
2021-09-17 05:35:16 +02:00
|
|
|
scopeModule :: Monad m
|
|
|
|
|
=> MapperM (ScoperT a m) ModuleItem
|
|
|
|
|
-> MapperM (ScoperT a m) Description
|
|
|
|
|
scopeModule moduleItemMapper description
|
|
|
|
|
| Part _ _ Module _ _ _ _ <- description =
|
|
|
|
|
scopePart moduleItemMapper description
|
|
|
|
|
| otherwise = return description
|
2021-02-10 18:43:59 +01:00
|
|
|
|
2021-09-17 05:35:16 +02:00
|
|
|
scopePart :: Monad m
|
|
|
|
|
=> MapperM (ScoperT a m) ModuleItem
|
|
|
|
|
-> MapperM (ScoperT a m) Description
|
|
|
|
|
scopePart moduleItemMapper description
|
|
|
|
|
| Part attrs extern kw liftetime name ports items <- description =
|
|
|
|
|
scopeModuleItems moduleItemMapper name items >>=
|
|
|
|
|
return . Part attrs extern kw liftetime name ports
|
|
|
|
|
| otherwise = return description
|
2020-07-03 02:50:26 +02:00
|
|
|
|
2021-09-17 05:35:16 +02:00
|
|
|
evalScoper :: Scoper a x -> x
|
|
|
|
|
evalScoper = flip evalState initialState
|
|
|
|
|
|
|
|
|
|
evalScoperT :: Monad m => ScoperT a m x -> m x
|
|
|
|
|
evalScoperT = flip evalStateT initialState
|
|
|
|
|
|
|
|
|
|
runScoper :: Scoper a x -> (x, Scopes a)
|
|
|
|
|
runScoper = flip runState initialState
|
|
|
|
|
|
|
|
|
|
runScoperT :: Monad m => ScoperT a m x -> m (x, Scopes a)
|
|
|
|
|
runScoperT = flip runStateT initialState
|
2020-08-09 04:43:47 +02:00
|
|
|
|
2021-09-17 05:35:16 +02:00
|
|
|
initialState :: Scopes a
|
2021-10-07 06:17:41 +02:00
|
|
|
initialState = Scopes [] Map.empty [] [] [] ""
|
|
|
|
|
|
|
|
|
|
tracePrefix :: String
|
|
|
|
|
tracePrefix = "Trace: "
|
2021-09-17 05:35:16 +02:00
|
|
|
|
|
|
|
|
scopeModuleItem
|
2020-08-09 04:43:47 +02:00
|
|
|
:: 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
|
2021-09-17 05:35:16 +02:00
|
|
|
-> MapperM (ScoperT a m) ModuleItem
|
2021-10-07 06:17:41 +02:00
|
|
|
scopeModuleItem declMapperRaw moduleItemMapper genItemMapper stmtMapperRaw =
|
2020-08-09 04:43:47 +02:00
|
|
|
wrappedModuleItemMapper
|
|
|
|
|
where
|
2020-07-03 02:50:26 +02:00
|
|
|
fullStmtMapper :: Stmt -> ScoperT a m Stmt
|
|
|
|
|
fullStmtMapper (Block kw name decls stmts) = do
|
|
|
|
|
enterScope name ""
|
2021-02-03 22:12:05 +01:00
|
|
|
decls' <- fmap concat $ mapM declMapper' decls
|
2021-07-12 02:43:30 +02:00
|
|
|
stmts' <- mapM fullStmtMapper $ filter (/= Null) stmts
|
2021-02-11 23:22:01 +01:00
|
|
|
exitScope
|
2020-07-03 02:50:26 +02:00
|
|
|
return $ Block kw name decls' stmts'
|
|
|
|
|
-- TODO: Do we need to support the various procedural loops?
|
2021-02-03 22:12:05 +01:00
|
|
|
fullStmtMapper stmt = do
|
|
|
|
|
stmt' <- stmtMapper stmt
|
|
|
|
|
injected <- consumeInjectedDecls
|
|
|
|
|
if null injected
|
|
|
|
|
then traverseSinglyNestedStmtsM fullStmtMapper stmt'
|
|
|
|
|
else fullStmtMapper $ Block Seq "" injected [stmt']
|
|
|
|
|
|
2021-10-07 06:17:41 +02:00
|
|
|
declMapper :: Decl -> ScoperT a m Decl
|
|
|
|
|
declMapper decl@(CommentDecl c) =
|
|
|
|
|
consumeComment c >> return decl
|
|
|
|
|
declMapper decl = declMapperRaw decl
|
|
|
|
|
|
|
|
|
|
stmtMapper :: Stmt -> ScoperT a m Stmt
|
|
|
|
|
stmtMapper stmt@(CommentStmt c) =
|
|
|
|
|
consumeComment c >> return stmt
|
|
|
|
|
stmtMapper stmt = stmtMapperRaw stmt
|
|
|
|
|
|
|
|
|
|
consumeComment :: String -> ScoperT a m ()
|
|
|
|
|
consumeComment c =
|
|
|
|
|
when (tracePrefix `isPrefixOf` c) $
|
|
|
|
|
modify' $ \s -> s { sLatestTrace = drop (length tracePrefix) c }
|
|
|
|
|
|
2021-02-03 22:12:05 +01:00
|
|
|
-- converts a decl and adds decls injected during conversion
|
|
|
|
|
declMapper' :: Decl -> ScoperT a m [Decl]
|
|
|
|
|
declMapper' decl = do
|
|
|
|
|
decl' <- declMapper decl
|
|
|
|
|
injected <- consumeInjectedDecls
|
|
|
|
|
if null injected
|
|
|
|
|
then return [decl']
|
|
|
|
|
else do
|
|
|
|
|
injected' <- mapM declMapper injected
|
|
|
|
|
return $ injected' ++ [decl']
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
mapTFDecls :: [Decl] -> ScoperT a m [Decl]
|
|
|
|
|
mapTFDecls = mapTFDecls' 0
|
|
|
|
|
where
|
|
|
|
|
mapTFDecls' :: Int -> [Decl] -> ScoperT a m [Decl]
|
|
|
|
|
mapTFDecls' _ [] = return []
|
|
|
|
|
mapTFDecls' idx (decl : decls) =
|
|
|
|
|
case argIdxDecl decl of
|
|
|
|
|
Nothing -> do
|
2021-02-03 22:12:05 +01:00
|
|
|
decl' <- declMapper' decl
|
2020-07-03 02:50:26 +02:00
|
|
|
decls' <- mapTFDecls' idx decls
|
2021-02-03 22:12:05 +01:00
|
|
|
return $ decl' ++ decls'
|
2020-07-03 02:50:26 +02:00
|
|
|
Just declFunc -> do
|
|
|
|
|
_ <- declMapper $ declFunc idx
|
2021-02-03 22:12:05 +01:00
|
|
|
decl' <- declMapper' decl
|
2020-07-03 02:50:26 +02:00
|
|
|
decls' <- mapTFDecls' (idx + 1) decls
|
2021-02-03 22:12:05 +01:00
|
|
|
return $ decl' ++ decls'
|
2020-07-03 02:50:26 +02:00
|
|
|
|
|
|
|
|
argIdxDecl :: Decl -> Maybe (Int -> Decl)
|
|
|
|
|
argIdxDecl (Variable d t _ a e) =
|
|
|
|
|
if d == Local
|
|
|
|
|
then Nothing
|
|
|
|
|
else Just $ \i -> Variable d t (show i) a e
|
2021-07-02 23:59:21 +02:00
|
|
|
argIdxDecl Net{} = Nothing
|
2020-07-03 02:50:26 +02:00
|
|
|
argIdxDecl Param{} = Nothing
|
|
|
|
|
argIdxDecl ParamType{} = Nothing
|
|
|
|
|
argIdxDecl CommentDecl{} = Nothing
|
|
|
|
|
|
2020-08-02 04:20:14 +02:00
|
|
|
redirectTFDecl :: Type -> Identifier -> ScoperT a m (Type, Identifier)
|
|
|
|
|
redirectTFDecl typ ident = do
|
|
|
|
|
res <- declMapper $ Variable Local typ ident [] Nil
|
2022-01-24 06:40:43 +01:00
|
|
|
(newType, newName, newRanges) <-
|
|
|
|
|
return $ case res of
|
|
|
|
|
Variable Local t x r Nil -> (t, x, r)
|
|
|
|
|
Net Local TWire DefaultStrength t x r Nil -> (t, x, r)
|
|
|
|
|
_ -> error "redirectTFDecl invariant violated"
|
2021-07-20 23:38:04 +02:00
|
|
|
return $ if null newRanges
|
|
|
|
|
then (newType, newName)
|
|
|
|
|
else
|
|
|
|
|
let (tf, rs2) = typeRanges newType
|
|
|
|
|
in (tf $ newRanges ++ rs2, newName)
|
2020-08-02 04:20:14 +02:00
|
|
|
|
2020-07-15 04:04:47 +02:00
|
|
|
wrappedModuleItemMapper :: ModuleItem -> ScoperT a m ModuleItem
|
|
|
|
|
wrappedModuleItemMapper item = do
|
|
|
|
|
item' <- fullModuleItemMapper item
|
2021-02-03 22:12:05 +01:00
|
|
|
injected <- consumeInjectedItems
|
2020-07-15 04:04:47 +02:00
|
|
|
if null injected
|
|
|
|
|
then return item'
|
|
|
|
|
else do
|
|
|
|
|
injected' <- mapM fullModuleItemMapper injected
|
|
|
|
|
return $ Generate $ map GenModuleItem $ injected' ++ [item']
|
2020-07-03 02:50:26 +02:00
|
|
|
fullModuleItemMapper :: ModuleItem -> ScoperT a m ModuleItem
|
|
|
|
|
fullModuleItemMapper (MIPackageItem (Function ml t x decls stmts)) = do
|
2020-08-02 04:20:14 +02:00
|
|
|
(t', x') <- redirectTFDecl t x
|
2020-07-02 01:25:33 +02:00
|
|
|
enterProcedure
|
2020-08-02 04:20:14 +02:00
|
|
|
enterScope x' ""
|
2020-07-03 02:50:26 +02:00
|
|
|
decls' <- mapTFDecls decls
|
|
|
|
|
stmts' <- mapM fullStmtMapper stmts
|
2021-02-11 23:22:01 +01:00
|
|
|
exitScope
|
2020-07-02 01:25:33 +02:00
|
|
|
exitProcedure
|
2020-08-02 04:20:14 +02:00
|
|
|
return $ MIPackageItem $ Function ml t' x' decls' stmts'
|
|
|
|
|
fullModuleItemMapper (MIPackageItem (Task ml x decls stmts)) = do
|
|
|
|
|
(_, x') <- redirectTFDecl (Implicit Unspecified []) x
|
2020-07-02 01:25:33 +02:00
|
|
|
enterProcedure
|
2020-08-02 04:20:14 +02:00
|
|
|
enterScope x' ""
|
2020-07-03 02:50:26 +02:00
|
|
|
decls' <- mapTFDecls decls
|
|
|
|
|
stmts' <- mapM fullStmtMapper stmts
|
2021-02-11 23:22:01 +01:00
|
|
|
exitScope
|
2020-07-02 01:25:33 +02:00
|
|
|
exitProcedure
|
2020-08-02 04:20:14 +02:00
|
|
|
return $ MIPackageItem $ Task ml x' decls' stmts'
|
2020-07-03 02:50:26 +02:00
|
|
|
fullModuleItemMapper (MIPackageItem (Decl decl)) =
|
|
|
|
|
declMapper decl >>= return . MIPackageItem . Decl
|
2022-01-26 04:52:14 +01:00
|
|
|
fullModuleItemMapper (MIPackageItem item@DPIImport{}) = do
|
|
|
|
|
let DPIImport spec prop alias typ name decls = item
|
|
|
|
|
(typ', name') <- redirectTFDecl typ name
|
|
|
|
|
decls' <- mapM declMapper decls
|
|
|
|
|
let item' = DPIImport spec prop alias typ' name' decls'
|
|
|
|
|
return $ MIPackageItem item'
|
|
|
|
|
fullModuleItemMapper (MIPackageItem (DPIExport spec alias kw name)) =
|
|
|
|
|
return $ MIPackageItem $ DPIExport spec alias kw name
|
2020-07-02 01:25:33 +02:00
|
|
|
fullModuleItemMapper (AlwaysC kw stmt) = do
|
|
|
|
|
enterProcedure
|
|
|
|
|
stmt' <- fullStmtMapper stmt
|
|
|
|
|
exitProcedure
|
|
|
|
|
return $ AlwaysC kw stmt'
|
|
|
|
|
fullModuleItemMapper (Initial stmt) = do
|
|
|
|
|
enterProcedure
|
|
|
|
|
stmt' <- fullStmtMapper stmt
|
|
|
|
|
exitProcedure
|
|
|
|
|
return $ Initial stmt'
|
|
|
|
|
fullModuleItemMapper (Final stmt) = do
|
|
|
|
|
enterProcedure
|
|
|
|
|
stmt' <- fullStmtMapper stmt
|
|
|
|
|
exitProcedure
|
|
|
|
|
return $ Final stmt'
|
2020-07-03 02:50:26 +02:00
|
|
|
fullModuleItemMapper (Generate genItems) =
|
2021-07-18 04:56:14 +02:00
|
|
|
fullGenItemBlockMapper genItems >>= return . Generate
|
2020-07-03 02:50:26 +02:00
|
|
|
fullModuleItemMapper (MIAttr attr item) =
|
|
|
|
|
fullModuleItemMapper item >>= return . MIAttr attr
|
|
|
|
|
fullModuleItemMapper item = moduleItemMapper item
|
|
|
|
|
|
|
|
|
|
fullGenItemMapper :: GenItem -> ScoperT a m GenItem
|
2020-07-16 03:04:11 +02:00
|
|
|
fullGenItemMapper genItem = do
|
|
|
|
|
genItem' <- genItemMapper genItem
|
2021-02-03 22:12:05 +01:00
|
|
|
injected <- consumeInjectedItems
|
2021-07-18 04:56:14 +02:00
|
|
|
genItem'' <- scopeGenItemMapper genItem'
|
|
|
|
|
mapM_ injectItem injected -- defer until enclosing block
|
|
|
|
|
return genItem''
|
|
|
|
|
|
|
|
|
|
-- akin to fullGenItemMapper, but for lists of generate items, and
|
|
|
|
|
-- allowing module items to be injected in the middle of the list
|
|
|
|
|
fullGenItemBlockMapper :: [GenItem] -> ScoperT a m [GenItem]
|
|
|
|
|
fullGenItemBlockMapper = fmap concat . mapM genblkStep
|
|
|
|
|
genblkStep :: GenItem -> ScoperT a m [GenItem]
|
|
|
|
|
genblkStep genItem = do
|
|
|
|
|
genItem' <- fullGenItemMapper genItem
|
|
|
|
|
injected <- consumeInjectedItems
|
2020-07-16 03:04:11 +02:00
|
|
|
if null injected
|
2021-07-18 04:56:14 +02:00
|
|
|
then return [genItem']
|
2020-07-16 03:04:11 +02:00
|
|
|
else do
|
|
|
|
|
injected' <- mapM fullModuleItemMapper injected
|
2021-07-18 04:56:14 +02:00
|
|
|
return $ map GenModuleItem injected' ++ [genItem']
|
|
|
|
|
|
|
|
|
|
-- enters and exits generate block scopes as appropriate
|
2020-07-03 02:50:26 +02:00
|
|
|
scopeGenItemMapper :: GenItem -> ScoperT a m GenItem
|
2021-07-18 04:56:14 +02:00
|
|
|
scopeGenItemMapper (GenFor _ _ _ GenNull) = return GenNull
|
2020-07-15 04:04:47 +02:00
|
|
|
scopeGenItemMapper (GenFor (index, a) b c genItem) = do
|
2021-07-18 04:56:14 +02:00
|
|
|
let GenBlock name genItems = genItem
|
|
|
|
|
enterScope name index
|
|
|
|
|
genItems' <- fullGenItemBlockMapper genItems
|
|
|
|
|
exitScope
|
|
|
|
|
let genItem' = GenBlock name genItems'
|
2020-07-15 04:04:47 +02:00
|
|
|
return $ GenFor (index, a) b c genItem'
|
2020-07-23 04:30:33 +02:00
|
|
|
scopeGenItemMapper (GenIf cond thenItem elseItem) = do
|
2021-07-18 04:56:14 +02:00
|
|
|
thenItem' <- fullGenItemMapper thenItem
|
|
|
|
|
elseItem' <- fullGenItemMapper elseItem
|
2020-07-23 04:30:33 +02:00
|
|
|
return $ GenIf cond thenItem' elseItem'
|
2020-07-03 02:50:26 +02:00
|
|
|
scopeGenItemMapper (GenBlock name genItems) = do
|
|
|
|
|
enterScope name ""
|
2021-07-18 04:56:14 +02:00
|
|
|
genItems' <- fullGenItemBlockMapper genItems
|
2021-02-11 23:22:01 +01:00
|
|
|
exitScope
|
2020-07-03 02:50:26 +02:00
|
|
|
return $ GenBlock name genItems'
|
|
|
|
|
scopeGenItemMapper (GenModuleItem moduleItem) =
|
2020-07-15 04:04:47 +02:00
|
|
|
wrappedModuleItemMapper moduleItem >>= return . GenModuleItem
|
2021-07-18 04:56:14 +02:00
|
|
|
scopeGenItemMapper genItem@GenCase{} =
|
2020-07-03 02:50:26 +02:00
|
|
|
traverseSinglyNestedGenItemsM fullGenItemMapper genItem
|
2021-07-18 04:56:14 +02:00
|
|
|
scopeGenItemMapper GenNull = return GenNull
|
2020-07-23 04:30:33 +02:00
|
|
|
|
2020-07-03 02:50:26 +02:00
|
|
|
partScoper
|
|
|
|
|
:: MapperM (Scoper a) Decl
|
|
|
|
|
-> MapperM (Scoper a) ModuleItem
|
|
|
|
|
-> MapperM (Scoper a) GenItem
|
|
|
|
|
-> MapperM (Scoper a) Stmt
|
2021-09-17 05:35:16 +02:00
|
|
|
-> Mapper Description
|
|
|
|
|
partScoper declMapper moduleItemMapper genItemMapper stmtMapper =
|
|
|
|
|
evalScoper . scopePart scoper
|
|
|
|
|
where scoper = scopeModuleItem
|
2020-07-03 02:50:26 +02:00
|
|
|
declMapper moduleItemMapper genItemMapper stmtMapper
|