mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-14 10:09:48 +00:00
c697fb7f7c
It is added an INTERNALLIB and not installed. It will be used by kyua. This is a preparatory commit for D24103. Reviewed by: emaste Obtained from: CheriBSD Sponsored by: DARPA
905 lines
24 KiB
C++
905 lines
24 KiB
C++
// Copyright 2011 Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// * Neither the name of Google Inc. nor the names of its contributors
|
|
// may be used to endorse or promote products derived from this software
|
|
// without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
extern "C" {
|
|
#include <unistd.h>
|
|
}
|
|
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
#include "c_gate.hpp"
|
|
#include "exceptions.hpp"
|
|
#include "state.ipp"
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
/// Wrapper around lua_getglobal to run in a protected environment.
|
|
///
|
|
/// \pre stack(-1) is the name of the global to get.
|
|
/// \post stack(-1) is the value of the global.
|
|
///
|
|
/// \param state The Lua C API state.
|
|
///
|
|
/// \return The number of return values pushed onto the stack.
|
|
static int
|
|
protected_getglobal(lua_State* state)
|
|
{
|
|
lua_getglobal(state, lua_tostring(state, -1));
|
|
return 1;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_gettable to run in a protected environment.
|
|
///
|
|
/// \pre stack(-2) is the table to get the element from.
|
|
/// \pre stack(-1) is the table index.
|
|
/// \post stack(-1) is the value of stack(-2)[stack(-1)].
|
|
///
|
|
/// \param state The Lua C API state.
|
|
///
|
|
/// \return The number of return values pushed onto the stack.
|
|
static int
|
|
protected_gettable(lua_State* state)
|
|
{
|
|
lua_gettable(state, -2);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_next to run in a protected environment.
|
|
///
|
|
/// \pre stack(-2) is the table to get the next element from.
|
|
/// \pre stack(-1) is the last processed key.
|
|
/// \post stack(-1) is the value of next(stack(-2), stack(-1)).
|
|
///
|
|
/// \param state The Lua C API state.
|
|
///
|
|
/// \return The number of return values pushed onto the stack.
|
|
static int
|
|
protected_next(lua_State* state)
|
|
{
|
|
const int more = lua_next(state, -2) != 0;
|
|
lua_pushboolean(state, more);
|
|
return more ? 3 : 1;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_setglobal to run in a protected environment.
|
|
///
|
|
/// \pre stack(-2) is the name of the global to set.
|
|
/// \pre stack(-1) is the value to set the global to.
|
|
///
|
|
/// \param state The Lua C API state.
|
|
///
|
|
/// \return The number of return values pushed onto the stack.
|
|
static int
|
|
protected_setglobal(lua_State* state)
|
|
{
|
|
lua_setglobal(state, lua_tostring(state, -2));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_settable to run in a protected environment.
|
|
///
|
|
/// \pre stack(-3) is the table to set the element into.
|
|
/// \pre stack(-2) is the table index.
|
|
/// \pre stack(-1) is the value to set.
|
|
///
|
|
/// \param state The Lua C API state.
|
|
///
|
|
/// \return The number of return values pushed onto the stack.
|
|
static int
|
|
protected_settable(lua_State* state)
|
|
{
|
|
lua_settable(state, -3);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/// Calls a C++ Lua function from a C calling environment.
|
|
///
|
|
/// Any errors reported by the C++ function are caught and reported to the
|
|
/// caller as Lua errors.
|
|
///
|
|
/// \param function The C++ function to call.
|
|
/// \param raw_state The raw Lua state.
|
|
///
|
|
/// \return The number of return values pushed onto the Lua stack by the
|
|
/// function.
|
|
static int
|
|
call_cxx_function_from_c(lutok::cxx_function function,
|
|
lua_State* raw_state) throw()
|
|
{
|
|
char error_buf[1024];
|
|
|
|
try {
|
|
lutok::state state = lutok::state_c_gate::connect(raw_state);
|
|
return function(state);
|
|
} catch (const std::exception& e) {
|
|
std::strncpy(error_buf, e.what(), sizeof(error_buf));
|
|
} catch (...) {
|
|
std::strncpy(error_buf, "Unhandled exception in Lua C++ hook",
|
|
sizeof(error_buf));
|
|
}
|
|
error_buf[sizeof(error_buf) - 1] = '\0';
|
|
// We raise the Lua error from outside the try/catch context and we use
|
|
// a stack-based buffer to hold the message to ensure that we do not leak
|
|
// any C++ objects (and, as a likely result, memory) when Lua performs its
|
|
// longjmp.
|
|
return luaL_error(raw_state, "%s", error_buf);
|
|
}
|
|
|
|
|
|
/// Lua glue to call a C++ closure.
|
|
///
|
|
/// This Lua binding is actually a closure that we have constructed from the
|
|
/// state.push_cxx_closure() method. The closure contains the same upvalues
|
|
/// provided by the user plus an extra upvalue that contains the address of the
|
|
/// C++ function we have to call. All we do here is safely delegate the
|
|
/// execution to the wrapped C++ closure.
|
|
///
|
|
/// \param raw_state The Lua C API state.
|
|
///
|
|
/// \return The number of return values of the called closure.
|
|
static int
|
|
cxx_closure_trampoline(lua_State* raw_state)
|
|
{
|
|
lutok::state state = lutok::state_c_gate::connect(raw_state);
|
|
|
|
int nupvalues;
|
|
{
|
|
lua_Debug debug;
|
|
lua_getstack(raw_state, 0, &debug);
|
|
lua_getinfo(raw_state, "u", &debug);
|
|
nupvalues = debug.nups;
|
|
}
|
|
|
|
lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >(
|
|
state.upvalue_index(nupvalues));
|
|
return call_cxx_function_from_c(*function, raw_state);
|
|
}
|
|
|
|
|
|
/// Lua glue to call a C++ function.
|
|
///
|
|
/// This Lua binding is actually a closure that we have constructed from the
|
|
/// state.push_cxx_function() method. The closure has a single upvalue that
|
|
/// contains the address of the C++ function we have to call. All we do here is
|
|
/// safely delegate the execution to the wrapped C++ function.
|
|
///
|
|
/// \param raw_state The Lua C API state.
|
|
///
|
|
/// \return The number of return values of the called function.
|
|
static int
|
|
cxx_function_trampoline(lua_State* raw_state)
|
|
{
|
|
lutok::state state = lutok::state_c_gate::connect(raw_state);
|
|
lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >(
|
|
state.upvalue_index(1));
|
|
return call_cxx_function_from_c(*function, raw_state);
|
|
}
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
const int lutok::registry_index = LUA_REGISTRYINDEX;
|
|
|
|
|
|
/// Internal implementation for lutok::state.
|
|
struct lutok::state::impl {
|
|
/// The Lua internal state.
|
|
lua_State* lua_state;
|
|
|
|
/// Whether we own the state or not (to decide if we close it).
|
|
bool owned;
|
|
|
|
/// Constructor.
|
|
///
|
|
/// \param lua_ The Lua internal state.
|
|
/// \param owned_ Whether we own the state or not.
|
|
impl(lua_State* lua_, bool owned_) :
|
|
lua_state(lua_),
|
|
owned(owned_)
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
/// Initializes the Lua state.
|
|
///
|
|
/// You must share the same state object alongside the lifetime of your Lua
|
|
/// session. As soon as the object is destroyed, the session is terminated.
|
|
lutok::state::state(void)
|
|
{
|
|
lua_State* lua = luaL_newstate();
|
|
if (lua == NULL)
|
|
throw lutok::error("lua open failed");
|
|
_pimpl.reset(new impl(lua, true));
|
|
}
|
|
|
|
|
|
/// Initializes the Lua state from an existing raw state.
|
|
///
|
|
/// Instances constructed using this method do NOT own the raw state. This
|
|
/// means that, on exit, the state will not be destroyed.
|
|
///
|
|
/// \param raw_state_ The raw Lua state to wrap.
|
|
lutok::state::state(void* raw_state_) :
|
|
_pimpl(new impl(reinterpret_cast< lua_State* >(raw_state_), false))
|
|
{
|
|
}
|
|
|
|
|
|
/// Destructor for the Lua state.
|
|
///
|
|
/// Closes the session unless it has already been closed by calling the
|
|
/// close() method. It is recommended to explicitly close the session in the
|
|
/// code.
|
|
lutok::state::~state(void)
|
|
{
|
|
if (_pimpl->owned && _pimpl->lua_state != NULL)
|
|
close();
|
|
}
|
|
|
|
|
|
/// Terminates this Lua session.
|
|
///
|
|
/// It is recommended to call this instead of relying on the destructor to do
|
|
/// the cleanup, but it is not a requirement to use close().
|
|
///
|
|
/// \pre close() has not yet been called.
|
|
/// \pre The Lua stack is empty. This is not truly necessary but ensures that
|
|
/// our code is consistent and clears the stack explicitly.
|
|
void
|
|
lutok::state::close(void)
|
|
{
|
|
assert(_pimpl->lua_state != NULL);
|
|
assert(lua_gettop(_pimpl->lua_state) == 0);
|
|
lua_close(_pimpl->lua_state);
|
|
_pimpl->lua_state = NULL;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_getglobal.
|
|
///
|
|
/// \param name The second parameter to lua_getglobal.
|
|
///
|
|
/// \throw api_error If lua_getglobal fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
void
|
|
lutok::state::get_global(const std::string& name)
|
|
{
|
|
lua_pushcfunction(_pimpl->lua_state, protected_getglobal);
|
|
lua_pushstring(_pimpl->lua_state, name.c_str());
|
|
if (lua_pcall(_pimpl->lua_state, 1, 1, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_getglobal");
|
|
}
|
|
|
|
|
|
/// Pushes a reference to the global table onto the stack.
|
|
///
|
|
/// This is a wrapper around the incompatible differences between Lua 5.1 and
|
|
/// 5.2 to access to the globals table.
|
|
///
|
|
/// \post state(-1) Contains the reference to the globals table.
|
|
void
|
|
lutok::state::get_global_table(void)
|
|
{
|
|
#if LUA_VERSION_NUM >= 502
|
|
lua_pushvalue(_pimpl->lua_state, registry_index);
|
|
lua_pushinteger(_pimpl->lua_state, LUA_RIDX_GLOBALS);
|
|
lua_gettable(_pimpl->lua_state, -2);
|
|
lua_remove(_pimpl->lua_state, -2);
|
|
#else
|
|
lua_pushvalue(_pimpl->lua_state, LUA_GLOBALSINDEX);
|
|
#endif
|
|
}
|
|
|
|
|
|
/// Wrapper around luaL_getmetafield.
|
|
///
|
|
/// \param index The second parameter to luaL_getmetafield.
|
|
/// \param name The third parameter to luaL_getmetafield.
|
|
///
|
|
/// \return The return value of luaL_getmetafield.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
bool
|
|
lutok::state::get_metafield(const int index, const std::string& name)
|
|
{
|
|
return luaL_getmetafield(_pimpl->lua_state, index, name.c_str()) != 0;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_getmetatable.
|
|
///
|
|
/// \param index The second parameter to lua_getmetatable.
|
|
///
|
|
/// \return The return value of lua_getmetatable.
|
|
bool
|
|
lutok::state::get_metatable(const int index)
|
|
{
|
|
return lua_getmetatable(_pimpl->lua_state, index) != 0;
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_gettable.
|
|
///
|
|
/// \param index The second parameter to lua_gettable.
|
|
///
|
|
/// \throw api_error If lua_gettable fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
void
|
|
lutok::state::get_table(const int index)
|
|
{
|
|
assert(lua_gettop(_pimpl->lua_state) >= 2);
|
|
lua_pushcfunction(_pimpl->lua_state, protected_gettable);
|
|
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
|
|
lua_pushvalue(_pimpl->lua_state, -3);
|
|
if (lua_pcall(_pimpl->lua_state, 2, 1, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_gettable");
|
|
lua_remove(_pimpl->lua_state, -2);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_gettop.
|
|
///
|
|
/// \return The return value of lua_gettop.
|
|
int
|
|
lutok::state::get_top(void)
|
|
{
|
|
return lua_gettop(_pimpl->lua_state);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_insert.
|
|
///
|
|
/// \param index The second parameter to lua_insert.
|
|
void
|
|
lutok::state::insert(const int index)
|
|
{
|
|
lua_insert(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isboolean.
|
|
///
|
|
/// \param index The second parameter to lua_isboolean.
|
|
///
|
|
/// \return The return value of lua_isboolean.
|
|
bool
|
|
lutok::state::is_boolean(const int index)
|
|
{
|
|
return lua_isboolean(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isfunction.
|
|
///
|
|
/// \param index The second parameter to lua_isfunction.
|
|
///
|
|
/// \return The return value of lua_isfunction.
|
|
bool
|
|
lutok::state::is_function(const int index)
|
|
{
|
|
return lua_isfunction(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isnil.
|
|
///
|
|
/// \param index The second parameter to lua_isnil.
|
|
///
|
|
/// \return The return value of lua_isnil.
|
|
bool
|
|
lutok::state::is_nil(const int index)
|
|
{
|
|
return lua_isnil(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isnumber.
|
|
///
|
|
/// \param index The second parameter to lua_isnumber.
|
|
///
|
|
/// \return The return value of lua_isnumber.
|
|
bool
|
|
lutok::state::is_number(const int index)
|
|
{
|
|
return lua_isnumber(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isstring.
|
|
///
|
|
/// \param index The second parameter to lua_isstring.
|
|
///
|
|
/// \return The return value of lua_isstring.
|
|
bool
|
|
lutok::state::is_string(const int index)
|
|
{
|
|
return lua_isstring(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_istable.
|
|
///
|
|
/// \param index The second parameter to lua_istable.
|
|
///
|
|
/// \return The return value of lua_istable.
|
|
bool
|
|
lutok::state::is_table(const int index)
|
|
{
|
|
return lua_istable(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_isuserdata.
|
|
///
|
|
/// \param index The second parameter to lua_isuserdata.
|
|
///
|
|
/// \return The return value of lua_isuserdata.
|
|
bool
|
|
lutok::state::is_userdata(const int index)
|
|
{
|
|
return lua_isuserdata(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around luaL_loadfile.
|
|
///
|
|
/// \param file The second parameter to luaL_loadfile.
|
|
///
|
|
/// \throw api_error If luaL_loadfile returns an error.
|
|
/// \throw file_not_found_error If the file cannot be accessed.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::load_file(const std::string& file)
|
|
{
|
|
if (::access(file.c_str(), R_OK) == -1)
|
|
throw lutok::file_not_found_error(file);
|
|
if (luaL_loadfile(_pimpl->lua_state, file.c_str()) != 0)
|
|
throw lutok::api_error::from_stack(*this, "luaL_loadfile");
|
|
}
|
|
|
|
|
|
/// Wrapper around luaL_loadstring.
|
|
///
|
|
/// \param str The second parameter to luaL_loadstring.
|
|
///
|
|
/// \throw api_error If luaL_loadstring returns an error.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::load_string(const std::string& str)
|
|
{
|
|
if (luaL_loadstring(_pimpl->lua_state, str.c_str()) != 0)
|
|
throw lutok::api_error::from_stack(*this, "luaL_loadstring");
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_newtable.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::new_table(void)
|
|
{
|
|
lua_newtable(_pimpl->lua_state);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_newuserdata.
|
|
///
|
|
/// This is internal. The public type-safe interface of this method should be
|
|
/// used instead.
|
|
///
|
|
/// \param size The second parameter to lua_newuserdata.
|
|
///
|
|
/// \return The return value of lua_newuserdata.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void*
|
|
lutok::state::new_userdata_voidp(const size_t size)
|
|
{
|
|
return lua_newuserdata(_pimpl->lua_state, size);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_next.
|
|
///
|
|
/// \param index The second parameter to lua_next.
|
|
///
|
|
/// \return True if there are more elements to process; false otherwise.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
bool
|
|
lutok::state::next(const int index)
|
|
{
|
|
assert(lua_istable(_pimpl->lua_state, index));
|
|
assert(lua_gettop(_pimpl->lua_state) >= 1);
|
|
lua_pushcfunction(_pimpl->lua_state, protected_next);
|
|
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
|
|
lua_pushvalue(_pimpl->lua_state, -3);
|
|
if (lua_pcall(_pimpl->lua_state, 2, LUA_MULTRET, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_next");
|
|
const bool more = lua_toboolean(_pimpl->lua_state, -1);
|
|
lua_pop(_pimpl->lua_state, 1);
|
|
if (more)
|
|
lua_remove(_pimpl->lua_state, -3);
|
|
else
|
|
lua_pop(_pimpl->lua_state, 1);
|
|
return more;
|
|
}
|
|
|
|
|
|
/// Wrapper around luaL_openlibs.
|
|
///
|
|
/// \throw api_error If luaL_openlibs fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::open_all(void)
|
|
{
|
|
luaL_openlibs(_pimpl->lua_state);
|
|
}
|
|
|
|
|
|
/// Wrapper around luaopen_base.
|
|
///
|
|
/// \throw api_error If luaopen_base fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::open_base(void)
|
|
{
|
|
lua_pushcfunction(_pimpl->lua_state, luaopen_base);
|
|
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "luaopen_base");
|
|
}
|
|
|
|
|
|
/// Wrapper around luaopen_string.
|
|
///
|
|
/// \throw api_error If luaopen_string fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::open_string(void)
|
|
{
|
|
#if LUA_VERSION_NUM >= 502
|
|
luaL_requiref(_pimpl->lua_state, LUA_STRLIBNAME, luaopen_string, 1);
|
|
lua_pop(_pimpl->lua_state, 1);
|
|
#else
|
|
lua_pushcfunction(_pimpl->lua_state, luaopen_string);
|
|
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "luaopen_string");
|
|
#endif
|
|
}
|
|
|
|
|
|
/// Wrapper around luaopen_table.
|
|
///
|
|
/// \throw api_error If luaopen_table fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::open_table(void)
|
|
{
|
|
#if LUA_VERSION_NUM >= 502
|
|
luaL_requiref(_pimpl->lua_state, LUA_TABLIBNAME, luaopen_table, 1);
|
|
lua_pop(_pimpl->lua_state, 1);
|
|
#else
|
|
lua_pushcfunction(_pimpl->lua_state, luaopen_table);
|
|
if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "luaopen_table");
|
|
#endif
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pcall.
|
|
///
|
|
/// \param nargs The second parameter to lua_pcall.
|
|
/// \param nresults The third parameter to lua_pcall.
|
|
/// \param errfunc The fourth parameter to lua_pcall.
|
|
///
|
|
/// \throw api_error If lua_pcall returns an error.
|
|
void
|
|
lutok::state::pcall(const int nargs, const int nresults, const int errfunc)
|
|
{
|
|
if (lua_pcall(_pimpl->lua_state, nargs, nresults, errfunc) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_pcall");
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pop.
|
|
///
|
|
/// \param count The second parameter to lua_pop.
|
|
void
|
|
lutok::state::pop(const int count)
|
|
{
|
|
assert(count <= lua_gettop(_pimpl->lua_state));
|
|
lua_pop(_pimpl->lua_state, count);
|
|
assert(lua_gettop(_pimpl->lua_state) >= 0);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushboolean.
|
|
///
|
|
/// \param value The second parameter to lua_pushboolean.
|
|
void
|
|
lutok::state::push_boolean(const bool value)
|
|
{
|
|
lua_pushboolean(_pimpl->lua_state, value ? 1 : 0);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushcclosure.
|
|
///
|
|
/// This is not a pure wrapper around lua_pushcclosure because this has to do
|
|
/// extra magic to allow passing C++ functions instead of plain C functions.
|
|
///
|
|
/// \param function The C++ function to be pushed as a closure.
|
|
/// \param nvalues The number of upvalues that the function receives.
|
|
void
|
|
lutok::state::push_cxx_closure(cxx_function function, const int nvalues)
|
|
{
|
|
cxx_function *data = static_cast< cxx_function* >(
|
|
lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function)));
|
|
*data = function;
|
|
lua_pushcclosure(_pimpl->lua_state, cxx_closure_trampoline, nvalues + 1);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushcfunction.
|
|
///
|
|
/// This is not a pure wrapper around lua_pushcfunction because this has to do
|
|
/// extra magic to allow passing C++ functions instead of plain C functions.
|
|
///
|
|
/// \param function The C++ function to be pushed.
|
|
void
|
|
lutok::state::push_cxx_function(cxx_function function)
|
|
{
|
|
cxx_function *data = static_cast< cxx_function* >(
|
|
lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function)));
|
|
*data = function;
|
|
lua_pushcclosure(_pimpl->lua_state, cxx_function_trampoline, 1);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushinteger.
|
|
///
|
|
/// \param value The second parameter to lua_pushinteger.
|
|
void
|
|
lutok::state::push_integer(const int value)
|
|
{
|
|
lua_pushinteger(_pimpl->lua_state, value);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushnil.
|
|
void
|
|
lutok::state::push_nil(void)
|
|
{
|
|
lua_pushnil(_pimpl->lua_state);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushstring.
|
|
///
|
|
/// \param str The second parameter to lua_pushstring.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void
|
|
lutok::state::push_string(const std::string& str)
|
|
{
|
|
lua_pushstring(_pimpl->lua_state, str.c_str());
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_pushvalue.
|
|
///
|
|
/// \param index The second parameter to lua_pushvalue.
|
|
void
|
|
lutok::state::push_value(const int index)
|
|
{
|
|
lua_pushvalue(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_rawget.
|
|
///
|
|
/// \param index The second parameter to lua_rawget.
|
|
void
|
|
lutok::state::raw_get(const int index)
|
|
{
|
|
lua_rawget(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_rawset.
|
|
///
|
|
/// \param index The second parameter to lua_rawset.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
void
|
|
lutok::state::raw_set(const int index)
|
|
{
|
|
lua_rawset(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_setglobal.
|
|
///
|
|
/// \param name The second parameter to lua_setglobal.
|
|
///
|
|
/// \throw api_error If lua_setglobal fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
void
|
|
lutok::state::set_global(const std::string& name)
|
|
{
|
|
lua_pushcfunction(_pimpl->lua_state, protected_setglobal);
|
|
lua_pushstring(_pimpl->lua_state, name.c_str());
|
|
lua_pushvalue(_pimpl->lua_state, -3);
|
|
if (lua_pcall(_pimpl->lua_state, 2, 0, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_setglobal");
|
|
lua_pop(_pimpl->lua_state, 1);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_setmetatable.
|
|
///
|
|
/// \param index The second parameter to lua_setmetatable.
|
|
void
|
|
lutok::state::set_metatable(const int index)
|
|
{
|
|
lua_setmetatable(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_settable.
|
|
///
|
|
/// \param index The second parameter to lua_settable.
|
|
///
|
|
/// \throw api_error If lua_settable fails.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory to manipulate
|
|
/// the Lua stack.
|
|
void
|
|
lutok::state::set_table(const int index)
|
|
{
|
|
lua_pushcfunction(_pimpl->lua_state, protected_settable);
|
|
lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index);
|
|
lua_pushvalue(_pimpl->lua_state, -4);
|
|
lua_pushvalue(_pimpl->lua_state, -4);
|
|
if (lua_pcall(_pimpl->lua_state, 3, 0, 0) != 0)
|
|
throw lutok::api_error::from_stack(*this, "lua_settable");
|
|
lua_pop(_pimpl->lua_state, 2);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_toboolean.
|
|
///
|
|
/// \param index The second parameter to lua_toboolean.
|
|
///
|
|
/// \return The return value of lua_toboolean.
|
|
bool
|
|
lutok::state::to_boolean(const int index)
|
|
{
|
|
assert(is_boolean(index));
|
|
return lua_toboolean(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_tointeger.
|
|
///
|
|
/// \param index The second parameter to lua_tointeger.
|
|
///
|
|
/// \return The return value of lua_tointeger.
|
|
long
|
|
lutok::state::to_integer(const int index)
|
|
{
|
|
assert(is_number(index));
|
|
return lua_tointeger(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_touserdata.
|
|
///
|
|
/// This is internal. The public type-safe interface of this method should be
|
|
/// used instead.
|
|
///
|
|
/// \param index The second parameter to lua_touserdata.
|
|
///
|
|
/// \return The return value of lua_touserdata.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
void*
|
|
lutok::state::to_userdata_voidp(const int index)
|
|
{
|
|
return lua_touserdata(_pimpl->lua_state, index);
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper around lua_tostring.
|
|
///
|
|
/// \param index The second parameter to lua_tostring.
|
|
///
|
|
/// \return The return value of lua_tostring.
|
|
///
|
|
/// \warning Terminates execution if there is not enough memory.
|
|
std::string
|
|
lutok::state::to_string(const int index)
|
|
{
|
|
assert(is_string(index));
|
|
const char *raw_string = lua_tostring(_pimpl->lua_state, index);
|
|
// Note that the creation of a string object below (explicit for clarity)
|
|
// implies that the raw string is duplicated and, henceforth, the string is
|
|
// safe even if the corresponding element is popped from the Lua stack.
|
|
return std::string(raw_string);
|
|
}
|
|
|
|
|
|
/// Wrapper around lua_upvalueindex.
|
|
///
|
|
/// \param index The first parameter to lua_upvalueindex.
|
|
///
|
|
/// \return The return value of lua_upvalueindex.
|
|
int
|
|
lutok::state::upvalue_index(const int index)
|
|
{
|
|
return lua_upvalueindex(index);
|
|
}
|
|
|
|
|
|
/// Gets the internal lua_State object.
|
|
///
|
|
/// \return The raw Lua state. This is returned as a void pointer to prevent
|
|
/// including the lua.hpp header file from our public interface. The only way
|
|
/// to call this method is by using the c_gate module, and c_gate takes care of
|
|
/// casting this object to the appropriate type.
|
|
void*
|
|
lutok::state::raw_state(void)
|
|
{
|
|
return _pimpl->lua_state;
|
|
}
|