roshask-0.2: src/executable/FieldImports.hs
{-# LANGUAGE OverloadedStrings #-}
-- | Analyze a MsgType to determine the module imports needed for the
-- message field types.
module FieldImports (genImports) where
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Char (toUpper)
import Data.List (foldl')
import Data.Set (Set, singleton)
import qualified Data.Set as S
import Types
genImports :: ByteString -> [ByteString] -> [MsgType] -> ByteString
genImports pkgPath pkgMsgs fieldTypes =
B.concat $ concatMap (\i -> ["import ", i, "\n"])
(S.toList (allImports fieldTypes))
where getDeps = typeDependency pkgPath pkgMsgs
allImports = foldl' ((. getDeps) . flip S.union) S.empty
intImport, wordImport, vectorDeps :: Set ByteString
intImport = singleton "qualified Data.Int as Int"
wordImport = singleton "qualified Data.Word as Word"
vectorDeps = S.fromList [ "qualified Data.Vector.Storable as V" ]
-- Generate a 'Set' of modules to be imported for the specified
-- 'MsgType'. The first argument is the package of the message type
-- currently being generated, the second argument is a list of all the
-- messages defined in that package (which can be referred to with
-- unqualified names), the third is the 'MsgType' to generate imports
-- for.
typeDependency :: ByteString -> [ByteString] -> MsgType -> Set ByteString
typeDependency _ _ RBool = wordImport
typeDependency _ _ RInt8 = intImport
typeDependency _ _ RChar = intImport
typeDependency _ _ RUInt8 = wordImport
typeDependency _ _ RByte = wordImport
typeDependency _ _ RInt16 = intImport
typeDependency _ _ RUInt16 = wordImport
typeDependency _ _ RUInt32 = wordImport
typeDependency _ _ RUInt64 = wordImport
typeDependency _ _ RInt64 = intImport
typeDependency _ _ RTime = singleton "Ros.Internal.RosTypes"
typeDependency _ _ RDuration = singleton "Ros.Internal.RosTypes"
typeDependency p m (RFixedArray _ t) = S.union vectorDeps $
typeDependency p m t
typeDependency p m (RVarArray t) = S.union vectorDeps $
typeDependency p m t
typeDependency _ _ (RUserType "Header") =
S.fromList ["qualified Ros.Std_msgs.Header as Header",
"Ros.Internal.Msg.HeaderSupport"]
typeDependency p m (RUserType ut) = if elem ut m
then singleton $
B.concat ["qualified ", p, ut,
" as ", ut]
else path2Module ut
typeDependency _ _ _ = S.empty
-- Non built-in types are either in the specified package or in the
-- Ros.Std_msgs namespace. If a package path is given, then it is
-- converted to a Haskell hierarchical module name and prefixed by
-- "Ros.".
path2Module :: ByteString -> Set ByteString
path2Module p
| B.elem '/' p = singleton $
B.concat ["qualified Ros.",
B.intercalate "." . map cap $ parts,
" as ", last parts]
| otherwise = singleton $
B.concat ["qualified Ros.Std_msgs.", p, " as ", p]
where cap s = B.cons (toUpper (B.head s)) (B.tail s)
parts = B.split '/' p