    {-# LANGUAGE ExistentialQuantification #-}
    {-# LANGUAGE DeriveGeneric             #-}
    {-# LANGUAGE MultiWayIf                #-}
    {-# LANGUAGE OverloadedStrings         #-}
    {-# LANGUAGE ScopedTypeVariables       #-}
    -- Copyright 2022 United States Government as represented by the Administrator
    -- of the National Aeronautics and Space Administration. All Rights Reserved.
    --
    -- Disclaimers
    --
    -- Licensed under the Apache License, Version 2.0 (the "License"); you may
    -- not use this file except in compliance with the License. You may obtain a
    -- copy of the License at
    --
    --      https://www.apache.org/licenses/LICENSE-2.0
    --
    -- Unless required by applicable law or agreed to in writing, software
    -- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    -- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    -- License for the specific language governing permissions and limitations
    -- under the License.
    --
    -- | Create <https://www.ros.org/ Robot Operating System> (ROS) applications
    -- that subscribe to obtain data and call Copilot when new values arrive.
    --
    -- It is the user's responsibility to modify the generated Copilot/C/C++ code
    -- to deal with the monitors they'd like to implement, and the data they must
    -- manipulate.

    {- HLINT ignore "Functor law" -}
    module Command.ROSApp
        ( command
        , CommandOptions(..)
        , Node(Node)
        , ErrorCode
        )
      where

    -- External imports
    import           Control.Applicative  (liftA2, (<|>))
    import qualified Control.Exception    as E
    import           Control.Monad.Except (ExceptT (..), liftEither)
    import           Data.Aeson           (ToJSON (..))
    import           Data.Maybe           (fromMaybe, mapMaybe, maybeToList)
    import           GHC.Generics         (Generic)

    -- External imports: auxiliary
    import System.Directory.Extra (copyTemplate)

    import qualified Command.Standalone

    -- Internal imports: auxiliary
    import Command.Result (Result (..))

    -- Internal imports
    import Command.Common
    import Command.Errors     (ErrorCode, ErrorTriplet (..))
    import Command.VariableDB (Connection (..), InputDef (..), TopicDef (..),
                               TypeDef (..), VariableDB, findConnection, findInput,
                               findTopic, findType, findTypeByType)

    -- | Generate a new ROS application connected to Copilot.
    command :: CommandOptions -- ^ Options to the ROS backend.
            -> IO (Result ErrorCode)
    command :: CommandOptions -> IO (Result ErrorCode)
    command CommandOptions
    options = ExceptT ErrorTriplet IO () -> IO (Result ErrorCode)
    forall (m :: * -> *) a.
    Monad m =>
    ExceptT ErrorTriplet m a -> m (Result ErrorCode)
    processResult (ExceptT ErrorTriplet IO () -> IO (Result ErrorCode))
    -> ExceptT ErrorTriplet IO () -> IO (Result ErrorCode)
    forall a b. (a -> b) -> a -> b
    $ do
        -- Obtain template dir
        String
    templateDir <- Maybe String -> String -> ExceptT ErrorTriplet IO String
    forall e. Maybe String -> String -> ExceptT e IO String
    locateTemplateDir Maybe String
    mTemplateDir String
    "ros"

        Value
    templateVars <- Maybe String -> ExceptT ErrorTriplet IO Value
    parseTemplateVarsFile Maybe String
    templateVarsF

        AppData
    appData <- CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData
    command' CommandOptions
    options ExprPair
    functions

        let subst :: Value
    subst = Value -> Value -> Value
    mergeObjects (AppData -> Value
    forall a. ToJSON a => a -> Value
    toJSON AppData
    appData) Value
    templateVars

        -- Expand template
        IO (Either ErrorTriplet ()) -> ExceptT ErrorTriplet IO ()
    forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
    ExceptT (IO (Either ErrorTriplet ()) -> ExceptT ErrorTriplet IO ())
    -> IO (Either ErrorTriplet ()) -> ExceptT ErrorTriplet IO ()
    forall a b. (a -> b) -> a -> b
    $ (Either SomeException () -> Either ErrorTriplet ())
    -> IO (Either SomeException ()) -> IO (Either ErrorTriplet ())
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (ErrorTriplet -> Either SomeException () -> Either ErrorTriplet ()
    forall c b. c -> Either SomeException b -> Either c b
    makeLeftE ErrorTriplet
    cannotCopyTemplate) (IO (Either SomeException ()) -> IO (Either ErrorTriplet ()))
    -> IO (Either SomeException ()) -> IO (Either ErrorTriplet ())
    forall a b. (a -> b) -> a -> b
    $ IO () -> IO (Either SomeException ())
    forall e a. Exception e => IO a -> IO (Either e a)
    E.try (IO () -> IO (Either SomeException ()))
    -> IO () -> IO (Either SomeException ())
    forall a b. (a -> b) -> a -> b
    $
          String -> Value -> String -> IO ()
    copyTemplate String
    templateDir Value
    subst String
    targetDir

      where

        targetDir :: String
    targetDir     = CommandOptions -> String
    commandTargetDir CommandOptions
    options
        mTemplateDir :: Maybe String
    mTemplateDir  = CommandOptions -> Maybe String
    commandTemplateDir CommandOptions
    options
        functions :: ExprPair
    functions     = String -> ExprPair
    exprPair (CommandOptions -> String
    commandPropFormat CommandOptions
    options)
        templateVarsF :: Maybe String
    templateVarsF = CommandOptions -> Maybe String
    commandExtraVars CommandOptions
    options

    command' :: CommandOptions
             -> ExprPair
             -> ExceptT ErrorTriplet IO AppData
    command' :: CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData
    command' CommandOptions
    options (ExprPair ExprPairT a
    exprT) = do
        -- Open files needed to fill in details in the template.
        Maybe [String]
    vs    <- Maybe String -> ExceptT ErrorTriplet IO (Maybe [String])
    parseVariablesFile Maybe String
    varNameFile
        Maybe [String]
    rs    <- Maybe String -> ExceptT ErrorTriplet IO (Maybe [String])
    parseRequirementsListFile Maybe String
    handlersFile
        VariableDB
    varDB <- [String] -> ExceptT ErrorTriplet IO VariableDB
    openVarDBFilesWithDefault [String]
    varDBFile

        Maybe (Spec a)
    specT <- ExceptT ErrorTriplet IO (Maybe (Spec a))
    -> (String -> ExceptT ErrorTriplet IO (Maybe (Spec a)))
    -> Maybe String
    -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Maybe (Spec a) -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall a. a -> ExceptT ErrorTriplet IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Spec a)
    forall a. Maybe a
    Nothing) (\String
    e -> Spec a -> Maybe (Spec a)
    forall a. a -> Maybe a
    Just (Spec a -> Maybe (Spec a))
    -> ExceptT ErrorTriplet IO (Spec a)
    -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> ExceptT ErrorTriplet IO (Spec a)
    parseInputExpr' String
    e) Maybe String
    cExpr
        Maybe (Spec a)
    specF <- ExceptT ErrorTriplet IO (Maybe (Spec a))
    -> (String -> ExceptT ErrorTriplet IO (Maybe (Spec a)))
    -> Maybe String
    -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Maybe (Spec a) -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall a. a -> ExceptT ErrorTriplet IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Spec a)
    forall a. Maybe a
    Nothing) (\String
    f -> Spec a -> Maybe (Spec a)
    forall a. a -> Maybe a
    Just (Spec a -> Maybe (Spec a))
    -> ExceptT ErrorTriplet IO (Spec a)
    -> ExceptT ErrorTriplet IO (Maybe (Spec a))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> ExceptT ErrorTriplet IO (Spec a)
    parseInputFile' String
    f) Maybe String
    fp

        let spec :: Maybe (Spec a)
    spec = Maybe (Spec a)
    specT Maybe (Spec a) -> Maybe (Spec a) -> Maybe (Spec a)
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Maybe (Spec a)
    specF

        Either ErrorTriplet () -> ExceptT ErrorTriplet IO ()
    forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
    liftEither (Either ErrorTriplet () -> ExceptT ErrorTriplet IO ())
    -> Either ErrorTriplet () -> ExceptT ErrorTriplet IO ()
    forall a b. (a -> b) -> a -> b
    $ Maybe (Spec a)
    -> Maybe [String] -> Maybe [String] -> Either ErrorTriplet ()
    forall a.
    Maybe (Spec a)
    -> Maybe [String] -> Maybe [String] -> Either ErrorTriplet ()
    checkArguments Maybe (Spec a)
    spec Maybe [String]
    vs Maybe [String]
    rs

        Maybe AppData
    copilotM <- Maybe (ExceptT ErrorTriplet IO AppData)
    -> ExceptT ErrorTriplet IO (Maybe AppData)
    forall (t :: * -> *) (f :: * -> *) a.
    (Traversable t, Applicative f) =>
    t (f a) -> f (t a)
    forall (f :: * -> *) a. Applicative f => Maybe (f a) -> f (Maybe a)
    sequenceA (Maybe (ExceptT ErrorTriplet IO AppData)
     -> ExceptT ErrorTriplet IO (Maybe AppData))
    -> Maybe (ExceptT ErrorTriplet IO AppData)
    -> ExceptT ErrorTriplet IO (Maybe AppData)
    forall a b. (a -> b) -> a -> b
    $ (\Spec a
    spec' -> Spec a
    -> Maybe String -> Maybe String -> ExceptT ErrorTriplet IO AppData
    processSpec Spec a
    spec' Maybe String
    fp Maybe String
    cExpr) (Spec a -> ExceptT ErrorTriplet IO AppData)
    -> Maybe (Spec a) -> Maybe (ExceptT ErrorTriplet IO AppData)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (Spec a)
    spec

        let varNames :: [String]
    varNames = [String] -> Maybe [String] -> [String]
    forall a. a -> Maybe a -> a
    fromMaybe (Maybe (Spec a) -> [String]
    forall a. Maybe (Spec a) -> [String]
    specExtractExternalVariables Maybe (Spec a)
    spec) Maybe [String]
    vs
            monitors :: [(String, Maybe String)]
    monitors = [(String, Maybe String)]
    -> ([String] -> [(String, Maybe String)])
    -> Maybe [String]
    -> [(String, Maybe String)]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe
                         (Maybe (Spec a) -> [(String, Maybe String)]
    forall a. Maybe (Spec a) -> [(String, Maybe String)]
    specExtractHandlers Maybe (Spec a)
    spec)
                         ((String -> (String, Maybe String))
    -> [String] -> [(String, Maybe String)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\String
    x -> (String
    x, Maybe String
    forall a. Maybe a
    Nothing)))
                         Maybe [String]
    rs

        let appData :: AppData
    appData =
              [VarDecl]
    -> [Monitor] -> Maybe AppData -> [Node] -> [VarDecl] -> AppData
    AppData [VarDecl]
    variables [Monitor]
    monitors' Maybe AppData
    copilotM [Node]
    testingAdditionalApps [VarDecl]
    testingVars

            variables :: [VarDecl]
    variables = (String -> Maybe VarDecl) -> [String] -> [VarDecl]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (VariableDB -> String -> Maybe VarDecl
    variableMap VariableDB
    varDB) [String]
    varNames
            monitors' :: [Monitor]
    monitors' = ((String, Maybe String) -> Maybe Monitor)
    -> [(String, Maybe String)] -> [Monitor]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (VariableDB -> (String, Maybe String) -> Maybe Monitor
    monitorMap VariableDB
    varDB) [(String, Maybe String)]
    monitors

            testingVars :: [VarDecl]
    testingVars
              | [String] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    testingLimitedVars
              = [VarDecl]
    variables
              | Bool
    otherwise
              = (VarDecl -> Bool) -> [VarDecl] -> [VarDecl]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\VarDecl
    x -> VarDecl -> String
    varDeclName VarDecl
    x String -> [String] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [String]
    testingLimitedVars) [VarDecl]
    variables

        AppData -> ExceptT ErrorTriplet IO AppData
    forall a. a -> ExceptT ErrorTriplet IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return AppData
    appData

      where

        cExpr :: Maybe String
    cExpr          = CommandOptions -> Maybe String
    commandConditionExpr CommandOptions
    options
        fp :: Maybe String
    fp             = CommandOptions -> Maybe String
    commandInputFile CommandOptions
    options
        varNameFile :: Maybe String
    varNameFile    = CommandOptions -> Maybe String
    commandVariables CommandOptions
    options
        varDBFile :: [String]
    varDBFile      = Maybe String -> [String]
    forall a. Maybe a -> [a]
    maybeToList (Maybe String -> [String]) -> Maybe String -> [String]
    forall a b. (a -> b) -> a -> b
    $ CommandOptions -> Maybe String
    commandVariableDB CommandOptions
    options
        handlersFile :: Maybe String
    handlersFile   = CommandOptions -> Maybe String
    commandHandlers CommandOptions
    options
        formatName :: String
    formatName     = CommandOptions -> String
    commandFormat CommandOptions
    options
        propFormatName :: String
    propFormatName = CommandOptions -> String
    commandPropFormat CommandOptions
    options
        propVia :: Maybe String
    propVia        = CommandOptions -> Maybe String
    commandPropVia CommandOptions
    options

        parseInputExpr' :: String -> ExceptT ErrorTriplet IO (Spec a)
    parseInputExpr' String
    e =
          String
    -> String
    -> Maybe String
    -> ExprPairT a
    -> ExceptT ErrorTriplet IO (Spec a)
    forall a.
    String
    -> String
    -> Maybe String
    -> ExprPairT a
    -> ExceptT ErrorTriplet IO (Spec a)
    parseInputExpr String
    e String
    propFormatName Maybe String
    propVia ExprPairT a
    exprT

        parseInputFile' :: String -> ExceptT ErrorTriplet IO (Spec a)
    parseInputFile' String
    f =
          String
    -> String
    -> String
    -> Maybe String
    -> ExprPairT a
    -> ExceptT ErrorTriplet IO (Spec a)
    forall a.
    String
    -> String
    -> String
    -> Maybe String
    -> ExprPairT a
    -> ExceptT ErrorTriplet IO (Spec a)
    parseInputFile String
    f String
    formatName String
    propFormatName Maybe String
    propVia ExprPairT a
    exprT

        processSpec :: Spec a
    -> Maybe String -> Maybe String -> ExceptT ErrorTriplet IO AppData
    processSpec Spec a
    spec' Maybe String
    expr' Maybe String
    fp' =
          Maybe String
    -> Maybe String
    -> String
    -> [(String, String)]
    -> ExprPairT a
    -> Spec a
    -> ExceptT ErrorTriplet IO AppData
    forall a.
    Maybe String
    -> Maybe String
    -> String
    -> [(String, String)]
    -> ExprPairT a
    -> Spec a
    -> ExceptT ErrorTriplet IO AppData
    Command.Standalone.commandLogic Maybe String
    expr' Maybe String
    fp' String
    "copilot" [] ExprPairT a
    exprT Spec a
    spec'

        testingAdditionalApps :: [Node]
    testingAdditionalApps = CommandOptions -> [Node]
    commandTestingApps CommandOptions
    options
        testingLimitedVars :: [String]
    testingLimitedVars    = CommandOptions -> [String]
    commandTestingVars CommandOptions
    options

    -- ** Argument processing

    -- | Options used to customize the conversion of specifications to ROS
    -- applications.
    data CommandOptions = CommandOptions
      { CommandOptions -> Maybe String
    commandConditionExpr :: Maybe String   -- ^ Trigger condition.
      , CommandOptions -> Maybe String
    commandInputFile   :: Maybe FilePath -- ^ Input specification file.
      , CommandOptions -> String
    commandTargetDir   :: FilePath       -- ^ Target directory where the
                                             -- application should be created.
      , CommandOptions -> Maybe String
    commandTemplateDir :: Maybe FilePath -- ^ Directory where the template is
                                             -- to be found.
      , CommandOptions -> Maybe String
    commandVariables   :: Maybe FilePath -- ^ File containing a list of
                                             -- variables to make available to
                                             -- Copilot.
      , CommandOptions -> Maybe String
    commandVariableDB  :: Maybe FilePath -- ^ File containing a list of known
                                             -- variables with their types and the
                                             -- message IDs they can be obtained
                                             -- from.
      , CommandOptions -> Maybe String
    commandHandlers    :: Maybe FilePath -- ^ File containing a list of
                                             -- handlers used in the Copilot
                                             -- specification. The handlers are
                                             -- assumed to receive no arguments.
      , CommandOptions -> String
    commandFormat      :: String         -- ^ Format of the input file.
      , CommandOptions -> String
    commandPropFormat  :: String         -- ^ Format used for input properties.
      , CommandOptions -> Maybe String
    commandPropVia     :: Maybe String   -- ^ Use external command to
                                             -- pre-process system properties.
      , CommandOptions -> Maybe String
    commandExtraVars   :: Maybe FilePath -- ^ File containing additional
                                             -- variables to make available to the
                                             -- template.
      , CommandOptions -> [Node]
    commandTestingApps :: [Node]         -- ^ Additional applications to turn
                                             -- on during testing.
      , CommandOptions -> [String]
    commandTestingVars :: [String]       -- ^ Limited list of variables to use
                                             -- for testing.
      }

    -- | Return the variable information needed to generate declarations
    -- and subscriptions for a given variable name and variable database.
    variableMap :: VariableDB
                -> String
                -> Maybe VarDecl
    variableMap :: VariableDB -> String -> Maybe VarDecl
    variableMap VariableDB
    varDB String
    varName = do
      InputDef
    inputDef <- VariableDB -> String -> Maybe InputDef
    findInput VariableDB
    varDB String
    varName
      String
    mid      <- Connection -> String
    connectionTopic (Connection -> String) -> Maybe Connection -> Maybe String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> InputDef -> String -> Maybe Connection
    findConnection InputDef
    inputDef String
    "ros/message"
      TopicDef
    topicDef <- VariableDB -> String -> String -> Maybe TopicDef
    findTopic VariableDB
    varDB String
    "ros/message" String
    mid
      String
    typeVar' <- Maybe String
    -> (TypeDef -> Maybe String) -> Maybe TypeDef -> Maybe String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe
                    (InputDef -> Maybe String
    inputType InputDef
    inputDef)
                    (String -> Maybe String
    forall a. a -> Maybe a
    Just (String -> Maybe String)
    -> (TypeDef -> String) -> TypeDef -> Maybe String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TypeDef -> String
    typeToType)
                    (VariableDB -> String -> String -> String -> Maybe TypeDef
    findType VariableDB
    varDB String
    varName String
    "ros/variable" String
    "C")
      let typeMsg' :: String
    typeMsg' = String -> Maybe String -> String
    forall a. a -> Maybe a -> a
    fromMaybe
                       (TopicDef -> String
    topicType TopicDef
    topicDef)
                       (TypeDef -> String
    typeFromType (TypeDef -> String) -> Maybe TypeDef -> Maybe String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> VariableDB -> String -> String -> String -> Maybe TypeDef
    findType VariableDB
    varDB String
    varName String
    "ros/message" String
    "C")
      VarDecl -> Maybe VarDecl
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (VarDecl -> Maybe VarDecl) -> VarDecl -> Maybe VarDecl
    forall a b. (a -> b) -> a -> b
    $ String -> String -> String -> String -> String -> VarDecl
    VarDecl String
    varName String
    typeVar' String
    mid String
    typeMsg' (String -> String
    randomBaseType String
    typeVar')

    -- | Return the monitor information needed to generate declarations and
    -- publishers for the given monitor info, and variable database.
    monitorMap :: VariableDB
               -> (String, Maybe String)
               -> Maybe Monitor
    monitorMap :: VariableDB -> (String, Maybe String) -> Maybe Monitor
    monitorMap VariableDB
    varDB (String
    monitorName, Maybe String
    Nothing) =
      Monitor -> Maybe Monitor
    forall a. a -> Maybe a
    Just (Monitor -> Maybe Monitor) -> Monitor -> Maybe Monitor
    forall a b. (a -> b) -> a -> b
    $ String -> Maybe String -> Maybe String -> Monitor
    Monitor String
    monitorName Maybe String
    forall a. Maybe a
    Nothing Maybe String
    forall a. Maybe a
    Nothing
    monitorMap VariableDB
    varDB (String
    monitorName, Just String
    ty) = do
      let ty1 :: String
    ty1 = String -> (TypeDef -> String) -> Maybe TypeDef -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe String
    ty TypeDef -> String
    typeFromType (Maybe TypeDef -> String) -> Maybe TypeDef -> String
    forall a b. (a -> b) -> a -> b
    $ VariableDB -> String -> String -> String -> Maybe TypeDef
    findTypeByType VariableDB
    varDB String
    "ros/variable" String
    "C" String
    ty
      String
    ty2 <- TypeDef -> String
    typeFromType (TypeDef -> String) -> Maybe TypeDef -> Maybe String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> VariableDB -> String -> String -> String -> Maybe TypeDef
    findTypeByType VariableDB
    varDB String
    "ros/message" String
    "C" String
    ty
      Monitor -> Maybe Monitor
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Monitor -> Maybe Monitor) -> Monitor -> Maybe Monitor
    forall a b. (a -> b) -> a -> b
    $ String -> Maybe String -> Maybe String -> Monitor
    Monitor String
    monitorName (String -> Maybe String
    forall a. a -> Maybe a
    Just String
    ty1) (String -> Maybe String
    forall a. a -> Maybe a
    Just String
    ty2)

    -- | The declaration of a variable in C, with a given type and name.
    data VarDecl = VarDecl
        { VarDecl -> String
    varDeclName    :: String
        , VarDecl -> String
    varDeclType    :: String
        , VarDecl -> String
    varDeclId      :: String
        , VarDecl -> String
    varDeclMsgType :: String
        , VarDecl -> String
    varDeclRandom  :: String
        }
      deriving (forall x. VarDecl -> Rep VarDecl x)
    -> (forall x. Rep VarDecl x -> VarDecl) -> Generic VarDecl
    forall x. Rep VarDecl x -> VarDecl
    forall x. VarDecl -> Rep VarDecl x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. VarDecl -> Rep VarDecl x
    from :: forall x. VarDecl -> Rep VarDecl x
    $cto :: forall x. Rep VarDecl x -> VarDecl
    to :: forall x. Rep VarDecl x -> VarDecl
    Generic

    instance ToJSON VarDecl

    -- | The name of a handler associated to each condition, and the type
    -- of value it receives, together with the type for the message.
    data Monitor = Monitor
        { Monitor -> String
    monitorName    :: String
        , Monitor -> Maybe String
    monitorType    :: Maybe String
        , Monitor -> Maybe String
    monitorMsgType :: Maybe String
        }
      deriving (forall x. Monitor -> Rep Monitor x)
    -> (forall x. Rep Monitor x -> Monitor) -> Generic Monitor
    forall x. Rep Monitor x -> Monitor
    forall x. Monitor -> Rep Monitor x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Monitor -> Rep Monitor x
    from :: forall x. Monitor -> Rep Monitor x
    $cto :: forall x. Rep Monitor x -> Monitor
    to :: forall x. Rep Monitor x -> Monitor
    Generic

    instance ToJSON Monitor

    -- | A package-qualified ROS 2 node name.
    data Node = Node
        { Node -> String
    nodePackage :: String
        , Node -> String
    nodeName    :: String
        }
      deriving (forall x. Node -> Rep Node x)
    -> (forall x. Rep Node x -> Node) -> Generic Node
    forall x. Rep Node x -> Node
    forall x. Node -> Rep Node x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Node -> Rep Node x
    from :: forall x. Node -> Rep Node x
    $cto :: forall x. Rep Node x -> Node
    to :: forall x. Rep Node x -> Node
    Generic

    instance ToJSON Node

    -- | Data that may be relevant to generate a ROS application.
    data AppData = AppData
      { AppData -> [VarDecl]
    variables        :: [VarDecl]
      , AppData -> [Monitor]
    monitors         :: [Monitor]
      , AppData -> Maybe AppData
    copilot          :: Maybe Command.Standalone.AppData
      , AppData -> [Node]
    testingApps      :: [Node]
      , AppData -> [VarDecl]
    testingVariables :: [VarDecl]
      }
      deriving ((forall x. AppData -> Rep AppData x)
    -> (forall x. Rep AppData x -> AppData) -> Generic AppData
    forall x. Rep AppData x -> AppData
    forall x. AppData -> Rep AppData x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. AppData -> Rep AppData x
    from :: forall x. AppData -> Rep AppData x
    $cto :: forall x. Rep AppData x -> AppData
    to :: forall x. Rep AppData x -> AppData
    Generic)

    instance ToJSON AppData

    -- | Name of the function to be used to generate random values of a given type.
    randomBaseType :: String -- ^ Type to generate random values of.
                   -> String
    randomBaseType :: String -> String
    randomBaseType String
    ty = case String
    ty of
      String
    "bool"     -> String
    "randomBool"
      String
    "uint8_t"  -> String
    "randomInt"
      String
    "uint16_t" -> String
    "randomInt"
      String
    "uint32_t" -> String
    "randomInt"
      String
    "uint64_t" -> String
    "randomInt"
      String
    "int8_t"   -> String
    "randomInt"
      String
    "int16_t"  -> String
    "randomInt"
      String
    "int32_t"  -> String
    "randomInt"
      String
    "int64_t"  -> String
    "randomInt"
      String
    "float"    -> String
    "randomFloat"
      String
    "double"   -> String
    "randomFloat"
      String
    def        -> String
    def