-- import Foreign.C
-- import Foreign

-- | 'eval' provides a typesafe (to a limit) form of runtime evaluation
-- for Haskell -- a limited form of /runtime metaprogramming/. The
-- 'String' argument to 'eval' is a Haskell source fragment to evaluate
-- at rutime. @imps@ are a list of module names to use in the context of
-- the compiled value.
--
-- The value returned by 'eval' is constrained to be 'Typeable' --
-- meaning we can perform a /limited/ runtime typecheck, using the
-- 'dynload' function. One consequence of this is that the code must
-- evaluate to a monomorphic value (which will be wrapped in a
-- 'Dynamic').
--
-- If the evaluated code typechecks under the 'Typeable' constraints,
-- 'Just v' is returned. 'Nothing' indicates typechecking failed.
-- Typechecking may fail at two places: when compiling the argument, or
-- when typechecking the splice point. 'eval' resembles a
-- metaprogramming 'run' operator for /closed/ source fragments.
--
-- To evaluate polymorphic values you need to wrap them in data
-- structures using rank-N types.
--
-- Examples:
--
-- > do i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int)
-- >    when (isJust i) $ putStrLn (show (fromJust i))
--
eval :: Typeable a => String -> [Import] -> IO (Maybe a)
eval src imps = do
    pwd                <- getCurrentDirectory
    (cmdline,loadpath) <- getPaths
    tmpf               <- mkUniqueWith dynwrap src imps
    status             <- make tmpf cmdline
    m_rsrc <- case status of
        MakeSuccess _ obj -> do
           m_v <- dynload obj [pwd] loadpath symbol
           case m_v of LoadFailure _      -> return Nothing
                       LoadSuccess _ rsrc -> return $ Just rsrc
        MakeFailure err -> mapM_ putStrLn err >> return Nothing
    makeCleaner tmpf
    return m_rsrc

--
-- | 'eval_' is a variety of 'eval' with all the internal hooks
-- available. You are able to set any extra arguments to the compiler
-- (for example, optimisation flags) or dynamic loader, as well as
-- having any errors returned in an 'Either' type.
--
eval :: Typeable a => String -> [Import] -> IO (Maybe a)
eval src imps = do
    pwd                <- getCurrentDirectory
    (cmdline,loadpath) <- getPaths
    tmpf               <- mkUniqueWith dynwrap src imps
    status             <- make tmpf cmdline
    m_rsrc <- case status of
        MakeSuccess _ obj -> do
           m_v <- dynload obj [pwd] loadpath symbol
           case m_v of LoadFailure _      -> return Nothing
                       LoadSuccess _ rsrc -> return $ Just rsrc
        MakeFailure err -> mapM_ putStrLn err >> return Nothing
    makeCleaner tmpf
    return m_rsrc

--
-- | 'eval_' is a variety of 'eval' with all the internal hooks
-- available. You are able to set any extra arguments to the compiler
-- (for example, optimisation flags) or dynamic loader, as well as
-- having any errors returned in an 'Either' type.
--
eval src imps = do
    pwd                <- getCurrentDirectory
    (cmdline,loadpath) <- getPaths
    tmpf               <- mkUniqueWith dynwrap src imps
    status             <- make tmpf cmdline
    m_rsrc <- case status of
        MakeSuccess _ obj -> do
           m_v <- dynload obj [pwd] loadpath symbol
           case m_v of LoadFailure _      -> return Nothing
                       LoadSuccess _ rsrc -> return $ Just rsrc
        MakeFailure err -> mapM_ putStrLn err >> return Nothing
    makeCleaner tmpf
    return m_rsrc

--
-- | 'eval_' is a variety of 'eval' with all the internal hooks
-- available. You are able to set any extra arguments to the compiler
-- (for example, optimisation flags) or dynamic loader, as well as
-- having any errors returned in an 'Either' type.
--