Commit a05659cd by Zachary Snow

better unfinished conditional directive error message

parent 80095810
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
* Port connection attributes (e.g., [pulp_soc.sv]) are now ignored with a * Port connection attributes (e.g., [pulp_soc.sv]) are now ignored with a
warning rather than failing to parse warning rather than failing to parse
* Improved error message when specifying an extraneous named port connection * Improved error message when specifying an extraneous named port connection
* Improved error message for an unfinished conditional directive, e.g., an
`ifdef` with no `endif`
* Added checks for accidental usage of interface or module names as type names * Added checks for accidental usage of interface or module names as type names
[pulp_soc.sv]: https://github.com/pulp-platform/pulp_soc/blob/0573a85c/rtl/pulp_soc/pulp_soc.sv#L733 [pulp_soc.sv]: https://github.com/pulp-platform/pulp_soc/blob/0573a85c/rtl/pulp_soc/pulp_soc.sv#L733
......
...@@ -39,12 +39,19 @@ data PP = PP ...@@ -39,12 +39,19 @@ data PP = PP
, ppPosition :: Position -- current file position , ppPosition :: Position -- current file position
, ppFilePath :: FilePath -- currently active filename , ppFilePath :: FilePath -- currently active filename
, ppEnv :: Env -- active macro definitions , ppEnv :: Env -- active macro definitions
, ppCondStack :: [Cond] -- if-else cascade state , ppCondStack :: [Level] -- if-else cascade state
, ppIncludePaths :: [FilePath] -- folders to search for includes , ppIncludePaths :: [FilePath] -- folders to search for includes
, ppMacroStack :: [[(String, String)]] -- arguments for in-progress macro expansions , ppMacroStack :: [[(String, String)]] -- arguments for in-progress macro expansions
, ppIncludeStack :: [(FilePath, Env)] -- in-progress includes for loop detection , ppIncludeStack :: [(FilePath, Env)] -- in-progress includes for loop detection
} }
-- if-else cascade level state and error information
data Level = Level
{ cfDesc :: String -- text of the directive, e.g., "ifdef FOO"
, cfPos :: Position -- location where this level started
, cfCond :: Cond -- whether or not this level is as has been satisfied
}
-- keeps track of the state of an if-else cascade level -- keeps track of the state of an if-else cascade level
data Cond data Cond
= CurrentlyTrue -- an active if/elsif/else branch (condition is met) = CurrentlyTrue -- an active if/elsif/else branch (condition is met)
...@@ -86,14 +93,19 @@ preprocess includePaths env path = do ...@@ -86,14 +93,19 @@ preprocess includePaths env path = do
, ppMacroStack = [] , ppMacroStack = []
, ppIncludeStack = [(path, env)] , ppIncludeStack = [(path, env)]
} }
finalState <- execStateT preprocessInput initialState finalState <- execStateT (preprocessInput >> checkConds) initialState
when (not $ null $ ppCondStack finalState) $
throwError $ path ++ ": unfinished conditional directives: " ++
(show $ length $ ppCondStack finalState)
let env' = ppEnv finalState let env' = ppEnv finalState
let output = reverse $ ppOutput finalState let output = reverse $ ppOutput finalState
return (env', output) return (env', output)
checkConds :: PPS ()
checkConds = do
condStack <- getCondStack
when (not $ null condStack) $ do
let level = head condStack
lexicalError $ "unfinished conditional directive `" ++ cfDesc level ++
" started at " ++ show (cfPos level)
-- position annotator entrypoint used for files that don't need any -- position annotator entrypoint used for files that don't need any
-- preprocessing -- preprocessing
annotate :: FilePath -> ExceptT String IO Contents annotate :: FilePath -> ExceptT String IO Contents
...@@ -162,9 +174,9 @@ getEnv = gets ppEnv ...@@ -162,9 +174,9 @@ getEnv = gets ppEnv
setEnv :: Env -> PPS () setEnv :: Env -> PPS ()
setEnv x = modify $ \s -> s { ppEnv = x } setEnv x = modify $ \s -> s { ppEnv = x }
-- cond stack accessors -- cond stack accessors
getCondStack :: PPS [Cond] getCondStack :: PPS [Level]
getCondStack = gets ppCondStack getCondStack = gets ppCondStack
setCondStack :: [Cond] -> PPS () setCondStack :: [Level] -> PPS ()
setCondStack x = modify $ \s -> s { ppCondStack = x } setCondStack x = modify $ \s -> s { ppCondStack = x }
-- macro stack accessors -- macro stack accessors
getMacroStack :: PPS [[(String, String)]] getMacroStack :: PPS [[(String, String)]]
...@@ -204,11 +216,15 @@ popIncludeStack = do ...@@ -204,11 +216,15 @@ popIncludeStack = do
modify $ \s -> s { ppIncludeStack = stack' } modify $ \s -> s { ppIncludeStack = stack' }
-- Push a condition onto the top of the preprocessor condition stack -- Push a condition onto the top of the preprocessor condition stack
pushCondStack :: Cond -> PPS () pushCondStack :: String -> String -> Position -> Cond -> PPS ()
pushCondStack c = getCondStack >>= setCondStack . (c :) pushCondStack typ name pos cond =
getCondStack >>= setCondStack . (level :)
where
level = Level { cfDesc = desc, cfPos = pos, cfCond = cond }
desc = typ ++ if null name then "" else " " ++ name
-- Pop the top from the preprocessor condition stack -- Pop the top from the preprocessor condition stack
popCondStack :: String -> PPS Cond popCondStack :: String -> PPS Level
popCondStack directive = do popCondStack directive = do
cs <- getCondStack cs <- getCondStack
case cs of case cs of
...@@ -566,7 +582,7 @@ preprocessInput = do ...@@ -566,7 +582,7 @@ preprocessInput = do
return () return ()
'`' : _ -> handleDirective False '`' : _ -> handleDirective False
_ : _ -> do _ : _ -> do
condStack <- getCondStack condStack <- map cfCond <$> getCondStack
if null macroStack && all (== CurrentlyTrue) condStack if null macroStack && all (== CurrentlyTrue) condStack
then consumeMany then consumeMany
else consumeWithSubstitution else consumeWithSubstitution
...@@ -727,7 +743,7 @@ handleDirective macrosOnly = do ...@@ -727,7 +743,7 @@ handleDirective macrosOnly = do
pushChars directive directivePos pushChars directive directivePos
env <- getEnv env <- getEnv
condStack <- getCondStack condStack <- map cfCond <$> getCondStack
if any (/= CurrentlyTrue) condStack if any (/= CurrentlyTrue) condStack
&& not (elem directive unskippableDirectives) then && not (elem directive unskippableDirectives) then
return () return ()
...@@ -795,19 +811,22 @@ handleDirective macrosOnly = do ...@@ -795,19 +811,22 @@ handleDirective macrosOnly = do
"ifdef" -> do "ifdef" -> do
dropSpaces dropSpaces
name <- takeIdentifier name <- takeIdentifier
pushCondStack $ ifCond $ Map.member name env pushCondStack "ifdef" name directivePos $
ifCond $ Map.member name env
"ifndef" -> do "ifndef" -> do
dropSpaces dropSpaces
name <- takeIdentifier name <- takeIdentifier
pushCondStack $ ifCond $ Map.notMember name env pushCondStack "ifndef" name directivePos $
ifCond $ Map.notMember name env
"else" -> do "else" -> do
c <- popCondStack "else" c <- cfCond <$> popCondStack "else"
pushCondStack $ elseCond c pushCondStack "else" "" directivePos (elseCond c)
"elsif" -> do "elsif" -> do
dropSpaces dropSpaces
name <- takeIdentifier name <- takeIdentifier
c <- popCondStack "elsif" c <- cfCond <$> popCondStack "elsif"
pushCondStack $ elsifCond (Map.member name env) c pushCondStack "elsif" name directivePos $
elsifCond (Map.member name env) c
"endif" -> do "endif" -> do
_ <- popCondStack "endif" _ <- popCondStack "endif"
return () return ()
...@@ -930,7 +949,7 @@ advance (Position f l c) _ = Position f l (c + 1) ...@@ -930,7 +949,7 @@ advance (Position f l c) _ = Position f l (c + 1)
-- adds a character (and its position) to the output state -- adds a character (and its position) to the output state
pushChar :: Char -> Position -> PPS () pushChar :: Char -> Position -> PPS ()
pushChar c p = do pushChar c p = do
condStack <- getCondStack condStack <- map cfCond <$> getCondStack
when (all (== CurrentlyTrue) condStack) $ do when (all (== CurrentlyTrue) condStack) $ do
output <- getOutput output <- getOutput
setOutput $ (c, p) : output setOutput $ (c, p) : output
......
// pattern: unfinished conditional directive `else started at unmatched_else_end.sv:3:1
`ifdef FOO
`else
// pattern: unfinished conditional directive `elsif BAR started at unmatched_elsif_end.sv:3:1
`ifdef FOO
`elsif BAR
// pattern: unfinished conditional directive `ifdef FOO started at unmatched_ifdef.sv:2:1
`ifdef FOO `ifdef FOO
// pattern: unfinished conditional directive `ifndef FOO started at unmatched_ifndef.sv:2:1
`ifndef FOO
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