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