Allow dynamic loading of Lua functions

Dynamically loading Lua functions allows distributing implementations
to multiple places.

Additionally, migrate bit.* functions to the new framework.
This commit is contained in:
Ilari Liusvaara 2011-09-14 21:19:54 +03:00
parent f170c7bab2
commit feb1a5d841
5 changed files with 243 additions and 174 deletions

View file

@ -11,7 +11,7 @@ LDFLAGS = $(shell sdl-config --libs) $(USER_LDFLAGS)
ifdef NO_LUA
OBJECTS += lua-dummy.o
else
OBJECTS += lua.o
OBJECTS += lua.o $(patsubst %.cpp,%.o,$(wildcard lua/*.cpp))
CFLAGS += $(shell pkg-config lua5.1 --cflags)
LDFLAGS += $(shell pkg-config lua5.1 --libs)
endif

32
lua-int.hpp Normal file
View file

@ -0,0 +1,32 @@
#ifndef _lua_int__hpp__included__
#define _lua_int__hpp__included__
#include "lua.hpp"
extern "C"
{
#include <lua.h>
}
template<typename T>
T get_numeric_argument(lua_State* LS, unsigned argindex, const char* fname)
{
if(lua_isnone(LS, argindex) || !lua_isnumber(LS, argindex)) {
lua_pushfstring(LS, "argument #%i to %s must be numeric", argindex, fname);
lua_error(LS);
}
return static_cast<T>(lua_tonumber(LS, argindex));
}
template<typename T>
void get_numeric_argument(lua_State* LS, unsigned argindex, T& value, const char* fname)
{
if(lua_isnoneornil(LS, argindex))
return;
if(lua_isnone(LS, argindex) || !lua_isnumber(LS, argindex)) {
lua_pushfstring(LS, "argument #%i to %s must be numeric if present", argindex, fname);
lua_error(LS);
}
value = static_cast<T>(lua_tonumber(LS, argindex));
}
#endif

260
lua.cpp
View file

@ -1,23 +1,108 @@
#include "lua.hpp"
#include "lua-int.hpp"
#include "command.hpp"
#include "misc.hpp"
#include "memorymanip.hpp"
#include "mainloop.hpp"
#include <map>
#include <string>
extern "C" {
#include <lua.h>
#include <lualib.h>
}
#include <iostream>
#include "fieldsplit.hpp"
#define BITWISE_BITS 48
#define BITWISE_MASK ((1ULL << (BITWISE_BITS)) - 1)
#define SETFIELDFUN(LSS, idx, name, fun) do { lua_pushcfunction(LSS, fun); lua_setfield(LSS, (idx) - 1, name); \
} while(0)
namespace
{
std::map<std::string, lua_function*>* functions;
lua_State* lua_initialized;
window* tmp_win;
int lua_trampoline_function(lua_State* L)
{
void* ptr = lua_touserdata(L, lua_upvalueindex(1));
lua_function* f = reinterpret_cast<lua_function*>(ptr);
return f->invoke(L, tmp_win);
}
//Pushes given table to top of stack, creating if needed.
void recursive_lookup_table(lua_State* L, const std::string& tab)
{
if(tab == "") {
lua_pushvalue(L, LUA_GLOBALSINDEX);
return;
}
std::string u = tab;
size_t split = u.find_last_of(".");
std::string u1;
std::string u2 = u;
if(split < u.length()) {
u1 = u.substr(0, split);
u2 = u.substr(split + 1);
}
recursive_lookup_table(L, u1);
lua_getfield(L, -1, u2.c_str());
if(lua_type(L, -1) != LUA_TTABLE) {
//Not a table, create a table.
lua_pop(L, 1);
lua_newtable(L);
lua_setfield(L, -2, u2.c_str());
lua_getfield(L, -1, u2.c_str());
}
//Get rid of previous table.
lua_insert(L, -2);
lua_pop(L, 1);
}
void register_lua_function(lua_State* L, const std::string& fun)
{
std::string u = fun;
size_t split = u.find_last_of(".");
std::string u1;
std::string u2 = u;
if(split < u.length()) {
u1 = u.substr(0, split);
u2 = u.substr(split + 1);
}
recursive_lookup_table(L, u1);
void* ptr = reinterpret_cast<void*>((*functions)[fun]);
lua_pushlightuserdata(L, ptr);
lua_pushcclosure(L, lua_trampoline_function, 1);
lua_setfield(L, -2, u2.c_str());
lua_pop(L, 1);
}
void register_lua_functions(lua_State* L)
{
if(functions)
for(auto i = functions->begin(); i != functions->end(); i++)
register_lua_function(L, i->first);
lua_initialized = L;
}
}
lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
{
if(!functions)
functions = new std::map<std::string, lua_function*>();
(*functions)[fname = name] = this;
if(lua_initialized)
register_lua_function(lua_initialized, fname);
}
lua_function::~lua_function() throw()
{
if(!functions)
return;
functions->erase(fname);
}
namespace
{
lua_State* L;
lua_render_context* rctx = NULL;
bool recursive_flag = false;
@ -109,16 +194,6 @@ namespace
}
}
template<typename T>
T get_numeric_argument(lua_State* LS, unsigned argindex, const char* fname)
{
if(lua_isnone(LS, argindex) || !lua_isnumber(LS, argindex)) {
lua_pushfstring(L, "argument #%i to %s must be numeric", argindex, fname);
lua_error(LS);
}
return static_cast<T>(lua_tonumber(LS, argindex));
}
std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
{
if(lua_isnone(LS, argindex)) {
@ -143,18 +218,6 @@ namespace
return (lua_toboolean(LS, argindex) != 0);
}
template<typename T>
void get_numeric_argument(lua_State* LS, unsigned argindex, T& value, const char* fname)
{
if(lua_isnoneornil(LS, argindex))
return;
if(lua_isnone(LS, argindex) || !lua_isnumber(LS, argindex)) {
lua_pushfstring(L, "argument #%i to %s must be numeric if present", argindex, fname);
lua_error(LS);
}
value = static_cast<T>(lua_tonumber(LS, argindex));
}
void do_eval_lua(const std::string& c, window* win) throw(std::bad_alloc)
{
push_string(c);
@ -195,136 +258,6 @@ namespace
}
}
int lua_symmetric_bitwise(lua_State* LS, uint64_t (*combine)(uint64_t chain, uint64_t arg), uint64_t init)
{
int stacksize = 0;
while(!lua_isnone(LS, stacksize + 1))
stacksize++;
uint64_t ret = init;
for(int i = 0; i < stacksize; i++)
ret = combine(ret, get_numeric_argument<uint64_t>(LS, i + 1, "<bitwise function>"));
lua_pushnumber(LS, ret);
return 1;
}
int lua_shifter(lua_State* LS, uint64_t (*shift)(uint64_t base, uint64_t amount, uint64_t bits))
{
uint64_t base;
uint64_t amount = 1;
uint64_t bits = BITWISE_BITS;
base = get_numeric_argument<uint64_t>(LS, 1, "<shift function>");
get_numeric_argument(LS, 2, amount, "<shift function>");
get_numeric_argument(LS, 3, bits, "<shift function>");
lua_pushnumber(LS, shift(base, amount, bits));
return 1;
}
uint64_t combine_none(uint64_t chain, uint64_t arg)
{
return (chain & ~arg) & BITWISE_MASK;
}
uint64_t combine_any(uint64_t chain, uint64_t arg)
{
return (chain | arg) & BITWISE_MASK;
}
uint64_t combine_all(uint64_t chain, uint64_t arg)
{
return (chain & arg) & BITWISE_MASK;
}
uint64_t combine_parity(uint64_t chain, uint64_t arg)
{
return (chain ^ arg) & BITWISE_MASK;
}
uint64_t shift_lrotate(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base = (base << amount) | (base >> (bits - amount));
return base & mask & BITWISE_MASK;
}
uint64_t shift_rrotate(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base = (base >> amount) | (base << (bits - amount));
return base & mask & BITWISE_MASK;
}
uint64_t shift_lshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base <<= amount;
return base & mask & BITWISE_MASK;
}
uint64_t shift_lrshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base >>= amount;
return base & BITWISE_MASK;
}
uint64_t shift_arshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
bool negative = ((base >> (bits - 1)) != 0);
base >>= amount;
base |= ((negative ? BITWISE_MASK : 0) << (bits - amount));
return base & mask & BITWISE_MASK;
}
int lua_bit_none(lua_State* LS)
{
return lua_symmetric_bitwise(LS, combine_none, BITWISE_MASK);
}
int lua_bit_any(lua_State* LS)
{
return lua_symmetric_bitwise(LS, combine_any, 0);
}
int lua_bit_all(lua_State* LS)
{
return lua_symmetric_bitwise(LS, combine_all, BITWISE_MASK);
}
int lua_bit_parity(lua_State* LS)
{
return lua_symmetric_bitwise(LS, combine_parity, 0);
}
int lua_bit_lrotate(lua_State* LS)
{
return lua_shifter(LS, shift_lrotate);
}
int lua_bit_rrotate(lua_State* LS)
{
return lua_shifter(LS, shift_rrotate);
}
int lua_bit_lshift(lua_State* LS)
{
return lua_shifter(LS, shift_lshift);
}
int lua_bit_arshift(lua_State* LS)
{
return lua_shifter(LS, shift_arshift);
}
int lua_bit_lrshift(lua_State* LS)
{
return lua_shifter(LS, shift_lrshift);
}
int lua_print(lua_State* LS)
{
int stacksize = 0;
@ -800,23 +733,6 @@ void init_lua(window* win) throw()
lua_pushcfunction(L, lua_exec);
lua_setglobal(L, "exec");
//Bit table.
lua_newtable(L);
SETFIELDFUN(L, -1, "none", lua_bit_none);
SETFIELDFUN(L, -1, "bnot", lua_bit_none);
SETFIELDFUN(L, -1, "any", lua_bit_any);
SETFIELDFUN(L, -1, "bor", lua_bit_any);
SETFIELDFUN(L, -1, "all", lua_bit_all);
SETFIELDFUN(L, -1, "band", lua_bit_all);
SETFIELDFUN(L, -1, "parity", lua_bit_parity);
SETFIELDFUN(L, -1, "bxor", lua_bit_parity);
SETFIELDFUN(L, -1, "lrotate", lua_bit_lrotate);
SETFIELDFUN(L, -1, "rrotate", lua_bit_rrotate);
SETFIELDFUN(L, -1, "lshift", lua_bit_lshift);
SETFIELDFUN(L, -1, "arshift", lua_bit_arshift);
SETFIELDFUN(L, -1, "lrshift", lua_bit_lrshift);
lua_setglobal(L, "bit");
//Gui table.
lua_newtable(L);
SETFIELDFUN(L, -1, "resolution", lua_gui_resolution);
@ -867,6 +783,8 @@ void init_lua(window* win) throw()
SETFIELDFUN(L, -1, "readonly", lua_movie_readonly);
SETFIELDFUN(L, -1, "set_readwrite", lua_movie_set_readwrite);
lua_setglobal(L, "movie");
register_lua_functions(L);
}
bool lua_requests_repaint = false;

View file

@ -12,6 +12,7 @@ struct lua_State;
*/
class lua_function
{
public:
/**
* Register function.
*/
@ -25,7 +26,7 @@ class lua_function
* Invoke function.
*/
virtual int invoke(lua_State* L, window* win) = 0;
private:
protected:
std::string fname;
};

118
lua/bit.cpp Normal file
View file

@ -0,0 +1,118 @@
#include "lua-int.hpp"
#define BITWISE_BITS 48
#define BITWISE_MASK ((1ULL << (BITWISE_BITS)) - 1)
namespace
{
uint64_t combine_none(uint64_t chain, uint64_t arg)
{
return (chain & ~arg) & BITWISE_MASK;
}
uint64_t combine_any(uint64_t chain, uint64_t arg)
{
return (chain | arg) & BITWISE_MASK;
}
uint64_t combine_all(uint64_t chain, uint64_t arg)
{
return (chain & arg) & BITWISE_MASK;
}
uint64_t combine_parity(uint64_t chain, uint64_t arg)
{
return (chain ^ arg) & BITWISE_MASK;
}
uint64_t shift_lrotate(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base = (base << amount) | (base >> (bits - amount));
return base & mask & BITWISE_MASK;
}
uint64_t shift_rrotate(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base = (base >> amount) | (base << (bits - amount));
return base & mask & BITWISE_MASK;
}
uint64_t shift_lshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base <<= amount;
return base & mask & BITWISE_MASK;
}
uint64_t shift_lrshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
base >>= amount;
return base & BITWISE_MASK;
}
uint64_t shift_arshift(uint64_t base, uint64_t amount, uint64_t bits)
{
uint64_t mask = ((1ULL << bits) - 1);
base &= mask;
bool negative = ((base >> (bits - 1)) != 0);
base >>= amount;
base |= ((negative ? BITWISE_MASK : 0) << (bits - amount));
return base & mask & BITWISE_MASK;
}
template<uint64_t (*combine)(uint64_t chain, uint64_t arg), uint64_t init>
class lua_symmetric_bitwise : public lua_function
{
public:
lua_symmetric_bitwise(const std::string& s) : lua_function(s) {};
int invoke(lua_State* L, window* win)
{
int stacksize = 0;
while(!lua_isnone(L, stacksize + 1))
stacksize++;
uint64_t ret = init;
for(int i = 0; i < stacksize; i++)
ret = combine(ret, get_numeric_argument<uint64_t>(L, i + 1, fname.c_str()));
lua_pushnumber(L, ret);
return 1;
}
};
template<uint64_t (*shift)(uint64_t base, uint64_t amount, uint64_t bits)>
class lua_shifter : public lua_function
{
public:
lua_shifter(const std::string& s) : lua_function(s) {};
int invoke(lua_State* L, window* win)
{
uint64_t base;
uint64_t amount = 1;
uint64_t bits = BITWISE_BITS;
base = get_numeric_argument<uint64_t>(L, 1, fname.c_str());
get_numeric_argument(L, 2, amount, fname.c_str());
get_numeric_argument(L, 3, bits, fname.c_str());
lua_pushnumber(L, shift(base, amount, bits));
return 1;
}
};
lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_none("bit.none");
lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_bnot("bit.bnot");
lua_symmetric_bitwise<combine_any, 0> bit_any("bit.any");
lua_symmetric_bitwise<combine_any, 0> bit_bor("bit.bor");
lua_symmetric_bitwise<combine_all, BITWISE_MASK> bit_all("bit.all");
lua_symmetric_bitwise<combine_all, BITWISE_MASK> bit_band("bit.band");
lua_symmetric_bitwise<combine_parity, 0> bit_parity("bit.parity");
lua_symmetric_bitwise<combine_parity, 0> bit_bxor("bit.bxor");
lua_shifter<shift_lrotate> bit_lrotate("bit.lrotate");
lua_shifter<shift_rrotate> bit_rrotate("bit.rrotate");
lua_shifter<shift_lshift> bit_lshift("bit.lshift");
lua_shifter<shift_arshift> bit_arshift("bit.arshift");
lua_shifter<shift_lrshift> bit_lrshift("bit.lrshift");
}