rename NodeRootSelectLambda -> NodeRootLambda
and improve common/luajit.hh
This commit is contained in:
parent
7d696cfbd9
commit
f96188ef14
@ -107,7 +107,7 @@ target_sources(nf7
|
||||
common/nfile_watcher.hh
|
||||
common/node.hh
|
||||
common/node_link_store.hh
|
||||
common/node_root_select_lambda.hh
|
||||
common/node_root_lambda.hh
|
||||
common/ptr_selector.hh
|
||||
common/queue.hh
|
||||
common/ring_buffer.hh
|
||||
|
322
common/luajit.cc
322
common/luajit.cc
@ -13,12 +13,11 @@
|
||||
#include "common/logger.hh"
|
||||
#include "common/logger_ref.hh"
|
||||
#include "common/luajit_thread.hh"
|
||||
#include "common/luajit_std.hh"
|
||||
|
||||
|
||||
namespace nf7::luajit {
|
||||
|
||||
static void PushStd(lua_State* L) noexcept;
|
||||
|
||||
// buffer <-> lua value conversion
|
||||
template <typename T>
|
||||
static size_t PushArrayFromBytes(
|
||||
@ -29,25 +28,6 @@ template <typename T>
|
||||
static size_t ToBytes(lua_State* L, uint8_t* ptr, uint8_t* end);
|
||||
|
||||
|
||||
void PushGlobalTable(lua_State* L) noexcept {
|
||||
if (luaL_newmetatable(L, "nf7::luajit::PushGlobalTable")) {
|
||||
PushStd(L);
|
||||
lua_setfield(L, -2, "std");
|
||||
}
|
||||
}
|
||||
void PushImmEnv(lua_State* L) noexcept {
|
||||
if (luaL_newmetatable(L, "nf7::luajit::PushImmEnv")) {
|
||||
lua_createtable(L, 0, 0);
|
||||
PushGlobalTable(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) { return luaL_error(L, "global is immutable"); });
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PushValue(lua_State* L, const nf7::Value& v) noexcept {
|
||||
new (lua_newuserdata(L, sizeof(v))) nf7::Value(v);
|
||||
|
||||
@ -102,14 +82,60 @@ void PushValue(lua_State* L, const nf7::Value& v) noexcept {
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
std::optional<nf7::Value> ToValue(lua_State* L, int idx) noexcept {
|
||||
if (lua_isnoneornil(L, idx)) {
|
||||
return nf7::Value {nf7::Value::Pulse {}};
|
||||
}
|
||||
if (lua_isnumber(L, idx)) {
|
||||
const double n = lua_tonumber(L, idx);
|
||||
return nf7::Value {n};
|
||||
}
|
||||
if (lua_isboolean(L, idx)) {
|
||||
return nf7::Value {bool {!!lua_toboolean(L, idx)}};
|
||||
}
|
||||
if (lua_isstring(L, idx)) {
|
||||
size_t len;
|
||||
const char* str = lua_tolstring(L, idx, &len);
|
||||
return nf7::Value {std::string {str, len}};
|
||||
}
|
||||
if (auto vec = ToVector(L, idx)) {
|
||||
return nf7::Value {std::move(*vec)};
|
||||
}
|
||||
if (auto vec = ToMutableVector(L, idx)) {
|
||||
return nf7::Value {std::move(*vec)};
|
||||
}
|
||||
if (lua_istable(L, idx)) {
|
||||
std::vector<nf7::Value::TuplePair> tup;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, idx)) {
|
||||
std::string name = "";
|
||||
if (lua_isstring(L, -2)) {
|
||||
name = lua_tostring(L, -2);
|
||||
}
|
||||
auto val = ToValue(L, -1);
|
||||
if (!val) return std::nullopt;
|
||||
tup.push_back({std::move(name), std::move(*val)});
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return nf7::Value {std::move(tup)};
|
||||
}
|
||||
if (auto val = ToRef<nf7::Value>(L, idx, "nf7::Value")) {
|
||||
return *val;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void PushVector(lua_State* L, const nf7::Value::ConstVector& v) noexcept {
|
||||
assert(v);
|
||||
static const char* kTypeName = "nf7::Value::ConstVector";
|
||||
using T = nf7::Value::ConstVector;
|
||||
|
||||
assert(v != nullptr);
|
||||
new (lua_newuserdata(L, sizeof(v))) nf7::Value::ConstVector(v);
|
||||
|
||||
if (luaL_newmetatable(L, "nf7::Value::ConstVector")) {
|
||||
if (luaL_newmetatable(L, kTypeName)) {
|
||||
lua_createtable(L, 0, 0);
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
const auto& v = CheckRef<nf7::Value::ConstVector>(L, 1, "nf7::Value::ConstVector");
|
||||
const auto& v = CheckRef<T>(L, 1, kTypeName);
|
||||
const auto offset = luaL_checkinteger(L, 2);
|
||||
if (offset < 0) {
|
||||
return luaL_error(L, "negative offset");
|
||||
@ -189,14 +215,14 @@ void PushVector(lua_State* L, const nf7::Value::ConstVector& v) noexcept {
|
||||
lua_setfield(L, -2, "get");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
const auto& v = CheckRef<nf7::Value::ConstVector>(L, 1, "nf7::Value::ConstVector");
|
||||
const auto& v = CheckRef<T>(L, 1, kTypeName);
|
||||
lua_pushlstring(L, reinterpret_cast<const char*>(v->data()), v->size());
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "str");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
const auto& v = CheckRef<nf7::Value::ConstVector>(L, 1, "nf7::Value::ConstVector");
|
||||
const auto& v = CheckRef<T>(L, 1, kTypeName);
|
||||
lua_pushinteger(L, static_cast<lua_Integer>(v->size()));
|
||||
return 1;
|
||||
});
|
||||
@ -204,20 +230,23 @@ void PushVector(lua_State* L, const nf7::Value::ConstVector& v) noexcept {
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
CheckRef<nf7::Value::ConstVector>(L, 1, "nf7::Value::ConstVector").~shared_ptr();
|
||||
CheckRef<T>(L, 1, kTypeName).~shared_ptr();
|
||||
return 0;
|
||||
});
|
||||
lua_setfield(L, -2, "__gc");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
new (lua_newuserdata(L, sizeof(v))) std::vector<uint8_t>(std::move(v));
|
||||
|
||||
if (luaL_newmetatable(L, "nf7::Value::MutableVector")) {
|
||||
void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
constexpr const char* kTypeName = "nf7::Value::MutableVector";
|
||||
using T = std::vector<uint8_t>;
|
||||
|
||||
new (lua_newuserdata(L, sizeof(v))) T(std::move(v));
|
||||
if (luaL_newmetatable(L, kTypeName)) {
|
||||
lua_createtable(L, 0, 0);
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto& v = CheckRef<std::vector<uint8_t>>(L, 1, "nf7::Value::MutableVector");
|
||||
auto& v = CheckRef<T>(L, 1, kTypeName);
|
||||
const lua_Integer offset = luaL_checkinteger(L, 2);
|
||||
if (offset < 0) return luaL_error(L, "negative offset");
|
||||
|
||||
@ -261,7 +290,7 @@ void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
lua_setfield(L, -2, "set");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto& v = CheckRef<std::vector<uint8_t>>(L, 1, "nf7::Value::MutableVector");
|
||||
auto& v = CheckRef<T>(L, 1, kTypeName);
|
||||
const lua_Integer size = luaL_checkinteger(L, 2);
|
||||
if (size < 0) return luaL_error(L, "negative size");
|
||||
v.resize(static_cast<size_t>(size));
|
||||
@ -270,10 +299,10 @@ void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
lua_setfield(L, -2, "resize");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto& dst = CheckRef<std::vector<uint8_t>>(L, 1, "nf7::Value::MutableVector");
|
||||
auto& dst = CheckRef<T>(L, 1, kTypeName);
|
||||
const auto dst_off = luaL_checkinteger(L, 2);
|
||||
|
||||
const std::vector<uint8_t>* src;
|
||||
const T* src;
|
||||
if (const auto& v = ToVector(L, 3)) {
|
||||
src = &**v;
|
||||
} else if (const auto& mv = ToMutableVector(L, 3)) {
|
||||
@ -302,23 +331,25 @@ void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
CheckRef<std::vector<uint8_t>>(L, 1, "nf7::Value::MutableVector").~vector();
|
||||
CheckRef<T>(L, 1, kTypeName).~vector();
|
||||
return 0;
|
||||
});
|
||||
lua_setfield(L, -2, "__gc");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
void PushNodeRootSelectLambda(
|
||||
lua_State* L, const std::shared_ptr<nf7::NodeRootSelectLambda>& la) noexcept {
|
||||
|
||||
void PushNodeRootLambda(
|
||||
lua_State* L, const std::shared_ptr<nf7::NodeRootLambda>& la) noexcept {
|
||||
constexpr const char* kTypeName = "nf7::NodeRootLambda";
|
||||
assert(la);
|
||||
|
||||
using T = std::shared_ptr<nf7::NodeRootSelectLambda>;
|
||||
using T = std::shared_ptr<nf7::NodeRootLambda>;
|
||||
new (lua_newuserdata(L, sizeof(T))) T {la};
|
||||
|
||||
if (luaL_newmetatable(L, "nf7::NodeRootSelectLambda")) {
|
||||
if (luaL_newmetatable(L, kTypeName)) {
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
CheckRef<T>(L, 1, "nf7::NodeRootSelectLambda").~T();
|
||||
CheckRef<T>(L, 1, kTypeName).~T();
|
||||
return 0;
|
||||
});
|
||||
lua_setfield(L, -2, "__gc");
|
||||
@ -327,205 +358,24 @@ void PushNodeRootSelectLambda(
|
||||
}
|
||||
|
||||
|
||||
std::optional<nf7::Value> ToValue(lua_State* L, int idx) noexcept {
|
||||
if (lua_isnoneornil(L, idx)) {
|
||||
return nf7::Value {nf7::Value::Pulse {}};
|
||||
void PushGlobalTable(lua_State* L) noexcept {
|
||||
if (luaL_newmetatable(L, "nf7::luajit::GlobalTable")) {
|
||||
PushStdTable(L);
|
||||
lua_setfield(L, -2, "std");
|
||||
}
|
||||
if (lua_isnumber(L, idx)) {
|
||||
const double n = lua_tonumber(L, idx);
|
||||
return nf7::Value {n};
|
||||
}
|
||||
if (lua_isboolean(L, idx)) {
|
||||
return nf7::Value {bool {!!lua_toboolean(L, idx)}};
|
||||
}
|
||||
if (lua_isstring(L, idx)) {
|
||||
size_t len;
|
||||
const char* str = lua_tolstring(L, idx, &len);
|
||||
return nf7::Value {std::string {str, len}};
|
||||
}
|
||||
if (auto vec = ToVector(L, idx)) {
|
||||
return nf7::Value {std::move(*vec)};
|
||||
}
|
||||
if (auto vec = ToMutableVector(L, idx)) {
|
||||
return nf7::Value {std::move(*vec)};
|
||||
}
|
||||
if (lua_istable(L, idx)) {
|
||||
std::vector<nf7::Value::TuplePair> tup;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, idx)) {
|
||||
std::string name = "";
|
||||
if (lua_isstring(L, -2)) {
|
||||
name = lua_tostring(L, -2);
|
||||
}
|
||||
auto val = ToValue(L, -1);
|
||||
if (!val) return std::nullopt;
|
||||
tup.push_back({std::move(name), std::move(*val)});
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
void PushImmEnv(lua_State* L) noexcept {
|
||||
if (luaL_newmetatable(L, "nf7::luajit::ImmEnv")) {
|
||||
lua_createtable(L, 0, 0);
|
||||
{
|
||||
PushGlobalTable(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, [](auto L) { return luaL_error(L, "global is immutable"); });
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
}
|
||||
return nf7::Value {std::move(tup)};
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
if (auto val = ToRef<nf7::Value>(L, idx, "nf7::Value")) {
|
||||
return *val;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<nf7::Value::ConstVector> ToVector(lua_State* L, int idx) noexcept {
|
||||
auto ptr = ToRef<nf7::Value::ConstVector>(L, idx, "nf7::Value::ConstVector");
|
||||
if (!ptr) return std::nullopt;
|
||||
return *ptr;
|
||||
}
|
||||
std::optional<std::vector<uint8_t>> ToMutableVector(lua_State* L, int idx) noexcept {
|
||||
auto ptr = ToRef<std::vector<uint8_t>>(L, idx, "nf7::Value::MutableVector");
|
||||
if (!ptr) return std::nullopt;
|
||||
return std::move(*ptr);
|
||||
}
|
||||
|
||||
|
||||
static void PushStd(lua_State* L) noexcept {
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 0);
|
||||
lua_createtable(L, 0, 0);
|
||||
{
|
||||
// ---- lua lib ----
|
||||
|
||||
// assert(expr[, msg])
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (lua_toboolean(L, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (lua_gettop(L) >= 2) {
|
||||
return luaL_error(L, lua_tostring(L, 2));
|
||||
} else {
|
||||
return luaL_error(L, "assertion failure");
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "assert");
|
||||
|
||||
// error(msg)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
return luaL_error(L, luaL_checkstring(L, 1));
|
||||
});
|
||||
lua_setfield(L, -2, "error");
|
||||
|
||||
// load(str)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (0 != luaL_loadstring(L, luaL_checkstring(L, 1))) {
|
||||
return luaL_error(L, "lua.load error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "load");
|
||||
|
||||
// pcall(func, args...) -> success, result
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (0 == lua_pcall(L, lua_gettop(L)-1, LUA_MULTRET, 0)) {
|
||||
lua_pushboolean(L, true);
|
||||
lua_insert(L, 1);
|
||||
return lua_gettop(L);
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
lua_insert(L, 1);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "pcall");
|
||||
|
||||
|
||||
// ---- math lib ----
|
||||
|
||||
// sin(theta)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::sin(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "sin");
|
||||
|
||||
// cos(theta)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::cos(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "cos");
|
||||
|
||||
// tan(slope)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::tan(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "tan");
|
||||
|
||||
|
||||
// ---- table lib ----
|
||||
|
||||
// meta(table, meta_table)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "meta");
|
||||
|
||||
|
||||
// ---- time lib ----
|
||||
|
||||
// now()
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
const auto now = nf7::Env::Clock::now().time_since_epoch();
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now);
|
||||
lua_pushnumber(L, static_cast<double>(ms.count())/1000.);
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "now");
|
||||
|
||||
|
||||
// ---- value lib ----
|
||||
|
||||
// value(entity) -> value
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (lua_isstring(L, 2)) {
|
||||
const auto type = std::string_view {lua_tostring(L, 2)};
|
||||
if (type == "integer" || type == "int") {
|
||||
PushValue(L, static_cast<nf7::Value::Integer>(luaL_checkinteger(L, 1)));
|
||||
} else {
|
||||
return luaL_error(L, "unknown type specifier: %s", type);
|
||||
}
|
||||
} else {
|
||||
PushValue(L, CheckValue(L, 1));
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "value");
|
||||
|
||||
// mvector(vector or mutable vector) -> mutable vector
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (auto imm = ToVector(L, 1)) {
|
||||
if (imm->use_count() == 1) {
|
||||
PushMutableVector(L, std::move(const_cast<std::vector<uint8_t>&>(**imm)));
|
||||
} else {
|
||||
PushMutableVector(L, std::vector<uint8_t> {**imm});
|
||||
}
|
||||
return 1;
|
||||
} else if (auto mut = ToMutableVector(L, 1)) {
|
||||
PushMutableVector(L, std::vector<uint8_t> {*mut});
|
||||
return 1;
|
||||
} else {
|
||||
PushMutableVector(L, {});
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "mvector");
|
||||
|
||||
|
||||
// ---- bit manip ----
|
||||
luaL_openlibs(L);
|
||||
luaL_loadstring(L, "return require(\"bit\")");
|
||||
lua_call(L, 0, 1);
|
||||
lua_setfield(L, -2, "bit");
|
||||
}
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
|
||||
|
150
common/luajit.hh
150
common/luajit.hh
@ -9,25 +9,84 @@
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "common/node_root_select_lambda.hh"
|
||||
#include "common/node_root_lambda.hh"
|
||||
#include "common/value.hh"
|
||||
|
||||
|
||||
namespace nf7::luajit {
|
||||
|
||||
void PushGlobalTable(lua_State*) noexcept;
|
||||
void PushImmEnv(lua_State*) noexcept;
|
||||
// ---- utility
|
||||
inline bool MatchMetaName(lua_State* L, int idx, const char* type) noexcept {
|
||||
if (0 == lua_getmetatable(L, idx)) {
|
||||
return false;
|
||||
}
|
||||
luaL_getmetatable(L, type);
|
||||
const bool ret = lua_rawequal(L, -1, -2);
|
||||
lua_pop(L, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline T& NewUserData(lua_State* L, Args&&... args) noexcept {
|
||||
return *(new (lua_newuserdata(L, sizeof(T))) T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
|
||||
// ---- reference conversion
|
||||
template <typename T>
|
||||
inline T* ToRef(lua_State* L, int idx, const char* type) noexcept {
|
||||
return MatchMetaName(L, idx, type)? reinterpret_cast<T*>(lua_touserdata(L, idx)): nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline T& CheckRef(lua_State* L, int idx, const char* type) {
|
||||
return *reinterpret_cast<T*>(luaL_checkudata(L, idx, type));
|
||||
}
|
||||
|
||||
|
||||
// ---- Value conversion
|
||||
void PushValue(lua_State*, const nf7::Value&) noexcept;
|
||||
void PushVector(lua_State*, const nf7::Value::ConstVector&) noexcept;
|
||||
void PushMutableVector(lua_State*, std::vector<uint8_t>&&) noexcept;
|
||||
void PushNodeRootSelectLambda(
|
||||
lua_State*, const std::shared_ptr<nf7::NodeRootSelectLambda>&) noexcept;
|
||||
|
||||
std::optional<nf7::Value> ToValue(lua_State*, int) noexcept;
|
||||
std::optional<nf7::Value::ConstVector> ToVector(lua_State*, int) noexcept;
|
||||
std::optional<std::vector<uint8_t>> ToMutableVector(lua_State*, int) noexcept;
|
||||
inline nf7::Value CheckValue(lua_State* L, int idx) {
|
||||
auto v = ToValue(L, idx);
|
||||
if (!v) luaL_error(L, "expected nf7::Value");
|
||||
return std::move(*v);
|
||||
}
|
||||
|
||||
void PushVector(lua_State*, const nf7::Value::ConstVector&) noexcept;
|
||||
inline std::optional<nf7::Value::ConstVector> ToVector(lua_State* L, int idx) noexcept {
|
||||
auto ptr = ToRef<nf7::Value::ConstVector>(L, idx, "nf7::Value::ConstVector");
|
||||
if (!ptr) return std::nullopt;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
void PushMutableVector(lua_State*, std::vector<uint8_t>&&) noexcept;
|
||||
inline std::optional<std::vector<uint8_t>> ToMutableVector(lua_State* L, int idx) noexcept {
|
||||
auto ptr = ToRef<std::vector<uint8_t>>(L, idx, "nf7::Value::MutableVector");
|
||||
if (!ptr) return std::nullopt;
|
||||
return std::move(*ptr);
|
||||
}
|
||||
|
||||
void PushNodeRootLambda(
|
||||
lua_State*, const std::shared_ptr<nf7::NodeRootLambda>&) noexcept;
|
||||
inline const std::shared_ptr<nf7::NodeRootLambda>& CheckNodeRootLambda(lua_State* L, int idx) {
|
||||
return CheckRef<std::shared_ptr<nf7::NodeRootLambda>>(L, idx, "nf7::NodeRootLambda");
|
||||
}
|
||||
|
||||
inline void ToStringList(lua_State* L, int idx, std::vector<std::string>& v) noexcept {
|
||||
const size_t n = lua_objlen(L, idx);
|
||||
v.clear();
|
||||
v.reserve(n);
|
||||
for (int i = 1; i <= static_cast<int>(n); ++i) {
|
||||
lua_rawgeti(L, idx, i);
|
||||
if (auto str = lua_tostring(L, -1)) {
|
||||
v.push_back(str);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- overloaded Push function for template
|
||||
template <typename T>
|
||||
void Push(lua_State* L, T v) noexcept {
|
||||
if constexpr (std::is_integral<T>::value) {
|
||||
@ -55,10 +114,11 @@ inline void Push(lua_State* L, const std::vector<uint8_t>& v) noexcept {
|
||||
inline void Push(lua_State* L, std::vector<uint8_t>&& v) noexcept {
|
||||
luajit::PushMutableVector(L, std::move(v));
|
||||
}
|
||||
inline void Push(lua_State* L, const std::shared_ptr<nf7::NodeRootSelectLambda>& la) noexcept {
|
||||
luajit::PushNodeRootSelectLambda(L, la);
|
||||
inline void Push(lua_State* L, const std::shared_ptr<nf7::NodeRootLambda>& la) noexcept {
|
||||
luajit::PushNodeRootLambda(L, la);
|
||||
}
|
||||
|
||||
// pushes all args and returns a number of them
|
||||
inline int PushAll(lua_State*) noexcept {
|
||||
return 0;
|
||||
}
|
||||
@ -73,68 +133,8 @@ int PushAll(lua_State* L, T v, Args&&... args) noexcept {
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline void PushWeakPtr(lua_State* L, const std::weak_ptr<T>& wptr) noexcept {
|
||||
new (lua_newuserdata(L, sizeof(wptr))) std::weak_ptr<T>(wptr);
|
||||
}
|
||||
template <typename T>
|
||||
inline void PushWeakPtrDeleter(lua_State* L, const std::weak_ptr<T>& = {}) noexcept {
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
reinterpret_cast<std::weak_ptr<T>*>(lua_touserdata(L, 1))->~weak_ptr();
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
inline bool MatchMetaName(lua_State* L, int idx, const char* type) noexcept {
|
||||
if (0 == lua_getmetatable(L, idx)) {
|
||||
return false;
|
||||
}
|
||||
luaL_getmetatable(L, type);
|
||||
const bool ret = lua_rawequal(L, -1, -2);
|
||||
lua_pop(L, 2);
|
||||
return ret;
|
||||
}
|
||||
template <typename T>
|
||||
inline T* ToRef(lua_State* L, int idx, const char* type) noexcept {
|
||||
return MatchMetaName(L, idx, type)? reinterpret_cast<T*>(lua_touserdata(L, idx)): nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::shared_ptr<T> CheckWeakPtr(lua_State* L, int idx, const char* type) {
|
||||
auto ptr = reinterpret_cast<std::weak_ptr<T>*>(luaL_checkudata(L, idx, type));
|
||||
if (auto ret = ptr->lock()) {
|
||||
return ret;
|
||||
} else {
|
||||
luaL_error(L, "object expired: %s", typeid(T).name());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline T& CheckRef(lua_State* L, int idx, const char* type) {
|
||||
return *reinterpret_cast<T*>(luaL_checkudata(L, idx, type));
|
||||
}
|
||||
inline const std::shared_ptr<nf7::NodeRootSelectLambda>& CheckNodeRootSelectLambda(
|
||||
lua_State* L, int idx) {
|
||||
return CheckRef<std::shared_ptr<nf7::NodeRootSelectLambda>>(
|
||||
L, idx, "nf7::NodeRootSelectLambda");
|
||||
}
|
||||
inline nf7::Value CheckValue(lua_State* L, int idx) {
|
||||
auto v = ToValue(L, idx);
|
||||
if (!v) luaL_error(L, "expected nf7::Value");
|
||||
return std::move(*v);
|
||||
}
|
||||
|
||||
inline void ToStringList(lua_State* L, std::vector<std::string>& v, int idx) {
|
||||
const size_t n = lua_objlen(L, idx);
|
||||
v.clear();
|
||||
v.reserve(n);
|
||||
for (int i = 1; i <= static_cast<int>(n); ++i) {
|
||||
lua_rawgeti(L, idx, i);
|
||||
if (auto str = lua_tostring(L, -1)) {
|
||||
v.push_back(str);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
// ---- global table
|
||||
void PushGlobalTable(lua_State*) noexcept;
|
||||
void PushImmEnv(lua_State*) noexcept;
|
||||
|
||||
} // namespace nf7
|
||||
|
155
common/luajit_std.hh
Normal file
155
common/luajit_std.hh
Normal file
@ -0,0 +1,155 @@
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "common/luajit.hh"
|
||||
|
||||
|
||||
namespace nf7::luajit {
|
||||
|
||||
inline void PushStdTable(lua_State* L) noexcept {
|
||||
lua_newuserdata(L, 0);
|
||||
lua_createtable(L, 0, 0);
|
||||
lua_createtable(L, 0, 0);
|
||||
{
|
||||
// ---- lua lib ----
|
||||
|
||||
// assert(expr[, msg])
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (lua_toboolean(L, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (lua_gettop(L) >= 2) {
|
||||
return luaL_error(L, lua_tostring(L, 2));
|
||||
} else {
|
||||
return luaL_error(L, "assertion failure");
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "assert");
|
||||
|
||||
// error(msg)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
return luaL_error(L, luaL_checkstring(L, 1));
|
||||
});
|
||||
lua_setfield(L, -2, "error");
|
||||
|
||||
// load(str)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (0 != luaL_loadstring(L, luaL_checkstring(L, 1))) {
|
||||
return luaL_error(L, "lua.load error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "load");
|
||||
|
||||
// pcall(func, args...) -> success, result
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (0 == lua_pcall(L, lua_gettop(L)-1, LUA_MULTRET, 0)) {
|
||||
lua_pushboolean(L, true);
|
||||
lua_insert(L, 1);
|
||||
return lua_gettop(L);
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
lua_insert(L, 1);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "pcall");
|
||||
|
||||
|
||||
// ---- math lib ----
|
||||
|
||||
// sin(theta)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::sin(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "sin");
|
||||
|
||||
// cos(theta)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::cos(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "cos");
|
||||
|
||||
// tan(theta)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
lua_pushnumber(L, std::tan(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "tan");
|
||||
|
||||
|
||||
// ---- table lib ----
|
||||
|
||||
// meta(table, meta_table)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "meta");
|
||||
|
||||
|
||||
// ---- time lib ----
|
||||
|
||||
// now()
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
const auto now = nf7::Env::Clock::now().time_since_epoch();
|
||||
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now);
|
||||
lua_pushnumber(L, static_cast<double>(ms.count())/1000.);
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "now");
|
||||
|
||||
|
||||
// ---- value lib ----
|
||||
|
||||
// value(entity) -> value
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (lua_isstring(L, 2)) {
|
||||
const auto type = std::string_view {lua_tostring(L, 2)};
|
||||
if (type == "integer" || type == "int") {
|
||||
PushValue(L, static_cast<nf7::Value::Integer>(luaL_checkinteger(L, 1)));
|
||||
} else {
|
||||
return luaL_error(L, "unknown type specifier: %s", type);
|
||||
}
|
||||
} else {
|
||||
PushValue(L, CheckValue(L, 1));
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(L, -2, "value");
|
||||
|
||||
// mvector(vector or mutable vector) -> mutable vector
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
if (auto imm = ToVector(L, 1)) {
|
||||
if (imm->use_count() == 1) {
|
||||
PushMutableVector(L, std::move(const_cast<std::vector<uint8_t>&>(**imm)));
|
||||
} else {
|
||||
PushMutableVector(L, std::vector<uint8_t> {**imm});
|
||||
}
|
||||
return 1;
|
||||
} else if (auto mut = ToMutableVector(L, 1)) {
|
||||
PushMutableVector(L, std::vector<uint8_t> {*mut});
|
||||
return 1;
|
||||
} else {
|
||||
PushMutableVector(L, {});
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "mvector");
|
||||
|
||||
|
||||
// ---- bit manip ----
|
||||
luaL_openlibs(L);
|
||||
luaL_loadstring(L, "return require(\"bit\")");
|
||||
lua_call(L, 0, 1);
|
||||
lua_setfield(L, -2, "bit");
|
||||
}
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
} // namespace nf7::luajit
|
@ -6,7 +6,7 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "common/node.hh"
|
||||
#include "common/node_root_select_lambda.hh"
|
||||
#include "common/node_root_lambda.hh"
|
||||
|
||||
|
||||
namespace nf7::luajit {
|
||||
@ -42,7 +42,7 @@ void Thread::Resume(lua_State* L, int narg) noexcept {
|
||||
|
||||
// set global table
|
||||
PushGlobalTable(L);
|
||||
PushWeakPtr(L, weak_from_this());
|
||||
NewUserData<std::weak_ptr<Thread>>(L, weak_from_this());
|
||||
PushMeta(L);
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setfield(L, -2, "nf7");
|
||||
@ -120,7 +120,10 @@ Thread::Handler Thread::CreateNodeLambdaHandler(
|
||||
|
||||
static void PushMeta(lua_State* L) noexcept {
|
||||
if (luaL_newmetatable(L, Thread::kTypeName)) {
|
||||
PushWeakPtrDeleter<Thread>(L);
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
CheckRef<std::weak_ptr<Thread>>(L, 1, Thread::kTypeName).~weak_ptr();
|
||||
return 0;
|
||||
});
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
@ -164,7 +167,7 @@ static void PushMeta(lua_State* L) noexcept {
|
||||
auto& f = th->env().GetFileOrThrow(static_cast<nf7::File::Id>(id));
|
||||
if (iface == "node") {
|
||||
th->ExecResume(
|
||||
L, nf7::NodeRootSelectLambda::Create(
|
||||
L, nf7::NodeRootLambda::Create(
|
||||
th->ctx(), f.template interfaceOrThrow<nf7::Node>()));
|
||||
} else {
|
||||
throw nf7::Exception {"unknown interface: "+iface};
|
||||
@ -193,7 +196,7 @@ static void PushMeta(lua_State* L) noexcept {
|
||||
// nf7:send(obj, params...)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto th = Thread::GetPtr(L, 1);
|
||||
auto la = luajit::CheckNodeRootSelectLambda(L, 2);
|
||||
auto la = luajit::CheckNodeRootLambda(L, 2);
|
||||
la->ExecSend(luaL_checkstring(L, 3), luajit::CheckValue(L, 4));
|
||||
return 0;
|
||||
});
|
||||
@ -202,7 +205,7 @@ static void PushMeta(lua_State* L) noexcept {
|
||||
// nf7:recv(obj, params...)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto th = Thread::GetPtr(L, 1);
|
||||
auto la = luajit::CheckNodeRootSelectLambda(L, 2);
|
||||
auto la = luajit::CheckNodeRootLambda(L, 2);
|
||||
|
||||
std::unordered_set<std::string> names;
|
||||
if (lua_istable(L, 3)) {
|
||||
|
@ -49,9 +49,14 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
|
||||
// must be called on luajit thread
|
||||
static std::shared_ptr<Thread> GetPtr(lua_State* L, int idx) {
|
||||
auto th = CheckWeakPtr<Thread>(L, idx, kTypeName);
|
||||
th->EnsureActive(L);
|
||||
return th;
|
||||
auto th = CheckRef<std::weak_ptr<Thread>>(L, idx, kTypeName).lock();
|
||||
if (th) {
|
||||
th->EnsureActive(L);
|
||||
return th;
|
||||
} else {
|
||||
luaL_error(L, "thread expired");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Thread() = delete;
|
||||
|
@ -19,14 +19,14 @@
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
class NodeRootSelectLambda : public nf7::Node::Lambda,
|
||||
public std::enable_shared_from_this<NodeRootSelectLambda> {
|
||||
class NodeRootLambda : public nf7::Node::Lambda,
|
||||
public std::enable_shared_from_this<NodeRootLambda> {
|
||||
public:
|
||||
using Pair = std::pair<std::string, nf7::Value>;
|
||||
|
||||
static std::shared_ptr<NodeRootSelectLambda> Create(
|
||||
static std::shared_ptr<NodeRootLambda> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, nf7::Node& n) noexcept {
|
||||
auto ret = std::make_shared<NodeRootSelectLambda>(ctx->env(), ctx->initiator(), ctx);
|
||||
auto ret = std::make_shared<NodeRootLambda>(ctx->env(), ctx->initiator(), ctx);
|
||||
ret->target_ = n.CreateLambda(ret);
|
||||
return ret;
|
||||
}
|
@ -232,14 +232,14 @@ nf7::Future<std::shared_ptr<LuaNode::Meta>> LuaNode::Build() noexcept {
|
||||
auto ret = std::make_shared<Meta>();
|
||||
|
||||
lua_getfield(L, 1, "inputs");
|
||||
nf7::luajit::ToStringList(L, ret->inputs, -1);
|
||||
nf7::luajit::ToStringList(L, -1, ret->inputs);
|
||||
if (nf7::util::Uniq(ret->inputs) > 0) {
|
||||
throw nf7::Exception {"duplicated inputs"};
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "outputs");
|
||||
nf7::luajit::ToStringList(L, ret->outputs, -1);
|
||||
nf7::luajit::ToStringList(L, -1, ret->outputs);
|
||||
if (nf7::util::Uniq(ret->outputs)) {
|
||||
throw nf7::Exception {"duplicated outputs"};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user