forked from OctaForge/libcubescript
pass callstack state with errors
parent
f1039148b0
commit
32c53a31a0
|
@ -315,8 +315,31 @@ enum {
|
||||||
CsLibAll = 0b111
|
CsLibAll = 0b111
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CsStackStateNode {
|
||||||
|
CsStackStateNode const *next;
|
||||||
|
CsIdent const *id;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CsStackState {
|
||||||
|
CsStackState(CsStackStateNode *nd = nullptr, bool gap = false);
|
||||||
|
CsStackState(CsStackState const &) = delete;
|
||||||
|
CsStackState(CsStackState &&st);
|
||||||
|
~CsStackState();
|
||||||
|
|
||||||
|
CsStackState &operator=(CsStackState const &) = delete;
|
||||||
|
CsStackState &operator=(CsStackState &&);
|
||||||
|
|
||||||
|
CsStackStateNode const *get() const;
|
||||||
|
bool gap() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CsStackStateNode *p_node;
|
||||||
|
bool p_gap;
|
||||||
|
};
|
||||||
|
|
||||||
using CsHookCb = ostd::Function<void()>;
|
using CsHookCb = ostd::Function<void()>;
|
||||||
using CsPanicCb = ostd::Function<void(CsString)>;
|
using CsPanicCb = ostd::Function<void(CsString, CsStackState)>;
|
||||||
|
|
||||||
struct OSTD_EXPORT CsState {
|
struct OSTD_EXPORT CsState {
|
||||||
CsMap<ostd::ConstCharRange, CsIdent *> idents;
|
CsMap<ostd::ConstCharRange, CsIdent *> idents;
|
||||||
|
@ -353,10 +376,13 @@ struct OSTD_EXPORT CsState {
|
||||||
CsPanicCb &get_panic_func();
|
CsPanicCb &get_panic_func();
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
bool pcall(F func, ostd::String *error) {
|
bool pcall(
|
||||||
|
F func, ostd::String *error = nullptr,
|
||||||
|
CsStackState *stack = nullptr
|
||||||
|
) {
|
||||||
return ipcall([](void *data) {
|
return ipcall([](void *data) {
|
||||||
(*static_cast<F *>(data))();
|
(*static_cast<F *>(data))();
|
||||||
}, error, &func);
|
}, error, stack, &func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(CsString msg);
|
void error(CsString msg);
|
||||||
|
@ -476,7 +502,10 @@ struct OSTD_EXPORT CsState {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CsIdent *add_ident(CsIdent *id);
|
CsIdent *add_ident(CsIdent *id);
|
||||||
bool ipcall(void (*f)(void *data), ostd::String *error, void *data);
|
bool ipcall(
|
||||||
|
void (*f)(void *data), ostd::String *error,
|
||||||
|
CsStackState *stack, void *data
|
||||||
|
);
|
||||||
|
|
||||||
CsHookCb p_callhook;
|
CsHookCb p_callhook;
|
||||||
CsPanicCb p_panicfunc;
|
CsPanicCb p_panicfunc;
|
||||||
|
@ -655,6 +684,27 @@ namespace util {
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename R>
|
||||||
|
inline ostd::Size print_stack(R &&writer, CsStackState const &st) {
|
||||||
|
ostd::Size ret = 0;
|
||||||
|
auto nd = st.get();
|
||||||
|
while (nd) {
|
||||||
|
auto rt = ostd::format(
|
||||||
|
writer,
|
||||||
|
((nd->index == 1) && st.gap())
|
||||||
|
? " ..%d) %s\n" : " %d) %s\n",
|
||||||
|
nd->index, nd->id->get_name()
|
||||||
|
);
|
||||||
|
if (rt > 0) {
|
||||||
|
ret += ostd::Size(rt);
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
nd = nd->next;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} /* namespace util */
|
} /* namespace util */
|
||||||
|
|
||||||
} /* namespace cscript */
|
} /* namespace cscript */
|
||||||
|
|
63
src/cs_vm.cc
63
src/cs_vm.cc
|
@ -69,6 +69,69 @@ ostd::ConstCharRange cs_debug_line(
|
||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CsStackState::CsStackState(CsStackStateNode *nd, bool gap):
|
||||||
|
p_node(nd), p_gap(gap)
|
||||||
|
{}
|
||||||
|
CsStackState::CsStackState(CsStackState &&st):
|
||||||
|
p_node(st.p_node), p_gap(st.p_gap)
|
||||||
|
{
|
||||||
|
st.p_node = nullptr;
|
||||||
|
st.p_gap = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsStackState::~CsStackState() {
|
||||||
|
delete[] p_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsStackState &CsStackState::operator=(CsStackState &&st) {
|
||||||
|
p_node = st.p_node;
|
||||||
|
p_gap = st.p_gap;
|
||||||
|
st.p_node = nullptr;
|
||||||
|
st.p_gap = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsStackStateNode const *CsStackState::get() const {
|
||||||
|
return p_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CsStackState::gap() const {
|
||||||
|
return p_gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsStackState cs_save_stack(CsState &cs) {
|
||||||
|
CsIvar *dalias = static_cast<CsIvar *>(cs.identmap[DbgaliasIdx]);
|
||||||
|
if (!dalias->get_value()) {
|
||||||
|
return CsStackState(nullptr, true);
|
||||||
|
}
|
||||||
|
int total = 0, depth = 0;
|
||||||
|
for (CsIdentLink *l = cs.p_callstack; l != &cs.noalias; l = l->next) {
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
CsStackStateNode *st =
|
||||||
|
new CsStackStateNode[ostd::min(total, dalias->get_value())];
|
||||||
|
CsStackStateNode *ret = st, *nd = st;
|
||||||
|
++st;
|
||||||
|
for (CsIdentLink *l = cs.p_callstack; l != &cs.noalias; l = l->next) {
|
||||||
|
++depth;
|
||||||
|
if (depth < dalias->get_value()) {
|
||||||
|
nd->id = l->id;
|
||||||
|
nd->index = total - depth + 1;
|
||||||
|
if (l->next == &cs.noalias) {
|
||||||
|
nd->next = nullptr;
|
||||||
|
} else {
|
||||||
|
nd->next = st;
|
||||||
|
}
|
||||||
|
nd = st++;
|
||||||
|
} else if (l->next == &cs.noalias) {
|
||||||
|
nd->id = l->id;
|
||||||
|
nd->index = 1;
|
||||||
|
nd->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CsStackState(ret, total != dalias->get_value());
|
||||||
|
}
|
||||||
|
|
||||||
void cs_debug_alias(CsState &cs) {
|
void cs_debug_alias(CsState &cs) {
|
||||||
CsIvar *dalias = static_cast<CsIvar *>(cs.identmap[DbgaliasIdx]);
|
CsIvar *dalias = static_cast<CsIvar *>(cs.identmap[DbgaliasIdx]);
|
||||||
if (!dalias->get_value()) {
|
if (!dalias->get_value()) {
|
||||||
|
|
11
src/cs_vm.hh
11
src/cs_vm.hh
|
@ -88,10 +88,15 @@ constexpr ostd::Size CsTypeStorageSize =
|
||||||
|
|
||||||
struct CsErrorException {
|
struct CsErrorException {
|
||||||
CsString errmsg;
|
CsString errmsg;
|
||||||
|
CsStackState stack;
|
||||||
CsErrorException() = delete;
|
CsErrorException() = delete;
|
||||||
CsErrorException(CsErrorException const &) = delete;
|
CsErrorException(CsErrorException const &) = delete;
|
||||||
CsErrorException(CsErrorException &&v): errmsg(ostd::move(v.errmsg)) {}
|
CsErrorException(CsErrorException &&v):
|
||||||
CsErrorException(CsString &&v): errmsg(ostd::move(v)) {}
|
errmsg(ostd::move(v.errmsg)), stack(ostd::move(v.stack))
|
||||||
|
{}
|
||||||
|
CsErrorException(CsString &&v, CsStackState &&st):
|
||||||
|
errmsg(ostd::move(v)), stack(ostd::move(st))
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
ostd::ConstCharRange cs_debug_line(
|
ostd::ConstCharRange cs_debug_line(
|
||||||
|
@ -100,6 +105,8 @@ ostd::ConstCharRange cs_debug_line(
|
||||||
|
|
||||||
void cs_debug_alias(CsState &cs);
|
void cs_debug_alias(CsState &cs);
|
||||||
|
|
||||||
|
CsStackState cs_save_stack(CsState &cs);
|
||||||
|
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
void cs_debug_code(CsState &cs, ostd::ConstCharRange fmt, A &&...args) {
|
void cs_debug_code(CsState &cs, ostd::ConstCharRange fmt, A &&...args) {
|
||||||
if (cs.nodebug) {
|
if (cs.nodebug) {
|
||||||
|
|
|
@ -261,7 +261,7 @@ CsState::CsState():
|
||||||
noalias.argstack = nullptr;
|
noalias.argstack = nullptr;
|
||||||
|
|
||||||
/* default panic func */
|
/* default panic func */
|
||||||
p_panicfunc = [this](CsString v) {
|
p_panicfunc = [this](CsString v, CsStackState) {
|
||||||
get_err().writefln(
|
get_err().writefln(
|
||||||
"PANIC: unprotected error in call to CubeScript (%s)", v
|
"PANIC: unprotected error in call to CubeScript (%s)", v
|
||||||
);
|
);
|
||||||
|
@ -418,15 +418,21 @@ CsPanicCb &CsState::get_panic_func() {
|
||||||
return p_panicfunc;
|
return p_panicfunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CsState::ipcall(void (*f)(void *data), ostd::String *error, void *data) {
|
bool CsState::ipcall(
|
||||||
|
void (*f)(void *data), ostd::String *error,
|
||||||
|
CsStackState *stack, void *data
|
||||||
|
) {
|
||||||
++protect;
|
++protect;
|
||||||
try {
|
try {
|
||||||
f(data);
|
f(data);
|
||||||
} catch (CsErrorException const &v) {
|
} catch (CsErrorException &v) {
|
||||||
--protect;
|
--protect;
|
||||||
if (error) {
|
if (error) {
|
||||||
*error = ostd::move(v.errmsg);
|
*error = ostd::move(v.errmsg);
|
||||||
}
|
}
|
||||||
|
if (stack) {
|
||||||
|
*stack = ostd::move(v.stack);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
--protect;
|
--protect;
|
||||||
|
@ -438,10 +444,10 @@ bool CsState::ipcall(void (*f)(void *data), ostd::String *error, void *data) {
|
||||||
|
|
||||||
void CsState::error(CsString msg) {
|
void CsState::error(CsString msg) {
|
||||||
if (protect) {
|
if (protect) {
|
||||||
throw CsErrorException(ostd::move(msg));
|
throw CsErrorException(ostd::move(msg), cs_save_stack(*this));
|
||||||
} else {
|
} else {
|
||||||
if (p_panicfunc) {
|
if (p_panicfunc) {
|
||||||
p_panicfunc(ostd::move(msg));
|
p_panicfunc(ostd::move(msg), cs_save_stack(*this));
|
||||||
}
|
}
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,7 @@ static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
|
||||||
CsValue ret;
|
CsValue ret;
|
||||||
signal(SIGINT, do_sigint);
|
signal(SIGINT, do_sigint);
|
||||||
ostd::String err;
|
ostd::String err;
|
||||||
|
cscript::CsStackState st;
|
||||||
if (!cs.pcall([&]() {
|
if (!cs.pcall([&]() {
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!cs.run_file(line, ret)) {
|
if (!cs.run_file(line, ret)) {
|
||||||
|
@ -205,9 +206,10 @@ static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
|
||||||
} else {
|
} else {
|
||||||
cs.run(line, ret);
|
cs.run(line, ret);
|
||||||
}
|
}
|
||||||
}, &err)) {
|
}, &err, &st)) {
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
ostd::writeln("error: ", err);
|
cs.get_out().writeln("error: ", err);
|
||||||
|
cscript::util::print_stack(cs.get_out().iter(), st);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
|
|
Loading…
Reference in New Issue