mirror of
https://github.com/zachjs/sv2v.git
synced 2026-08-22 05:47:21 +02:00
handle directives when writing to a directory
This commit is contained in:
@@ -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
|
## v0.0.12
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
+1
-5
@@ -139,11 +139,7 @@ readJob =
|
|||||||
setWrite :: Job -> IO Job
|
setWrite :: Job -> IO Job
|
||||||
setWrite job = do
|
setWrite job = do
|
||||||
w <- parseWrite $ writeRaw job
|
w <- parseWrite $ writeRaw job
|
||||||
case (w, passThrough job) of
|
return $ job { write = w }
|
||||||
(Directory{}, True) -> do
|
|
||||||
hPutStr stderr "can't use --pass-through when writing to a dir"
|
|
||||||
exitFailure
|
|
||||||
_ -> return $ job { write = w }
|
|
||||||
|
|
||||||
setSuccinct :: Job -> Job
|
setSuccinct :: Job -> Job
|
||||||
setSuccinct job | verbose job = job { exclude = Succinct : exclude job }
|
setSuccinct job | verbose job = job { exclude = Succinct : exclude job }
|
||||||
|
|||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
{- sv2v
|
||||||
|
- Author: Zachary Snow <[email protected]>
|
||||||
|
-
|
||||||
|
- 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 }
|
||||||
+10
-13
@@ -16,6 +16,7 @@ import Convert (convert)
|
|||||||
import Job (readJob, Job(..), Write(..))
|
import Job (readJob, Job(..), Write(..))
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
import Language.SystemVerilog.Parser (parseFiles, Config(..))
|
import Language.SystemVerilog.Parser (parseFiles, Config(..))
|
||||||
|
import Split (splitDescriptions)
|
||||||
|
|
||||||
isComment :: Description -> Bool
|
isComment :: Description -> Bool
|
||||||
isComment (PackageItem (Decl CommentDecl{})) = True
|
isComment (PackageItem (Decl CommentDecl{})) = True
|
||||||
@@ -60,17 +61,6 @@ rewritePath path = do
|
|||||||
ext = ".sv"
|
ext = ".sv"
|
||||||
(base, end) = splitExtension path
|
(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 :: Write -> [FilePath] -> [AST] -> IO ()
|
||||||
writeOutput _ [] [] =
|
writeOutput _ [] [] =
|
||||||
hPutStrLn stderr "Warning: No input files specified (try `sv2v --help`)"
|
hPutStrLn stderr "Warning: No input files specified (try `sv2v --help`)"
|
||||||
@@ -82,9 +72,16 @@ writeOutput Adjacent inPaths asts = do
|
|||||||
outPaths <- mapM rewritePath inPaths
|
outPaths <- mapM rewritePath inPaths
|
||||||
let results = map (++ "\n") $ map show asts
|
let results = map (++ "\n") $ map show asts
|
||||||
zipWithM_ writeFile outPaths results
|
zipWithM_ writeFile outPaths results
|
||||||
writeOutput (Directory d) _ asts = do
|
writeOutput (Directory d) _ asts =
|
||||||
let (outPaths, outputs) = unzip $ splitModules d $ concat asts
|
|
||||||
zipWithM_ writeFile outPaths outputs
|
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 :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ executable sv2v
|
|||||||
Convert.Wildcard
|
Convert.Wildcard
|
||||||
-- sv2v CLI modules
|
-- sv2v CLI modules
|
||||||
Job
|
Job
|
||||||
|
Split
|
||||||
Paths_sv2v
|
Paths_sv2v
|
||||||
autogen-modules:
|
autogen-modules:
|
||||||
Paths_sv2v
|
Paths_sv2v
|
||||||
|
|||||||
+66
-7
@@ -89,13 +89,6 @@ test_directory() {
|
|||||||
rm -f dirout/*
|
rm -f dirout/*
|
||||||
mkdir -p 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
|
runAndCapture --write dirout *.sv
|
||||||
assertTrue "directory conversion should succeed" $result
|
assertTrue "directory conversion should succeed" $result
|
||||||
assertNull "stdout should be empty" "$stdout"
|
assertNull "stdout should be empty" "$stdout"
|
||||||
@@ -104,12 +97,78 @@ test_directory() {
|
|||||||
assertTrue "one.v should exist" "[ -f dirout/one.v ]"
|
assertTrue "one.v should exist" "[ -f dirout/one.v ]"
|
||||||
assertTrue "two.v should exist" "[ -f dirout/two.v ]"
|
assertTrue "two.v should exist" "[ -f dirout/two.v ]"
|
||||||
assertTrue "three.v should exist" "[ -f dirout/three.v ]"
|
assertTrue "three.v should exist" "[ -f dirout/three.v ]"
|
||||||
|
assertFalse "P.v should not exist" "[ -f dirout/P.v ]"
|
||||||
|
|
||||||
actual=`cat dirout/*.v`
|
actual=`cat dirout/*.v`
|
||||||
assertEquals "directory output should match combined" "$expected" "$actual"
|
assertEquals "directory output should match combined" "$expected" "$actual"
|
||||||
clearArtifacts
|
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() {
|
test_unknown() {
|
||||||
runAndCapture --write=unknown *.sv
|
runAndCapture --write=unknown *.sv
|
||||||
assertFalse "unknown write mode should fail" $result
|
assertFalse "unknown write mode should fail" $result
|
||||||
|
|||||||
Reference in New Issue
Block a user