mirror of https://github.com/zachjs/sv2v.git
handle directives when writing to a directory
This commit is contained in:
parent
fdfa597115
commit
6eda946f57
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,3 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed `--write path/to/dir/` with directives like `` `default_nettype ``
|
||||
|
||||
### Other Enhancements
|
||||
|
||||
* `--write path/to/dir/` can now also be used with `--pass-through`
|
||||
|
||||
## v0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
|||
|
|
@ -139,11 +139,7 @@ readJob =
|
|||
setWrite :: Job -> IO Job
|
||||
setWrite job = do
|
||||
w <- parseWrite $ writeRaw job
|
||||
case (w, passThrough job) of
|
||||
(Directory{}, True) -> do
|
||||
hPutStr stderr "can't use --pass-through when writing to a dir"
|
||||
exitFailure
|
||||
_ -> return $ job { write = w }
|
||||
return $ job { write = w }
|
||||
|
||||
setSuccinct :: Job -> Job
|
||||
setSuccinct job | verbose job = job { exclude = Succinct : exclude job }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Split descriptions into individual files
|
||||
-}
|
||||
|
||||
module Split (splitDescriptions) where
|
||||
|
||||
import Data.List (isPrefixOf)
|
||||
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
splitDescriptions :: AST -> [PackageItem] -> ([(String, AST)], [PackageItem])
|
||||
splitDescriptions (PackageItem item : ungrouped) itemsBefore =
|
||||
(grouped, item : itemsAfter)
|
||||
where
|
||||
(grouped, itemsAfter) = splitDescriptions ungrouped (item : itemsBefore)
|
||||
splitDescriptions (description : descriptions) itemsBefore =
|
||||
((name, surrounded) : grouped, itemsAfter)
|
||||
where
|
||||
(grouped, itemsAfter) = splitDescriptions descriptions itemsBefore
|
||||
name = case description of
|
||||
Part _ _ _ _ x _ _ -> x
|
||||
Package _ x _ -> x
|
||||
Class _ x _ _ -> x
|
||||
surrounded = surroundDescription itemsBefore description itemsAfter
|
||||
splitDescriptions [] _ = ([], [])
|
||||
|
||||
data SurroundState = SurroundState
|
||||
{ sKeptBefore :: [PackageItem]
|
||||
, sKeptAfter :: [PackageItem]
|
||||
, sCellDefine :: Bool
|
||||
, sUnconnectedDrive :: Maybe PackageItem
|
||||
, sDefaultNettype :: Maybe PackageItem
|
||||
, sComment :: Maybe PackageItem
|
||||
}
|
||||
|
||||
-- filter and include the surrounding package items for this description
|
||||
surroundDescription :: [PackageItem] -> Description -> [PackageItem] -> AST
|
||||
surroundDescription itemsBefore description itemsAfter =
|
||||
map PackageItem itemsBefore' ++ description : map PackageItem itemsAfter'
|
||||
where
|
||||
itemsBefore' = extraBefore ++ reverse (sKeptBefore state2)
|
||||
itemsAfter' = sKeptAfter state2 ++ reverse extraAfter
|
||||
|
||||
state0 = SurroundState [] [] False Nothing Nothing Nothing
|
||||
state1 = foldr stepBefore state0 itemsBefore
|
||||
state2 = foldr stepAfter state1 itemsAfter
|
||||
|
||||
(extraBefore, extraAfter) = foldr (<>) mempty $ map ($ state2) $
|
||||
[ applyLeader sDefaultNettype
|
||||
, applyCellDefine
|
||||
, applyUnconnectedDrive
|
||||
, applyLeader sComment
|
||||
]
|
||||
|
||||
applyCellDefine :: SurroundState -> ([PackageItem], [PackageItem])
|
||||
applyCellDefine state
|
||||
| sCellDefine state =
|
||||
([Directive "`celldefine"], [Directive "`endcelldefine"])
|
||||
| otherwise = ([], [])
|
||||
|
||||
applyUnconnectedDrive :: SurroundState -> ([PackageItem], [PackageItem])
|
||||
applyUnconnectedDrive state
|
||||
| Just item <- sUnconnectedDrive state =
|
||||
([item], [Directive "`nounconnected_drive"])
|
||||
| otherwise = ([], [])
|
||||
|
||||
applyLeader :: (SurroundState -> Maybe PackageItem) -> SurroundState
|
||||
-> ([PackageItem], [PackageItem])
|
||||
applyLeader getter state
|
||||
| Just item <- getter state = ([item], [])
|
||||
| otherwise = ([], [])
|
||||
|
||||
-- update the state with a pre-description item
|
||||
stepBefore :: PackageItem -> SurroundState -> SurroundState
|
||||
stepBefore item@(Decl CommentDecl{}) state =
|
||||
state { sComment = Just item }
|
||||
stepBefore item@(Directive directive) state
|
||||
| matches "celldefine" = state { sCellDefine = True }
|
||||
| matches "endcelldefine" = state { sCellDefine = False }
|
||||
| matches "unconnected_drive" = state { sUnconnectedDrive = Just item }
|
||||
| matches "nounconnected_drive" = state { sUnconnectedDrive = Nothing }
|
||||
| matches "default_nettype" = state { sDefaultNettype = Just item }
|
||||
| matches "resetall" = state
|
||||
{ sCellDefine = False
|
||||
, sUnconnectedDrive = Nothing
|
||||
, sDefaultNettype = Nothing
|
||||
}
|
||||
where matches = flip isPrefixOf directive . ('`' :)
|
||||
stepBefore item state =
|
||||
state { sKeptBefore = item : sKeptBefore state }
|
||||
|
||||
-- update the state with a post-description item
|
||||
stepAfter :: PackageItem -> SurroundState -> SurroundState
|
||||
stepAfter (Decl CommentDecl{}) state = state
|
||||
stepAfter (Directive directive) state
|
||||
| matches "celldefine" = state
|
||||
| matches "endcelldefine" = state
|
||||
| matches "unconnected_drive" = state
|
||||
| matches "nounconnected_drive" = state
|
||||
| matches "default_nettype" = state
|
||||
| matches "resetall" = state
|
||||
where matches = flip isPrefixOf directive . ('`' :)
|
||||
stepAfter item state =
|
||||
state { sKeptAfter = item : sKeptAfter state }
|
||||
23
src/sv2v.hs
23
src/sv2v.hs
|
|
@ -16,6 +16,7 @@ import Convert (convert)
|
|||
import Job (readJob, Job(..), Write(..))
|
||||
import Language.SystemVerilog.AST
|
||||
import Language.SystemVerilog.Parser (parseFiles, Config(..))
|
||||
import Split (splitDescriptions)
|
||||
|
||||
isComment :: Description -> Bool
|
||||
isComment (PackageItem (Decl CommentDecl{})) = True
|
||||
|
|
@ -60,17 +61,6 @@ rewritePath path = do
|
|||
ext = ".sv"
|
||||
(base, end) = splitExtension path
|
||||
|
||||
splitModules :: FilePath -> AST -> [(FilePath, String)]
|
||||
splitModules dir (PackageItem (Decl CommentDecl{}) : ast) =
|
||||
splitModules dir ast
|
||||
splitModules dir (description : ast) =
|
||||
(path, output) : splitModules dir ast
|
||||
where
|
||||
Part _ _ Module _ name _ _ = description
|
||||
path = combine dir $ name ++ ".v"
|
||||
output = show description ++ "\n"
|
||||
splitModules _ [] = []
|
||||
|
||||
writeOutput :: Write -> [FilePath] -> [AST] -> IO ()
|
||||
writeOutput _ [] [] =
|
||||
hPutStrLn stderr "Warning: No input files specified (try `sv2v --help`)"
|
||||
|
|
@ -82,9 +72,16 @@ writeOutput Adjacent inPaths asts = do
|
|||
outPaths <- mapM rewritePath inPaths
|
||||
let results = map (++ "\n") $ map show asts
|
||||
zipWithM_ writeFile outPaths results
|
||||
writeOutput (Directory d) _ asts = do
|
||||
let (outPaths, outputs) = unzip $ splitModules d $ concat asts
|
||||
writeOutput (Directory d) _ asts =
|
||||
zipWithM_ writeFile outPaths outputs
|
||||
where
|
||||
(outPaths, outputs) =
|
||||
unzip $ map prepare $ fst $ splitDescriptions (concat asts) []
|
||||
prepare :: (String, AST) -> (FilePath, String)
|
||||
prepare (name, ast) = (path, output)
|
||||
where
|
||||
path = combine d $ name ++ ".v"
|
||||
output = concatMap (++ "\n") $ map show ast
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ executable sv2v
|
|||
Convert.Wildcard
|
||||
-- sv2v CLI modules
|
||||
Job
|
||||
Split
|
||||
Paths_sv2v
|
||||
autogen-modules:
|
||||
Paths_sv2v
|
||||
|
|
|
|||
|
|
@ -89,13 +89,6 @@ test_directory() {
|
|||
rm -f dirout/*
|
||||
mkdir -p dirout
|
||||
|
||||
runAndCapture --pass-through --write dirout *.sv
|
||||
assertFalse "directory conversion should succeed" $result
|
||||
assertNull "stdout should be empty" "$stdout"
|
||||
assertEquals "stderr should have expected message" \
|
||||
"can't use --pass-through when writing to a dir" \
|
||||
"$stderr"
|
||||
|
||||
runAndCapture --write dirout *.sv
|
||||
assertTrue "directory conversion should succeed" $result
|
||||
assertNull "stdout should be empty" "$stdout"
|
||||
|
|
@ -104,12 +97,78 @@ test_directory() {
|
|||
assertTrue "one.v should exist" "[ -f dirout/one.v ]"
|
||||
assertTrue "two.v should exist" "[ -f dirout/two.v ]"
|
||||
assertTrue "three.v should exist" "[ -f dirout/three.v ]"
|
||||
assertFalse "P.v should not exist" "[ -f dirout/P.v ]"
|
||||
|
||||
actual=`cat dirout/*.v`
|
||||
assertEquals "directory output should match combined" "$expected" "$actual"
|
||||
clearArtifacts
|
||||
}
|
||||
|
||||
test_directory_pass_through() {
|
||||
rm -f dirout/*
|
||||
mkdir -p dirout
|
||||
|
||||
runAndCapture --pass-through --write dirout *.sv
|
||||
assertTrue "directory conversion should succeed" $result
|
||||
assertNull "stdout should be empty" "$stdout"
|
||||
assertNull "stderr should be empty" "$stderr"
|
||||
|
||||
assertTrue "one.v should exist" "[ -f dirout/one.v ]"
|
||||
assertTrue "two.v should exist" "[ -f dirout/two.v ]"
|
||||
assertTrue "three.v should exist" "[ -f dirout/three.v ]"
|
||||
assertTrue "P.v should exist" "[ -f dirout/P.v ]"
|
||||
clearArtifacts
|
||||
}
|
||||
|
||||
test_directory_directives() {
|
||||
module_inp="logic a, b;module example;wire x;endmodule logic c, d;"
|
||||
module_out="logic a;
|
||||
logic b;
|
||||
module example;
|
||||
wire x;
|
||||
endmodule
|
||||
logic c;
|
||||
logic d;"
|
||||
|
||||
check_directory_example "$module_inp" "$module_out"
|
||||
check_directory_example "\`default_nettype none\n$module_inp\`resetall" "\`default_nettype none\n$module_out"
|
||||
check_directory_example "\`default_nettype none\n\`default_nettype wire\n$module_inp" "\`default_nettype wire\n$module_out"
|
||||
check_directory_example "\`celldefine\n$module_inp" "\`celldefine\n$module_out\n\`endcelldefine"
|
||||
check_directory_example "\`celldefine\n\`endcelldefine\n$module_inp" "$module_out"
|
||||
check_directory_example "\`unconnected_drive pull0\n$module_inp" "\`unconnected_drive pull0\n$module_out\n\`nounconnected_drive"
|
||||
check_directory_example "\`unconnected_drive pull0\n\`nounconnected_drive\n$module_inp" "$module_out"
|
||||
check_directory_example "\`default_nettype none\n\`celldefine\n\`unconnected_drive pull1\n\`resetall\n$module_inp" "$module_out"
|
||||
check_directory_example "\`default_nettype none
|
||||
\`celldefine
|
||||
\`unconnected_drive pull1
|
||||
$module_inp" "\`default_nettype none
|
||||
\`celldefine
|
||||
\`unconnected_drive pull1
|
||||
$module_out
|
||||
\`nounconnected_drive
|
||||
\`endcelldefine"
|
||||
}
|
||||
|
||||
check_directory_example() {
|
||||
tmp_inp=$SHUNIT_TMPDIR/example.sv
|
||||
tmp_out=$SHUNIT_TMPDIR/example.v
|
||||
tmp_ref=$SHUNIT_TMPDIR/example_ref.v
|
||||
|
||||
echo -e "$1" > $tmp_inp
|
||||
echo -e "$2" | sed -E 's/ /\t/g' > $tmp_ref
|
||||
|
||||
rm -f $tmp_out
|
||||
runAndCapture --pass-through --write $SHUNIT_TMPDIR $tmp_inp
|
||||
assertTrue "directory conversion should succeed" $result
|
||||
assertNull "stdout should be empty: $stdout" "$stdout"
|
||||
assertNull "stderr should be empty: $stderr" "$stderr"
|
||||
|
||||
grep -v '//' < $tmp_out > $tmp_out.bak
|
||||
mv $tmp_out.bak $tmp_out
|
||||
output=`diff --unified $tmp_ref $tmp_out`
|
||||
assertTrue "output doesn't match:\n$output" $?
|
||||
}
|
||||
|
||||
test_unknown() {
|
||||
runAndCapture --write=unknown *.sv
|
||||
assertFalse "unknown write mode should fail" $result
|
||||
|
|
|
|||
Loading…
Reference in New Issue