diff --git a/CMakeLists.txt b/CMakeLists.txt index b6cfe10d..16f6106b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,3 +251,7 @@ if (USE_WS OR USE_TEST) add_subdirectory(test) endif() endif() + +if (USE_LUAROCKS) + add_subdirectory(luarocks) +endif() diff --git a/luarocks/CMakeLists.txt b/luarocks/CMakeLists.txt new file mode 100644 index 00000000..4524afe9 --- /dev/null +++ b/luarocks/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# Author: Benjamin Sergeant +# Copyright (c) 2020 Machine Zone, Inc. All rights reserved. +# + +cmake_minimum_required (VERSION 3.4.1) +project (luarocks) + +# There's -Weverything too for clang +if (NOT WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") +endif() + +set (CMAKE_CXX_STANDARD 14) + +option(USE_TLS "Add TLS support" ON) + +include_directories(luarocks .) + +add_executable(luarocks main.cpp) + +include(FindLua) +find_package(lua REQUIRED) +target_link_libraries(luarocks ${LUA_LIBRARIES}) +target_include_directories(luarocks PRIVATE ${LUA_INCLUDE_DIR}) + +# library with the most dependencies come first +target_link_libraries(luarocks ixwebsocket) + +install(TARGETS luarocks RUNTIME DESTINATION bin) diff --git a/luarocks/LuaPlayer.hpp b/luarocks/LuaPlayer.hpp new file mode 100644 index 00000000..475a45a5 --- /dev/null +++ b/luarocks/LuaPlayer.hpp @@ -0,0 +1,93 @@ +#ifndef LUAPLAYER_HPP +#define LUAPLAYER_HPP + +#include +#include + +extern "C" +{ +#include "lua.h" +#include "lauxlib.h" +} + +#include "luawrapper.hpp" +#include "Player.hpp" + +Player* Player_new(lua_State* L) +{ + const char* name = luaL_checkstring(L, 1); + unsigned int health = luaL_checkinteger(L, 2); + return new Player(name, health); +} + +int Player_getName(lua_State* L) +{ + Player* player = luaW_check(L, 1); + lua_pushstring(L, player->getName()); + return 1; +} + +int Player_getHealth(lua_State* L) +{ + Player* player = luaW_check(L, 1); + lua_pushinteger(L, player->getHealth()); + return 1; +} + +int Player_setHealth(lua_State* L) +{ + Player* player = luaW_check(L, 1); + unsigned int health = luaL_checkinteger(L, 2); + player->setHealth(health); + return 0; +} + +int Player_heal(lua_State* L) +{ + Player* player = luaW_check(L, 1); + Player* target = luaW_check(L, 2); + player->heal(target); + return 0; +} + +int Player_say(lua_State* L) +{ + Player* player = luaW_check(L, 1); + const char* text = luaL_checkstring(L, 2); + player->say(text); + return 0; +} + +int Player_info(lua_State* L) +{ + Player* player = luaW_check(L, 1); + player->info(); + return 0; +} + +static luaL_Reg Player_table[] = { + { NULL, NULL } +}; + +static luaL_Reg Player_metatable[] = { + { "getName", Player_getName }, + { "getHealth", Player_getHealth }, + { "setHealth", Player_setHealth }, + { "heal", Player_heal }, + { "say", Player_say }, + { "info", Player_info }, + { NULL, NULL } +}; + +int luaopen_Player(lua_State* L) +{ + luaW_register(L, + "Player", + Player_table, + Player_metatable, + Player_new + ); + return 1; +} + +#endif // LUAPLAYER_HPP \ No newline at end of file diff --git a/luarocks/Player.hpp b/luarocks/Player.hpp new file mode 100644 index 00000000..d6b636e6 --- /dev/null +++ b/luarocks/Player.hpp @@ -0,0 +1,56 @@ +#ifndef PLAYER_HPP +#define PLAYER_HPP + +#include + +class Player +{ +public: + Player(const char* name, unsigned int health) : + m_Name(name), + m_Health(health) + { + } + + void info() + { + std::cout << m_Name << " have " << m_Health << " HP" << std::endl; + } + + void say(const char* text) + { + std::cout << m_Name << ": " << text << std::endl; + } + + void heal(Player* target) + { + target->setHealth(100); + } + + const char* getName() + { + return m_Name; + } + + unsigned int getHealth() + { + return m_Health; + } + + bool setHealth(unsigned int health) + { + if (health >= 0 && health <= 100) + { + m_Health = health; + return true; + } + else + return false; + } + +private: + const char* m_Name; + unsigned int m_Health; +}; + +#endif // PLAYER_HPP \ No newline at end of file diff --git a/luarocks/README.md b/luarocks/README.md new file mode 100644 index 00000000..caf566e0 --- /dev/null +++ b/luarocks/README.md @@ -0,0 +1,7 @@ +Wrapper based on https://github.com/LuaxY/cpp-lua + +Examples to build C++ +https://github.com/siffiejoe/lua-fltk4lua/blob/master/fltk4lua-scm-0.rockspec +https://github.com/lua4web/refser/blob/master/rockspecs/refser-0.2-1.rockspec + + diff --git a/luarocks/functions.hpp b/luarocks/functions.hpp new file mode 100644 index 00000000..d64b983d --- /dev/null +++ b/luarocks/functions.hpp @@ -0,0 +1,12 @@ +#ifndef FUNCTIONS_HPP +#define FUNCTIONS_HPP + +#include + +int lua_info(lua_State* L) +{ + std::cout << "C++ Lua v0.1" << std::endl << std::endl; + return 0; +} + +#endif // FUNCTIONS_HPP \ No newline at end of file diff --git a/luarocks/ia.lua b/luarocks/ia.lua new file mode 100644 index 00000000..d6891c04 --- /dev/null +++ b/luarocks/ia.lua @@ -0,0 +1,27 @@ +info() + +batman = Player.new("Batman", 100) +robin = Player.new("Robin", 100) + +robin:say("I'm the team lea...") +batman:say("Shut up!\n") + +print(batman:getName().." slap "..robin:getName()) +math.randomseed(os.time()) +robin:setHealth(math.random(20, 80)) +robin:info() + +print("\n") + +print(batman:getName().." heal "..robin:getName()) +batman:heal(robin) +robin:info() + +-- Robin: I'm the team lea... +-- Batman: Shut up! +-- +-- Batman slap Robin +-- Robin have 80 HP +-- +-- Batman heal Robin +-- Robin have 100 HP \ No newline at end of file diff --git a/luarocks/luawrapper.hpp b/luarocks/luawrapper.hpp new file mode 100644 index 00000000..a8f62f36 --- /dev/null +++ b/luarocks/luawrapper.hpp @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2010-2013 Alexander Ames + * Alexander.Ames@gmail.com + * See Copyright Notice at the end of this file + */ + +// API Summary: +// +// LuaWrapper is a library designed to help bridge the gab between Lua and +// C++. It is designed to be small (a single header file), simple, fast, +// and typesafe. It has no external dependencies, and does not need to be +// precompiled; the header can simply be dropped into a project and used +// immediately. It even supports class inheritance to a certain degree. Objects +// can be created in either Lua or C++, and passed back and forth. +// +// The main functions of interest are the following: +// luaW_is +// luaW_to +// luaW_check +// luaW_push +// luaW_register +// luaW_setfuncs +// luaW_extend +// luaW_hold +// luaW_release +// +// These functions allow you to manipulate arbitrary classes just like you +// would the primitive types (e.g. numbers or strings). If you are familiar +// with the normal Lua API the behavior of these functions should be very +// intuative. +// +// For more information see the README and the comments below + +#ifndef LUA_WRAPPER_H_ +#define LUA_WRAPPER_H_ + +// If you are linking against Lua compiled in C++, define LUAW_NO_EXTERN_C +#ifndef LUAW_NO_EXTERN_C +extern "C" +{ +#endif // LUAW_NO_EXTERN_C + +#include "lua.h" +#include "lauxlib.h" + +#ifndef LUAW_NO_EXTERN_C +} +#endif // LUAW_NO_EXTERN_C + +#define LUAW_POSTCTOR_KEY "__postctor" +#define LUAW_EXTENDS_KEY "__extends" +#define LUAW_STORAGE_KEY "storage" +#define LUAW_CACHE_KEY "cache" +#define LUAW_CACHE_METATABLE_KEY "cachemetatable" +#define LUAW_HOLDS_KEY "holds" +#define LUAW_WRAPPER_KEY "LuaWrapper" + +// A simple utility function to adjust a given index +// Useful for when a parameter index needs to be adjusted +// after pushing or popping things off the stack +inline int luaW_correctindex(lua_State* L, int index, int correction) +{ + return index < 0 ? index - correction : index; +} + +// These are the default allocator and deallocator. If you would prefer an +// alternative option, you may select a different function when registering +// your class. +template +T* luaW_defaultallocator(lua_State*) +{ + return new T(); +} +template +void luaW_defaultdeallocator(lua_State*, T* obj) +{ + delete obj; +} + +// The identifier function is responsible for pushing a value unique to each +// object on to the stack. Most of the time, this can simply be the address +// of the pointer, but sometimes that is not adaquate. For example, if you +// are using shared_ptr you would need to push the address of the object the +// shared_ptr represents, rather than the address of the shared_ptr itself. +template +void luaW_defaultidentifier(lua_State* L, T* obj) +{ + lua_pushlightuserdata(L, obj); +} + +// This class is what is used by LuaWrapper to contain the userdata. data +// stores a pointer to the object itself, and cast is used to cast toward the +// base class if there is one and it is necessary. Rather than use RTTI and +// typid to compare types, I use the clever trick of using the cast to compare +// types. Because there is at most one cast per type, I can use it to identify +// when and object is the type I want. This is only used internally. +struct luaW_Userdata +{ + luaW_Userdata(void* vptr = NULL, luaW_Userdata (*udcast)(const luaW_Userdata&) = NULL) + : data(vptr), cast(udcast) {} + void* data; + luaW_Userdata (*cast)(const luaW_Userdata&); +}; + +// This class cannot actually to be instantiated. It is used only hold the +// table name and other information. +template +class LuaWrapper +{ +public: + static const char* classname; + static void (*identifier)(lua_State*, T*); + static T* (*allocator)(lua_State*); + static void (*deallocator)(lua_State*, T*); + static luaW_Userdata (*cast)(const luaW_Userdata&); +private: + LuaWrapper(); +}; +template const char* LuaWrapper::classname; +template void (*LuaWrapper::identifier)(lua_State*, T*); +template T* (*LuaWrapper::allocator)(lua_State*); +template void (*LuaWrapper::deallocator)(lua_State*, T*); +template luaW_Userdata (*LuaWrapper::cast)(const luaW_Userdata&); + +// Cast from an object of type T to an object of type U. This template +// function is instantiated by calling luaW_extend(L). This is only used +// internally. +template +luaW_Userdata luaW_cast(const luaW_Userdata& obj) +{ + return luaW_Userdata(static_cast(static_cast(obj.data)), LuaWrapper::cast); +} + +template +void luaW_identify(lua_State* L, T* obj) +{ + LuaWrapper::identifier(L, static_cast(obj)); +} + +template +inline void luaW_wrapperfield(lua_State* L, const char* field) +{ + lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper + lua_getfield(L, -1, field); // ... LuaWrapper LuaWrapper.field + lua_getfield(L, -1, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.field LuaWrapper.field.class + lua_replace(L, -3); // ... LuaWrapper.field.class LuaWrapper.field + lua_pop(L, 1); // ... LuaWrapper.field.class +} + +// Analogous to lua_is(boolean|string|*) +// +// Returns 1 if the value at the given acceptable index is of type T (or if +// strict is false, convertable to type T) and 0 otherwise. +template +bool luaW_is(lua_State *L, int index, bool strict = false) +{ + bool equal = false;// lua_isnil(L, index); + if (!equal && lua_isuserdata(L, index) && lua_getmetatable(L, index)) + { + // ... ud ... udmt + luaL_getmetatable(L, LuaWrapper::classname); // ... ud ... udmt Tmt + equal = lua_rawequal(L, -1, -2) != 0; + if (!equal && !strict) + { + lua_getfield(L, -2, LUAW_EXTENDS_KEY); // ... ud ... udmt Tmt udmt.extends + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) + { + // ... ud ... udmt Tmt udmt.extends k v + equal = lua_rawequal(L, -1, -4) != 0; + if (equal) + { + lua_pop(L, 2); // ... ud ... udmt Tmt udmt.extends + break; + } + } + lua_pop(L, 1); // ... ud ... udmt Tmt + } + lua_pop(L, 2); // ... ud ... + } + return equal; +} + +// Analogous to lua_to(boolean|string|*) +// +// Converts the given acceptable index to a T*. That value must be of (or +// convertable to) type T; otherwise, returns NULL. +template +T* luaW_to(lua_State* L, int index, bool strict = false) +{ + if (luaW_is(L, index, strict)) + { + luaW_Userdata* pud = static_cast(lua_touserdata(L, index)); + luaW_Userdata ud; + while (!strict && LuaWrapper::cast != pud->cast) + { + ud = pud->cast(*pud); + pud = &ud; + } + return static_cast(pud->data); + } + return NULL; +} + +// Analogous to luaL_check(boolean|string|*) +// +// Converts the given acceptable index to a T*. That value must be of (or +// convertable to) type T; otherwise, an error is raised. +template +T* luaW_check(lua_State* L, int index, bool strict = false) +{ + T* obj = NULL; + if (luaW_is(L, index, strict)) + { + luaW_Userdata* pud = (luaW_Userdata*)lua_touserdata(L, index); + luaW_Userdata ud; + while (!strict && LuaWrapper::cast != pud->cast) + { + ud = pud->cast(*pud); + pud = &ud; + } + obj = (T*)pud->data; + } + else + { + const char *msg = lua_pushfstring(L, "%s expected, got %s", LuaWrapper::classname, luaL_typename(L, index)); + luaL_argerror(L, index, msg); + } + return obj; +} + +template +T* luaW_opt(lua_State* L, int index, T* fallback = NULL, bool strict = false) +{ + if (lua_isnil(L, index)) + return fallback; + else + return luaW_check(L, index, strict); +} + +// Analogous to lua_push(boolean|string|*) +// +// Pushes a userdata of type T onto the stack. If this object already exists in +// the Lua environment, it will assign the existing storage table to it. +// Otherwise, a new storage table will be created for it. +template +void luaW_push(lua_State* L, T* obj) +{ + if (obj) + { + LuaWrapper::identifier(L, obj); // ... id + luaW_wrapperfield(L, LUAW_CACHE_KEY); // ... id cache + lua_pushvalue(L, -2); // ... id cache id + lua_gettable(L, -2); // ... id cache obj + if (lua_isnil(L, -1)) + { + // Create the new luaW_userdata and place it in the cache + lua_pop(L, 1); // ... id cache + lua_insert(L, -2); // ... cache id + luaW_Userdata* ud = static_cast(lua_newuserdata(L, sizeof(luaW_Userdata))); // ... cache id obj + ud->data = obj; + ud->cast = LuaWrapper::cast; + lua_pushvalue(L, -1); // ... cache id obj obj + lua_insert(L, -4); // ... obj cache id obj + lua_settable(L, -3); // ... obj cache + + luaL_getmetatable(L, LuaWrapper::classname); // ... obj cache mt + lua_setmetatable(L, -3); // ... obj cache + + lua_pop(L, 1); // ... obj + } + else + { + lua_replace(L, -3); // ... obj cache + lua_pop(L, 1); // ... obj + } + } + else + { + lua_pushnil(L); + } +} + +// Instructs LuaWrapper that it owns the userdata, and can manage its memory. +// When all references to the object are removed, Lua is free to garbage +// collect it and delete the object. +// +// Returns true if luaW_hold took hold of the object, and false if it was +// already held +template +bool luaW_hold(lua_State* L, T* obj) +{ + luaW_wrapperfield(L, LUAW_HOLDS_KEY); // ... holds + LuaWrapper::identifier(L, obj); // ... holds id + lua_pushvalue(L, -1); // ... holds id id + lua_gettable(L, -3); // ... holds id hold + // If it's not held, hold it + if (!lua_toboolean(L, -1)) + { + // Apply hold boolean + lua_pop(L, 1); // ... holds id + lua_pushboolean(L, true); // ... holds id true + lua_settable(L, -3); // ... holds + lua_pop(L, 1); // ... + return true; + } + lua_pop(L, 3); // ... + return false; +} + +// Releases LuaWrapper's hold on an object. This allows the user to remove +// all references to an object in Lua and ensure that Lua will not attempt to +// garbage collect it. +// +// This function takes the index of the identifier for an object rather than +// the object itself. This is because needs to be able to run after the object +// has already been deallocated. A wrapper is provided for when it is more +// convenient to pass in the object directly. +template +void luaW_release(lua_State* L, int index) +{ + luaW_wrapperfield(L, LUAW_HOLDS_KEY); // ... id ... holds + lua_pushvalue(L, luaW_correctindex(L, index, 1)); // ... id ... holds id + lua_pushnil(L); // ... id ... holds id nil + lua_settable(L, -3); // ... id ... holds + lua_pop(L, 1); // ... id ... +} + +template +void luaW_release(lua_State* L, T* obj) +{ + LuaWrapper::identifier(L, obj); // ... id + luaW_release(L, -1); // ... id + lua_pop(L, 1); // ... +} + +// This function is called from Lua, not C++ +// +// Calls the lua post-constructor (LUAW_POSTCTOR_KEY or "__postctor") on a +// userdata. Assumes the userdata is on top of the stack, and numargs arguments +// are below it. This runs the LUAW_POSTCTOR_KEY function on T's metatable, +// using the object as the first argument and whatever else is below it as +// the rest of the arguments This exists to allow types to adjust values in +// thier storage table, which can not be created until after the constructor is +// called. +template +void luaW_postconstructor(lua_State* L, int numargs) +{ + // ... args... ud + lua_getfield(L, -1, LUAW_POSTCTOR_KEY); // ... args... ud ud.__postctor + if (lua_type(L, -1) == LUA_TFUNCTION) + { + lua_pushvalue(L, -2); // ... args... ud ud.__postctor ud + lua_insert(L, -3 - numargs); // ... ud args... ud ud.__postctor + lua_insert(L, -3 - numargs); // ... ud.__postctor ud args... ud + lua_insert(L, -3 - numargs); // ... ud ud.__postctor ud args... + lua_call(L, numargs + 1, 0); // ... ud + } + else + { + lua_pop(L, 1); // ... ud + } +} + +// This function is generally called from Lua, not C++ +// +// Creates an object of type T using the constructor and subsequently calls the +// post-constructor on it. +template +inline int luaW_new(lua_State* L, int args) +{ + T* obj = LuaWrapper::allocator(L); + luaW_push(L, obj); + luaW_hold(L, obj); + luaW_postconstructor(L, args); + return 1; +} + +template +int luaW_new(lua_State* L) +{ + return luaW_new(L, lua_gettop(L)); +} + +// This function is called from Lua, not C++ +// +// The default metamethod to call when indexing into lua userdata representing +// an object of type T. This will first check the userdata's environment table +// and if it's not found there it will check the metatable. This is done so +// individual userdata can be treated as a table, and can hold thier own +// values. +template +int luaW_index(lua_State* L) +{ + // obj key + T* obj = luaW_to(L, 1); + luaW_wrapperfield(L, LUAW_STORAGE_KEY); // obj key storage + LuaWrapper::identifier(L, obj); // obj key storage id + lua_gettable(L, -2); // obj key storage store + + // Check if storage table exists + if (!lua_isnil(L, -1)) + { + lua_pushvalue(L, -3); // obj key storage store key + lua_gettable(L, -2); // obj key storage store store[k] + } + + // If either there is no storage table or the key wasn't found + // then fall back to the metatable + if (lua_isnil(L, -1)) + { + lua_settop(L, 2); // obj key + lua_getmetatable(L, -2); // obj key mt + lua_pushvalue(L, -2); // obj key mt k + lua_gettable(L, -2); // obj key mt mt[k] + } + return 1; +} + +// This function is called from Lua, not C++ +// +// The default metamethod to call when creating a new index on lua userdata +// representing an object of type T. This will index into the the userdata's +// environment table that it keeps for personal storage. This is done so +// individual userdata can be treated as a table, and can hold thier own +// values. +template +int luaW_newindex(lua_State* L) +{ + // obj key value + T* obj = luaW_check(L, 1); + luaW_wrapperfield(L, LUAW_STORAGE_KEY); // obj key value storage + LuaWrapper::identifier(L, obj); // obj key value storage id + lua_pushvalue(L, -1); // obj key value storage id id + lua_gettable(L, -3); // obj key value storage id store + + // Add the storage table if there isn't one already + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); // obj key value storage id + lua_newtable(L); // obj key value storage id store + lua_pushvalue(L, -1); // obj key value storage id store store + lua_insert(L, -3); // obj key value storage store id store + lua_settable(L, -4); // obj key value storage store + } + + lua_pushvalue(L, 2); // obj key value ... store key + lua_pushvalue(L, 3); // obj key value ... store key value + lua_settable(L, -3); // obj key value ... store + + return 0; +} + +// This function is called from Lua, not C++ +// +// The __gc metamethod handles cleaning up userdata. The userdata's reference +// count is decremented and if this is the final reference to the userdata its +// environment table is nil'd and pointer deleted with the destructor callback. +template +int luaW_gc(lua_State* L) +{ + // obj + T* obj = luaW_to(L, 1); + LuaWrapper::identifier(L, obj); // obj key value storage id + luaW_wrapperfield(L, LUAW_HOLDS_KEY); // obj id counts count holds + lua_pushvalue(L, 2); // obj id counts count holds id + lua_gettable(L, -2); // obj id counts count holds hold + if (lua_toboolean(L, -1) && LuaWrapper::deallocator) + { + LuaWrapper::deallocator(L, obj); + } + + luaW_wrapperfield(L, LUAW_STORAGE_KEY); // obj id counts count holds hold storage + lua_pushvalue(L, 2); // obj id counts count holds hold storage id + lua_pushnil(L); // obj id counts count holds hold storage id nil + lua_settable(L, -3); // obj id counts count holds hold storage + + luaW_release(L, 2); + return 0; +} + +// Thakes two tables and registers them with Lua to the table on the top of the +// stack. +// +// This function is only called from LuaWrapper internally. +inline void luaW_registerfuncs(lua_State* L, const luaL_Reg defaulttable[], const luaL_Reg table[]) +{ + // ... T +#if LUA_VERSION_NUM > 501 + if (defaulttable) + luaL_setfuncs(L, defaulttable, 0); // ... T + if (table) + luaL_setfuncs(L, table, 0); // ... T +#else + if (defaulttable) + luaL_register(L, NULL, defaulttable); // ... T + if (table) + luaL_register(L, NULL, table); // ... T +#endif +} + +// Initializes the LuaWrapper tables used to track internal state. +// +// This function is only called from LuaWrapper internally. +inline void luaW_initialize(lua_State* L) +{ + // Ensure that the LuaWrapper table is set up + lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper + if (lua_isnil(L, -1)) + { + lua_newtable(L); // ... nil {} + lua_pushvalue(L, -1); // ... nil {} {} + lua_setfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... nil LuaWrapper + + // Create a storage table + lua_newtable(L); // ... LuaWrapper nil {} + lua_setfield(L, -2, LUAW_STORAGE_KEY); // ... nil LuaWrapper + + // Create a holds table + lua_newtable(L); // ... LuaWrapper {} + lua_setfield(L, -2, LUAW_HOLDS_KEY); // ... nil LuaWrapper + + // Create a cache table, with weak values so that the userdata will not + // be ref counted + lua_newtable(L); // ... nil LuaWrapper {} + lua_setfield(L, -2, LUAW_CACHE_KEY); // ... nil LuaWrapper + + lua_newtable(L); // ... nil LuaWrapper {} + lua_pushstring(L, "v"); // ... nil LuaWrapper {} "v" + lua_setfield(L, -2, "__mode"); // ... nil LuaWrapper {} + lua_setfield(L, -2, LUAW_CACHE_METATABLE_KEY); // ... nil LuaWrapper + + lua_pop(L, 1); // ... nil + } + lua_pop(L, 1); // ... +} + +// Run luaW_register or luaW_setfuncs to create a table and metatable for your +// class. These functions create a table with filled with the function from +// the table argument in addition to the functions new and build (This is +// generally for things you think of as static methods in C++). The given +// metatable argument becomes a metatable for each object of your class. These +// can be thought of as member functions or methods. +// +// You may also supply constructors and destructors for classes that do not +// have a default constructor or that require special set up or tear down. You +// may specify NULL as the constructor, which means that you will not be able +// to call the new function on your class table. You will need to manually push +// objects from C++. By default, the default constructor is used to create +// objects and a simple call to delete is used to destroy them. +// +// By default LuaWrapper uses the address of C++ object to identify unique +// objects. In some cases this is not desired, such as in the case of +// shared_ptrs. Two shared_ptrs may themselves have unique locations in memory +// but still represent the same object. For cases like that, you may specify an +// identifier function which is responsible for pushing a key representing your +// object on to the stack. +// +// luaW_register will set table as the new value of the global of the given +// name. luaW_setfuncs is identical to luaW_register, but it does not set the +// table globally. As with luaL_register and luaL_setfuncs, both funcstions +// leave the new table on the top of the stack. +template +void luaW_setfuncs(lua_State* L, const char* classname, const luaL_Reg* table, const luaL_Reg* metatable, T* (*allocator)(lua_State*) = luaW_defaultallocator, void (*deallocator)(lua_State*, T*) = luaW_defaultdeallocator, void (*identifier)(lua_State*, T*) = luaW_defaultidentifier) +{ + luaW_initialize(L); + + LuaWrapper::classname = classname; + LuaWrapper::identifier = identifier; + LuaWrapper::allocator = allocator; + LuaWrapper::deallocator = deallocator; + + const luaL_Reg defaulttable[] = + { + { "new", luaW_new }, + { NULL, NULL } + }; + const luaL_Reg defaultmetatable[] = + { + { "__index", luaW_index }, + { "__newindex", luaW_newindex }, + { "__gc", luaW_gc }, + { NULL, NULL } + }; + + // Set up per-type tables + lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage + lua_newtable(L); // ... LuaWrapper LuaWrapper.storage {} + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.storage + lua_pop(L, 1); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds + lua_newtable(L); // ... LuaWrapper LuaWrapper.holds {} + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.holds + lua_pop(L, 1); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache + lua_newtable(L); // ... LuaWrapper LuaWrapper.cache {} + luaW_wrapperfield(L, LUAW_CACHE_METATABLE_KEY); // ... LuaWrapper LuaWrapper.cache {} cmt + lua_setmetatable(L, -2); // ... LuaWrapper LuaWrapper.cache {} + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.cache + + lua_pop(L, 2); // ... + + // Open table + lua_newtable(L); // ... T + luaW_registerfuncs(L, allocator ? defaulttable : NULL, table); // ... T + + // Open metatable, set up extends table + luaL_newmetatable(L, classname); // ... T mt + lua_newtable(L); // ... T mt {} + lua_setfield(L, -2, LUAW_EXTENDS_KEY); // ... T mt + luaW_registerfuncs(L, defaultmetatable, metatable); // ... T mt + lua_setfield(L, -2, "metatable"); // ... T +} + +template +void luaW_register(lua_State* L, const char* classname, const luaL_Reg* table, const luaL_Reg* metatable, T* (*allocator)(lua_State*) = luaW_defaultallocator, void (*deallocator)(lua_State*, T*) = luaW_defaultdeallocator, void (*identifier)(lua_State*, T*) = luaW_defaultidentifier) +{ + luaW_setfuncs(L, classname, table, metatable, allocator, deallocator, identifier); // ... T + lua_pushvalue(L, -1); // ... T T + lua_setglobal(L, classname); // ... T +} + +// luaW_extend is used to declare that class T inherits from class U. All +// functions in the base class will be available to the derived class (except +// when they share a function name, in which case the derived class's function +// wins). This also allows luaW_to to cast your object apropriately, as +// casts straight through a void pointer do not work. +template +void luaW_extend(lua_State* L) +{ + if(!LuaWrapper::classname) + luaL_error(L, "attempting to call extend on a type that has not been registered"); + + if(!LuaWrapper::classname) + luaL_error(L, "attempting to extend %s by a type that has not been registered", LuaWrapper::classname); + + LuaWrapper::cast = luaW_cast; + LuaWrapper::identifier = luaW_identify; + + luaL_getmetatable(L, LuaWrapper::classname); // mt + luaL_getmetatable(L, LuaWrapper::classname); // mt emt + + // Point T's metatable __index at U's metatable for inheritance + lua_newtable(L); // mt emt {} + lua_pushvalue(L, -2); // mt emt {} emt + lua_setfield(L, -2, "__index"); // mt emt {} + lua_setmetatable(L, -3); // mt emt + + // Set up per-type tables to point at parent type + lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage + lua_getfield(L, -1, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.storage U + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.storage + lua_pop(L, 1); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds + lua_getfield(L, -1, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.holds U + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.holds + lua_pop(L, 1); // ... LuaWrapper + + lua_getfield(L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache + lua_getfield(L, -1, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.cache U + lua_setfield(L, -2, LuaWrapper::classname); // ... LuaWrapper LuaWrapper.cache + + lua_pop(L, 2); // ... + + // Make a list of all types that inherit from U, for type checking + lua_getfield(L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends + lua_pushvalue(L, -2); // mt emt mt.extends emt + lua_setfield(L, -2, LuaWrapper::classname); // mt emt mt.extends + lua_getfield(L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends emt.extends + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) + { + // mt emt mt.extends emt.extends k v + lua_pushvalue(L, -2); // mt emt mt.extends emt.extends k v k + lua_pushvalue(L, -2); // mt emt mt.extends emt.extends k v k + lua_rawset(L, -6); // mt emt mt.extends emt.extends k v + } + + lua_pop(L, 4); // mt emt +} + +/* + * Copyright (c) 2010-2013 Alexander Ames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#endif // LUA_WRAPPER_H_ diff --git a/luarocks/luawrapperutil.hpp b/luarocks/luawrapperutil.hpp new file mode 100644 index 00000000..d19ce6df --- /dev/null +++ b/luarocks/luawrapperutil.hpp @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2010-2013 Alexander Ames + * Alexander.Ames@gmail.com + * See Copyright Notice at the end of this file + */ + +// API Summary: +// +// This is a set of utility functions that add to the functionalit of +// LuaWrapper. Over time I found myself repeating a few patterns, such as +// writing many trvial getter and setter functions, and wanting pass ownership +// of one object to another and have the Lua script properly handle that case. +// +// This file contains the additional functions that I've added but that do +// not really belong in the core API. + +#ifndef LUAWRAPPERUTILS_HPP_ +#define LUAWRAPPERUTILS_HPP_ + +#include "luawrapper.hpp" + +#ifndef LUAW_NO_CXX11 +#include +#endif + +#ifndef LUAW_STD +#define LUAW_STD std +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// A set of templated luaL_check and lua_push functions for use in the getters +// and setters below +// +// It is often useful to override luaU_check, luaU_to and/or luaU_push to +// operate on your own simple types rather than register your type with +// LuaWrapper, especially with small objects. +// + +template +struct luaU_Impl +{ + static U luaU_check(lua_State* L, int index); + static U luaU_to (lua_State* L, int index); + static void luaU_push (lua_State* L, const U& value); + static void luaU_push (lua_State* L, U& value); +}; + +template U luaU_check(lua_State* L, int index) { return luaU_Impl::luaU_check(L, index); } +template U luaU_to (lua_State* L, int index) { return luaU_Impl::luaU_to (L, index); } +template void luaU_push (lua_State* L, const U& value) { luaU_Impl::luaU_push (L, value); } +template void luaU_push (lua_State* L, U& value) { luaU_Impl::luaU_push (L, value); } + +//////////////////////////////////////////////////////////////////////////////// +// +// This is slightly different than the previous three functions in that you +// shouldn't need to write your own version of it, since it uses luaU_check +// automatically. +// +template +U luaU_opt(lua_State* L, int index, const U& fallback = U()) +{ + if (lua_isnil(L, index)) + return fallback; + else + return luaU_Impl::luaU_check(L, index); +} + +template<> +struct luaU_Impl +{ + static bool luaU_check(lua_State* L, int index) { return lua_toboolean (L, index) != 0; } + static bool luaU_to (lua_State* L, int index) { return lua_toboolean (L, index) != 0; } + static void luaU_push (lua_State* L, const bool& value) { lua_pushboolean(L, value); } +}; + +template<> +struct luaU_Impl +{ + static const char* luaU_check(lua_State* L, int index) { return luaL_checkstring(L, index); } + static const char* luaU_to (lua_State* L, int index) { return lua_tostring (L, index); } + static void luaU_push (lua_State* L, const char* const& value) { lua_pushstring (L, value); } +}; + +template<> +struct luaU_Impl +{ + static unsigned int luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } + static unsigned int luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } + static void luaU_push (lua_State* L, const unsigned int& value) { lua_pushinteger (L, value); } +}; + +template<> +struct luaU_Impl +{ + static int luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } + static int luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } + static void luaU_push (lua_State* L, const int& value) { lua_pushinteger (L, value); } +}; + +template<> +struct luaU_Impl +{ + static unsigned char luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } + static unsigned char luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } + static void luaU_push (lua_State* L, const unsigned char& value) { lua_pushinteger (L, value); } +}; + +template<> +struct luaU_Impl +{ + static char luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } + static char luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } + static void luaU_push (lua_State* L, const char& value) { lua_pushinteger (L, value); } +}; + +template<> +struct luaU_Impl +{ + static float luaU_check(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } + static float luaU_to (lua_State* L, int index) { return static_cast(lua_tonumber (L, index)); } + static void luaU_push (lua_State* L, const float& value) { lua_pushnumber (L, value); } +}; + +template<> +struct luaU_Impl +{ + static double luaU_check(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } + static double luaU_to (lua_State* L, int index) { return static_cast(lua_tonumber (L, index)); } + static void luaU_push (lua_State* L, const double& value) { lua_pushnumber (L, value); } +}; + +#ifndef LUAW_NO_CXX11 +template +struct luaU_Impl::value>::type> +{ + static T luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger (L, index)); } + static T luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } + static void luaU_push (lua_State* L, const T& value) { lua_pushnumber(L, static_cast(value )); } +}; + +template +struct luaU_Impl::value>::type> +{ + static T* luaU_check( lua_State* L, int index) { return luaW_check(L, index); } + static T* luaU_to ( lua_State* L, int index) { return luaW_to (L, index); } + static void luaU_push ( lua_State* L, T*& value) { luaW_push (L, value); } + static void luaU_push ( lua_State* L, T* value) { luaW_push (L, value); } +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// These are just some functions I've always felt should exist +// + +template +inline U luaU_getfield(lua_State* L, int index, const char* field) +{ +#ifndef LUAW_NO_CXX11 + static_assert(!std::is_same::value, + "luaU_getfield is not safe to use on const char*'s. (The string will be popped from the stack.)"); +#endif + lua_getfield(L, index, field); + U val = luaU_to(L, -1); + lua_pop(L, 1); + return val; +} + +template +inline U luaU_checkfield(lua_State* L, int index, const char* field) +{ +#ifndef LUAW_NO_CXX11 + static_assert(!std::is_same::value, + "luaU_checkfield is not safe to use on const char*'s. (The string will be popped from the stack.)"); +#endif + lua_getfield(L, index, field); + U val = luaU_check(L, -1); + lua_pop(L, 1); + return val; +} + +template +inline void luaU_setfield(lua_State* L, int index, const char* field, U val) +{ + luaU_push(L, val); + lua_setfield(L, luaW_correctindex(L, index, 1), field); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// A set of trivial getter and setter templates. These templates are designed +// to call trivial getters or setters. +// +// There are four forms: +// 1. Getting or setting a public member variable that is of a primitive type +// 2. Getting or setting a public member variable that is a pointer to an +// object +// 3. Getting or setting a private member variable that is of a primitive type +// through a getter or setter +// 3. Getting or setting a private member variable that is is a pointer to an +// object through a getter or setter +// +// The interface to all of them is the same however. In addition to plain +// getter and setter functions, there is a getset which does both - if an +// argument is supplied it attempts to set the value, and in either case it +// returns the value. In your lua table declaration in C++ rather than write +// individiual wrappers for each getter and setter you may do the following: +// +// static luaL_reg Foo_metatable[] = +// { +// { "GetBar", luaU_get }, +// { "SetBar", luaU_set }, +// { "Bar", luaU_getset }, +// { NULL, NULL } +// } +// +// Getters and setters must have one of the following signatures: +// void T::Setter(U value); +// void T::Setter(U* value); +// void T::Setter(const U& value); +// U Getter() const; +// U* Getter() const; +// +// In this example, the variable Foo::bar is private and so it is accessed +// through getter and setter functions. If Foo::bar were public, it could be +// accessed directly, like so: +// +// static luaL_reg Foo_metatable[] = +// { +// { "GetBar", luaU_get }, +// { "SetBar", luaU_set }, +// { "Bar", luaU_getset }, +// } +// +// In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar() +// + +template +int luaU_get(lua_State* L) +{ + T* obj = luaW_check(L, 1); + luaU_push(L, obj->*Member); + return 1; +} + +template +int luaU_get(lua_State* L) +{ + T* obj = luaW_check(L, 1); + luaW_push(L, obj->*Member); + return 1; +} + +template +int luaU_get(lua_State* L) +{ + T* obj = luaW_check(L, 1); + luaU_push(L, (obj->*Getter)()); + return 1; +} + +template +int luaU_get(lua_State* L) +{ + T* obj = luaW_check(L, 1); + luaU_push(L, (obj->*Getter)()); + return 1; +} + +template +int luaU_get(lua_State* L) +{ + T* obj = luaW_check(L, 1); + luaW_push(L, (obj->*Getter)()); + return 1; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + obj->*Member = luaU_check(L, 2); + return 0; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + { + U* member = luaW_opt(L, 2); + obj->*Member = member; + } + return 0; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + { + U* member = luaW_opt(L, 2); + obj->*Member = member; + } + return 0; +} + +template +int luaU_setandrelease(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + { + U* member = luaW_opt(L, 2); + obj->*Member = member; + if (member) + luaW_release(L, member); + } + return 0; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + (obj->*Setter)(luaU_check(L, 2)); + return 0; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + (obj->*Setter)(luaU_check(L, 2)); + return 0; +} + +template +int luaU_set(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + { + U* member = luaW_opt(L, 2); + (obj->*Setter)(member); + } + return 0; +} + +template +int luaU_setandrelease(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj) + { + U* member = luaW_opt(L, 2); + (obj->*Setter)(member); + if (member) + luaW_release(L, member); + } + return 0; +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + obj->*Member = luaU_check(L, 2); + return 0; + } + else + { + luaU_push(L, obj->*Member); + return 1; + } +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + U* member = luaW_opt(L, 2); + obj->*Member = member; + return 0; + } + else + { + luaW_push(L, obj->*Member); + return 1; + } +} + +template +int luaU_getsetandrelease(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + U* member = luaW_opt(L, 2); + obj->*Member = member; + if (member) + luaW_release(L, member); + return 0; + } + else + { + luaW_push(L, obj->*Member); + return 1; + } +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + (obj->*Setter)(luaU_check(L, 2)); + return 0; + } + else + { + luaU_push(L, (obj->*Getter)()); + return 1; + } +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + (obj->*Setter)(luaU_check(L, 2)); + return 0; + } + else + { + luaU_push(L, (obj->*Getter)()); + return 1; + } +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + (obj->*Setter)(luaU_check(L, 2)); + return 0; + } + else + { + luaU_push(L, (obj->*Getter)()); + return 1; + } +} + +template +int luaU_getset(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + U* member = luaW_opt(L, 2); + (obj->*Setter)(member); + return 0; + } + else + { + luaW_push(L, (obj->*Getter)()); + return 1; + } +} + +template +int luaU_getsetandrelease(lua_State* L) +{ + T* obj = luaW_check(L, 1); + if (obj && lua_gettop(L) >= 2) + { + U* member = luaW_opt(L, 2); + (obj->*Setter)(member); + if (member) + luaW_release(L, member); + return 0; + } + else + { + luaW_push(L, (obj->*Getter)()); + return 1; + } +} + +#if !defined(_WIN32) && !defined(LUAW_NO_CXX11) + +/////////////////////////////////////////////////////////////////////////////// +// +// luaU_func is a special macro that expands into a simple function wrapper. +// Unlike the getter setters above, you merely need to name the function you +// would like to wrap. +// +// For example, +// +// struct Foo +// { +// int DoSomething(int, const char*); +// }; +// +// static luaL_reg Foo_metatable[] = +// { +// { "DoSomething", luaU_func(&Foo::DoSomething) }, +// { NULL, NULL } +// } +// +// This macro will expand based on the function signature of Foo::DoSomething +// In this example, it would expand into the following wrapper: +// +// luaU_push(luaW_check(L, 1)->DoSomething(luaU_check(L, 2), luaU_check(L, 3))); +// return 1; +// +// In this example there is only one member function called DoSomething. In some +// cases there may be multiple overrides for a function. For those cases, an +// additional macro has been provided, luaU_funcsig, which takes the entire +// function signature. The arguments to the macro reflect the order they would +// appear in the function signature: return type, type name, function name, and +// finally a list of all the argument types. For example: +// +// struct Foo +// { +// int DoSomething (const char*); +// int DoSomething (const char*, int); +// }; +// +// const struct luaL_Reg Foo_metatable[] = +// { +// {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*)) }, +// {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*, int)) }, +// { NULL, NULL } +// }; +// +// These macros and it's underlying templates are somewhat experimental and some +// refinements are probably needed. There are cases where it does not +// currently work and I expect some changes can be made to refine its behavior. +// + +#define luaU_func(memberfunc) &luaU_FuncWrapper::call +#define luaU_funcsig(returntype, type, funcname, ...) luaU_func(static_cast(&type::funcname)) + +template struct luaU_IntPack { }; +template struct luaU_MakeIntRangeType { typedef typename luaU_MakeIntRangeType::type type; }; +template struct luaU_MakeIntRangeType { typedef luaU_IntPack type; }; +template inline typename luaU_MakeIntRangeType::type luaU_makeIntRange() { return typename luaU_MakeIntRangeType::type(); } +template struct luaU_FuncWrapper; + +template +struct luaU_FuncWrapper +{ +public: + static int call(lua_State* L) + { + return callImpl(L, luaU_makeIntRange<2,sizeof...(Args)>()); + } + +private: + template + static int callImpl(lua_State* L, luaU_IntPack) + { + luaU_push(L, (luaW_check(L, 1)->*MemberFunc)(luaU_check(L, indices)...)); + return 1; + } +}; + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Calls the copy constructor for an object of type T. +// Arguments may be passed in, in case they're needed for the postconstructor +// +// e.g. +// +// C++: +// luaL_reg Foo_Metatable[] = +// { +// { "clone", luaU_clone }, +// { NULL, NULL } +// }; +// +// Lua: +// foo = Foo.new() +// foo2 = foo:clone() +// +template +int luaU_clone(lua_State* L) +{ + // obj ... + T* obj = new T(*luaW_check(L, 1)); + lua_remove(L, 1); // ... + int numargs = lua_gettop(L); + luaW_push(L, obj); // ... clone + luaW_hold(L, obj); + luaW_postconstructor(L, numargs); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// luaU_build is intended to be used to initialize many values by passing in a +// table. They keys of the table are used as function names, and values are +// used as arguments to the function. This is intended to be used on functions +// that are simple setters. +// +// For example, if luaU_build is set as the post constructor, you can +// initialize an object as so: +// +// f = Foo.new +// { +// X = 10; +// Y = 20; +// } +// +// After the object is constructed, luaU_build will do the equivalent of +// calling f:X(10) and f:Y(20). +// +template +int luaU_build(lua_State* L) +{ + // obj {} + lua_insert(L, -2); // {} obj + if (lua_type(L, 1) == LUA_TTABLE) + { + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) + { + // {} obj k v + lua_pushvalue(L, -2); // {} obj k v k + lua_gettable(L, -4); // {} obj k v ud[k] + lua_pushvalue(L, -4); // {} obj k v ud[k] ud + lua_pushvalue(L, -3); // {} obj k v ud[k] ud v + lua_call(L, 2, 0); // {} obj k v + } + // {} ud + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Takes the object of type T at the top of the stack and stores it in on a +// table with the name storagetable, on the table at the specified index. +// +// You may manually call luaW_hold and luaW_release to handle pointer +// ownership, but it is often easier to simply store a Lua userdata on a table +// that is owned by its parent. This ensures that your object will not be +// prematurely freed, and that it can only be destoryed after its parent. +// +// e.g. +// +// Foo* parent = luaW_check(L, 1); +// Bar* child = luaW_check(L, 2); +// if (parent && child) +// { +// luaU_store(L, 1, "Children"); +// parent->AddChild(child); +// } +// +template +void luaU_store(lua_State* L, int index, const char* storagetable, const char* key = NULL) +{ + // ... store ... obj + lua_getfield(L, index, storagetable); // ... store ... obj store.storagetable + if (key) + lua_pushstring(L, key); // ... store ... obj store.storagetable key + else + LuaWrapper::identifier(L, luaW_to(L, -2)); // ... store ... obj store.storagetable key + lua_pushvalue(L, -3); // ... store ... obj store.storagetable key obj + lua_settable(L, -3); // ... store ... obj store.storagetable + lua_pop(L, 1); // ... store ... obj +} + +/* + * Copyright (c) 2010-2011 Alexander Ames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#endif // LUAWRAPPERUTILS_HPP_ diff --git a/luarocks/main.cpp b/luarocks/main.cpp new file mode 100644 index 00000000..a96711a1 --- /dev/null +++ b/luarocks/main.cpp @@ -0,0 +1,27 @@ +#include + +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} + +#include "functions.hpp" +#include "LuaPlayer.hpp" + +int main() +{ + lua_State* L = luaL_newstate(); + luaL_openlibs(L); + + // Functions + lua_register(L, "info", lua_info); + + // Objets + luaopen_Player(L); + + luaL_dofile(L, "ia.lua"); + lua_close(L); +} +