summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-03-13 09:27:50 -0400
committerJoe Crayne <joe@jerkface.net>2019-03-13 09:27:50 -0400
commit29cb139e8b4939353ca6334cc2540b8a8476b057 (patch)
treea8424a2fbd42750e403d24259187e5cb6859ec6d
parentcbadeada6d0f449df9ab708251ece9eddfc5ab70 (diff)
First successful function transpile.
-rw-r--r--monkeypatch.hs277
1 files changed, 209 insertions, 68 deletions
diff --git a/monkeypatch.hs b/monkeypatch.hs
index fc26093..c09fcc7 100644
--- a/monkeypatch.hs
+++ b/monkeypatch.hs
@@ -92,10 +92,14 @@ specs _ = []
92declrSym :: CDeclarator t -> Maybe Ident 92declrSym :: CDeclarator t -> Maybe Ident
93declrSym (CDeclr m _ _ _ _) = m 93declrSym (CDeclr m _ _ _ _) = m
94 94
95declnSym :: CDeclaration a -> [Maybe Ident]
96declnSym (CDecl specs ms _) = ms >>= \(m,_,_) -> maybe [] (pure . declrSym) m
97declnSym _ = []
98
95-- Used by update to add a symbols to the database. 99-- Used by update to add a symbols to the database.
96sym :: CExternalDeclaration a -> [Maybe Ident] 100sym :: CExternalDeclaration a -> [Maybe Ident]
97sym (CFDefExt (CFunDef specs m _ _ _)) = [ declrSym m ] 101sym (CFDefExt (CFunDef specs m _ _ _)) = [ declrSym m ]
98sym (CDeclExt (CDecl specs ms _)) = ms >>= \(m,_,_) -> maybe [] (pure . declrSym) m 102sym (CDeclExt decl) = declnSym decl
99sym _ = [] 103sym _ = []
100 104
101isStatic :: CDeclarationSpecifier a -> Bool 105isStatic :: CDeclarationSpecifier a -> Bool
@@ -133,19 +137,141 @@ transField (CDecl [CTypeSpec (CSUType (CStruct CStructTag mctyp Nothing [] _) _)
133 137
134transField _ = [] 138transField _ = []
135 139
136transpile :: CExternalDeclaration a -> Maybe (Q Dec) 140data Computation st = Computation
137transpile (CDeclExt (CDecl [ CTypeSpec (CSUType 141 { compFree :: Map String ()
138 (CStruct CStructTag mbIdent (Just fields) [] _) 142 , compIntro :: Map String ()
139 _) ] 143 , comp :: st
140 [] 144 }
141 _) ) 145 deriving (Eq,Ord,Functor)
142 | Just struct_name <- capitalize . identToString <$> mbIdent
143 , let typ = mkName struct_name
144 = Just $ returnQ $ DataD [] typ [] Nothing [RecC typ fs] []
145 where fs = fields >>= transField
146
147transpile _ = Nothing
148 146
147grokExpression (CVar cv _) = Just Computation
148 { compFree = Map.singleton (identToString cv) ()
149 , compIntro = Map.empty
150 , comp = hsvar (identToString cv)
151 }
152grokExpression (CBinary CNeqOp a b _) = do
153 ca <- grokExpression a
154 cb <- grokExpression b
155 return Computation
156 { compFree = compFree ca `Map.union` compFree cb
157 , compIntro = Map.empty
158 , comp = InfixApp () (comp ca) hsopNeq (comp cb)
159 }
160grokExpression _ = Nothing
161
162
163hsvar :: String -> HS.Exp ()
164hsvar v = Var () (UnQual () (HS.Ident () v))
165
166hspvar :: String -> HS.Pat ()
167hspvar v = PVar () (HS.Ident () v)
168
169cvarName (CVar (C.Ident n _ _) _) = Just n
170cvarName _ = Nothing
171
172hsopApp = QVarOp () (UnQual () (Symbol () "$"))
173
174hsopBind = QVarOp () (UnQual () (Symbol () ">>="))
175
176hsopNeq = QVarOp () (UnQual () (Symbol () "/="))
177
178hsopUnit = HS.Con () (Special () (UnitCon ()))
179
180
181
182
183applyComputation :: Computation (HS.Exp ()) -> Computation (HS.Exp ()) -> Computation (HS.Exp ())
184applyComputation a@Computation{ comp = (Lambda () [PVar () govar] exp) } b =
185 let matchgo (Var () (UnQual () v)) = v==govar
186 matchgo _ = False
187 in case listify matchgo exp of
188 (_:_:_) -> error "TODO: Multiple go-refs; make let binding."
189 _ -> Computation
190 { compFree = Map.union (compFree a) (compFree b) Map.\\ compIntro a
191 , compIntro = compIntro a `Map.union` compIntro b
192 , comp = let subst x | matchgo x = comp b
193 | otherwise = x
194 in everywhere (mkT subst) exp
195 }
196applyComputation a b = a
197
198varmap :: [String] -> Map String ()
199varmap vs = Map.fromList $ map (,()) vs
200
201
202grokStatement :: CCompoundBlockItem a -> Maybe (Computation (HS.Exp ()))
203grokStatement (CBlockStmt (CReturn (Just exp) _)) = do
204 x <- grokExpression exp
205 let k = uniqIdentifier "go" (compFree x `Map.union` compIntro x)
206 return $ fmap (\y -> Lambda () [hspvar k] $ App () (hsvar "return") y) x
207
208grokStatement (CBlockStmt (CExpr (Just
209 (CAssign CAssignOp cvarnew
210 (C.CCall cvarfun [] _) _)) _)) = do
211 v <- cvarName cvarnew
212 fn <- cvarName cvarfun
213 let k = uniqIdentifier "go" (varmap [v,fn])
214 return Computation
215 { compFree = Map.singleton fn ()
216 , compIntro = Map.singleton v ()
217 , comp = Lambda () [hspvar k]
218 $ InfixApp () (hsvar fn) hsopBind
219 $ Lambda () [hspvar v] (hsvar k)
220 }
221grokStatement (CBlockStmt (CIf exp (CCompound [] stmts _) Nothing _)) = do
222 x <- grokExpression exp
223 ss <- sequence $ map grokStatement stmts
224 let s = foldr applyComputation (Computation Map.empty Map.empty (hsvar k)) ss
225 k = uniqIdentifier "go" (Map.union (compFree x) (compFree s))
226 return Computation
227 { compFree = compFree x `Map.union` compFree s
228 , compIntro = compIntro s
229 , comp = Lambda () [hspvar k] $ If () (comp x) (comp s) (hsvar k)
230 }
231grokStatement (CBlockDecl (CDecl (t:_) (v:vs) _)) = do
232 return Computation
233 { compFree = Map.empty
234 , compIntro = Map.empty
235 , comp = Lambda () [hspvar "go"] $ hsvar "go"
236 }
237grokStatement _ = Nothing
238
239
240transpile :: C2HaskellOptions -> FilePath -> IncludeStack -> CTranslationUnit NodeInfo -> IO ()
241transpile o fname incs (CTranslUnit edecls _) = do
242 let db = foldr update initTranspile edecls
243 locals = case oSelectFunction o of
244 Just sel -> maybe Map.empty (Map.singleton sel) $ Map.lookup sel (syms db)
245 Nothing -> Map.filter symbolLocal (syms db)
246 forM_ (Map.toList locals) $ \(hname,sym) -> do
247 -- putStrLn $ "symbol " ++ hname ++ " sym="++show (length $ symbolSource sym)
248 forM_ (getsig ((),sym)) $ \(ns,(_,h,c)) -> do
249 -- putStrLn $ "getsig " ++ show c
250 -- CDerivedDeclarator n0’ with actual type ‘CExternalDeclaration NodeInfo
251 let as = do
252 a <- getArgList c
253 m <- case makeParameterNamesM a of
254 Just (CFunDeclr (Right (ps,_)) _ _, _) -> map declnSym ps
255 _ -> []
256 i <- m
257 maybe [] (return . identToString) i
258 -- mapM_ (putStrLn . show . pretty) (symbolSource sym)
259 forM_ (take 1 h) $ \hh -> do
260 putStrLn . HS.prettyPrint $ changeType makeFunctionUseIO hh
261 putStrLn $ unwords (hname:as) ++ " ="
262 let bdy = concat $ take 1 $ dropWhile null $ map body $ symbolSource sym
263 if oPrettyTree o
264 then forM_ bdy $ \d -> putStrLn $ ppShow $ everywhere (mkT eraseNodeInfo) $ d
265 else do
266 let mhask = do
267 xs <- sequence $ map grokStatement bdy
268 return $ foldr applyComputation (Computation Map.empty Map.empty hsopUnit) xs
269 case mhask of
270 Just hask -> mapM_ (putStrLn . (" "++)) $ lines $ HS.prettyPrint $ comp hask
271 Nothing -> forM_ bdy $ \d -> do
272 putStrLn . show . pretty $ d
273 mapM_ (putStrLn . HS.prettyPrint . comp) (grokStatement d)
274 return ()
149 275
150isHeaderDecl :: CNode a => a -> Bool 276isHeaderDecl :: CNode a => a -> Bool
151isHeaderDecl = maybe False (isSuffixOf ".h") . fileOfNode 277isHeaderDecl = maybe False (isSuffixOf ".h") . fileOfNode
@@ -307,6 +433,11 @@ extractType (HS.TypeDecl _ _ ftyp) = ftyp
307extractType (HS.TypeSig _ _ ftyp) = ftyp 433extractType (HS.TypeSig _ _ ftyp) = ftyp
308extractType _ = TyCon () (Special () (UnitCon ())) 434extractType _ = TyCon () (Special () (UnitCon ()))
309 435
436changeType :: (HS.Type a -> HS.Type a) -> Decl a -> Decl a
437changeType f (HS.TypeDecl a b ftyp) = HS.TypeDecl a b (f ftyp)
438changeType f (HS.TypeSig a b ftyp) = HS.TypeSig a b (f ftyp)
439changeType f x = x
440
310{- 441{-
311hsTransFieldExt :: Show b => 442hsTransFieldExt :: Show b =>
312 [CDeclarationSpecifier b] 443 [CDeclarationSpecifier b]
@@ -418,40 +549,34 @@ commented :: String -> String
418commented s = unlines $ map ("-- " ++) (lines s) 549commented s = unlines $ map ("-- " ++) (lines s)
419 550
420data C2HaskellOptions = C2HaskellOptions 551data C2HaskellOptions = C2HaskellOptions
421 { selectFunction :: Maybe String 552 { oSelectFunction :: Maybe String
422 , prettyC :: Bool 553 , oPrettyC :: Bool
423 , prettyTree :: Bool 554 , oPrettyTree :: Bool
424 , verbose :: Bool 555 , oVerbose :: Bool
425 , preprocess :: Bool 556 , oPreprocess :: Bool
557 , oTranspile :: Bool
426 } 558 }
427 559
428defopts :: C2HaskellOptions 560defopts :: C2HaskellOptions
429defopts = C2HaskellOptions 561defopts = C2HaskellOptions
430 { selectFunction = Nothing 562 { oSelectFunction = Nothing
431 , prettyC = False 563 , oPrettyC = False
432 , prettyTree = False 564 , oPrettyTree = False
433 , verbose = False 565 , oVerbose = False
434 , preprocess = False 566 , oPreprocess = False
567 , oTranspile = False
435 } 568 }
436 569
437parseOptions :: [String] -> C2HaskellOptions -> C2HaskellOptions 570parseOptions :: [String] -> C2HaskellOptions -> C2HaskellOptions
438parseOptions [] opts = opts 571parseOptions [] o = o
439parseOptions ("-f":f:args) opts = parseOptions args opts 572parseOptions ("-f":f:args) o = parseOptions args o{ oSelectFunction = Just f }
440 { selectFunction = Just f 573parseOptions ("-t":args) o = parseOptions args o{ oPrettyTree = True }
441 } 574parseOptions ("-p":args) o = parseOptions args o{ oPrettyC = True }
442parseOptions ("-t":args) opts = parseOptions args opts 575parseOptions ("--cpp":args) o = parseOptions args o{ oPreprocess = True }
443 { prettyTree = True 576parseOptions ("-v":args) o = parseOptions args o{ oVerbose = True }
444 } 577parseOptions ("--tohs":args) o = parseOptions args o{ oTranspile = True }
445parseOptions ("-p":args) opts = parseOptions args opts 578parseOptions as o = error (show as)
446 { prettyC = True 579
447 }
448parseOptions ("--cpp":args) opts = parseOptions args opts
449 { preprocess = True
450 }
451parseOptions ("-v":args) opts = parseOptions args opts
452 { verbose = True
453 }
454parseOptions as x = error (show as)
455 580
456tnames :: Show b => 581tnames :: Show b =>
457 CExternalDeclaration b -> [(String, Maybe String)] 582 CExternalDeclaration b -> [(String, Maybe String)]
@@ -465,11 +590,12 @@ getsig :: (a, SymbolInformation [CExternalDeclaration NodeInfo])
465 , CExternalDeclaration NodeInfo))] -- c declaration (with fixups) 590 , CExternalDeclaration NodeInfo))] -- c declaration (with fixups)
466getsig (k,si) = do 591getsig (k,si) = do
467 d0 <- take 1 $ symbolSource si 592 d0 <- take 1 $ symbolSource si
468 let d = case getArgList d0 of 593 d <- case getArgList d0 of
469 oargs:xs -> let args = fst $ makeParameterNames oargs 594 oargs:xs -> case makeParameterNamesM oargs of
470 in changeArgList (const $ args:xs) d0 595 Just (args,_) -> [changeArgList (const $ args:xs) d0]
471 _ -> d0 596 Nothing -> []
472 ts = tnames d 597 _ -> [d0]
598 let ts = tnames d
473 s = sig d 599 s = sig d
474 [(ts,(k,s,d))] 600 [(ts,(k,s,d))]
475 601
@@ -508,6 +634,13 @@ seekComment ni cs = break (\c -> lineOfComment c>=posRow (posOfNode ni)) cs
508 634
509strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace 635strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace
510 636
637
638data GStatement x = GStatement
639 { gsTopDoc :: String
640 , gsSideDoc :: String
641 , gstatemnt :: x
642 }
643
511-- c2haskell :: Foldable t => C2HaskellOptions -> p -> t String -> CTranslationUnit NodeInfo -> IO () 644-- c2haskell :: Foldable t => C2HaskellOptions -> p -> t String -> CTranslationUnit NodeInfo -> IO ()
512c2haskell :: C2HaskellOptions 645c2haskell :: C2HaskellOptions
513 -> p1 -> FilePath -> [String] -> IncludeStack -> CTranslationUnit NodeInfo -> IO () 646 -> p1 -> FilePath -> [String] -> IncludeStack -> CTranslationUnit NodeInfo -> IO ()
@@ -515,7 +648,7 @@ c2haskell opts cs cmodname missings incs (CTranslUnit edecls _) = do
515 let db = foldr update initTranspile edecls 648 let db = foldr update initTranspile edecls
516 {- exported symbols in this module -} 649 {- exported symbols in this module -}
517 es = Map.filter (\d -> symbolLocal d && not (symbolStatic d)) (syms db) 650 es = Map.filter (\d -> symbolLocal d && not (symbolStatic d)) (syms db)
518 case selectFunction opts of 651 case oSelectFunction opts of
519 Nothing -> do 652 Nothing -> do
520 createDirectoryIfMissing False "MonkeyPatch" 653 createDirectoryIfMissing False "MonkeyPatch"
521 let fname = ("MonkeyPatch/" ++ modname ++ ".hs") 654 let fname = ("MonkeyPatch/" ++ modname ++ ".hs")
@@ -808,12 +941,10 @@ parameterIdent (CDecl _ xs n) = listToMaybe $ do
808 (Just (CDeclr (Just x) _ _ _ _),_,_) <- xs 941 (Just (CDeclr (Just x) _ _ _ _),_,_) <- xs
809 return x 942 return x
810 943
811 944makeParameterNamesM :: CDerivedDeclarator n -> Maybe (CDerivedDeclarator n,[CExpression n])
812-- makeParameterNames :: CDerivedDeclarator NodeInfo -> (CDerivedDeclarator NodeInfo,[CExpression NodeInfo]) 945makeParameterNamesM (CFunDeclr (Right (ps, flg)) z2 z3) = case ps of
813makeParameterNames :: CDerivedDeclarator n -> (CDerivedDeclarator n,[CExpression n]) 946 [CDecl [CTypeSpec (CVoidType _)] [] _] -> Just ( CFunDeclr (Right (ps, flg)) z2 z3 , []) -- void argument list.
814makeParameterNames (CFunDeclr (Right (ps, flg)) z2 z3) = case ps of 947 _ -> Just ( CFunDeclr (Right (qs, flg)) z2 z3 , map expr qs )
815 [CDecl [CTypeSpec (CVoidType _)] [] _] -> ( CFunDeclr (Right (ps, flg)) z2 z3 , []) -- void argument list.
816 _ -> ( CFunDeclr (Right (qs, flg)) z2 z3 , map expr qs )
817 where 948 where
818 -- TODO: ensure uniqueness of generated parameter names 949 -- TODO: ensure uniqueness of generated parameter names
819 qs = zipWith mkp [0..] ps 950 qs = zipWith mkp [0..] ps
@@ -822,8 +953,11 @@ makeParameterNames (CFunDeclr (Right (ps, flg)) z2 z3) = case ps of
822 mkp num (CDecl rtyp [] n) 953 mkp num (CDecl rtyp [] n)
823 = (CDecl rtyp ((Just (CDeclr (Just $ mkidn num undefNode) [] Nothing [] n),Nothing,Nothing):[]) n) 954 = (CDecl rtyp ((Just (CDeclr (Just $ mkidn num undefNode) [] Nothing [] n),Nothing,Nothing):[]) n)
824 mkp num p = p 955 mkp num p = p
825-- CPtrDeclr [] () 956makeParameterNamesM _ = Nothing
826makeParameterNames x = error $ "makeParameterNames " ++ show (fmap (const ()) x) 957
958-- makeParameterNames :: CDerivedDeclarator NodeInfo -> (CDerivedDeclarator NodeInfo,[CExpression NodeInfo])
959makeParameterNames :: CDerivedDeclarator n -> (CDerivedDeclarator n,[CExpression n])
960makeParameterNames x = fromMaybe (error $ "makeParameterNames " ++ show (fmap (const ()) x)) $ makeParameterNamesM x
827 961
828expr :: CDeclaration a -> CExpression a 962expr :: CDeclaration a -> CExpression a
829expr (CDecl rtyp ((Just (CDeclr (Just i) typ x ys z),a,b):xs) n) = CVar i n 963expr (CDecl rtyp ((Just (CDeclr (Just i) typ x ys z),a,b):xs) n) = CVar i n
@@ -1003,6 +1137,13 @@ usage args =
1003(<&>) :: Functor f => f a -> (a -> b) -> f b 1137(<&>) :: Functor f => f a -> (a -> b) -> f b
1004m <&> f = fmap f m 1138m <&> f = fmap f m
1005 1139
1140uniqIdentifier :: String -> Map String a -> String
1141uniqIdentifier n emap = head $ dropWhile (`Map.member` emap) ns
1142 where
1143 ns = n : map ((n ++) . show) [1 ..]
1144
1145
1146-- | Remove duplicates from a collection.
1006uniq :: (Ord k, Foldable t) => t k -> [k] 1147uniq :: (Ord k, Foldable t) => t k -> [k]
1007uniq xs = Map.keys $ foldr (\x m -> Map.insert x () m) Map.empty xs 1148uniq xs = Map.keys $ foldr (\x m -> Map.insert x () m) Map.empty xs
1008 1149
@@ -1078,7 +1219,8 @@ main = do
1078 let m = usage args 1219 let m = usage args
1079 fromMaybe (putStrLn usageString) $ m <&> \(hopts,cargs,fname:fs) -> do 1220 fromMaybe (putStrLn usageString) $ m <&> \(hopts,cargs,fname:fs) -> do
1080 prer <- runPreprocessor (newGCC "gcc") (rawCppArgs cargs fname) 1221 prer <- runPreprocessor (newGCC "gcc") (rawCppArgs cargs fname)
1081 let r = do 1222 let r :: Either (Either ExitCode ParseError) (IncludeStack, CTranslUnit)
1223 r = do
1082 pre <- left Left $ prer 1224 pre <- left Left $ prer
1083 c <- left Right $ parseC pre (initPos fname) 1225 c <- left Right $ parseC pre (initPos fname)
1084 return (includeStack pre,c) 1226 return (includeStack pre,c)
@@ -1086,17 +1228,16 @@ main = do
1086 -- putStrLn $ "includes = " ++ ppShow (fmap fst r) 1228 -- putStrLn $ "includes = " ++ ppShow (fmap fst r)
1087 -- cs <- readComments fname 1229 -- cs <- readComments fname
1088 case () of 1230 case () of
1089 _ | preprocess hopts -- --cpp 1231 _ | oPreprocess hopts -- --cpp
1090 -> do 1232 -> case prer of
1091 case prer of 1233 Left e -> print e
1092 Left e -> print e 1234 Right bs -> putStrLn $ ppShow $ includeStack $ bs
1093 Right bs -> putStrLn $ ppShow $ includeStack $ bs 1235 _ | oPrettyC hopts -- -p
1094 _ | prettyC hopts -- -p 1236 -> either print (\(incs,decls) -> print $ prettyUsingInclude incs decls) r
1095 -> do 1237 _ | oPrettyTree hopts && not (oTranspile hopts) -- -t
1096 either print (\(incs,decls) -> print $ prettyUsingInclude incs decls) r 1238 -> putStrLn $ ppShow $ everywhere (mkT eraseNodeInfo) . snd <$> r
1097 _ | prettyTree hopts -- -t 1239 _ | oTranspile hopts -- --tohs
1098 -> do 1240 -> either print (uncurry $ transpile hopts fname) r
1099 putStrLn $ ppShow $ everywhere (mkT eraseNodeInfo) . snd <$> r
1100 _ -> do 1241 _ -> do
1101 syms <- linker (cargs ++ reverse fs) fname 1242 syms <- linker (cargs ++ reverse fs) fname
1102 either print (uncurry $ c2haskell hopts () fname syms) r 1243 either print (uncurry $ c2haskell hopts () fname syms) r