200 lines
5.9 KiB
C++
200 lines
5.9 KiB
C++
#include "common/luajit.hh"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <chrono>
|
|
#include <cinttypes>
|
|
#include <cctype>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <variant>
|
|
|
|
#include <lua.hpp>
|
|
|
|
#include "common/logger.hh"
|
|
#include "common/logger_ref.hh"
|
|
#include "common/luajit_thread.hh"
|
|
|
|
|
|
namespace nf7::luajit {
|
|
|
|
template <> void PushMeta<StdTable>(lua_State* L) noexcept {
|
|
if (!luaL_newmetatable(L, MetaName<StdTable>::kValue)) {
|
|
return;
|
|
}
|
|
luaL_openlibs(L);
|
|
lua_createtable(L, 0, 0);
|
|
{
|
|
// ---- 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") {
|
|
Push(L, static_cast<nf7::Value::Integer>(luaL_checkinteger(L, 1)));
|
|
} else {
|
|
return luaL_error(L, "unknown type specifier: %s", type);
|
|
}
|
|
} else {
|
|
Push(L, Check<nf7::Value>(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");
|
|
|
|
|
|
// ---- lua std libs ----
|
|
const auto Copy =
|
|
[L](const char* name, const char* expr, bool imm) {
|
|
luaL_loadstring(L, expr);
|
|
lua_call(L, 0, 1);
|
|
if (imm) {
|
|
Push(L, ImmTable {});
|
|
lua_setmetatable(L, -2);
|
|
}
|
|
lua_setfield(L, -2, name);
|
|
};
|
|
Copy("assert", "return assert", false);
|
|
Copy("error", "return error", false);
|
|
Copy("ipairs", "return ipairs", false);
|
|
Copy("loadstring", "return loadstring", false);
|
|
Copy("next", "return next", false);
|
|
Copy("pairs", "return pairs", false);
|
|
Copy("pcall", "return pcall", false);
|
|
Copy("rawequal", "return rawequal", false);
|
|
Copy("rawget", "return rawget", false);
|
|
Copy("select", "return select", false);
|
|
Copy("setfenv", "return setfenv", false);
|
|
Copy("setmetatable", "return setmetatable", false);
|
|
Copy("tonumber", "return tonumber", false);
|
|
Copy("tostring", "return tostring", false);
|
|
Copy("type", "return type", false);
|
|
Copy("unpack", "return unpack", false);
|
|
Copy("_VERSION", "return _VERSION", false);
|
|
Copy("xpcall", "return xpcall", false);
|
|
|
|
Copy("bit", "return require(\"bit\")", true);
|
|
Copy("coroutine", "return coroutine", true);
|
|
Copy("math", "return math", true);
|
|
Copy("string", "return string", true);
|
|
Copy("table", "return table", true);
|
|
}
|
|
lua_setfield(L, -2, "__index");
|
|
}
|
|
|
|
template <> void PushMeta<std::shared_ptr<nf7::NodeRootLambda>>(lua_State* L) noexcept {
|
|
using T = std::shared_ptr<nf7::NodeRootLambda>;
|
|
if (!luaL_newmetatable(L, MetaName<T>::kValue)) {
|
|
return;
|
|
}
|
|
lua_createtable(L, 0, 0);
|
|
{
|
|
// la:send(nf7, key, value)
|
|
lua_pushcfunction(L, [](auto L) {
|
|
auto la = Check<T>(L, 1);
|
|
la->ExecSend(luaL_checkstring(L, 2), Check<nf7::Value>(L, 3));
|
|
return 0;
|
|
});
|
|
lua_setfield(L, -2, "send");
|
|
|
|
// la:recv(nf7, {name1, name2, ...})
|
|
lua_pushcfunction(L, [](auto L) {
|
|
auto la = Check<T>(L, 1);
|
|
auto th = luajit::Thread::GetPtr(L, 2);
|
|
|
|
const auto names = Check<std::vector<std::string>>(L, 3);
|
|
if (names.size() == 0) {
|
|
return 0;
|
|
}
|
|
|
|
auto fu = la->Select(
|
|
std::unordered_set<std::string>(names.begin(), names.end()));
|
|
if (fu.done()) {
|
|
try {
|
|
const auto& p = fu.value();
|
|
lua_pushstring(L, p.first.c_str());
|
|
luajit::Push(L, p.second);
|
|
return 2;
|
|
} catch (nf7::Exception&) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
fu.ThenIf([L, th](auto& p) {
|
|
th->ExecResume(L, p.first, p.second);
|
|
}).template Catch<nf7::Exception>(nullptr, [L, th](nf7::Exception&) {
|
|
th->ExecResume(L);
|
|
});
|
|
return th->Yield(L, la);
|
|
}
|
|
});
|
|
lua_setfield(L, -2, "recv");
|
|
}
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, [](auto L) {
|
|
Check<T>(L, 1).~shared_ptr();
|
|
return 0;
|
|
});
|
|
lua_setfield(L, -2, "__gc");
|
|
}
|
|
|
|
void Push(lua_State* L, GlobalTable) noexcept {
|
|
if (luaL_newmetatable(L, "nf7::luajit::GlobalTable")) {
|
|
Push(L, StdTable {});
|
|
lua_setfield(L, -2, "std");
|
|
}
|
|
}
|
|
void Push(lua_State* L, ImmEnv) noexcept {
|
|
if (luaL_newmetatable(L, "nf7::luajit::ImmEnv")) {
|
|
lua_createtable(L, 0, 0);
|
|
{
|
|
Push(L, GlobalTable {});
|
|
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 Push(lua_State* L, ImmTable) noexcept {
|
|
if (luaL_newmetatable(L, "nf7::luajit::ImmTable")) {
|
|
lua_pushcfunction(L, [](auto L) { return luaL_error(L, "table is immutable"); });
|
|
lua_setfield(L, -2, "__newindex");
|
|
}
|
|
}
|
|
|
|
} // namespace nf7::luajit
|