mirror of https://github.com/zachjs/sv2v.git
preliminary scoped errors with approximate source location
- scoped traversals can now raise errors which contain the path of the current scope and an approximate source location based on preceding trace comments, if available - initially, this new error messaging has only been added for the illegal size cast checks in the TypeOf and Cast conversions - error suite tests can provide a verbose mode expected source location
This commit is contained in:
parent
f061e88214
commit
84edbae503
|
|
@ -5,6 +5,11 @@
|
|||
* Added support for excluding the conversion of unbased unsized literals (e.g.,
|
||||
`'1`, `'x`) via `--exclude UnbasedUniszed`
|
||||
|
||||
### Other Enhancements
|
||||
|
||||
* Certain errors raised during conversion now also provide hierarchical and
|
||||
approximate source location information to help locate the error
|
||||
|
||||
## v0.0.9
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
|||
|
|
@ -115,7 +115,8 @@ convertCastM (Number size) _ _
|
|||
where
|
||||
maybeInt = numberToInteger size
|
||||
Just int = maybeInt
|
||||
illegal s = error $ "size cast width " ++ show size ++ " is not " ++ s
|
||||
illegal = scopedErrorM . msg
|
||||
msg s = "size cast width " ++ show size ++ " is not " ++ s
|
||||
convertCastM (Number size) (Number value) signed =
|
||||
return $ Number $
|
||||
numberCast signed (fromIntegral size') value
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ module Convert.Scoper
|
|||
, withinProcedureM
|
||||
, procedureLoc
|
||||
, procedureLocM
|
||||
, scopedError
|
||||
, scopedErrorM
|
||||
, isLoopVar
|
||||
, isLoopVarM
|
||||
, loopVarDepth
|
||||
|
|
@ -68,7 +70,7 @@ module Convert.Scoper
|
|||
) where
|
||||
|
||||
import Control.Monad.State.Strict
|
||||
import Data.List (findIndices, partition)
|
||||
import Data.List (findIndices, intercalate, isPrefixOf, partition)
|
||||
import Data.Maybe (isNothing)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
|
|
@ -105,6 +107,7 @@ data Scopes a = Scopes
|
|||
, sProcedureLoc :: [Access]
|
||||
, sInjectedItems :: [(Bool, ModuleItem)]
|
||||
, sInjectedDecls :: [Decl]
|
||||
, sLatestTrace :: String
|
||||
} deriving Show
|
||||
|
||||
extractMapping :: Scopes a -> Map.Map Identifier a
|
||||
|
|
@ -353,6 +356,26 @@ procedureLocM = gets procedureLoc
|
|||
procedureLoc :: Scopes a -> [Access]
|
||||
procedureLoc = sProcedureLoc
|
||||
|
||||
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)
|
||||
|
||||
isLoopVar :: Scopes a -> Identifier -> Bool
|
||||
isLoopVar scopes x = any matches $ sCurrent scopes
|
||||
where matches = (== x) . tierIndex
|
||||
|
|
@ -411,7 +434,10 @@ runScoperT :: Monad m => ScoperT a m x -> m (x, Scopes a)
|
|||
runScoperT = flip runStateT initialState
|
||||
|
||||
initialState :: Scopes a
|
||||
initialState = Scopes [] Map.empty [] [] []
|
||||
initialState = Scopes [] Map.empty [] [] [] ""
|
||||
|
||||
tracePrefix :: String
|
||||
tracePrefix = "Trace: "
|
||||
|
||||
scopeModuleItem
|
||||
:: forall a m. Monad m
|
||||
|
|
@ -420,7 +446,7 @@ scopeModuleItem
|
|||
-> MapperM (ScoperT a m) GenItem
|
||||
-> MapperM (ScoperT a m) Stmt
|
||||
-> MapperM (ScoperT a m) ModuleItem
|
||||
scopeModuleItem declMapper moduleItemMapper genItemMapper stmtMapper =
|
||||
scopeModuleItem declMapperRaw moduleItemMapper genItemMapper stmtMapperRaw =
|
||||
wrappedModuleItemMapper
|
||||
where
|
||||
fullStmtMapper :: Stmt -> ScoperT a m Stmt
|
||||
|
|
@ -438,6 +464,21 @@ scopeModuleItem declMapper moduleItemMapper genItemMapper stmtMapper =
|
|||
then traverseSinglyNestedStmtsM fullStmtMapper stmt'
|
||||
else fullStmtMapper $ Block Seq "" injected [stmt']
|
||||
|
||||
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 }
|
||||
|
||||
-- converts a decl and adds decls injected during conversion
|
||||
declMapper' :: Decl -> ScoperT a m [Decl]
|
||||
declMapper' decl = do
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ traverseExprM other =
|
|||
elaborateSizeCast :: Expr -> Expr -> ST Expr
|
||||
elaborateSizeCast (Number size) _ | Just 0 == numberToInteger size =
|
||||
-- special case because zero-width ranges cannot be represented
|
||||
error $ "size cast width " ++ show size ++ " is not a positive integer"
|
||||
scopedErrorM $ "size cast width " ++ show size
|
||||
++ " is not a positive integer"
|
||||
elaborateSizeCast size value = do
|
||||
t <- typeof value
|
||||
force <- isStringParam value
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
runErrorTest() {
|
||||
extractFlag pattern $1.sv
|
||||
pattern="${flag:-.}"
|
||||
extractFlag location $1.sv
|
||||
location="${flag//./\.}"
|
||||
location="${location:-.}"
|
||||
|
||||
runAndCapture $1.sv
|
||||
assertFalse "regular conversion should have failed" $result
|
||||
|
|
@ -15,6 +18,7 @@ runErrorTest() {
|
|||
assertNull "verbose stdout should be empty" "$stdout"
|
||||
assertNotNull "verbose stderr should not be empty" "$stderr"
|
||||
assertMatch "verbose error message" "$stderr" "$pattern"
|
||||
assertMatch "verbose location" "$stderr" "$location[^0-9]"
|
||||
}
|
||||
|
||||
addTest() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 1'sb1 is not a positive integer
|
||||
// location: size_cast_neg_lit_1.sv:4:13
|
||||
module top;
|
||||
initial $display((1'sb1)'(2));
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 2'sb11 is not a positive integer
|
||||
// location: size_cast_neg_lit_2.sv:4:13
|
||||
module top;
|
||||
initial $display((2'sb11)'(2));
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 1'sb1 is not a positive integer
|
||||
// location: size_cast_neg_var_1.sv:5:13
|
||||
module top;
|
||||
wire x = 0;
|
||||
initial $display((1'sb1)'(x));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 2'sb11 is not a positive integer
|
||||
// location: size_cast_neg_var_2.sv:5:13
|
||||
module top;
|
||||
wire x = 0;
|
||||
initial $display((2'sb11)'(x));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 1'bx is not an integer
|
||||
// location: size_cast_x_lit.sv:4:13
|
||||
module top;
|
||||
initial $display((1'bx)'(2));
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 1'bx is not an integer
|
||||
// location: size_cast_x_var.sv:5:13
|
||||
module top;
|
||||
wire x = 0;
|
||||
initial $display((1'bx)'(x));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 0 is not a positive integer
|
||||
// location: size_cast_zero_lit.sv:4:13
|
||||
module top;
|
||||
initial $display((0)'(2));
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// pattern: size cast width 0 is not a positive integer
|
||||
// location: size_cast_zero_var.sv:5:13
|
||||
module top;
|
||||
wire x = 0;
|
||||
initial $display((0)'(x));
|
||||
|
|
|
|||
Loading…
Reference in New Issue