{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : HsLua.Packaging.Documentation
Copyright   : © 2020-2026 Albert Krewinkel
License     : MIT
Maintainer  : Albert Krewinkel <tarleb@hslua.org>

Provides a function to print documentation if available.
-}
module HsLua.Packaging.Documentation
  ( -- * Setting and retrieving documentation
    getdocumentation
  , registerDocumentation
  , docsField
    -- * Documentation Types
  , ModuleDoc (..)
  , FunctionDoc (..)
  , DocumentationObject (..)
  , pushDocumentationObject
  , peekDocumentationObject
  , pushModuleDoc
  , peekModuleDoc
  , pushFunctionDoc
  , peekFunctionDoc
  , pushTypeDoc
  , peekTypeDoc
  -- * Creating documentation values
  , generateFunctionDocumentation
  , generateModuleDocumentation
  , generateTypeDocumentation
  ) where

import Data.Version (showVersion)
import HsLua.Core as Lua
import HsLua.Marshalling
import HsLua.ObjectOrientation (UDTypeGeneric (..))
import HsLua.Packaging.Types
import HsLua.Typing (pushTypeSpec)
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import qualified HsLua.Core.Utf8 as Utf8

-- | Pushes the documentation for the element at the given stack index.
-- Returns the type of the documentation object.
getdocumentation :: LuaError e => StackIndex -> LuaE e Lua.Type
getdocumentation :: forall e. LuaError e => StackIndex -> LuaE e Type
getdocumentation StackIndex
idx = do
  idx' <- StackIndex -> LuaE e StackIndex
forall e. StackIndex -> LuaE e StackIndex
absindex StackIndex
idx
  pushDocumentationTable
  pushvalue idx'
  rawget (nth 2) <* Lua.remove (nth 2)  -- remove documentation table

-- | Registers the object at the top of the stack as documentation for
-- the object at index @idx@. Pops the documentation of the stack.
registerDocumentation :: LuaError e
                      => StackIndex  -- ^ @idx@
                      -> LuaE e ()
registerDocumentation :: forall e. LuaError e => StackIndex -> LuaE e ()
registerDocumentation StackIndex
idx = do
  Int -> String -> LuaE e ()
forall e. LuaError e => Int -> String -> LuaE e ()
checkstack' Int
10 String
"registerDocumentation"  -- keep some buffer
  idx' <- StackIndex -> LuaE e StackIndex
forall e. StackIndex -> LuaE e StackIndex
absindex StackIndex
idx
  pushDocumentationTable
  pushvalue idx'    -- the documented object
  pushvalue (nth 3) -- documentation object
  rawset (nth 3)    -- add to docs table
  pop 2             -- docs table and documentation object

-- | Name of the registry field holding the documentation table. The
-- documentation table is indexed by the documented objects, like module
-- tables and functions, and contains documentation objects as values.
--
-- The table is an ephemeron table, i.e., an entry gets garbage
-- collected if the key is no longer reachable.
docsField :: Name
docsField :: Name
docsField = Name
"HsLua docs"

-- | Pushes the documentation table that's stored in the registry to the
-- top of the stack, creating it if necessary. The documentation table
-- is indexed by the documented objects, like module tables and
-- functions, and contains documentation strings as values.
--
-- The table is an ephemeron table, i.e., an entry gets garbage
-- collected if the key is no longer reachable.
pushDocumentationTable :: LuaError e => LuaE e ()
pushDocumentationTable :: forall e. LuaError e => LuaE e ()
pushDocumentationTable = StackIndex -> Name -> LuaE e Type
forall e. LuaError e => StackIndex -> Name -> LuaE e Type
Lua.getfield StackIndex
registryindex Name
docsField LuaE e Type -> (Type -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Type
Lua.TypeTable -> () -> LuaE e ()
forall a. a -> LuaE e a
forall (m :: * -> *) a. Monad m => a -> m a
return () -- documentation table already initialized
  Type
_ -> do
    Int -> LuaE e ()
forall e. Int -> LuaE e ()
pop Int
1            -- pop non-table value
    LuaE e ()
forall e. LuaE e ()
newtable         -- create documentation table
    ByteString -> LuaE e ()
forall e. ByteString -> LuaE e ()
pushstring ByteString
"k"   -- Make it an "ephemeron table" and..
    StackIndex -> Name -> LuaE e ()
forall e. LuaError e => StackIndex -> Name -> LuaE e ()
setfield (CInt -> StackIndex
nth CInt
2) Name
"__mode"  -- collect docs if documented object is GCed
    StackIndex -> LuaE e ()
forall e. StackIndex -> LuaE e ()
pushvalue StackIndex
top    -- add copy of table to registry
    StackIndex -> Name -> LuaE e ()
forall e. LuaError e => StackIndex -> Name -> LuaE e ()
setfield StackIndex
registryindex Name
docsField

--
-- Generating
--

-- | Generate documentation for a module.
generateModuleDocumentation :: Module e -> ModuleDoc
generateModuleDocumentation :: forall e. Module e -> ModuleDoc
generateModuleDocumentation Module e
mdl =
  let name :: Name
name = Module e -> Name
forall e. Module e -> Name
moduleName Module e
mdl
  in ModuleDoc
    { moduleDocName :: Text
moduleDocName = Name -> Text
nameToText Name
name
    , moduleDocDescription :: Text
moduleDocDescription = Module e -> Text
forall e. Module e -> Text
moduleDescription Module e
mdl
    , moduleDocFields :: [FieldDoc]
moduleDocFields = (Field e -> FieldDoc) -> [Field e] -> [FieldDoc]
forall a b. (a -> b) -> [a] -> [b]
map (Name -> Field e -> FieldDoc
forall e. Name -> Field e -> FieldDoc
generateFieldDocumentation Name
name) ([Field e] -> [FieldDoc]) -> [Field e] -> [FieldDoc]
forall a b. (a -> b) -> a -> b
$ Module e -> [Field e]
forall e. Module e -> [Field e]
moduleFields Module e
mdl
    , moduleDocFunctions :: [FunctionDoc]
moduleDocFunctions = (DocumentedFunction e -> FunctionDoc)
-> [DocumentedFunction e] -> [FunctionDoc]
forall a b. (a -> b) -> [a] -> [b]
map (Maybe Name -> DocumentedFunction e -> FunctionDoc
forall e. Maybe Name -> DocumentedFunction e -> FunctionDoc
generateFunctionDocumentation Maybe Name
forall a. Maybe a
Nothing) ([DocumentedFunction e] -> [FunctionDoc])
-> [DocumentedFunction e] -> [FunctionDoc]
forall a b. (a -> b) -> a -> b
$
                               Module e -> [DocumentedFunction e]
forall e. Module e -> [DocumentedFunction e]
moduleFunctions Module e
mdl
    , moduleDocTypes :: [TypeDoc]
moduleDocTypes = Module e -> [TypeDoc]
forall e. Module e -> [TypeDoc]
moduleTypeDocs Module e
mdl
    }

-- | Generate 'FieldDoc' documentation for a module field.
generateFieldDocumentation :: Name     -- ^ module name
                           -> Field e  -- ^ field that's part of the module
                           -> FieldDoc
generateFieldDocumentation :: forall e. Name -> Field e -> FieldDoc
generateFieldDocumentation Name
mdlName Field e
fld =
  let doc :: FieldDoc
doc = Field e -> FieldDoc
forall e. Field e -> FieldDoc
fieldDoc Field e
fld
  in FieldDoc
doc { fieldDocName = nameToText mdlName <> "." <> fieldDocName doc }

-- | Generate 'FunctionDoc' documentation for module functions.
generateFunctionDocumentation :: Maybe Name
                              -> DocumentedFunction e
                              -> FunctionDoc
generateFunctionDocumentation :: forall e. Maybe Name -> DocumentedFunction e -> FunctionDoc
generateFunctionDocumentation Maybe Name
name DocumentedFunction e
fn =
  let doc :: FunctionDoc
doc = DocumentedFunction e -> FunctionDoc
forall e. DocumentedFunction e -> FunctionDoc
functionDoc DocumentedFunction e
fn
      prefix :: Text
prefix = Text -> (Name -> Text) -> Maybe Name -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
forall a. Monoid a => a
mempty (\Name
n -> Name -> Text
nameToText Name
n Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".") Maybe Name
name
  in FunctionDoc
doc { funDocName = prefix <> funDocName doc }

-- | Generate documentation for a 'UDType'.
generateTypeDocumentation :: DocumentedType e a -> TypeDoc
generateTypeDocumentation :: forall e a. DocumentedType e a -> TypeDoc
generateTypeDocumentation DocumentedType e a
ty =
  let name :: Name
name = DocumentedType e a -> Name
forall e fn a. UDTypeGeneric e fn a -> Name
udName DocumentedType e a
ty
  in TypeDoc
  { typeDocName :: Text
typeDocName = Name -> Text
nameToText Name
name
  , typeDocDescription :: Text
typeDocDescription = Text
""
  , typeDocOperations :: [(Operation, FunctionDoc)]
typeDocOperations = []
  , typeDocMethods :: [FunctionDoc]
typeDocMethods = ((Name, DocumentedFunction e) -> FunctionDoc)
-> [(Name, DocumentedFunction e)] -> [FunctionDoc]
forall a b. (a -> b) -> [a] -> [b]
map (Maybe Name -> DocumentedFunction e -> FunctionDoc
forall e. Maybe Name -> DocumentedFunction e -> FunctionDoc
generateFunctionDocumentation (Name -> Maybe Name
forall a. a -> Maybe a
Just Name
name) (DocumentedFunction e -> FunctionDoc)
-> ((Name, DocumentedFunction e) -> DocumentedFunction e)
-> (Name, DocumentedFunction e)
-> FunctionDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name, DocumentedFunction e) -> DocumentedFunction e
forall a b. (a, b) -> b
snd) ([(Name, DocumentedFunction e)] -> [FunctionDoc])
-> [(Name, DocumentedFunction e)] -> [FunctionDoc]
forall a b. (a -> b) -> a -> b
$
                         Map Name (DocumentedFunction e) -> [(Name, DocumentedFunction e)]
forall k a. Map k a -> [(k, a)]
Map.toList (DocumentedType e a -> Map Name (DocumentedFunction e)
forall e fn a. UDTypeGeneric e fn a -> Map Name fn
udMethods DocumentedType e a
ty)
  }

-- | Convert a Lua name to UTF-8 text.
nameToText :: Name -> T.Text
nameToText :: Name -> Text
nameToText = ByteString -> Text
Utf8.toText (ByteString -> Text) -> (Name -> ByteString) -> Name -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> ByteString
fromName

--
-- Retrieving and pushing documentation
--

-- | The metatable name of documentation objecs
documentationObjectName :: Name
documentationObjectName :: Name
documentationObjectName = Name
"HsLua DocumentationObject"

-- | Pushes the metatable for documentation objects.
peekDocumentationObject :: Peeker e DocumentationObject
peekDocumentationObject :: forall e. Peeker e DocumentationObject
peekDocumentationObject StackIndex
idx = do
  LuaE e (Maybe DocumentationObject)
-> Peek e (Maybe DocumentationObject)
forall e a. LuaE e a -> Peek e a
liftLua (StackIndex -> Name -> LuaE e (Maybe DocumentationObject)
forall a e. StackIndex -> Name -> LuaE e (Maybe a)
fromuserdata StackIndex
idx Name
documentationObjectName) Peek e (Maybe DocumentationObject)
-> (Maybe DocumentationObject -> Peek e DocumentationObject)
-> Peek e DocumentationObject
forall a b. Peek e a -> (a -> Peek e b) -> Peek e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe DocumentationObject
Nothing  -> ByteString -> Peek e DocumentationObject
forall a e. ByteString -> Peek e a
failPeek ByteString
"Not a documentation object"
    Just DocumentationObject
doc -> DocumentationObject -> Peek e DocumentationObject
forall a. a -> Peek e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure DocumentationObject
doc

-- | Pushes a 'DocumentationObject' to the Lua stack.
pushDocumentationObject :: LuaError e => Pusher e DocumentationObject
pushDocumentationObject :: forall e. LuaError e => Pusher e DocumentationObject
pushDocumentationObject DocumentationObject
obj = do
  DocumentationObject -> Int -> LuaE e ()
forall a e. a -> Int -> LuaE e ()
newhsuserdatauv DocumentationObject
obj Int
0
  LuaE e ()
forall e. LuaError e => LuaE e ()
pushDocumentationObjectMT
  StackIndex -> LuaE e ()
forall e. StackIndex -> LuaE e ()
setmetatable (CInt -> StackIndex
nth CInt
2)

-- | Pushes the metatable for documentation objects.
pushDocumentationObjectMT :: LuaError e => LuaE e ()
pushDocumentationObjectMT :: forall e. LuaError e => LuaE e ()
pushDocumentationObjectMT = Name -> LuaE e Bool
forall e. Name -> LuaE e Bool
newudmetatable Name
documentationObjectName LuaE e Bool -> (Bool -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Bool
False -> () -> LuaE e ()
forall a. a -> LuaE e a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Bool
True -> do -- newly created metatable at the top of the stack
    -- Allow to "call" the documentation object, in which case it should
    -- return a Lua table that has all the relevant info.
    HaskellFunction e -> LuaE e ()
forall e. LuaError e => HaskellFunction e -> LuaE e ()
pushHaskellFunction (HaskellFunction e -> LuaE e ()) -> HaskellFunction e -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ do
      -- object is the first argument
      Peek e DocumentationObject -> LuaE e DocumentationObject
forall e a. LuaError e => Peek e a -> LuaE e a
forcePeek (Peeker e DocumentationObject
forall e. Peeker e DocumentationObject
peekDocumentationObject (CInt -> StackIndex
nthBottom CInt
1)) LuaE e DocumentationObject
-> (DocumentationObject -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        DocObjectFunction FunctionDoc
fn -> Pusher e FunctionDoc
forall e. LuaError e => Pusher e FunctionDoc
pushFunctionDocAsTable FunctionDoc
fn
        DocObjectModule ModuleDoc
mdl  -> Pusher e ModuleDoc
forall e. LuaError e => Pusher e ModuleDoc
pushModuleDocAsTable ModuleDoc
mdl
        DocObjectType TypeDoc
ty     -> Pusher e TypeDoc
forall e. LuaError e => Pusher e TypeDoc
pushTypeDocAsTable TypeDoc
ty
      NumResults -> HaskellFunction e
forall a. a -> LuaE e a
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> NumResults
NumResults CInt
1)
    StackIndex -> Name -> LuaE e ()
forall e. LuaError e => StackIndex -> Name -> LuaE e ()
setfield (CInt -> StackIndex
nth CInt
2) Name
"__call"

-- | Pushes the documentation of a module as userdata.
pushModuleDoc :: LuaError e => Pusher e ModuleDoc
pushModuleDoc :: forall e. LuaError e => Pusher e ModuleDoc
pushModuleDoc = Pusher e DocumentationObject
forall e. LuaError e => Pusher e DocumentationObject
pushDocumentationObject Pusher e DocumentationObject
-> (ModuleDoc -> DocumentationObject) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> DocumentationObject
DocObjectModule

-- | Retrieves a module documentation object from the Lua stack.
peekModuleDoc :: Peeker e ModuleDoc
peekModuleDoc :: forall e. Peeker e ModuleDoc
peekModuleDoc StackIndex
idx = Peeker e DocumentationObject
forall e. Peeker e DocumentationObject
peekDocumentationObject StackIndex
idx Peek e DocumentationObject
-> (DocumentationObject -> Peek e ModuleDoc) -> Peek e ModuleDoc
forall a b. Peek e a -> (a -> Peek e b) -> Peek e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  DocObjectModule ModuleDoc
mdldoc -> ModuleDoc -> Peek e ModuleDoc
forall a. a -> Peek e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ModuleDoc
mdldoc
  DocumentationObject
_ -> ByteString -> Peek e ModuleDoc
forall a e. ByteString -> Peek e a
failPeek ByteString
"Not a module documentation object"

-- | Pushes function documentation as userdata.
pushFunctionDoc :: LuaError e => Pusher e FunctionDoc
pushFunctionDoc :: forall e. LuaError e => Pusher e FunctionDoc
pushFunctionDoc = Pusher e DocumentationObject
forall e. LuaError e => Pusher e DocumentationObject
pushDocumentationObject Pusher e DocumentationObject
-> (FunctionDoc -> DocumentationObject) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> DocumentationObject
DocObjectFunction

-- | Retrieve function documentation from the Lua stack.
peekFunctionDoc :: Peeker e FunctionDoc
peekFunctionDoc :: forall e. Peeker e FunctionDoc
peekFunctionDoc StackIndex
idx = Peeker e DocumentationObject
forall e. Peeker e DocumentationObject
peekDocumentationObject StackIndex
idx Peek e DocumentationObject
-> (DocumentationObject -> Peek e FunctionDoc)
-> Peek e FunctionDoc
forall a b. Peek e a -> (a -> Peek e b) -> Peek e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  DocObjectFunction FunctionDoc
fndoc -> FunctionDoc -> Peek e FunctionDoc
forall a. a -> Peek e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FunctionDoc
fndoc
  DocumentationObject
_ -> ByteString -> Peek e FunctionDoc
forall a e. ByteString -> Peek e a
failPeek ByteString
"Not a function documentation"

-- | Pushes documentation type documentation as userdata.
pushTypeDoc :: LuaError e => Pusher e FunctionDoc
pushTypeDoc :: forall e. LuaError e => Pusher e FunctionDoc
pushTypeDoc = Pusher e DocumentationObject
forall e. LuaError e => Pusher e DocumentationObject
pushDocumentationObject Pusher e DocumentationObject
-> (FunctionDoc -> DocumentationObject) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> DocumentationObject
DocObjectFunction

-- | Retrieve function documentation from the Lua stack.
peekTypeDoc :: Peeker e TypeDoc
peekTypeDoc :: forall e. Peeker e TypeDoc
peekTypeDoc StackIndex
idx = Peeker e DocumentationObject
forall e. Peeker e DocumentationObject
peekDocumentationObject StackIndex
idx Peek e DocumentationObject
-> (DocumentationObject -> Peek e TypeDoc) -> Peek e TypeDoc
forall a b. Peek e a -> (a -> Peek e b) -> Peek e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  DocObjectType TypeDoc
tydoc -> TypeDoc -> Peek e TypeDoc
forall a. a -> Peek e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TypeDoc
tydoc
  DocumentationObject
_ -> ByteString -> Peek e TypeDoc
forall a e. ByteString -> Peek e a
failPeek ByteString
"Not a type documentation"


-- | Pushes the documentation of a module as a table with string fields
-- @name@ and @description@.
pushModuleDocAsTable :: LuaError e => Pusher e ModuleDoc
pushModuleDocAsTable :: forall e. LuaError e => Pusher e ModuleDoc
pushModuleDocAsTable = [(Name, ModuleDoc -> LuaE e ())] -> ModuleDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"name", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (ModuleDoc -> Text) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> Text
moduleDocName)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (ModuleDoc -> Text) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> Text
moduleDocDescription)
  , (Name
"fields", Pusher e FieldDoc -> [FieldDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e FieldDoc
forall e. LuaError e => Pusher e FieldDoc
pushFieldDocAsTable ([FieldDoc] -> LuaE e ())
-> (ModuleDoc -> [FieldDoc]) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> [FieldDoc]
moduleDocFields)
  , (Name
"functions", Pusher e FunctionDoc -> [FunctionDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e FunctionDoc
forall e. LuaError e => Pusher e FunctionDoc
pushFunctionDocAsTable ([FunctionDoc] -> LuaE e ())
-> (ModuleDoc -> [FunctionDoc]) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> [FunctionDoc]
moduleDocFunctions)
  , (Name
"types", Pusher e TypeDoc -> [TypeDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e TypeDoc
forall e. LuaError e => Pusher e TypeDoc
pushTypeDocAsTable ([TypeDoc] -> LuaE e ())
-> (ModuleDoc -> [TypeDoc]) -> ModuleDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleDoc -> [TypeDoc]
moduleDocTypes)
  ]

-- | Pushes the documentation of a field as a table with string fields
-- @name@ and @description@.
pushFieldDocAsTable :: LuaError e => Pusher e FieldDoc
pushFieldDocAsTable :: forall e. LuaError e => Pusher e FieldDoc
pushFieldDocAsTable = [(Name, FieldDoc -> LuaE e ())] -> FieldDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"name", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (FieldDoc -> Text) -> FieldDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldDoc -> Text
fieldDocName)
  , (Name
"type", TypeSpec -> LuaE e ()
forall e. LuaError e => TypeSpec -> LuaE e ()
pushTypeSpec (TypeSpec -> LuaE e ())
-> (FieldDoc -> TypeSpec) -> FieldDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldDoc -> TypeSpec
fieldDocType)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (FieldDoc -> Text) -> FieldDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldDoc -> Text
fieldDocDescription)
  ]

-- | Pushes the documentation of a function as a table with string
-- fields, @name@, @description@, and @since@, sequence field
-- @parameters@, and sequence or string field @results@.
pushFunctionDocAsTable :: LuaError e => Pusher e FunctionDoc
pushFunctionDocAsTable :: forall e. LuaError e => Pusher e FunctionDoc
pushFunctionDocAsTable = [(Name, FunctionDoc -> LuaE e ())] -> FunctionDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"name", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (FunctionDoc -> Text) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> Text
funDocName)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (FunctionDoc -> Text) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> Text
funDocDescription)
  , (Name
"parameters", Pusher e ParameterDoc -> [ParameterDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e ParameterDoc
forall e. LuaError e => Pusher e ParameterDoc
pushParameterDocAsTable ([ParameterDoc] -> LuaE e ())
-> (FunctionDoc -> [ParameterDoc]) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> [ParameterDoc]
funDocParameters)
  , (Name
"results", Pusher e ResultsDoc
forall e. LuaError e => Pusher e ResultsDoc
pushResultsDoc Pusher e ResultsDoc
-> (FunctionDoc -> ResultsDoc) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> ResultsDoc
funDocResults)
  , (Name
"since", LuaE e () -> (Version -> LuaE e ()) -> Maybe Version -> LuaE e ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe LuaE e ()
forall e. LuaE e ()
pushnil (String -> LuaE e ()
forall e. String -> LuaE e ()
pushString (String -> LuaE e ())
-> (Version -> String) -> Version -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> String
showVersion) (Maybe Version -> LuaE e ())
-> (FunctionDoc -> Maybe Version) -> FunctionDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionDoc -> Maybe Version
funDocSince)
  ]

-- | Pushes the documentation of a parameter as a table with boolean
-- field @optional@ and string fields @name@, @type@, and @description@.
pushParameterDocAsTable :: LuaError e => Pusher e ParameterDoc
pushParameterDocAsTable :: forall e. LuaError e => Pusher e ParameterDoc
pushParameterDocAsTable = [(Name, ParameterDoc -> LuaE e ())] -> ParameterDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"name", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text
-> (ParameterDoc -> Text) -> ParameterDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParameterDoc -> Text
parameterName)
  , (Name
"type", TypeSpec -> LuaE e ()
forall e. LuaError e => TypeSpec -> LuaE e ()
pushTypeSpec (TypeSpec -> LuaE e ())
-> (ParameterDoc -> TypeSpec) -> ParameterDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParameterDoc -> TypeSpec
parameterType)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text
-> (ParameterDoc -> Text) -> ParameterDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParameterDoc -> Text
parameterDescription)
  , (Name
"optional", Pusher e Bool
forall e. Pusher e Bool
pushBool Pusher e Bool
-> (ParameterDoc -> Bool) -> ParameterDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParameterDoc -> Bool
parameterIsOptional)
  ]

-- | Pushes a the documentation for a function's return values as either
-- a simple string, or as a sequence of tables with @type@ and
-- @description@ fields.
pushResultsDoc :: LuaError e => Pusher e ResultsDoc
pushResultsDoc :: forall e. LuaError e => Pusher e ResultsDoc
pushResultsDoc = \case
  ResultsDocMult Text
desc -> Pusher e Text
forall e. Pusher e Text
pushText Text
desc
  ResultsDocList [ResultValueDoc]
resultDocs -> Pusher e ResultValueDoc -> [ResultValueDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e ResultValueDoc
forall e. LuaError e => Pusher e ResultValueDoc
pushResultValueDoc [ResultValueDoc]
resultDocs

-- | Pushes the documentation of a single result value as a table with
-- fields @type@ and @description@.
pushResultValueDoc :: LuaError e => Pusher e ResultValueDoc
pushResultValueDoc :: forall e. LuaError e => Pusher e ResultValueDoc
pushResultValueDoc = [(Name, ResultValueDoc -> LuaE e ())]
-> ResultValueDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"type", TypeSpec -> LuaE e ()
forall e. LuaError e => TypeSpec -> LuaE e ()
pushTypeSpec (TypeSpec -> LuaE e ())
-> (ResultValueDoc -> TypeSpec) -> ResultValueDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResultValueDoc -> TypeSpec
resultValueType)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text
-> (ResultValueDoc -> Text) -> ResultValueDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResultValueDoc -> Text
resultValueDescription)
  ]

-- | Pushes the documentation of a UDType as a Lua table.
pushTypeDocAsTable :: LuaError e => Pusher e TypeDoc
pushTypeDocAsTable :: forall e. LuaError e => Pusher e TypeDoc
pushTypeDocAsTable = [(Name, TypeDoc -> LuaE e ())] -> TypeDoc -> LuaE e ()
forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"name", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (TypeDoc -> Text) -> TypeDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypeDoc -> Text
typeDocName)
  , (Name
"description", Pusher e Text
forall e. Pusher e Text
pushText Pusher e Text -> (TypeDoc -> Text) -> TypeDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypeDoc -> Text
typeDocDescription)
  , (Name
"methods", Pusher e FunctionDoc -> [FunctionDoc] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList Pusher e FunctionDoc
forall e. LuaError e => Pusher e FunctionDoc
pushFunctionDoc ([FunctionDoc] -> LuaE e ())
-> (TypeDoc -> [FunctionDoc]) -> TypeDoc -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypeDoc -> [FunctionDoc]
typeDocMethods)
  ]