forked from OctaForge/libcubescript
use normal exception handling to handle errors C++-side, also guarantee valid pointer from alloc
parent
35ebb0e822
commit
4510e53916
|
@ -336,6 +336,36 @@ private:
|
|||
bool p_gap;
|
||||
};
|
||||
|
||||
struct CsErrorException {
|
||||
friend struct CsState;
|
||||
|
||||
CsErrorException() = delete;
|
||||
CsErrorException(CsErrorException const &) = delete;
|
||||
CsErrorException(CsErrorException &&v):
|
||||
p_errmsg(v.p_errmsg), p_stack(ostd::move(v.p_stack))
|
||||
{}
|
||||
|
||||
ostd::ConstCharRange what() const {
|
||||
return p_errmsg;
|
||||
}
|
||||
|
||||
CsStackState &get_stack() {
|
||||
return p_stack;
|
||||
}
|
||||
|
||||
CsStackState const &get_stack() const {
|
||||
return p_stack;
|
||||
}
|
||||
|
||||
private:
|
||||
CsErrorException(ostd::ConstCharRange v, CsStackState &&st):
|
||||
p_errmsg(v), p_stack(ostd::move(st))
|
||||
{}
|
||||
|
||||
ostd::ConstCharRange p_errmsg;
|
||||
CsStackState p_stack;
|
||||
};
|
||||
|
||||
using CsHookCb = ostd::Function<void(CsState &)>;
|
||||
using CsPanicCb =
|
||||
ostd::Function<void(CsState &, ostd::ConstCharRange, CsStackState)>;
|
||||
|
@ -379,15 +409,10 @@ struct OSTD_EXPORT CsState {
|
|||
CsIdentLink *p_callstack = nullptr;
|
||||
|
||||
int identflags = 0;
|
||||
int protect = 0;
|
||||
|
||||
CsState();
|
||||
virtual ~CsState();
|
||||
|
||||
bool is_alive() const {
|
||||
return bool(p_state);
|
||||
}
|
||||
|
||||
CsStream const &get_out() const;
|
||||
CsStream &get_out();
|
||||
void set_out(CsStream &s);
|
||||
|
@ -407,31 +432,32 @@ struct OSTD_EXPORT CsState {
|
|||
));
|
||||
}
|
||||
|
||||
virtual void *alloc(void *ptr, ostd::Size olds, ostd::Size news);
|
||||
void *alloc(void *ptr, ostd::Size olds, ostd::Size news);
|
||||
|
||||
template<typename T, typename ...A>
|
||||
T *create(A &&...args) {
|
||||
T *ret = static_cast<T *>(alloc(nullptr, 0, sizeof(T)));
|
||||
new (ret) T(ostd::forward<A>(args)...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *create_array(ostd::Size len) {
|
||||
T *ret = static_cast<T *>(alloc(nullptr, 0, len * sizeof(T)));
|
||||
for (ostd::Size i = 0; i < len; ++i) {
|
||||
new (&ret[i]) T();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void destroy(T *v) noexcept {
|
||||
v->~T();
|
||||
alloc(v, sizeof(T), 0);
|
||||
}
|
||||
|
||||
void init_libs(int libs = CsLibAll);
|
||||
|
||||
CsPanicCb set_panic_func(CsPanicCb func);
|
||||
CsPanicCb const &get_panic_func() const;
|
||||
CsPanicCb &get_panic_func();
|
||||
|
||||
template<typename F>
|
||||
CsPanicCb set_panic_func(F &&f) {
|
||||
return set_panic_func(CsPanicCb(
|
||||
ostd::allocator_arg, CsAllocator<char>(*this), ostd::forward<F>(f)
|
||||
));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool pcall(
|
||||
F func, ostd::ConstCharRange *error = nullptr,
|
||||
CsStackState *stack = nullptr
|
||||
) {
|
||||
return ipcall([](void *data) {
|
||||
(*static_cast<F *>(data))();
|
||||
}, error, stack, &func);
|
||||
}
|
||||
|
||||
void error(ostd::ConstCharRange msg);
|
||||
|
||||
template<typename ...A>
|
||||
|
@ -584,14 +610,9 @@ struct OSTD_EXPORT CsState {
|
|||
|
||||
private:
|
||||
CsIdent *add_ident(CsIdent *id);
|
||||
bool ipcall(
|
||||
void (*f)(void *data), ostd::ConstCharRange *error,
|
||||
CsStackState *stack, void *data
|
||||
);
|
||||
|
||||
char p_errbuf[512];
|
||||
CsHookCb p_callhook;
|
||||
CsPanicCb p_panicfunc;
|
||||
CsStream *p_out, *p_err;
|
||||
};
|
||||
|
||||
|
|
66
src/cs_vm.hh
66
src/cs_vm.hh
|
@ -98,72 +98,6 @@ template<typename T>
|
|||
constexpr ostd::Size CsTypeStorageSize =
|
||||
(sizeof(T) - 1) / sizeof(ostd::Uint32) + 1;
|
||||
|
||||
struct CsErrorException {
|
||||
ostd::ConstCharRange errmsg;
|
||||
CsStackState stack;
|
||||
CsErrorException() = delete;
|
||||
CsErrorException(CsErrorException const &) = delete;
|
||||
CsErrorException(CsErrorException &&v):
|
||||
errmsg(v.errmsg), stack(ostd::move(v.stack))
|
||||
{}
|
||||
CsErrorException(ostd::ConstCharRange v, CsStackState &&st):
|
||||
errmsg(v), stack(ostd::move(st))
|
||||
{}
|
||||
};
|
||||
|
||||
inline void *cs_alloc_throw(
|
||||
CsState &cs, void *ptr, ostd::Size olds, ostd::Size news
|
||||
) {
|
||||
void *ret = cs.alloc(ptr, olds, news);
|
||||
if (news && !ret) {
|
||||
cs.error("could not allocate memory");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T, typename ...A>
|
||||
inline T *cs_new(CsState &cs, A &&...args) {
|
||||
void *ret = cs.alloc(nullptr, 0, sizeof(T));
|
||||
if (!ret) {
|
||||
return nullptr;
|
||||
}
|
||||
new (ret) T(ostd::forward<A>(args)...);
|
||||
return static_cast<T *>(ret);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T *cs_new_array(CsState &cs, ostd::Size len) {
|
||||
T *ret = static_cast<T *>(cs.alloc(nullptr, 0, len * sizeof(T)));
|
||||
if (ret) {
|
||||
for (ostd::Size i = 0; i < len; ++i) {
|
||||
new (&ret[i]) T();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T, typename ...A>
|
||||
inline T *cs_new_throw(CsState &cs, A &&...args) {
|
||||
void *ret = cs_alloc_throw(cs, nullptr, 0, sizeof(T));
|
||||
new (ret) T(ostd::forward<A>(args)...);
|
||||
return static_cast<T *>(ret);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T *cs_new_array_throw(CsState &cs, ostd::Size len) {
|
||||
T *ret = static_cast<T *>(cs_alloc_throw(cs, nullptr, 0, len * sizeof(T)));
|
||||
for (ostd::Size i = 0; i < len; ++i) {
|
||||
new (&ret[i]) T();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void cs_delete(CsState &cs, T *v) noexcept {
|
||||
v->~T();
|
||||
cs.alloc(v, sizeof(T), 0);
|
||||
}
|
||||
|
||||
CsStackState cs_save_stack(CsState &cs);
|
||||
|
||||
template<typename ...A>
|
||||
|
|
|
@ -253,26 +253,9 @@ int CsCommand::get_num_args() const {
|
|||
void cs_init_lib_base(CsState &cs);
|
||||
|
||||
CsState::CsState():
|
||||
p_state(nullptr), p_callhook(), p_panicfunc(),
|
||||
p_state(create<CsSharedState>()), p_callhook(),
|
||||
p_out(&ostd::out), p_err(&ostd::err)
|
||||
{
|
||||
CsSharedState *ps = static_cast<CsSharedState *>(
|
||||
alloc(nullptr, 0, sizeof(CsSharedState))
|
||||
);
|
||||
if (!ps) {
|
||||
return;
|
||||
}
|
||||
/* TODO: protect with a Box */
|
||||
new (ps) CsSharedState();
|
||||
p_state = ps;
|
||||
|
||||
/* default panic func */
|
||||
p_panicfunc = [](CsState &cs, ostd::ConstCharRange v, CsStackState) {
|
||||
cs.get_err().writefln(
|
||||
"PANIC: unprotected error in call to CubeScript (%s)", v
|
||||
);
|
||||
};
|
||||
|
||||
for (int i = 0; i < MaxArguments; ++i) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "arg%d", i + 1);
|
||||
|
@ -363,10 +346,9 @@ CsState::~CsState() {
|
|||
a->get_value().force_null();
|
||||
CsAliasInternal::clean_code(a);
|
||||
}
|
||||
delete i;
|
||||
destroy(i);
|
||||
}
|
||||
p_state->~CsSharedState();
|
||||
alloc(p_state, sizeof(CsSharedState), 0);
|
||||
destroy(p_state);
|
||||
}
|
||||
|
||||
CsStream const &CsState::get_out() const {
|
||||
|
@ -408,49 +390,10 @@ CsHookCb &CsState::get_call_hook() {
|
|||
}
|
||||
|
||||
void *CsState::alloc(void *ptr, ostd::Size, ostd::Size ns) {
|
||||
delete[] static_cast<ostd::byte *>(ptr);
|
||||
if (!ns) {
|
||||
return nullptr;
|
||||
delete static_cast<unsigned char *>(ptr);
|
||||
}
|
||||
return new ostd::byte[ns];
|
||||
}
|
||||
|
||||
CsPanicCb CsState::set_panic_func(CsPanicCb func) {
|
||||
auto hk = ostd::move(p_panicfunc);
|
||||
p_panicfunc = ostd::move(func);
|
||||
return hk;
|
||||
}
|
||||
|
||||
CsPanicCb const &CsState::get_panic_func() const {
|
||||
return p_panicfunc;
|
||||
}
|
||||
|
||||
CsPanicCb &CsState::get_panic_func() {
|
||||
return p_panicfunc;
|
||||
}
|
||||
|
||||
bool CsState::ipcall(
|
||||
void (*f)(void *data), ostd::ConstCharRange *error,
|
||||
CsStackState *stack, void *data
|
||||
) {
|
||||
++protect;
|
||||
try {
|
||||
f(data);
|
||||
} catch (CsErrorException &v) {
|
||||
--protect;
|
||||
if (error) {
|
||||
*error = v.errmsg;
|
||||
}
|
||||
if (stack) {
|
||||
*stack = ostd::move(v.stack);
|
||||
}
|
||||
return false;
|
||||
} catch (...) {
|
||||
--protect;
|
||||
throw;
|
||||
}
|
||||
--protect;
|
||||
return true;
|
||||
return new unsigned char[ns];
|
||||
}
|
||||
|
||||
void CsState::error(ostd::ConstCharRange msg) {
|
||||
|
@ -459,14 +402,7 @@ void CsState::error(ostd::ConstCharRange msg) {
|
|||
}
|
||||
memcpy(p_errbuf, msg.data(), msg.size());
|
||||
auto err = ostd::ConstCharRange(p_errbuf, msg.size());
|
||||
if (protect) {
|
||||
throw CsErrorException(err, cs_save_stack(*this));
|
||||
} else {
|
||||
if (p_panicfunc) {
|
||||
p_panicfunc(*this, err, cs_save_stack(*this));
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
throw CsErrorException(err, cs_save_stack(*this));
|
||||
}
|
||||
|
||||
void CsState::clear_override(CsIdent &id) {
|
||||
|
@ -528,7 +464,7 @@ CsIdent *CsState::new_ident(ostd::ConstCharRange name, int flags) {
|
|||
);
|
||||
return p_state->identmap[DummyIdx];
|
||||
}
|
||||
id = add_ident(new CsAlias(name, flags));
|
||||
id = add_ident(create<CsAlias>(name, flags));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
@ -585,20 +521,24 @@ CsConstIdentRange CsState::get_idents() const {
|
|||
CsIvar *CsState::new_ivar(
|
||||
ostd::ConstCharRange n, CsInt m, CsInt x, CsInt v, CsVarCb f, int flags
|
||||
) {
|
||||
return add_ident(new CsIvar(n, m, x, v, ostd::move(f), flags))->get_ivar();
|
||||
return add_ident(
|
||||
create<CsIvar>(n, m, x, v, ostd::move(f), flags)
|
||||
)->get_ivar();
|
||||
}
|
||||
|
||||
CsFvar *CsState::new_fvar(
|
||||
ostd::ConstCharRange n, CsFloat m, CsFloat x, CsFloat v, CsVarCb f, int flags
|
||||
) {
|
||||
return add_ident(new CsFvar(n, m, x, v, ostd::move(f), flags))->get_fvar();
|
||||
return add_ident(
|
||||
create<CsFvar>(n, m, x, v, ostd::move(f), flags)
|
||||
)->get_fvar();
|
||||
}
|
||||
|
||||
CsSvar *CsState::new_svar(
|
||||
ostd::ConstCharRange n, CsString v, CsVarCb f, int flags
|
||||
) {
|
||||
return add_ident(
|
||||
new CsSvar(n, ostd::move(v), ostd::move(f), flags)
|
||||
create<CsSvar>(n, ostd::move(v), ostd::move(f), flags)
|
||||
)->get_svar();
|
||||
}
|
||||
|
||||
|
@ -654,7 +594,7 @@ void CsState::set_alias(ostd::ConstCharRange name, CsValue v) {
|
|||
} else if (cs_check_num(name)) {
|
||||
cs_debug_code(*this, "cannot alias number %s", name);
|
||||
} else {
|
||||
add_ident(new CsAlias(name, ostd::move(v), identflags));
|
||||
add_ident(create<CsAlias>(name, ostd::move(v), identflags));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1084,7 +1024,7 @@ CsCommand *CsState::new_command(
|
|||
}
|
||||
}
|
||||
return static_cast<CsCommand *>(
|
||||
add_ident(new CsCommand(name, args, nargs, ostd::move(func)))
|
||||
add_ident(create<CsCommand>(name, args, nargs, ostd::move(func)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1145,21 +1085,20 @@ void cs_init_lib_base(CsState &gcs) {
|
|||
ret.set_int(0);
|
||||
return;
|
||||
}
|
||||
ostd::ConstCharRange errmsg;
|
||||
CsValue result, tback;
|
||||
CsStackState stack;
|
||||
bool rc = cs.pcall([&cs, &args, &result]() {
|
||||
bool rc = true;
|
||||
try {
|
||||
cs.run(args[0].get_code(), result);
|
||||
}, &errmsg, &stack);
|
||||
ret.set_int(rc);
|
||||
if (!rc) {
|
||||
result.set_str(errmsg);
|
||||
if (stack.get()) {
|
||||
} catch (CsErrorException const &e) {
|
||||
result.set_str(e.what());
|
||||
if (e.get_stack().get()) {
|
||||
auto app = ostd::appender<CsString>();
|
||||
cscript::util::print_stack(app, stack);
|
||||
cscript::util::print_stack(app, e.get_stack());
|
||||
tback.set_str(ostd::move(app.get()));
|
||||
}
|
||||
rc = false;
|
||||
}
|
||||
ret.set_int(rc);
|
||||
CsAliasInternal::set_alias(cret, cs, result);
|
||||
if (css->get_index() != DummyIdx) {
|
||||
CsAliasInternal::set_alias(css, cs, tback);
|
||||
|
|
|
@ -194,9 +194,7 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
|
|||
CsValue ret;
|
||||
scs = &cs;
|
||||
signal(SIGINT, do_sigint);
|
||||
ostd::ConstCharRange err;
|
||||
cscript::CsStackState st;
|
||||
auto tocall = [&]() {
|
||||
try {
|
||||
if (file) {
|
||||
if (!cs.run_file(line, ret)) {
|
||||
ostd::err.writeln("cannot read file: ", line);
|
||||
|
@ -204,11 +202,10 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
|
|||
} else {
|
||||
cs.run(line, ret);
|
||||
}
|
||||
};
|
||||
if (!cs.pcall(ostd::move(tocall), &err, &st)) {
|
||||
} catch (cscript::CsErrorException const &e) {
|
||||
signal(SIGINT, SIG_DFL);
|
||||
scs = nullptr;
|
||||
ostd::ConstCharRange terr = err;
|
||||
ostd::ConstCharRange terr = e.what();
|
||||
auto col = ostd::find(terr, ':');
|
||||
if (!col.empty()) {
|
||||
terr = col + 2;
|
||||
|
@ -216,9 +213,9 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
|
|||
if (!file && ((terr == "missing \"]\"") || (terr == "missing \")\""))) {
|
||||
return true;
|
||||
}
|
||||
cs.get_out().writeln(col.empty() ? "stdin: " : "stdin:", err);
|
||||
if (st.get()) {
|
||||
cscript::util::print_stack(cs.get_out().iter(), st);
|
||||
cs.get_out().writeln(col.empty() ? "stdin: " : "stdin:", e.what());
|
||||
if (e.get_stack().get()) {
|
||||
cscript::util::print_stack(cs.get_out().iter(), e.get_stack());
|
||||
cs.get_out().write('\n');
|
||||
}
|
||||
return false;
|
||||
|
@ -273,9 +270,6 @@ static void do_tty(CsState &cs) {
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
CsState gcs;
|
||||
if (!gcs.is_alive()) {
|
||||
return 1;
|
||||
}
|
||||
gcs.init_libs();
|
||||
|
||||
gcs.new_command("exec", "sb", [](CsState &cs, auto args, auto &res) {
|
||||
|
|
Loading…
Reference in New Issue