module Foreign.Lua.Util
( getglobal'
, setglobal'
, run
, runEither
, raiseError
, Optional (Optional, fromOptional)
, peekEither
, peekRead
, popValue
) where
import Control.Exception (bracket, try)
import Data.List (groupBy)
import Foreign.Lua.Core (Lua, NumResults, StackIndex)
import Foreign.Lua.Types (Peekable, Pushable)
import Text.Read (readMaybe)
import qualified Control.Monad.Catch as Catch
import qualified Foreign.Lua.Core as Lua
import qualified Foreign.Lua.Types as Lua
run :: Lua a -> IO a
run :: Lua a -> IO a
run = (IO State
Lua.newstate IO State -> (State -> IO ()) -> (State -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
`bracket` State -> IO ()
Lua.close) ((State -> IO a) -> IO a)
-> (Lua a -> State -> IO a) -> Lua a -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (State -> Lua a -> IO a) -> Lua a -> State -> IO a
forall a b c. (a -> b -> c) -> b -> a -> c
flip State -> Lua a -> IO a
forall a. State -> Lua a -> IO a
Lua.runWith (Lua a -> State -> IO a)
-> (Lua a -> Lua a) -> Lua a -> State -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lua a -> Lua a
forall (m :: * -> *) a. MonadMask m => m a -> m a
Catch.mask_
runEither :: Lua a -> IO (Either Lua.Exception a)
runEither :: Lua a -> IO (Either Exception a)
runEither = IO a -> IO (Either Exception a)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO a -> IO (Either Exception a))
-> (Lua a -> IO a) -> Lua a -> IO (Either Exception a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lua a -> IO a
forall a. Lua a -> IO a
run
getglobal' :: String -> Lua ()
getglobal' :: String -> Lua ()
getglobal' = [String] -> Lua ()
getnested ([String] -> Lua ()) -> (String -> [String]) -> String -> Lua ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitdot
setglobal' :: String -> Lua ()
setglobal' :: String -> Lua ()
setglobal' s :: String
s =
case [String] -> [String]
forall a. [a] -> [a]
reverse (String -> [String]
splitdot String
s) of
[] ->
() -> Lua ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
[_] ->
String -> Lua ()
Lua.setglobal String
s
(lastField :: String
lastField : xs :: [String]
xs) -> do
[String] -> Lua ()
getnested ([String] -> [String]
forall a. [a] -> [a]
reverse [String]
xs)
StackIndex -> Lua ()
Lua.pushvalue (CInt -> StackIndex
Lua.nthFromTop 2)
StackIndex -> String -> Lua ()
Lua.setfield (CInt -> StackIndex
Lua.nthFromTop 2) String
lastField
StackIndex -> Lua ()
Lua.pop 1
splitdot :: String -> [String]
splitdot :: String -> [String]
splitdot = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= ".") ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char -> Bool) -> String -> [String]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (\a :: Char
a b :: Char
b -> Char
a Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '.' Bool -> Bool -> Bool
&& Char
b Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '.')
getnested :: [String] -> Lua ()
getnested :: [String] -> Lua ()
getnested [] = () -> Lua ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
getnested (x :: String
x:xs :: [String]
xs) = do
String -> Lua ()
Lua.getglobal String
x
(String -> Lua ()) -> [String] -> Lua ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\a :: String
a -> StackIndex -> String -> Lua ()
Lua.getfield StackIndex
Lua.stackTop String
a Lua () -> Lua () -> Lua ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> StackIndex -> Lua ()
Lua.remove (CInt -> StackIndex
Lua.nthFromTop 2)) [String]
xs
raiseError :: Pushable a => a -> Lua NumResults
raiseError :: a -> Lua NumResults
raiseError e :: a
e = do
a -> Lua ()
forall a. Pushable a => a -> Lua ()
Lua.push a
e
Lua NumResults
Lua.error
{-# INLINABLE raiseError #-}
newtype Optional a = Optional { Optional a -> Maybe a
fromOptional :: Maybe a }
instance Peekable a => Peekable (Optional a) where
peek :: StackIndex -> Lua (Optional a)
peek idx :: StackIndex
idx = do
Bool
noValue <- StackIndex -> Lua Bool
Lua.isnoneornil StackIndex
idx
if Bool
noValue
then Optional a -> Lua (Optional a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Optional a -> Lua (Optional a)) -> Optional a -> Lua (Optional a)
forall a b. (a -> b) -> a -> b
$ Maybe a -> Optional a
forall a. Maybe a -> Optional a
Optional Maybe a
forall a. Maybe a
Nothing
else Maybe a -> Optional a
forall a. Maybe a -> Optional a
Optional (Maybe a -> Optional a) -> (a -> Maybe a) -> a -> Optional a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe a
forall a. a -> Maybe a
Just (a -> Optional a) -> Lua a -> Lua (Optional a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua a
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx
instance Pushable a => Pushable (Optional a) where
push :: Optional a -> Lua ()
push (Optional Nothing) = Lua ()
Lua.pushnil
push (Optional (Just x :: a
x)) = a -> Lua ()
forall a. Pushable a => a -> Lua ()
Lua.push a
x
peekRead :: Read a => StackIndex -> Lua a
peekRead :: StackIndex -> Lua a
peekRead idx :: StackIndex
idx = do
String
s <- StackIndex -> Lua String
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx
case String -> Maybe a
forall a. Read a => String -> Maybe a
readMaybe String
s of
Just x :: a
x -> a -> Lua a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
Nothing -> String -> Lua a
forall a. String -> Lua a
Lua.throwException ("Could not read: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s)
peekEither :: Peekable a => StackIndex -> Lua (Either String a)
peekEither :: StackIndex -> Lua (Either String a)
peekEither idx :: StackIndex
idx = (Exception -> Either String a)
-> (a -> Either String a) -> Either Exception a -> Either String a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Either String a
forall a b. a -> Either a b
Left (String -> Either String a)
-> (Exception -> String) -> Exception -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Exception -> String
Lua.exceptionMessage) a -> Either String a
forall a b. b -> Either a b
Right (Either Exception a -> Either String a)
-> Lua (Either Exception a) -> Lua (Either String a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
Lua a -> Lua (Either Exception a)
forall a. Lua a -> Lua (Either Exception a)
Lua.try (StackIndex -> Lua a
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
popValue :: Peekable a => Lua a
popValue :: Lua a
popValue = StackIndex -> Lua a
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
Lua.stackTop Lua a -> Lua () -> Lua a
forall (m :: * -> *) a b. MonadMask m => m a -> m b -> m a
`Catch.finally` StackIndex -> Lua ()
Lua.pop 1
{-# INLINABLE popValue #-}