{-# 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