Commit 84edbae5 by Zachary Snow

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
parent f061e882
......@@ -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() {
......
// 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
// 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
// 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));
......
// 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));
......
// 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
// 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));
......
// 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
// 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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment