    -- Copyright 2020 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.
    --
    -- | Generate C methods that process message dealing with the structs
    -- defined in a header file.
    --
    -- This module contains the pure conversion from CStructs into C code.
    -- Normally, this module would be implemented as a conversion between C ASTs,
    -- but we want to add comments to the generated code, which are not
    -- representable in the abstract syntax tree.
    module Language.Trans.CStructs2MsgHandlers where

    -- Internal imports: C AST representation.
    import qualified Language.C.AbsC as C ( TranslationUnit (MkTranslationUnit) )

    -- Internal imports: Copilot's own CStruct representation.
    import Language.Copilot.CStruct ( CStruct (cStructName) )

    import Language.Trans.CStruct2CopilotStruct ( camelCaseTypeName, mkCStruct )

    -- | Generate a C methods that process message dealing with the structs
    -- defined in a header file.
    cstructs2MsgHandlers :: C.TranslationUnit -> Either String String
    cstructs2MsgHandlers :: TranslationUnit -> Either String String
    cstructs2MsgHandlers (C.MkTranslationUnit [ExternalDeclaration]
    gs) =
      [String] -> String
    unlines ([String] -> String)
    -> Either String [String] -> Either String String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (ExternalDeclaration -> Either String String)
    -> [ExternalDeclaration] -> Either String [String]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ((CStruct -> String)
    -> Either String CStruct -> Either String String
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap CStruct -> String
    cstruct2MsgHandler (Either String CStruct -> Either String String)
    -> (ExternalDeclaration -> Either String CStruct)
    -> ExternalDeclaration
    -> Either String String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ExternalDeclaration -> Either String CStruct
    mkCStruct) [ExternalDeclaration]
    gs

    -- | Generate a C method that processes one message dealing with one
    -- kind of struct.
    cstruct2MsgHandler :: CStruct -> String
    cstruct2MsgHandler :: CStruct -> String
    cstruct2MsgHandler CStruct
    cstruct = [String] -> String
    unlines
        [ String
    nameCStruct String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    nameLocalVar String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ";"
        , String
    ""
        , String
    "/**"
        , String
    "* Make ICAROUS data available to Copilot and run monitors."
        , String
    "*/"
        , String
    "void COPILOT_Process" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    nameVar String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "Monitor(void)"
        , String
    "{"
        , String
    "  " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    nameCStruct String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "* msg;"
        , String
    "  msg = (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    nameCStruct  String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "*) COPILOTMsgPtr;"
        , String
    "  " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    nameLocalVar String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " = *msg;"
        , String
    ""
        , String
    "  // Run all copilot monitors."
        , String
    "  step();"
        , String
    "}"
        ]
      where
        nameCStruct :: String
    nameCStruct  = CStruct -> String
    cStructName CStruct
    cstruct
        nameVar :: String
    nameVar      = String -> String
    camelCaseTypeName String
    nameCStruct
        nameLocalVar :: String
    nameLocalVar = Char
    'm' Char -> String -> String
    forall a. a -> [a] -> [a]
    : Char
    'y' Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    camelCaseTypeName String
    nameCStruct