{-# LANGUAGE OverloadedStrings #-}
module Foreign.Lua.Module
( requirehs
, preloadhs
, addfield
, addfunction
, create
, Module (..)
, Field (..)
, registerModule
, preloadModule
, pushModule
, render
)
where
import Control.Monad (unless, forM_)
import Data.Text (Text)
import Foreign.Lua.Call (HaskellFunction)
import Foreign.Lua.Core
import Foreign.Lua.Push (pushText)
import Foreign.Lua.Types (Pushable, push)
import Foreign.Lua.FunctionCalling
( ToHaskellFunction
, pushHaskellFunction
)
import qualified Data.Text as T
import qualified Foreign.Lua.Call as Call
requirehs :: String -> Lua () -> Lua ()
requirehs :: String -> Lua () -> Lua ()
requirehs String
modname Lua ()
pushMod = do
StackIndex -> String -> Lua ()
getfield StackIndex
registryindex String
loadedTableRegistryField
StackIndex -> String -> Lua ()
getfield StackIndex
stackTop String
modname
Bool
alreadyLoaded <- StackIndex -> Lua Bool
toboolean StackIndex
stackTop
Bool -> Lua () -> Lua ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
alreadyLoaded (Lua () -> Lua ()) -> Lua () -> Lua ()
forall a b. (a -> b) -> a -> b
$ do
StackIndex -> Lua ()
pop StackIndex
1
Lua ()
pushMod
StackIndex -> Lua ()
pushvalue StackIndex
stackTop
StackIndex -> String -> Lua ()
setfield (CInt -> StackIndex
nthFromTop CInt
3) String
modname
StackIndex -> Lua ()
remove (CInt -> StackIndex
nthFromTop CInt
2)
preloadhs :: String -> Lua NumResults -> Lua ()
preloadhs :: String -> Lua NumResults -> Lua ()
preloadhs String
name Lua NumResults
pushMod = do
StackIndex -> String -> Lua ()
getfield StackIndex
registryindex String
preloadTableRegistryField
Lua NumResults -> Lua ()
forall a. ToHaskellFunction a => a -> Lua ()
pushHaskellFunction Lua NumResults
pushMod
StackIndex -> String -> Lua ()
setfield (CInt -> StackIndex
nthFromTop CInt
2) String
name
StackIndex -> Lua ()
pop StackIndex
1
addfield :: Pushable a => String -> a -> Lua ()
addfield :: String -> a -> Lua ()
addfield String
name a
value = do
String -> Lua ()
forall a. Pushable a => a -> Lua ()
push String
name
a -> Lua ()
forall a. Pushable a => a -> Lua ()
push a
value
StackIndex -> Lua ()
rawset (CInt -> StackIndex
nthFromTop CInt
3)
addfunction :: ToHaskellFunction a => String -> a -> Lua ()
addfunction :: String -> a -> Lua ()
addfunction String
name a
fn = do
String -> Lua ()
forall a. Pushable a => a -> Lua ()
push String
name
a -> Lua ()
forall a. ToHaskellFunction a => a -> Lua ()
pushHaskellFunction a
fn
StackIndex -> Lua ()
rawset (CInt -> StackIndex
nthFromTop CInt
3)
create :: Lua ()
create :: Lua ()
create = Lua ()
newtable
data Module = Module
{ Module -> Text
moduleName :: Text
, Module -> Text
moduleDescription :: Text
, Module -> [Field]
moduleFields :: [Field]
, Module -> [(Text, HaskellFunction)]
moduleFunctions :: [(Text, HaskellFunction)]
}
data Field = Field
{ Field -> Text
fieldName :: Text
, Field -> Text
fieldDescription :: Text
, Field -> Lua ()
fieldPushValue :: Lua ()
}
registerModule :: Module -> Lua ()
registerModule :: Module -> Lua ()
registerModule Module
mdl =
String -> Lua () -> Lua ()
requirehs (Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Module -> Text
moduleName Module
mdl) (Module -> Lua ()
pushModule Module
mdl)
preloadModule :: Module -> Lua ()
preloadModule :: Module -> Lua ()
preloadModule Module
mdl =
String -> Lua NumResults -> Lua ()
preloadhs (Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Module -> Text
moduleName Module
mdl) (Lua NumResults -> Lua ()) -> Lua NumResults -> Lua ()
forall a b. (a -> b) -> a -> b
$ do
Module -> Lua ()
pushModule Module
mdl
NumResults -> Lua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> NumResults
NumResults CInt
1)
pushModule :: Module -> Lua ()
pushModule :: Module -> Lua ()
pushModule Module
mdl = do
Lua ()
create
[(Text, HaskellFunction)]
-> ((Text, HaskellFunction) -> Lua ()) -> Lua ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Module -> [(Text, HaskellFunction)]
moduleFunctions Module
mdl) (((Text, HaskellFunction) -> Lua ()) -> Lua ())
-> ((Text, HaskellFunction) -> Lua ()) -> Lua ()
forall a b. (a -> b) -> a -> b
$ \(Text
name, HaskellFunction
fn) -> do
Pusher Text
pushText Text
name
HaskellFunction -> Lua ()
Call.pushHaskellFunction HaskellFunction
fn
StackIndex -> Lua ()
rawset (CInt -> StackIndex
nthFromTop CInt
3)
render :: Module -> Text
render :: Module -> Text
render Module
mdl =
let fields :: [Field]
fields = Module -> [Field]
moduleFields Module
mdl
in [Text] -> Text
T.unlines
[ Text
"# " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Module -> Text
moduleName Module
mdl
, Text
""
, Module -> Text
moduleDescription Module
mdl
, if [Field] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Module -> [Field]
moduleFields Module
mdl) then Text
"" else [Field] -> Text
renderFields [Field]
fields
, Text
"## Functions"
, Text
""
]
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
"\n"
(((Text, HaskellFunction) -> Text)
-> [(Text, HaskellFunction)] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map ((Text -> HaskellFunction -> Text)
-> (Text, HaskellFunction) -> Text
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Text -> HaskellFunction -> Text
renderFunctionDoc) (Module -> [(Text, HaskellFunction)]
moduleFunctions Module
mdl))
renderFunctionDoc :: Text
-> HaskellFunction
-> Text
renderFunctionDoc :: Text -> HaskellFunction -> Text
renderFunctionDoc Text
name HaskellFunction
fn =
case HaskellFunction -> Maybe FunctionDoc
Call.functionDoc HaskellFunction
fn of
Maybe FunctionDoc
Nothing -> Text
""
Just FunctionDoc
fnDoc -> Text -> [Text] -> Text
T.intercalate Text
"\n"
[ Text
"### " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionDoc -> Text
renderFunctionParams FunctionDoc
fnDoc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"
, Text
""
, FunctionDoc -> Text
Call.render FunctionDoc
fnDoc
]
renderFunctionParams :: Call.FunctionDoc -> Text
renderFunctionParams :: FunctionDoc -> Text
renderFunctionParams FunctionDoc
fd =
Text -> [Text] -> Text
T.intercalate Text
", "
([Text] -> Text)
-> ([ParameterDoc] -> [Text]) -> [ParameterDoc] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ParameterDoc -> Text) -> [ParameterDoc] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map ParameterDoc -> Text
Call.parameterName
([ParameterDoc] -> Text) -> [ParameterDoc] -> Text
forall a b. (a -> b) -> a -> b
$ FunctionDoc -> [ParameterDoc]
Call.parameterDocs FunctionDoc
fd
renderFields :: [Field] -> Text
renderFields :: [Field] -> Text
renderFields [Field]
fs =
if [Field] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Field]
fs
then Text
forall a. Monoid a => a
mempty
else [Text] -> Text
T.unlines ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ (Field -> Text) -> [Field] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Field -> Text
renderField [Field]
fs
renderField :: Field -> Text
renderField :: Field -> Text
renderField Field
f =
Text
"### " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Field -> Text
fieldName Field
f Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Field -> Text
fieldDescription Field
f Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"