forked from OctaForge/libcubescript
pass callstack state with errors
parent
f1039148b0
commit
32c53a31a0
|
@ -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 */
|
||||
|
|
63
src/cs_vm.cc
63
src/cs_vm.cc
|
@ -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()) {
|
||||
|
|
11
src/cs_vm.hh
11
src/cs_vm.hh
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue