diff options
author | Joe Crayne <joe@jerkface.net> | 2019-03-21 16:28:07 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-03-21 16:28:07 -0400 |
commit | 9e1579d5074f895cce9ac4a32ea5b94c70e4b269 (patch) | |
tree | b2450529c5a383f43aadc71b4fada0af41465fdb | |
parent | 9f4cfc458fbe6140ac2793a29068794bcd23883e (diff) |
While parsing coments, use width 8 tabs.
-rw-r--r-- | Comments.hs | 31 | ||||
-rw-r--r-- | GrepNested.hs | 93 | ||||
-rw-r--r-- | monkeypatch.cabal | 2 | ||||
-rw-r--r-- | monkeypatch.hs | 50 |
4 files changed, 137 insertions, 39 deletions
diff --git a/Comments.hs b/Comments.hs deleted file mode 100644 index 25cd7de..0000000 --- a/Comments.hs +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | {-# LANGUAGE BangPatterns #-} | ||
2 | {-# LANGUAGE LambdaCase #-} | ||
3 | module Comments where | ||
4 | |||
5 | import Control.Arrow | ||
6 | |||
7 | parseComments :: (Num col, Num lin) => lin -> col -> [Char] -> [(lin, col, [Char])] | ||
8 | parseComments !lin !col = \case | ||
9 | ('/':'*':cs) -> let (lcnt,col',bcnt) = findCloser 1 (0,col,0) cs | ||
10 | (xs,cs') = case drop (bcnt-2) cs of | ||
11 | '*':'/':_ -> second (drop 2) $ splitAt (bcnt-2) cs | ||
12 | _ -> splitAt bcnt cs | ||
13 | in mkComment lin col xs : parseComments (lin + lcnt) col' cs' | ||
14 | ('/':'/':cs) -> let (comment,ds) = break (=='\n') cs | ||
15 | in mkComment lin col comment : parseComments (lin + 1) 1 cs | ||
16 | ('\n' : cs) -> parseComments (lin+1) 1 cs | ||
17 | ( x : cs) -> parseComments lin (col+1) cs | ||
18 | [] -> [] | ||
19 | |||
20 | |||
21 | findCloser :: (Num a4, Num a3, Num a2, Num a1, Eq a1) => | ||
22 | a1 -> (a4, a2, a3) -> [Char] -> (a4, a2, a3) | ||
23 | findCloser !1 (l,c,b) ('*':'/':_) = (l,c+2,b+2) | ||
24 | findCloser !d (l,c,b) ('*':'/':xs) = findCloser (d - 1) (l,c+2,b+2) xs | ||
25 | findCloser !d (l,c,b) ('/':'*':xs) = findCloser (d + 1) (l,c+2,b+2) xs | ||
26 | findCloser !d (l,c,b) ('\n':xs) = findCloser d (l+1,1,b+1) xs | ||
27 | findCloser !d (l,c,b) (_:xs) = findCloser d (l,c+1,b+1) xs | ||
28 | findCloser !d (l,c,b) [] = (l,c,b) | ||
29 | |||
30 | mkComment :: a -> b -> c -> (a, b, c) | ||
31 | mkComment lin no str = (lin,no,str) | ||
diff --git a/GrepNested.hs b/GrepNested.hs new file mode 100644 index 0000000..c62262f --- /dev/null +++ b/GrepNested.hs | |||
@@ -0,0 +1,93 @@ | |||
1 | {-# LANGUAGE BangPatterns #-} | ||
2 | {-# LANGUAGE LambdaCase #-} | ||
3 | {-# LANGUAGE OverloadedStrings #-} | ||
4 | module GrepNested | ||
5 | ( grepCComments | ||
6 | , grepNested | ||
7 | , CommentProtocol(..) | ||
8 | , CommentToken(..) | ||
9 | ) where | ||
10 | |||
11 | import Control.Arrow | ||
12 | import Data.List | ||
13 | import Data.String | ||
14 | import qualified Data.ByteString.Lazy.Char8 as BL | ||
15 | |||
16 | grepCComments :: Num a => a -> Int -> String -> [(a, Int, String)] | ||
17 | grepCComments !lin !col = grepNested ccomments lin col | ||
18 | |||
19 | data CommentToken = NullInput -- ^ Empty string. | ||
20 | | OpenNested -- ^ Open nested comment. | ||
21 | | CloseNested -- ^ Close nested comment. | ||
22 | | StartLine -- ^ Open line-comment. | ||
23 | | EOL -- ^ Close line-comment. | ||
24 | | IgnoredChar Int -- ^ Miscellaneous character. Argument is column width (e.g. 8 for tabs, 1 otherwise). | ||
25 | |||
26 | data CommentProtocol a = CommentProtocol | ||
27 | { cmtToken :: a -> (CommentToken,Int,a) | ||
28 | , cmtSplitAt :: Int -> a -> (a,a) | ||
29 | } | ||
30 | |||
31 | ccomments :: CommentProtocol String | ||
32 | ccomments = CommentProtocol | ||
33 | { cmtToken = \case | ||
34 | [] -> (NullInput , 0 , "") | ||
35 | '/':'*':s -> (OpenNested , 2 , s) | ||
36 | '/':'/':s -> (StartLine , 2 , s) | ||
37 | '*':'/':s -> (CloseNested , 2 , s) | ||
38 | '\n':s -> (EOL , 1 , s) | ||
39 | '\t':s -> (IgnoredChar 8 , 1 , s) | ||
40 | _:s -> (IgnoredChar 1 , 1 , s) | ||
41 | , cmtSplitAt = splitAt | ||
42 | } | ||
43 | |||
44 | ccommentsBL :: CommentProtocol BL.ByteString | ||
45 | ccommentsBL = CommentProtocol | ||
46 | { cmtToken = \s -> | ||
47 | if BL.null s then (NullInput,0,s) | ||
48 | else if BL.isPrefixOf "/*" s then (OpenNested , 2, BL.drop 2 s) | ||
49 | else if BL.isPrefixOf "*/" s then (CloseNested , 2, BL.drop 2 s) | ||
50 | else if BL.isPrefixOf "//" s then (StartLine , 2, BL.drop 2 s) | ||
51 | else if BL.isPrefixOf "\n" s then (EOL , 1, BL.drop 1 s) | ||
52 | else (IgnoredChar (if BL.head s=='\t' then 8 else 1),1,BL.drop 1 s) | ||
53 | , cmtSplitAt = BL.splitAt . fromIntegral | ||
54 | } | ||
55 | |||
56 | grepNested :: Num a => | ||
57 | CommentProtocol c -> a -> Int -> c -> [(a, Int, c)] | ||
58 | grepNested p !lin !col s = case cmtToken p s of | ||
59 | (OpenNested,tlen,cs) | ||
60 | -> let (lcnt,col',bcnt,clserlen) = findCloser p 1 (0,col,0) cs | ||
61 | (xs,cs') = case cmtSplitAt p (bcnt-clserlen) cs of | ||
62 | (s1,s2) | (CloseNested,l,s3) <- cmtToken p s2 | ||
63 | -> (s1, snd . cmtSplitAt p clserlen $ s2) | ||
64 | _ -> cmtSplitAt p bcnt cs | ||
65 | in mkComment lin col xs : grepNested p (lin + lcnt) col' cs' | ||
66 | (StartLine,tlen,cs) | ||
67 | -> let findEOL !tot xs = case cmtToken p xs of | ||
68 | (EOL,tlen,_) -> tot | ||
69 | (tok,tlen,ys) -> findEOL (tot + tlen) ys | ||
70 | (comment,_) = cmtSplitAt p (findEOL 0 cs) cs | ||
71 | in mkComment lin col comment : grepNested p (lin + 1) 1 cs | ||
72 | (EOL,tlen,cs) -> grepNested p (lin+1) 1 cs | ||
73 | (NullInput,tlen,_) -> [] | ||
74 | (IgnoredChar clen,_,cs) -> grepNested p lin (col+clen) cs | ||
75 | |||
76 | |||
77 | findCloser :: Num lin => CommentProtocol t | ||
78 | -> Int -- ^ Nested comment depth, used by recursive calls, pass 1. | ||
79 | -> (lin, Int, Int) -- ^ Accumulated result. | ||
80 | -> t | ||
81 | -> (lin, Int, Int, Int) -- ^ (line,col,bytes,closer length) | ||
82 | findCloser p !d (l,c,b) s = l `seq` c `seq` b `seq` case cmtToken p s of | ||
83 | (NullInput,tlen,_) -> (l,c,b,tlen) | ||
84 | (CloseNested,tlen,xs) -> if d==1 then (l,c+tlen,b+tlen,tlen) | ||
85 | else findCloser p (d - 1) (l,c+tlen,b+tlen) xs | ||
86 | (OpenNested,tlen,xs) -> findCloser p (d + 1) (l,c+tlen,b+tlen) xs | ||
87 | (EOL,tlen,xs) -> findCloser p d (l+1,1,b+tlen) xs | ||
88 | (IgnoredChar clen,tlen,xs) -> findCloser p d (l,c+clen,b+tlen) xs | ||
89 | (StartLine,tlen,xs) -> findCloser p d (l,c+tlen,b+tlen) xs | ||
90 | |||
91 | |||
92 | mkComment :: a -> b -> c -> (a, b, c) | ||
93 | mkComment lin no str = (lin,no,str) | ||
diff --git a/monkeypatch.cabal b/monkeypatch.cabal index ac31a6d..23bc405 100644 --- a/monkeypatch.cabal +++ b/monkeypatch.cabal | |||
@@ -52,7 +52,7 @@ extra-source-files: CHANGELOG.md | |||
52 | 52 | ||
53 | executable monkeypatch | 53 | executable monkeypatch |
54 | main-is: monkeypatch.hs | 54 | main-is: monkeypatch.hs |
55 | other-modules: Comments | 55 | other-modules: GrepNested |
56 | -- other-extensions: | 56 | -- other-extensions: |
57 | build-depends: base >=4.10.1.0 && <=4.12 | 57 | build-depends: base >=4.10.1.0 && <=4.12 |
58 | , containers ^>=0.5.10.2 | 58 | , containers ^>=0.5.10.2 |
diff --git a/monkeypatch.hs b/monkeypatch.hs index 461d3c1..ea97252 100644 --- a/monkeypatch.hs +++ b/monkeypatch.hs | |||
@@ -24,6 +24,7 @@ import qualified Data.IntMap as IntMap | |||
24 | import qualified Data.Map as Map | 24 | import qualified Data.Map as Map |
25 | ;import Data.Map (Map) | 25 | ;import Data.Map (Map) |
26 | import Data.Maybe | 26 | import Data.Maybe |
27 | import Data.Ord | ||
27 | import qualified Data.Set as Set | 28 | import qualified Data.Set as Set |
28 | ;import Data.Set (Set) | 29 | ;import Data.Set (Set) |
29 | import Language.C.Data.Ident as C | 30 | import Language.C.Data.Ident as C |
@@ -47,7 +48,7 @@ import Text.PrettyPrint (Doc, doubleQuotes, empty, text, vcat, ($$), | |||
47 | (<+>)) | 48 | (<+>)) |
48 | import Text.Show.Pretty | 49 | import Text.Show.Pretty |
49 | 50 | ||
50 | import Comments | 51 | import GrepNested |
51 | 52 | ||
52 | trace :: p -> a -> a | 53 | trace :: p -> a -> a |
53 | trace _ = id | 54 | trace _ = id |
@@ -480,6 +481,31 @@ isFunctionDecl _ = False | |||
480 | cleanTree :: (Functor f, Data (f b)) => f b -> f Ordering | 481 | cleanTree :: (Functor f, Data (f b)) => f b -> f Ordering |
481 | cleanTree d = fmap (const LT) $ everywhere (mkT eraseNodeInfo) $ d | 482 | cleanTree d = fmap (const LT) $ everywhere (mkT eraseNodeInfo) $ d |
482 | 483 | ||
484 | |||
485 | data SymbolExtent = SymbolExtent { startExtent :: Position, stopExtent :: Position } | ||
486 | |||
487 | instance Show SymbolExtent where | ||
488 | show (SymbolExtent a b) = "sed -n "++show al++","++show bl++"p "++fn | ||
489 | where | ||
490 | fn = posFile a | ||
491 | al = posRow a | ||
492 | bl = posRow b | ||
493 | |||
494 | getSymbolExtent :: (CNode a1, Data a2) => | ||
495 | SymbolInformation a2 -- ^ Symbol database record (symbolSource must have Postion data in it). | ||
496 | -> [a1] -- ^ function body (only used for filename) | ||
497 | -> SymbolExtent | ||
498 | getSymbolExtent sym bdy = | ||
499 | -- TODO: This could probably be a lot more efficient using NodeInfo's PosLength field. | ||
500 | let bdy_poss = map (posOfNode . nodeInfo) bdy | ||
501 | -- hpos = map (posOfNode . nodeInfo) (symbolSource sym) | ||
502 | cmodule = map posFile (take 1 $ filter isSourcePos $ bdy_poss) -- TODO: What if first statement is provided by macro? | ||
503 | allposss = listify (\p -> case cmodule of { [f] | isSourcePos p -> posFile p == f ; _ -> isSourcePos p }) (symbolSource sym) :: [Position] | ||
504 | start = minimumBy (comparing posRow) allposss | ||
505 | stop = maximumBy (comparing posRow) allposss | ||
506 | in SymbolExtent start stop | ||
507 | |||
508 | |||
483 | transpile :: C2HaskellOptions -> FilePath -> IncludeStack -> CTranslationUnit NodeInfo -> IO () | 509 | transpile :: C2HaskellOptions -> FilePath -> IncludeStack -> CTranslationUnit NodeInfo -> IO () |
484 | transpile o fname incs (CTranslUnit edecls _) = do | 510 | transpile o fname incs (CTranslUnit edecls _) = do |
485 | let db = foldr update initTranspile edecls | 511 | let db = foldr update initTranspile edecls |
@@ -529,6 +555,15 @@ transpile o fname incs (CTranslUnit edecls _) = do | |||
529 | 555 | ||
530 | Nothing -> putStrLn $ "??: " ++ ppShow (cleanTree d) | 556 | Nothing -> putStrLn $ "??: " ++ ppShow (cleanTree d) |
531 | putStrLn "" | 557 | putStrLn "" |
558 | let extent = getSymbolExtent sym bdy | ||
559 | cs <- readComments (posFile $ startExtent extent) | ||
560 | let (pcs,cs') = seekComment (startExtent extent) cs | ||
561 | (cs'',ds) = seekComment (stopExtent extent) cs' | ||
562 | -- lineOfComment | ||
563 | forM_ cs' $ \(_,col,cmt) -> do | ||
564 | putStrLn "" | ||
565 | putStrLn $ replicate col ' ' ++ cmt | ||
566 | print extent | ||
532 | return () | 567 | return () |
533 | 568 | ||
534 | isHeaderDecl :: CNode a => a -> Bool | 569 | isHeaderDecl :: CNode a => a -> Bool |
@@ -895,8 +930,9 @@ enumCases (CDeclExt (CDecl xs _ ni)) = do | |||
895 | lineOfComment :: (Int, b, String) -> Int | 930 | lineOfComment :: (Int, b, String) -> Int |
896 | lineOfComment (l,_,s) = l + length (lines s) | 931 | lineOfComment (l,_,s) = l + length (lines s) |
897 | 932 | ||
898 | seekComment :: NodeInfo -> [(Int,Int,String)] -> ([(Int,Int,String)],[(Int,Int,String)]) | 933 | -- Break a comment list into comments preceding the given node and comments that come after it. |
899 | seekComment ni cs = break (\c -> lineOfComment c>=posRow (posOfNode ni)) cs | 934 | seekComment :: Position -> [(Int,Int,String)] -> ([(Int,Int,String)],[(Int,Int,String)]) |
935 | seekComment pos cs = break (\c -> lineOfComment c>=posRow pos) cs | ||
900 | 936 | ||
901 | strip :: [Char] -> [Char] | 937 | strip :: [Char] -> [Char] |
902 | strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace | 938 | strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace |
@@ -955,13 +991,13 @@ c2haskell opts cs cmodname missings incs (CTranslUnit edecls _) = do | |||
955 | cs <- maybe (return []) readComments symfile | 991 | cs <- maybe (return []) readComments symfile |
956 | -- mapM_ (hPutStrLn haskmod . commented . ppShow) $ cs | 992 | -- mapM_ (hPutStrLn haskmod . commented . ppShow) $ cs |
957 | -- mapM_ (hPutStrLn haskmod . commented . ppShow) $ symbolSource si | 993 | -- mapM_ (hPutStrLn haskmod . commented . ppShow) $ symbolSource si |
958 | let (_,cs') = seekComment eni cs | 994 | let (_,cs') = seekComment (posOfNode eni) cs |
959 | forM_ (take 1 cs') $ \(_,c,s) -> | 995 | forM_ (take 1 cs') $ \(_,c,s) -> |
960 | when (c==1) $ hPutStr haskmod $ commented $ "| " ++ strip s | 996 | when (c==1) $ hPutStr haskmod $ commented $ "| " ++ strip s |
961 | hPutStrLn haskmod $ unwords ["newtype",t,"=",t,"CInt"] | 997 | hPutStrLn haskmod $ unwords ["newtype",t,"=",t,"CInt"] |
962 | forM_ (zip es [0..]) $ \((e,_),n) -> do | 998 | forM_ (zip es [0..]) $ \((e,_),n) -> do |
963 | let r = posRow . posOfNode . nodeInfo $ e | 999 | let r = posRow . posOfNode . nodeInfo $ e |
964 | case seekComment (nodeInfo e) cs' of | 1000 | case seekComment (posOfNode $ nodeInfo e) cs' of |
965 | (_,(lno,cno,s):_) | lno==r-1 && cno==1 | 1001 | (_,(lno,cno,s):_) | lno==r-1 && cno==1 |
966 | || cno>1 && lno == r | 1002 | || cno>1 && lno == r |
967 | -> hPutStr haskmod $ commented $ "| " ++ strip s | 1003 | -> hPutStr haskmod $ commented $ "| " ++ strip s |
@@ -1356,8 +1392,8 @@ goMissing haskmod db cfun = do | |||
1356 | htyp -> hPutStr haskmod $ commented $ "Unsupported haskell type: " ++ HS.prettyPrint htyp | 1392 | htyp -> hPutStr haskmod $ commented $ "Unsupported haskell type: " ++ HS.prettyPrint htyp |
1357 | 1393 | ||
1358 | 1394 | ||
1359 | readComments :: (Num lin, Num col) => FilePath -> IO [(lin, col, [Char])] | 1395 | readComments :: Num lin => FilePath -> IO [(lin, Int, [Char])] |
1360 | readComments fname = parseComments 1 1 <$> readFile fname | 1396 | readComments fname = grepCComments 1 1 <$> readFile fname |
1361 | 1397 | ||
1362 | sanitizeArgs :: [String] -> [String] | 1398 | sanitizeArgs :: [String] -> [String] |
1363 | sanitizeArgs (('-':'M':_):args) = sanitizeArgs args | 1399 | sanitizeArgs (('-':'M':_):args) = sanitizeArgs args |