Reworking the keyword parser, also fixed some dynamic linking issues
This commit is contained in:
@@ -115,7 +115,7 @@ ifeq "$(OS)" "Linux"
|
|||||||
LUPREXSTATIC_EXE=luprexstatic
|
LUPREXSTATIC_EXE=luprexstatic
|
||||||
COMPILE=g++ -Wall $(OPT) -std=c++17 -fvisibility=hidden -c -MMD -fPIC -o
|
COMPILE=g++ -Wall $(OPT) -std=c++17 -fvisibility=hidden -c -MMD -fPIC -o
|
||||||
LINKDLL=g++ -Wall $(OPT) -std=c++17 -export-dynamic -Wl,--no-allow-shlib-undefined -Wl,-z,defs -shared -o
|
LINKDLL=g++ -Wall $(OPT) -std=c++17 -export-dynamic -Wl,--no-allow-shlib-undefined -Wl,-z,defs -shared -o
|
||||||
LINKEXE=g++ -Wall $(OPT) -std=c++17 -o
|
LINKEXE=g++ -Wall $(OPT) -std=c++17 -export-dynamic -o
|
||||||
MAKEDEPS=true
|
MAKEDEPS=true
|
||||||
OPENSSL_INCLUDE=-I./ext/openssl-3.0.1/inc
|
OPENSSL_INCLUDE=-I./ext/openssl-3.0.1/inc
|
||||||
LUA_FLAGS=-DLUA_USE_APICHECK -DLUA_USE_POSIX
|
LUA_FLAGS=-DLUA_USE_APICHECK -DLUA_USE_POSIX
|
||||||
|
|||||||
@@ -927,12 +927,6 @@ static void replaycore_step(EngineWrapper *w) {
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#define DLLEXPORT __attribute__((visibility("default")))
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#define DLLEXPORT __declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void init_engine_wrapper_helper(EngineWrapper *w) {
|
static void init_engine_wrapper_helper(EngineWrapper *w) {
|
||||||
static bool called_initializer;
|
static bool called_initializer;
|
||||||
assert(DrivenEngineInitializerReg::func != nullptr);
|
assert(DrivenEngineInitializerReg::func != nullptr);
|
||||||
@@ -973,6 +967,12 @@ static void init_engine_wrapper_helper(EngineWrapper *w) {
|
|||||||
w->release = release;
|
w->release = release;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define DLLEXPORT __attribute__((visibility("default")))
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
DLLEXPORT void init_engine_wrapper(EngineWrapper *w) {
|
DLLEXPORT void init_engine_wrapper(EngineWrapper *w) {
|
||||||
init_engine_wrapper_helper(w);
|
init_engine_wrapper_helper(w);
|
||||||
|
|||||||
@@ -744,51 +744,51 @@ void HttpClientRequest::set_defaults() {
|
|||||||
void HttpClientRequest::configure(LuaKeywordParser &kp) {
|
void HttpClientRequest::configure(LuaKeywordParser &kp) {
|
||||||
LuaVar val;
|
LuaVar val;
|
||||||
LuaExtStack LS(kp.state(), val);
|
LuaExtStack LS(kp.state(), val);
|
||||||
if (kp.parse(val, "method")) {
|
if (kp.optional(val, "method")) {
|
||||||
set_method(LS, val);
|
set_method(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "host")) {
|
if (kp.optional(val, "host")) {
|
||||||
set_host(LS, val);
|
set_host(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "port")) {
|
if (kp.optional(val, "port")) {
|
||||||
set_port(LS, val);
|
set_port(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "path")) {
|
if (kp.optional(val, "path")) {
|
||||||
set_path(LS, val);
|
set_path(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "params")) {
|
if (kp.optional(val, "params")) {
|
||||||
set_params(LS, val);
|
set_params(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "url")) {
|
if (kp.optional(val, "url")) {
|
||||||
set_url(LS, val);
|
set_url(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "verifycertificate")) {
|
if (kp.optional(val, "verifycertificate")) {
|
||||||
set_verify_certificate(LS, val);
|
set_verify_certificate(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "mimetype")) {
|
if (kp.optional(val, "mimetype")) {
|
||||||
set_mime_type(LS, val);
|
set_mime_type(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "content")) {
|
if (kp.optional(val, "content")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "html")) {
|
if (kp.optional(val, "html")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("text/html");
|
set_mime_type("text/html");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "text")) {
|
if (kp.optional(val, "text")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("text/plain");
|
set_mime_type("text/plain");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "json")) {
|
if (kp.optional(val, "json")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("application/json");
|
set_mime_type("application/json");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "bytes")) {
|
if (kp.optional(val, "bytes")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("application/octet-stream");
|
set_mime_type("application/octet-stream");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "jsonvalue")) {
|
if (kp.optional(val, "jsonvalue")) {
|
||||||
set_jsonvalue(LS, val);
|
set_jsonvalue(LS, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1044,35 +1044,35 @@ void HttpServerResponse::set_jsonvalue(LuaCoreStack &LS, LuaSlot val) {
|
|||||||
void HttpServerResponse::configure(LuaKeywordParser &kp) {
|
void HttpServerResponse::configure(LuaKeywordParser &kp) {
|
||||||
LuaVar val;
|
LuaVar val;
|
||||||
LuaExtStack LS(kp.state(), val);
|
LuaExtStack LS(kp.state(), val);
|
||||||
if (kp.parse(val, "status")) {
|
if (kp.optional(val, "status")) {
|
||||||
set_status(LS, val);
|
set_status(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "maxage")) {
|
if (kp.optional(val, "maxage")) {
|
||||||
set_max_age(LS, val);
|
set_max_age(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "mimetype")) {
|
if (kp.optional(val, "mimetype")) {
|
||||||
set_mime_type(LS, val);
|
set_mime_type(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "content")) {
|
if (kp.optional(val, "content")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "html")) {
|
if (kp.optional(val, "html")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("text/html");
|
set_mime_type("text/html");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "text")) {
|
if (kp.optional(val, "text")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("text/plain");
|
set_mime_type("text/plain");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "json")) {
|
if (kp.optional(val, "json")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("application/json");
|
set_mime_type("application/json");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "bytes")) {
|
if (kp.optional(val, "bytes")) {
|
||||||
set_content(LS, val);
|
set_content(LS, val);
|
||||||
set_mime_type("application/octet-stream");
|
set_mime_type("application/octet-stream");
|
||||||
}
|
}
|
||||||
if (kp.parse(val, "jsonvalue")) {
|
if (kp.optional(val, "jsonvalue")) {
|
||||||
set_jsonvalue(LS, val);
|
set_jsonvalue(LS, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
LuaSpecial LuaRegistry(LUA_REGISTRYINDEX);
|
LuaSpecial LuaRegistry(LUA_REGISTRYINDEX);
|
||||||
LuaNilMarker LuaNil;
|
LuaNilMarker LuaNil;
|
||||||
LuaNewTableMarker LuaNewTable;
|
LuaNewTableMarker LuaNewTable;
|
||||||
|
static LuaToken token_error("error");
|
||||||
|
static LuaToken token_found("found");
|
||||||
|
|
||||||
|
|
||||||
LuaFunctionReg::LuaFunctionReg(const char *n, const char *a, const char *d, bool s, lua_CFunction f) {
|
LuaFunctionReg::LuaFunctionReg(const char *n, const char *a, const char *d, bool s, lua_CFunction f) {
|
||||||
name_ = n;
|
name_ = n;
|
||||||
@@ -650,52 +653,101 @@ void LuaCoreStack::guard_nopredict(const char *fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaKeywordParser::LuaKeywordParser(lua_State *L, int slot) {
|
LuaKeywordParser::LuaKeywordParser(const LuaCoreStack &LS0, LuaSlot slot)
|
||||||
L_ = L;
|
: keytab(slot.index()), LS(LS0.state(), found, error, key, val) {
|
||||||
slot_ = slot;
|
istable = LS.istable(keytab);
|
||||||
not_table_ = !lua_istable(L_, slot_);
|
if (istable) {
|
||||||
if (not_table_) {
|
LS.rawget(found, keytab, token_found);
|
||||||
lua_newtable(L_);
|
if (!LS.istable(found)) {
|
||||||
lua_replace(L_, slot_);
|
LS.set(found, LuaNewTable);
|
||||||
|
LS.rawset(keytab, token_found, found);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LuaKeywordParser::parse(LuaSlot out, const char *kw) {
|
bool LuaKeywordParser::optional(LuaSlot out, const char *kw) {
|
||||||
lua_pushstring(L_, kw);
|
if (!istable) {
|
||||||
lua_rawget(L_, slot_);
|
LS.set(out, LuaNil);
|
||||||
lua_replace(L_, out.index());
|
return false;
|
||||||
if (!lua_isnil(L_, out.index())) {
|
}
|
||||||
parsed_.insert(kw);
|
|
||||||
|
LS.rawget(out, keytab, kw);
|
||||||
|
if (!LS.isnil(out)) {
|
||||||
|
LS.rawset(found, kw, true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
eng::string LuaKeywordParser::final_check() {
|
bool LuaKeywordParser::required(LuaSlot out, const char *kw) {
|
||||||
if (not_table_) {
|
if (!istable) {
|
||||||
return "expected a keyword table";
|
LS.set(out, LuaNil);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
lua_pushnil(L_);
|
|
||||||
while (lua_next(L_, slot_) != 0) {
|
LS.rawget(out, keytab, kw);
|
||||||
lua_pop(L_, 1); // Don't need the value.
|
if (!LS.isnil(out)) {
|
||||||
if (!lua_isstring(L_, -1)) {
|
LS.rawset(found, kw, true);
|
||||||
return "keyword table contains non-string key";
|
return true;
|
||||||
|
} else {
|
||||||
|
LS.rawget(error, keytab, token_error);
|
||||||
|
if (!LS.isstring(error)) {
|
||||||
|
LS.rawset(keytab, token_error, util::ss("required keyword argument not present: ", kw));
|
||||||
}
|
}
|
||||||
const char *kw = lua_tostring(L_, -1);
|
return false;
|
||||||
if (parsed_.find(kw) == parsed_.end()) {
|
}
|
||||||
eng::ostringstream oss;
|
};
|
||||||
oss << "keyword " << kw << " not known";
|
|
||||||
return oss.str();
|
eng::string LuaKeywordParser::check() {
|
||||||
|
if (!istable) {
|
||||||
|
return "keyword arguments must be a table";
|
||||||
|
}
|
||||||
|
|
||||||
|
LS.rawget(error, keytab, token_error);
|
||||||
|
auto str = LS.trystring(error);
|
||||||
|
if (str.has_value()) return str.value();
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
eng::string LuaKeywordParser::final_check() {
|
||||||
|
if (!istable) {
|
||||||
|
return "keyword arguments must be a table";
|
||||||
|
}
|
||||||
|
|
||||||
|
LS.rawget(error, keytab, token_error);
|
||||||
|
auto str = LS.trystring(error);
|
||||||
|
if (str.has_value()) return str.value();
|
||||||
|
|
||||||
|
LS.set(key, LuaNil);
|
||||||
|
while (LS.next(keytab, key, val)) {
|
||||||
|
if (LS.istoken(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto kw = LS.trystringview(key);
|
||||||
|
if (!kw.has_value()) {
|
||||||
|
return "keyword arguments include a non-string key";
|
||||||
|
}
|
||||||
|
LS.rawget(val, found, key);
|
||||||
|
if (!LS.rawequal(val, true)) {
|
||||||
|
return util::ss("unrecognized keyword argument: ", kw.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaKeywordParser::check_throw() {
|
||||||
|
eng::string err = check();
|
||||||
|
if (!err.empty()) {
|
||||||
|
luaL_error(LS.state(), "%s", err.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LuaKeywordParser::final_check_throw() {
|
void LuaKeywordParser::final_check_throw() {
|
||||||
eng::string err = final_check();
|
eng::string err = final_check();
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
luaL_error(L_, "%s", err.c_str());
|
luaL_error(LS.state(), "%s", err.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1201,49 +1201,83 @@ public:
|
|||||||
//
|
//
|
||||||
// * It makes sure the keyword table actually is a table.
|
// * It makes sure the keyword table actually is a table.
|
||||||
//
|
//
|
||||||
// * It makes sure that you didn't put an unrecognized keyword
|
// * It makes sure that all required keywords are present.
|
||||||
// into the keyword table. Unrecognized keywords are defined
|
|
||||||
// as keywords that are never checked using 'parse'.
|
|
||||||
//
|
//
|
||||||
// * It makes sure that you didn't put anything that isn't a
|
// * It makes sure that you didn't put anything that isn't a
|
||||||
// keyword into the keyword table.
|
// known keyword into the keyword table.
|
||||||
|
//
|
||||||
|
// This module adds two fields to the table:
|
||||||
|
//
|
||||||
|
// [ERROR] - stores an error message, initially nil.
|
||||||
|
// [FOUND] - the set of keywords successfully parsed.
|
||||||
|
//
|
||||||
|
// If at any time, this module detects an error, it doesn't throw.
|
||||||
|
// Instead, it stores an error report in the table key [ERROR].
|
||||||
|
// Later, you can check for an error string using the function
|
||||||
|
// final_check or final_check_throw. If an error is
|
||||||
|
// detected when there is already an error report in the table,
|
||||||
|
// the error report is not overwritten, so therefore, the error
|
||||||
|
// reported is always the first error detected.
|
||||||
|
//
|
||||||
|
// When this module finds a keyword in the table, it adds the keyword
|
||||||
|
// to the [FOUND] set of all keywords successfully parsed.
|
||||||
|
//
|
||||||
|
// If the keyword table that you pass in isn't a table at all,
|
||||||
|
// then the keyword-fetching functions will always return false.
|
||||||
|
// Later, when you call 'check', an appropriate error will be
|
||||||
|
// generated.
|
||||||
|
//
|
||||||
|
// The lua module 'keywords' contains the same functions as this
|
||||||
|
// C++ class. You can write code where a C++ function does some
|
||||||
|
// of the parsing, and the lua code does the rest of the parsing.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class LuaKeywordParser {
|
class LuaKeywordParser {
|
||||||
struct cmp_char {
|
|
||||||
bool operator () (const char *s1, const char *s2) const {
|
|
||||||
return strcmp(s1, s2) < 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
bool not_table_;
|
LuaVar found, error, key, val;
|
||||||
lua_State *L_;
|
LuaSpecial keytab;
|
||||||
int slot_;
|
LuaExtStack LS;
|
||||||
eng::set<const char *, cmp_char> parsed_;
|
bool istable;
|
||||||
|
|
||||||
void init(const lua_State *L, int slot);
|
void init(const lua_State *L, int slot);
|
||||||
public:
|
public:
|
||||||
// If the slot is not a table, sets the not_table
|
LuaKeywordParser(const LuaCoreStack &LS, LuaSlot slot);
|
||||||
// flag and creates a dummy table in the slot.
|
|
||||||
LuaKeywordParser(lua_State *L, int slot);
|
|
||||||
LuaKeywordParser(const LuaCoreStack &LS, LuaSlot slot) : LuaKeywordParser(LS.state(), slot.index()) {}
|
|
||||||
|
|
||||||
// Fetch a value from the table. This never throws.
|
// Fetch the value of the keyword. If the keyword is found, then the
|
||||||
// Return true if the value is non-nil.
|
// keyword is added to the [FOUND] set, the value is returned in slot,
|
||||||
bool parse(LuaSlot slot, const char *kw);
|
// and returns true. Otherwise, sets slot to nil and returns false.
|
||||||
|
bool optional(LuaSlot slot, const char *kw);
|
||||||
|
|
||||||
// Check if there were any errors. If so, return an
|
// Fetch the value of the keyword. If the keyword is found, then the
|
||||||
// error message.
|
// keyword is added to the [FOUND] set, the value is returned in slot,
|
||||||
|
// and returns true. Otherwise, sets slot to nil, returns false, and
|
||||||
|
// stores an [ERROR] report in the keyword table.
|
||||||
|
bool required(LuaSlot slot, const char *kw);
|
||||||
|
|
||||||
|
// Check if there are any errors so far. If any error has been
|
||||||
|
// detected, returns an error message, otherwise, returns empty
|
||||||
|
// string.
|
||||||
|
eng::string check();
|
||||||
|
|
||||||
|
// Check if there are any errors so far. Also check that all keyword
|
||||||
|
// arguments present in the table are in the [FOUND] set. If there are
|
||||||
|
// any errors, returns an error message, otherwise returns empty string.
|
||||||
eng::string final_check();
|
eng::string final_check();
|
||||||
|
|
||||||
// Check if there are any errors. If so, throw a lua error.
|
// If check() returns an error, throws the error using luaL_error.
|
||||||
|
void check_throw();
|
||||||
|
|
||||||
|
// If final_check() returns an error, throws the error using luaL_error.
|
||||||
void final_check_throw();
|
void final_check_throw();
|
||||||
|
|
||||||
// Fetch the state pointer.
|
// Fetch the state pointer.
|
||||||
lua_State *state() const { return L_; }
|
lua_State *state() const { return LS.state(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Lua Byte Reader
|
// Lua Byte Reader
|
||||||
|
|||||||
@@ -834,18 +834,20 @@ void PlaneScan::configure(LuaKeywordParser &kp) {
|
|||||||
bool have_shape = false;
|
bool have_shape = false;
|
||||||
bool have_near = false;
|
bool have_near = false;
|
||||||
|
|
||||||
if (kp.parse(val, "plane")) {
|
kp.check_throw();
|
||||||
|
|
||||||
|
if (kp.optional(val, "plane")) {
|
||||||
plane_ = LS.ckstring(val, "plane");
|
plane_ = LS.ckstring(val, "plane");
|
||||||
have_plane = true;
|
have_plane = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "center")) {
|
if (kp.optional(val, "center")) {
|
||||||
util::DXYZ xyz = LS.ckxyz(val, "center");
|
util::DXYZ xyz = LS.ckxyz(val, "center");
|
||||||
center_ = xyz;
|
center_ = xyz;
|
||||||
have_center = true;
|
have_center = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "radius")) {
|
if (kp.optional(val, "radius")) {
|
||||||
auto simple = LS.trynumber(val);
|
auto simple = LS.trynumber(val);
|
||||||
if (simple) {
|
if (simple) {
|
||||||
radius_ = *simple;
|
radius_ = *simple;
|
||||||
@@ -862,7 +864,7 @@ void PlaneScan::configure(LuaKeywordParser &kp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "shape")) {
|
if (kp.optional(val, "shape")) {
|
||||||
eng::string shape = LS.ckstring(val, "shape");
|
eng::string shape = LS.ckstring(val, "shape");
|
||||||
if (shape == "box") {
|
if (shape == "box") {
|
||||||
shape_ = BOX;
|
shape_ = BOX;
|
||||||
@@ -876,7 +878,7 @@ void PlaneScan::configure(LuaKeywordParser &kp) {
|
|||||||
have_shape = true;
|
have_shape = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "near")) {
|
if (kp.optional(val, "near")) {
|
||||||
int64_t id = LS.tanid(val);
|
int64_t id = LS.tanid(val);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
luaL_error(L, "scan configuration: 'near' must be a tangible");
|
luaL_error(L, "scan configuration: 'near' must be a tangible");
|
||||||
@@ -893,14 +895,14 @@ void PlaneScan::configure(LuaKeywordParser &kp) {
|
|||||||
have_near = true;
|
have_near = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "include")) {
|
if (kp.optional(val, "include")) {
|
||||||
if (!have_near) {
|
if (!have_near) {
|
||||||
luaL_error(L, "scan configuration: 'include' specified without 'near'");
|
luaL_error(L, "scan configuration: 'include' specified without 'near'");
|
||||||
}
|
}
|
||||||
include_near_ = LS.ckboolean(val, "include");
|
include_near_ = LS.ckboolean(val, "include");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kp.parse(val, "wholeplane")) {
|
if (kp.optional(val, "wholeplane")) {
|
||||||
if (have_plane || have_center || have_radius || have_shape) {
|
if (have_plane || have_center || have_radius || have_shape) {
|
||||||
luaL_error(L, "scan configuration: do not specify plane, center, shape, or radius with 'wholeplane'");
|
luaL_error(L, "scan configuration: do not specify plane, center, shape, or radius with 'wholeplane'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,13 +243,14 @@ public:
|
|||||||
void PrettyPrintOptions::parse(LuaKeywordParser &kp) {
|
void PrettyPrintOptions::parse(LuaKeywordParser &kp) {
|
||||||
LuaVar option;
|
LuaVar option;
|
||||||
LuaExtStack LS(kp.state(), option);
|
LuaExtStack LS(kp.state(), option);
|
||||||
if (kp.parse(option, "indent")) {
|
kp.check_throw();
|
||||||
|
if (kp.optional(option, "indent")) {
|
||||||
indent = LS.ckboolean(option);
|
indent = LS.ckboolean(option);
|
||||||
}
|
}
|
||||||
if (kp.parse(option, "level")) {
|
if (kp.optional(option, "level")) {
|
||||||
level = LS.ckint(option);
|
level = LS.ckint(option);
|
||||||
}
|
}
|
||||||
if (kp.parse(option, "expand")) {
|
if (kp.optional(option, "expand")) {
|
||||||
expand = LS.ckboolean(option);
|
expand = LS.ckboolean(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,7 +307,7 @@ LuaDefine(string_pprintx, "options",
|
|||||||
PrettyPrintOptions options;
|
PrettyPrintOptions options;
|
||||||
LuaKeywordParser kp(LS, loptions);
|
LuaKeywordParser kp(LS, loptions);
|
||||||
options.parse(kp);
|
options.parse(kp);
|
||||||
if (!kp.parse(value, "value")) {
|
if (!kp.optional(value, "value")) {
|
||||||
LS.set(value, LuaNil);
|
LS.set(value, LuaNil);
|
||||||
}
|
}
|
||||||
kp.final_check_throw();
|
kp.final_check_throw();
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ LuaDefine(tangible_animate, "tan,options,config",
|
|||||||
bool replace = false;
|
bool replace = false;
|
||||||
if (!LS.isnil(options)) {
|
if (!LS.isnil(options)) {
|
||||||
LuaKeywordParser kp(LS, options);
|
LuaKeywordParser kp(LS, options);
|
||||||
if (kp.parse(option, "replace")) {
|
if (kp.optional(option, "replace")) {
|
||||||
replace = LS.ckboolean(option);
|
replace = LS.ckboolean(option);
|
||||||
}
|
}
|
||||||
kp.final_check_throw();
|
kp.final_check_throw();
|
||||||
@@ -274,27 +274,48 @@ LuaDefine(tangible_delete, "tan",
|
|||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_build, "config",
|
LuaDefine(tangible_build, "config",
|
||||||
"|Build a new tangible object."
|
"|Build a new tangible object."
|
||||||
"|"
|
"|"
|
||||||
"|The config table must contain: class,animstate."
|
"|The configuration table must contain the keyword 'class', which"
|
||||||
"|" ){
|
"|must be the name of a class created with 'makeclass'. It may also"
|
||||||
|
"|contain the following values:"
|
||||||
|
"|"
|
||||||
|
"| bp - the unreal blueprint, defaults to class name."
|
||||||
|
"| plane - the plane, defaults to actor.plane"
|
||||||
|
"| xyz - the xyz coordinate, defaults to actor.xyz"
|
||||||
|
"| facing - the rotation, defaults to actor.facing"
|
||||||
|
"|"
|
||||||
|
"|Tangible.build will create an initial animstate containing only"
|
||||||
|
"|bp, plane, xyz, and facing."
|
||||||
|
"|"
|
||||||
|
"|After creating the tangible and setting up the initial animation"
|
||||||
|
"|state, build will call the constructor for the tangible."
|
||||||
|
"|The constructor must have this prototype:"
|
||||||
|
"|"
|
||||||
|
"| function myclass.init(place, actor, config)"
|
||||||
|
"|"
|
||||||
|
"|The configuration table passed to tangible.build is then passed"
|
||||||
|
"|directly to the init function. The constructor should use the keywords"
|
||||||
|
"|module to parse the keyword arguments."
|
||||||
|
"|"
|
||||||
|
"|The constructor is not allowed to block."
|
||||||
|
){
|
||||||
LuaArg config;
|
LuaArg config;
|
||||||
LuaVar classname, classtab, mt, animstate;
|
LuaVar classname, classtab, bp, plane, xyz, facing, mt;
|
||||||
LuaRet database;
|
LuaRet database;
|
||||||
LuaDefStack LS(L, config, classname, classtab, database, mt, animstate);
|
LuaDefStack LS(L, config, classname, classtab, bp, plane, xyz, facing, mt, database);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
|
||||||
LuaKeywordParser kp(LS, config);
|
LuaKeywordParser kp(LS, config);
|
||||||
|
kp.required(classname, "class");
|
||||||
|
kp.optional(bp, "bp");
|
||||||
|
kp.optional(plane, "plane");
|
||||||
|
kp.optional(xyz, "xyz");
|
||||||
|
kp.optional(facing, "facing");
|
||||||
|
kp.check_throw();
|
||||||
|
|
||||||
// Get the keyword arguments.
|
// Verify the class.
|
||||||
if (!kp.parse(classname, "class")) {
|
|
||||||
luaL_error(L, "You must specify a class for the tangible");
|
|
||||||
}
|
|
||||||
if (!kp.parse(animstate, "animstate")) {
|
|
||||||
luaL_error(L, "You must specify an animstate table");
|
|
||||||
}
|
|
||||||
kp.final_check_throw();
|
|
||||||
|
|
||||||
// Find the class.
|
|
||||||
eng::string err = LS.getclass(classtab, classname);
|
eng::string err = LS.getclass(classtab, classname);
|
||||||
if (err != "") {
|
if (err != "") {
|
||||||
luaL_error(L, "%s", err.c_str());
|
luaL_error(L, "%s", err.c_str());
|
||||||
@@ -302,19 +323,29 @@ LuaDefine(tangible_build, "config",
|
|||||||
|
|
||||||
// Calculate the initial animation state.
|
// Calculate the initial animation state.
|
||||||
AnimState state;
|
AnimState state;
|
||||||
err = state.from_lua(LS, animstate, true, false);
|
if (!LS.isnil(bp)) {
|
||||||
if (err != "") {
|
state.set_string("bp", LS.ckstring(bp));
|
||||||
luaL_error(L, "%s", err.c_str());
|
} else {
|
||||||
|
state.set_string("bp", LS.ckstring(classname));
|
||||||
}
|
}
|
||||||
if (!state.contains("xyz") || !state.contains("plane")) {
|
if (!LS.isnil(plane)) {
|
||||||
luaL_error(L, "You must specify both xyz and plane in animstate");
|
state.set_string("plane", LS.ckstring(plane));
|
||||||
}
|
}
|
||||||
err = state.add_defaults(nullptr);
|
if (!LS.isnil(xyz)) {
|
||||||
|
state.set_dxyz("xyz", LS.ckxyz(xyz));
|
||||||
|
}
|
||||||
|
if (!LS.isnil(facing)) {
|
||||||
|
state.set_number("facing", LS.cknumber(facing));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add default values from the actor. Set persistent flags.
|
||||||
|
Tangible *actor = w->tangible_get(w->lthread_actor_id_);
|
||||||
|
AnimState actorstate = actor->anim_queue_.get_final_persistent();
|
||||||
|
err = state.add_defaults(&actorstate);
|
||||||
if (err != "") {
|
if (err != "") {
|
||||||
luaL_error(L, "%s", err.c_str());
|
luaL_error(L, "%s", err.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
|
||||||
int64_t new_id = w->alloc_id_predictable();
|
int64_t new_id = w->alloc_id_predictable();
|
||||||
Tangible *tan = w->tangible_make(LS, database, new_id);
|
Tangible *tan = w->tangible_make(LS, database, new_id);
|
||||||
|
|
||||||
@@ -322,9 +353,12 @@ LuaDefine(tangible_build, "config",
|
|||||||
LS.getmetatable(mt, database);
|
LS.getmetatable(mt, database);
|
||||||
LS.rawset(mt, "__index", classtab);
|
LS.rawset(mt, "__index", classtab);
|
||||||
|
|
||||||
|
// Initialize the animstate of the new tangible.
|
||||||
tan->anim_queue_.clear(state);
|
tan->anim_queue_.clear(state);
|
||||||
tan->update_plane_item();
|
tan->update_plane_item();
|
||||||
|
|
||||||
|
// TODO: call the constructor.
|
||||||
|
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,7 +873,7 @@ LuaDefine(pprintx, "options",
|
|||||||
PrettyPrintOptions options;
|
PrettyPrintOptions options;
|
||||||
LuaKeywordParser kp(LS, loptions);
|
LuaKeywordParser kp(LS, loptions);
|
||||||
options.parse(kp);
|
options.parse(kp);
|
||||||
if (!kp.parse(value, "value")) {
|
if (!kp.optional(value, "value")) {
|
||||||
LS.set(value, LuaNil);
|
LS.set(value, LuaNil);
|
||||||
}
|
}
|
||||||
kp.final_check_throw();
|
kp.final_check_throw();
|
||||||
|
|||||||
@@ -238,9 +238,11 @@ static std::u32string console_read() {
|
|||||||
|
|
||||||
static void call_init_engine_wrapper(const std::filesystem::path &luprexroot, EngineWrapper *w) {
|
static void call_init_engine_wrapper(const std::filesystem::path &luprexroot, EngineWrapper *w) {
|
||||||
using InitFn = void (*)(EngineWrapper *);
|
using InitFn = void (*)(EngineWrapper *);
|
||||||
InitFn initfn = (InitFn)dlsym(nullptr, "init_engine_wrapper");
|
void *exe_handle = dlopen(nullptr, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
InitFn initfn = (InitFn)dlsym(exe_handle, "init_engine_wrapper");
|
||||||
if (initfn == nullptr) {
|
if (initfn == nullptr) {
|
||||||
std::string path = luprexroot / "build/linux/luprexlib.so";
|
fprintf(stderr, "loading luprexlib.so...\n");
|
||||||
|
std::string path = luprexroot / "build/Linux/luprexlib.so";
|
||||||
void *dll_handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
|
void *dll_handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
|
||||||
assert(dll_handle != nullptr);
|
assert(dll_handle != nullptr);
|
||||||
initfn = (InitFn)dlsym(dll_handle, "init_engine_wrapper");
|
initfn = (InitFn)dlsym(dll_handle, "init_engine_wrapper");
|
||||||
|
|||||||
Reference in New Issue
Block a user