-- Copyright 2024 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.

-- | Typechecking of Copilot specs.
module Copilot.Language.Reify.Extra
    ( reifySpec )
  where

-- External imports
import qualified Copilot.Core                 as Core
import qualified Copilot.Language             as Copilot
import qualified Copilot.Language.Reify       as Copilot
import qualified Language.Haskell.Interpreter as HI

-- | Read a specification from a 'String' and reify it.
--
-- This function receives a list of possibly qualified imports.
reifySpec :: [(String, Maybe String)] -> String -> IO Core.Spec
reifySpec :: [(String, Maybe String)] -> String -> IO Spec
reifySpec [(String, Maybe String)]
imports String
specText = do
  coreSpecE <- InterpreterT IO Spec -> IO (Either InterpreterError Spec)
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
InterpreterT m a -> m (Either InterpreterError a)
HI.runInterpreter (InterpreterT IO Spec -> IO (Either InterpreterError Spec))
-> InterpreterT IO Spec -> IO (Either InterpreterError Spec)
forall a b. (a -> b) -> a -> b
$ do
                 [(String, Maybe String)] -> InterpreterT IO ()
forall (m :: * -> *).
MonadInterpreter m =>
[(String, Maybe String)] -> m ()
HI.setImportsQ [(String, Maybe String)]
imports
                 copilotSpec <- String -> Spec -> InterpreterT IO Spec
forall (m :: * -> *) a.
(MonadInterpreter m, Typeable a) =>
String -> a -> m a
HI.interpret String
specText (Spec
forall a. Typeable a => a
HI.as :: Copilot.Spec)
                 HI.liftIO $ Copilot.reify copilotSpec

  case coreSpecE of
    Left InterpreterError
err -> do String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Error: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ InterpreterError -> String
forall a. Show a => a -> String
show InterpreterError
err
                   String -> IO Spec
forall a. HasCallStack => String -> a
error (String -> IO Spec) -> String -> IO Spec
forall a b. (a -> b) -> a -> b
$ InterpreterError -> String
forall a. Show a => a -> String
show InterpreterError
err

    Right Spec
coreSpec -> Spec -> IO Spec
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Spec
coreSpec