diff options
author | Joe Crayne <joe@jerkface.net> | 2018-11-19 21:53:11 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2018-11-19 21:53:11 -0500 |
commit | d7897ff1c2ac599a133b09bc48134a7f74af3d03 (patch) | |
tree | a7ea6d476c57263142de71cae925398dc326468f | |
parent | d52b9beb1c8735b0915a0fa6a9e27ccd33478532 (diff) |
Compilable output.
-rw-r--r-- | c2haskell.hs | 180 |
1 files changed, 153 insertions, 27 deletions
diff --git a/c2haskell.hs b/c2haskell.hs index d3075e4..2fbbfc2 100644 --- a/c2haskell.hs +++ b/c2haskell.hs | |||
@@ -20,6 +20,7 @@ import qualified Data.Set as Set | |||
20 | import Language.C.Data.Ident as C | 20 | import Language.C.Data.Ident as C |
21 | import Language.C as C hiding (prettyUsingInclude) | 21 | import Language.C as C hiding (prettyUsingInclude) |
22 | import Language.C.System.GCC | 22 | import Language.C.System.GCC |
23 | import Language.Haskell.Exts.Parser as HS | ||
23 | import Language.Haskell.Exts.Pretty as HS | 24 | import Language.Haskell.Exts.Pretty as HS |
24 | import Language.Haskell.Exts.Syntax as HS | 25 | import Language.Haskell.Exts.Syntax as HS |
25 | import Language.Haskell.TH | 26 | import Language.Haskell.TH |
@@ -63,6 +64,7 @@ specs _ = [] | |||
63 | declrSym :: CDeclarator t -> Maybe Ident | 64 | declrSym :: CDeclarator t -> Maybe Ident |
64 | declrSym (CDeclr m _ _ _ _) = m | 65 | declrSym (CDeclr m _ _ _ _) = m |
65 | 66 | ||
67 | -- Used by update to add a symbols to the database. | ||
66 | sym :: CExternalDeclaration a -> [Maybe Ident] | 68 | sym :: CExternalDeclaration a -> [Maybe Ident] |
67 | sym (CFDefExt (CFunDef specs m _ _ _)) = [ declrSym m ] | 69 | sym (CFDefExt (CFunDef specs m _ _ _)) = [ declrSym m ] |
68 | sym (CDeclExt (CDecl specs ms _)) = ms >>= \(m,_,_) -> maybe [] (pure . declrSym) m | 70 | sym (CDeclExt (CDecl specs ms _)) = ms >>= \(m,_,_) -> maybe [] (pure . declrSym) m |
@@ -152,7 +154,9 @@ grokSymbol d k msi = | |||
152 | , symbolSource = d : symbolSource si | 154 | , symbolSource = d : symbolSource si |
153 | } | 155 | } |
154 | 156 | ||
155 | -- update :: CExternalDeclaration a -> Transpile -> Transpile | 157 | update :: CExternalDeclaration NodeInfo |
158 | -> Transpile [CExternalDeclaration NodeInfo] | ||
159 | -> Transpile [CExternalDeclaration NodeInfo] | ||
156 | update d transpile = transpile | 160 | update d transpile = transpile |
157 | { syms = foldr (\k m -> Map.alter (grokSymbol d k) k m) (syms transpile) | 161 | { syms = foldr (\k m -> Map.alter (grokSymbol d k) k m) (syms transpile) |
158 | $ map (maybe "" identToString) $ sym d | 162 | $ map (maybe "" identToString) $ sym d |
@@ -168,23 +172,40 @@ hsMkName str = HS.UnQual () (foo () str) | |||
168 | where | 172 | where |
169 | foo = HS.Ident -- alternative: HS.Symbol | 173 | foo = HS.Ident -- alternative: HS.Symbol |
170 | 174 | ||
171 | hsTypeSpec :: CDeclarationSpecifier t -> [String] | 175 | |
172 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint8_t" _ _) _)) = ["Word8"] | 176 | notKnown "Word8" = False |
173 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint16_t" _ _) _)) = ["Word16"] | 177 | notKnown "Word16" = False |
174 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint32_t" _ _) _)) = ["Word32"] | 178 | notKnown "Word32" = False |
175 | hsTypeSpec (CTypeSpec (CTypeDef ctyp _)) = [capitalize . identToString $ ctyp] | 179 | notKnown "Bool" = False |
176 | hsTypeSpec (CTypeSpec (CBoolType _)) = ["Bool"] | 180 | notKnown "Int" = False |
177 | hsTypeSpec (CTypeSpec (CIntType _)) = ["Int"] | 181 | notKnown "Char" = False |
178 | hsTypeSpec (CTypeSpec (CCharType _)) = ["Char"] | 182 | notKnown "()" = False |
179 | hsTypeSpec (CTypeSpec (CSUType (CStruct CStructTag mctyp Nothing [] _) _)) = maybeToList $ fmap (capitalize . identToString) mctyp | 183 | notKnown _ = True |
180 | hsTypeSpec (CTypeSpec unhandled) = trace ("hsTypeSpec unhandled: "++ show (const () <$> unhandled)) | 184 | |
181 | $ [] | 185 | hsTypeSpec :: CDeclarationSpecifier t -> [Either Ident String] |
182 | hsTypeSpec _ = [] | 186 | hsTypeSpec (CTypeSpec (CVoidType _)) = [ Right "()" ] |
187 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint8_t" _ _) _)) = [ Right "Word8"] | ||
188 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint16_t" _ _) _)) = [ Right "Word16"] | ||
189 | hsTypeSpec (CTypeSpec (CTypeDef (C.Ident "uint32_t" _ _) _)) = [ Right "Word32"] | ||
190 | hsTypeSpec (CTypeSpec (CTypeDef ctyp _)) = [ Left ctyp ] | ||
191 | hsTypeSpec (CTypeSpec (CBoolType _)) = [ Right "Bool"] | ||
192 | hsTypeSpec (CTypeSpec (CIntType _)) = [ Right "Int"] | ||
193 | hsTypeSpec (CTypeSpec (CCharType _)) = [ Right "Char"] | ||
194 | hsTypeSpec (CTypeSpec (CSUType (CStruct CStructTag mctyp Nothing [] _) _)) = maybeToList $ fmap Left mctyp | ||
195 | |||
196 | hsTypeSpec (CTypeSpec unhandled) = trace ("hsTypeSpec unhandled: "++ show (const () <$> unhandled)) $ [] | ||
197 | hsTypeSpec _ = [] | ||
198 | |||
183 | 199 | ||
184 | -- hsTransField :: [CDeclarationSpecifier t3] -> [(Maybe (CDeclarator t2), Maybe t1, Maybe t)] -> [HS.Decl ()] | 200 | -- hsTransField :: [CDeclarationSpecifier t3] -> [(Maybe (CDeclarator t2), Maybe t1, Maybe t)] -> [HS.Decl ()] |
201 | -- recursive for function signatures. | ||
202 | hsTransField :: Show b => | ||
203 | [CDeclarationSpecifier b] -- c structure name | ||
204 | -> [(Maybe (CDeclarator b), Maybe (CInitializer b), Maybe (CExpression b))] -- c variable declarations | ||
205 | -> [(String{-field name-}, HS.Type () {- haskell type -}) ] | ||
185 | hsTransField ctyps vars | 206 | hsTransField ctyps vars |
186 | = do | 207 | = do |
187 | typname <- hsMkName <$> (hsTypeSpec =<< ctyps) | 208 | typname <- hsMkName . either (capitalize . identToString) id <$> (hsTypeSpec =<< ctyps) |
188 | trace ("typname="++show typname) $ return () | 209 | trace ("typname="++show typname) $ return () |
189 | (var,Nothing,Nothing) <- vars | 210 | (var,Nothing,Nothing) <- vars |
190 | trace ("var="++show var) $ return () | 211 | trace ("var="++show var) $ return () |
@@ -195,8 +216,12 @@ hsTransField ctyps vars | |||
195 | grok bs b = case bs of | 216 | grok bs b = case bs of |
196 | [] -> b | 217 | [] -> b |
197 | (CPtrDeclr [] _:cs) -> HS.TyApp () (HS.TyCon () (hsMkName "Ptr")) (grok cs b) | 218 | (CPtrDeclr [] _:cs) -> HS.TyApp () (HS.TyCon () (hsMkName "Ptr")) (grok cs b) |
198 | [CFunDeclr (Right (args,flg)) attrs _] -> let (as,ts) = unzip $ concatMap (\(CDecl rs as _) -> hsTransField rs as) args | 219 | CFunDeclr (Right (args,flg)) attrs _:p -> |
199 | in foldr (HS.TyFun ()) b ts | 220 | let (as,ts) = unzip $ concatMap (\(CDecl rs as _) -> hsTransField rs as) args |
221 | b0 = case p of | ||
222 | CPtrDeclr [] _:cs -> HS.TyApp () (HS.TyCon () (hsMkName "Ptr")) (grok cs b) | ||
223 | [] -> b | ||
224 | in foldr (HS.TyFun ()) b0 ts | ||
200 | _ -> HS.TyCon () (hsMkName $ show $ map (fmap (const ())) ptrdeclr) | 225 | _ -> HS.TyCon () (hsMkName $ show $ map (fmap (const ())) ptrdeclr) |
201 | ftyp = grok ptrdeclr btyp | 226 | ftyp = grok ptrdeclr btyp |
202 | fieldName = identToString fident | 227 | fieldName = identToString fident |
@@ -215,11 +240,44 @@ transField (CDecl [CTypeSpec (CSUType (CStruct CStructTag mctyp Nothing [] _) _) | |||
215 | hsTransField _ _ = [] | 240 | hsTransField _ _ = [] |
216 | -} | 241 | -} |
217 | 242 | ||
243 | extractType (HS.TypeDecl _ _ ftyp) = ftyp | ||
244 | extractType (HS.TypeSig _ _ ftyp) = ftyp | ||
245 | extractType _ = TyCon () (Special () (UnitCon ())) | ||
246 | |||
247 | hsTransFieldExt :: Show b => | ||
248 | [CDeclarationSpecifier b] | ||
249 | -> [(Maybe (CDeclarator b), Maybe (CInitializer b), | ||
250 | Maybe (CExpression b))] | ||
251 | -> [Decl ()] | ||
218 | hsTransFieldExt rs as = concatMap (\(fieldName,ftyp)-> [ HS.TypeSig () [ HS.Ident () fieldName ] ftyp ]) | 252 | hsTransFieldExt rs as = concatMap (\(fieldName,ftyp)-> [ HS.TypeSig () [ HS.Ident () fieldName ] ftyp ]) |
219 | $ hsTransField rs as | 253 | $ hsTransField rs as |
220 | 254 | ||
221 | sig (CDeclExt (CDecl rs as _)) = hsTransFieldExt rs as | 255 | hsTransSig rs as = concatMap (\(fieldName,ftyp)-> [ HS.TypeDecl () (DHead () (HS.Ident () ("Sig_" ++ fieldName))) ftyp ]) |
222 | sig (CFDefExt (CFunDef rs cdeclr [] bdy _)) = hsTransFieldExt rs [(Just cdeclr, Nothing, Nothing)] | 256 | $ hsTransField rs as |
257 | |||
258 | types (HS.TypeDecl _ _ typ) = primtypes typ | ||
259 | |||
260 | primtypes (HS.TyFun _ a b) = primtypes a ++ primtypes b | ||
261 | primtypes t = [t] | ||
262 | |||
263 | tname (HS.TyCon () (HS.UnQual () (HS.Ident () str))) = str | ||
264 | tname _ = "_unkonwn" | ||
265 | |||
266 | getPtrType (HS.TyApp _ (HS.TyCon _ (HS.UnQual _ (HS.Ident _ "Ptr"))) x) = Just x | ||
267 | getPtrType _ = Nothing | ||
268 | |||
269 | -- pointers :: [HS.Decl ()] -> [String] | ||
270 | pointers :: [HS.Type l] -> [HS.Type l] | ||
271 | pointers decls = do | ||
272 | d <- decls | ||
273 | maybeToList $ getPtrType d | ||
274 | |||
275 | |||
276 | sig :: Show t => CExternalDeclaration t -> [HS.Decl ()] | ||
277 | sig = sigf hsTransFieldExt | ||
278 | |||
279 | sigf f (CDeclExt (CDecl rs as _)) = f rs as | ||
280 | sigf f (CFDefExt (CFunDef rs cdeclr [] bdy _)) = f rs [(Just cdeclr, Nothing, Nothing)] | ||
223 | 281 | ||
224 | body0 (CFDefExt (CFunDef rs cdeclr [] bdy _)) = Just bdy | 282 | body0 (CFDefExt (CFunDef rs cdeclr [] bdy _)) = Just bdy |
225 | body0 _ = Nothing | 283 | body0 _ = Nothing |
@@ -278,17 +336,52 @@ parseOptions ("-v":args) opts = parseOptions args opts | |||
278 | { verbose = True | 336 | { verbose = True |
279 | } | 337 | } |
280 | 338 | ||
339 | getsig (k,si) = do | ||
340 | d <- take 1 $ symbolSource si | ||
341 | let ts = filter notKnown $ map tname $ pointers $ concatMap types $ sigf hsTransSig d | ||
342 | s = sig d | ||
343 | [(ts,(k,s))] | ||
344 | |||
345 | isAcceptableImport (HS.TyFun _ (TyCon _ (UnQual _ (HS.Ident _ x))) xs) | not (notKnown x) = isAcceptableImport xs | ||
346 | isAcceptableImport (HS.TyFun _ (TyApp _ (TyCon _ (UnQual _ (HS.Ident _ "Ptr"))) x) xs) = isAcceptableImport xs | ||
347 | isAcceptableImport (HS.TyFun _ (TyApp _ (TyCon _ (UnQual _ (HS.Ident _ "Ptr"))) x) xs) = isAcceptableImport xs | ||
348 | isAcceptableImport (TyCon _ _) = True | ||
349 | isAcceptableImport (TyApp _ _ _) = True | ||
350 | isAcceptableImport _ = False | ||
351 | |||
281 | c2haskell opts cs (CTranslUnit edecls _) = do | 352 | c2haskell opts cs (CTranslUnit edecls _) = do |
282 | let db = foldr update initTranspile edecls | 353 | let db = foldr update initTranspile edecls |
283 | es = Map.filter (\d -> symbolLocal d && not (symbolStatic d)) (syms db) | 354 | es = Map.filter (\d -> symbolLocal d && not (symbolStatic d)) (syms db) |
284 | case selectFunction opts of | 355 | case selectFunction opts of |
285 | Nothing -> forM_ (Map.toList es) $ \(k,si) -> do | 356 | Nothing -> do |
286 | putStrLn "" | 357 | putStrLn $ "module T where" |
287 | putStrLn (commented k) | 358 | putStrLn $ "import Foreign.Ptr" |
288 | forM_ (symbolSource si) $ \d -> do | 359 | putStrLn $ "import Data.Word" |
289 | putStr $ commented (ppShow (fmap (const ()) d)) | 360 | let sigs = concatMap getsig (Map.toList es) |
290 | putStr $ commented (show $ pretty d) | 361 | ts = foldr (\t -> Map.insert t ()) Map.empty $ concatMap fst sigs |
291 | mapM_ (putStrLn . HS.prettyPrint) (sig d) | 362 | forM_ (Map.keys ts) $ \t -> do |
363 | putStrLn $ "data " ++ t | ||
364 | forM_ sigs $ \(_,(k,hs)) -> do | ||
365 | forM_ hs $ \hdecl -> do | ||
366 | {- | ||
367 | putStr (commented k) | ||
368 | putStr $ commented $ show $ length $ symbolSource si | ||
369 | forM_ (take 1 $ symbolSource si) $ \d -> do | ||
370 | let ts = filter notKnown $ map tname $ pointers $ concatMap types $ sigf hsTransSig d | ||
371 | -- putStr $ commented (ppShow (fmap (const ()) d)) | ||
372 | -- putStr $ commented (show $ pretty d) | ||
373 | let typ = (TyCon () (Special () (UnitCon ()))) | ||
374 | -- when (null $ sig d) $ putStr $ commented (ppShow (fmap (const ()) d)) | ||
375 | forM_ (sig d) $ \hs -> case hs of | ||
376 | htyp -> -- putStr $ commented $ "Unsupported haskell type: " ++ HS.prettyPrint htyp | ||
377 | -} | ||
378 | let htyp = extractType hdecl | ||
379 | putStrLn $ (if isAcceptableImport htyp then id else commented) | ||
380 | $ HS.prettyPrint $ (HS.ForImp () (HS.CCall ()) Nothing (Just k) | ||
381 | (HS.Ident () k) | ||
382 | htyp) | ||
383 | |||
384 | -- mapM_ (putStrLn . HS.prettyPrint) (sig d) | ||
292 | {- | 385 | {- |
293 | forM_ (body d) $ \stmt -> do | 386 | forM_ (body d) $ \stmt -> do |
294 | putStr $ commented (take 130 $ show (fmap (const ()) stmt)) | 387 | putStr $ commented (take 130 $ show (fmap (const ()) stmt)) |
@@ -304,8 +397,39 @@ c2haskell opts cs (CTranslUnit edecls _) = do | |||
304 | forM_ (symbolSource $ syms db Map.! cfun) $ \d -> do | 397 | forM_ (symbolSource $ syms db Map.! cfun) $ \d -> do |
305 | -- putStr $ commented (ppShow (fmap (const ()) d)) | 398 | -- putStr $ commented (ppShow (fmap (const ()) d)) |
306 | -- putStr $ commented (show $ pretty d) | 399 | -- putStr $ commented (show $ pretty d) |
307 | when (verbose opts) $ print (sig d) | 400 | -- when (verbose opts) $ print (sig d) |
308 | mapM_ (putStrLn . HS.prettyPrint) (sig d) | 401 | let ts = filter notKnown $ map tname $ pointers $ concatMap types $ sigf hsTransSig d |
402 | forM_ ts $ \t -> do | ||
403 | putStrLn $ "data " ++ t | ||
404 | forM_ (sigf hsTransSig d) $ \hs -> do | ||
405 | putStrLn . HS.prettyPrint $ hs | ||
406 | case hs of | ||
407 | HS.TypeDecl _ (DHead _ (HS.Ident _ signame)) ftyp -> do | ||
408 | let wrapname = "wrap" ++ drop 3 signame | ||
409 | settername = "setf" ++ drop 3 signame | ||
410 | funptr = (TyApp () (TyCon () (UnQual () (HS.Ident () "FunPtr"))) | ||
411 | (TyCon () (UnQual () (HS.Ident () signame)))) | ||
412 | -- putStrLn $ ppShow $ HS.parseDecl "foreign import ccall \"wrapper\" fname :: Spec -> IO (FunPtr Spec)" | ||
413 | -- mapM_ (putStrLn . HS.prettyPrint) (importWrapper $ sigf hsTransSig d) | ||
414 | putStrLn $ HS.prettyPrint $ | ||
415 | (HS.ForImp () (HS.CCall ()) Nothing (Just "wrapper") | ||
416 | (HS.Ident () wrapname) | ||
417 | (TyFun () | ||
418 | (TyCon () (UnQual () (HS.Ident () signame))) | ||
419 | (TyApp () | ||
420 | (TyCon () (UnQual () (HS.Ident () "IO"))) | ||
421 | (TyParen () funptr)))) | ||
422 | putStrLn $ HS.prettyPrint $ | ||
423 | (HS.ForImp () (HS.CCall ()) Nothing (Just settername) | ||
424 | (HS.Ident () settername) | ||
425 | (TyFun () | ||
426 | funptr | ||
427 | (TyApp () | ||
428 | (TyCon () (UnQual () (HS.Ident () "IO"))) | ||
429 | (TyCon () (Special () (UnitCon ())))))) | ||
430 | |||
431 | |||
432 | htyp -> putStr $ commented $ "Unsupported haskell type: " ++ HS.prettyPrint htyp | ||
309 | 433 | ||
310 | 434 | ||
311 | readComments fname = parseComments 1 1 <$> readFile fname | 435 | readComments fname = parseComments 1 1 <$> readFile fname |
@@ -319,6 +443,7 @@ findCloser !d (l,c,b) [] = (l,c,b) | |||
319 | 443 | ||
320 | mkComment lin no str = (lin,no,str) | 444 | mkComment lin no str = (lin,no,str) |
321 | 445 | ||
446 | parseComments :: (Num col, Num lin) => lin -> col -> [Char] -> [(lin, col, [Char])] | ||
322 | parseComments !lin !col = \case | 447 | parseComments !lin !col = \case |
323 | ('/':'*':cs) -> let (lcnt,col',bcnt) = findCloser 1 (0,col,0) cs | 448 | ('/':'*':cs) -> let (lcnt,col',bcnt) = findCloser 1 (0,col,0) cs |
324 | (xs,cs') = splitAt bcnt cs | 449 | (xs,cs') = splitAt bcnt cs |
@@ -348,6 +473,7 @@ usage args = do | |||
348 | return (hopts,cargs,fname) | 473 | return (hopts,cargs,fname) |
349 | _ -> Nothing | 474 | _ -> Nothing |
350 | 475 | ||
476 | (<&>) :: Functor f => f a -> (a -> b) -> f b | ||
351 | m <&> f = fmap f m | 477 | m <&> f = fmap f m |
352 | 478 | ||
353 | main :: IO () | 479 | main :: IO () |