pass callstack state with errors

master
Daniel Kolesa 2016-09-09 19:19:50 +02:00
parent f1039148b0
commit 32c53a31a0
5 changed files with 141 additions and 13 deletions

View File

@ -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 */

View File

@ -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()) {

View File

@ -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) {

View File

@ -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);
} }

View File

@ -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);