view C++/Luae.cpp @ 186:d4b8416e9ab1

Move C
author David Demelier <markand@malikania.fr>
date Sat, 23 Nov 2013 16:14:05 +0100
parents 15b264d9e833
children 258087829c66
line wrap: on
line source

/*
 * Luae.cpp -- Lua helpers and such
 *
 * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Luae.h"

void LuaeClass::createClass(lua_State *L, const LuaObject &cls)
{
	LUA_STACK_CHECKBEGIN(L);

	// Already registered?
	if (luaL_newmetatable(L, cls.name) == 0)
		return;

	// Add it's "name" field
	lua_pushstring(L, cls.name);
	lua_setfield(L, -2, LUAE_CLASS_FIELDNAME);

	// Create a list of parent for a faster cast
	lua_createtable(L, 0, 0);

	int i = 0;
	for (auto p = cls.parent; p != nullptr; p = p->parent) {
		lua_pushstring(L, p->name);
		lua_rawseti(L, -2, ++i);
	}
	lua_setfield(L, -2, LUAE_CLASS_FIELDPARENTS);

	// Metamethods
	if (cls.metamethods.size() > 0)
		luaL_setfuncs(L, cls.metamethods.data(), 0);

	// Methods
	lua_createtable(L, 0, 0);

	if (cls.methods.size() > 0) {
		luaL_setfuncs(L, cls.methods.data(), 0);
	}

	/*
	 * Add a metatable to this __index table so that if
	 * a method is not found it use the parent table recursively
	 */
	if (cls.parent) {
		// 1. Get the parent 
		luaL_getmetatable(L, cls.parent->name);
		assert(lua_type(L, -1) != LUA_TNIL);

		// 2. Create an anonymous metatable
		lua_createtable(L, 1, 1);

		// 3. Get the __index field from this metatable
		lua_getfield(L, -2, "__index");
		assert(lua_type(L, -1) != LUA_TNIL);
		lua_setfield(L, -2, "__index");
		lua_setmetatable(L, -3);
		lua_pop(L, 1);
	}

	lua_setfield(L, -2, "__index");

	// Pop that metatable
	lua_pop(L, 1);

	LUA_STACK_CHECKEQUALS(L);
}

/* --------------------------------------------------------
 * Luae public methods
 * -------------------------------------------------------- */

void Luae::createEnum(lua_State *L, const LuaEnum *enumeration)
{
	lua_createtable(L, 0, 0);

	for (int i = 0; enumeration[i].name != nullptr; ++i) {
		lua_pushinteger(L, enumeration[i].value);
		lua_setfield(L, -2, enumeration[i].name);
	}
}

void Luae::createLibrary(lua_State *L, const luaL_Reg *functions)
{
	LUA_STACK_CHECKBEGIN(L);

	lua_createtable(L, 0, 0);
	luaL_setfuncs(L, functions, 0);

	LUA_STACK_CHECKEND(L, - 1);
}

template <>
bool Luae::getField(lua_State *L, int idx, const std::string & name)
{
	bool value = false;

	lua_getfield(L, idx, name.c_str());
	if (lua_type(L, idx) == LUA_TBOOLEAN)
		value = lua_toboolean(L, -1) == 1;
	lua_pop(L, 1);

	return value;
}

template <>
double Luae::getField(lua_State *L, int idx, const std::string & name)
{
	double value = 0;

	lua_getfield(L, idx, name.c_str());
	if (lua_type(L, idx) == LUA_TNUMBER)
		value = lua_tonumber(L, -1);
	lua_pop(L, 1);

	return value;
}

template <>
int Luae::getField(lua_State *L, int idx, const std::string & name)
{
	int value = 0;

	lua_getfield(L, idx, name.c_str());
	if (lua_type(L, idx) == LUA_TNUMBER)
		value = lua_tointeger(L, -1);
	lua_pop(L, 1);

	return value;
}

template <>
std::string Luae::getField(lua_State *L, int idx, const std::string & name)
{
	std::string value;

	lua_getfield(L, idx, name.c_str());
	if (lua_type(L, idx) == LUA_TSTRING)
		value = lua_tostring(L, -1);
	lua_pop(L, 1);

	return value;
}

void Luae::preload(lua_State *L, const std::string & name, lua_CFunction func)
{
	LUA_STACK_CHECKBEGIN(L);

	lua_getglobal(L, "package");
	lua_getfield(L, -1, "preload");
	lua_pushcfunction(L, func);
	lua_setfield(L, -2, name.c_str());
	lua_pop(L, 2);

	LUA_STACK_CHECKEQUALS(L);
}

void Luae::readTable(lua_State *L, int idx, ReadFunction func)
{
	lua_pushnil(L);

	if (idx < 0)
		--idx;

	while (lua_next(L, idx)) {
		func(L, lua_type(L, -2), lua_type(L, -1));
		lua_pop(L, 1);
	}

	lua_pop(L, 1);
}

int Luae::referenceField(lua_State *L, int idx, int type, const std::string & name)
{
	int ref = LUA_REFNIL;

	lua_getfield(L, idx, name.c_str());

	if (lua_type(L, -1) == type) {
		lua_pushvalue(L, -1);
		ref = luaL_ref(L, LUA_REGISTRYINDEX);
	}

	lua_pop(L, 1);

	return ref;
}

void Luae::require(lua_State *L, const std::string & name, lua_CFunction func, bool global)
{
	LUA_STACK_CHECKBEGIN(L);

	luaL_requiref(L, name.c_str(), func, global);
	lua_pop(L, 1);

	LUA_STACK_CHECKEQUALS(L);
}

void * operator new(size_t size, lua_State *L)
{
	return lua_newuserdata(L, size);
}

void * operator new(size_t size, lua_State *L, const char *metaname)
{
	void *object;

	object = lua_newuserdata(L, size);
	luaL_setmetatable(L, metaname);

	return object;
}

void operator delete(void *, lua_State *)
{
}

void operator delete(void *, lua_State *L, const char *)
{
	lua_pushnil(L);
	lua_setmetatable(L, -2);
}