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
};
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 CsPanicCb = ostd::Function<void(CsString)>;
using CsPanicCb = ostd::Function<void(CsString, CsStackState)>;
struct OSTD_EXPORT CsState {
CsMap<ostd::ConstCharRange, CsIdent *> idents;
@ -353,10 +376,13 @@ struct OSTD_EXPORT CsState {
CsPanicCb &get_panic_func();
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) {
(*static_cast<F *>(data))();
}, error, &func);
}, error, stack, &func);
}
void error(CsString msg);
@ -476,7 +502,10 @@ struct OSTD_EXPORT CsState {
private:
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;
CsPanicCb p_panicfunc;
@ -655,6 +684,27 @@ namespace util {
}
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 cscript */

View File

@ -69,6 +69,69 @@ ostd::ConstCharRange cs_debug_line(
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) {
CsIvar *dalias = static_cast<CsIvar *>(cs.identmap[DbgaliasIdx]);
if (!dalias->get_value()) {

View File

@ -88,10 +88,15 @@ constexpr ostd::Size CsTypeStorageSize =
struct CsErrorException {
CsString errmsg;
CsStackState stack;
CsErrorException() = delete;
CsErrorException(CsErrorException const &) = delete;
CsErrorException(CsErrorException &&v): errmsg(ostd::move(v.errmsg)) {}
CsErrorException(CsString &&v): errmsg(ostd::move(v)) {}
CsErrorException(CsErrorException &&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(
@ -100,6 +105,8 @@ ostd::ConstCharRange cs_debug_line(
void cs_debug_alias(CsState &cs);
CsStackState cs_save_stack(CsState &cs);
template<typename ...A>
void cs_debug_code(CsState &cs, ostd::ConstCharRange fmt, A &&...args) {
if (cs.nodebug) {

View File

@ -261,7 +261,7 @@ CsState::CsState():
noalias.argstack = nullptr;
/* default panic func */
p_panicfunc = [this](CsString v) {
p_panicfunc = [this](CsString v, CsStackState) {
get_err().writefln(
"PANIC: unprotected error in call to CubeScript (%s)", v
);
@ -418,15 +418,21 @@ CsPanicCb &CsState::get_panic_func() {
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;
try {
f(data);
} catch (CsErrorException const &v) {
} catch (CsErrorException &v) {
--protect;
if (error) {
*error = ostd::move(v.errmsg);
}
if (stack) {
*stack = ostd::move(v.stack);
}
return false;
} catch (...) {
--protect;
@ -438,10 +444,10 @@ bool CsState::ipcall(void (*f)(void *data), ostd::String *error, void *data) {
void CsState::error(CsString msg) {
if (protect) {
throw CsErrorException(ostd::move(msg));
throw CsErrorException(ostd::move(msg), cs_save_stack(*this));
} else {
if (p_panicfunc) {
p_panicfunc(ostd::move(msg));
p_panicfunc(ostd::move(msg), cs_save_stack(*this));
}
exit(EXIT_FAILURE);
}

View File

@ -197,6 +197,7 @@ static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
CsValue ret;
signal(SIGINT, do_sigint);
ostd::String err;
cscript::CsStackState st;
if (!cs.pcall([&]() {
if (file) {
if (!cs.run_file(line, ret)) {
@ -205,9 +206,10 @@ static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) {
} else {
cs.run(line, ret);
}
}, &err)) {
}, &err, &st)) {
signal(SIGINT, SIG_DFL);
ostd::writeln("error: ", err);
cs.get_out().writeln("error: ", err);
cscript::util::print_stack(cs.get_out().iter(), st);
return;
}
signal(SIGINT, SIG_DFL);