remove separate stack_state

master
Daniel Kolesa 2021-05-09 20:21:35 +02:00
parent fdcc8a09e9
commit 1739cbed6e
5 changed files with 42 additions and 102 deletions

View File

@ -18,61 +18,6 @@ namespace cubescript {
struct state; struct state;
/** @brief Represents the simplified call stack at a point in time.
*
* This is a simplified call stack; it is generally carried by errors
* and can be utilized to print out a stack trace.
*
* The actual stack is represented as a linked list of nodes. There can
* be a gap in the list, if the user has limited the maximum debug depth
* with the `dbgalias` cubescript variable; the bottommost node will always
* represent the bottom of the stack, while the nodes above it will be the
* rest of the stack or a part of the stack starting from the top.
*/
struct LIBCUBESCRIPT_EXPORT stack_state {
/** @brief A node in the call stack.
*
* The nodes are indexed. The bottommost node has index 1, the topmost
* node has index N (where N is the number of levels the call stack has).
*/
struct node {
node const *next; /**< @brief Next level. */
struct ident const *id; /**< @brief The ident of this level. */
std::size_t index; /**< @brief The level index. */
};
stack_state() = delete;
/** @brief Construct the stack state. */
stack_state(state &cs, node *nd = nullptr);
stack_state(stack_state const &) = delete;
/** @brief Move the stack state somewhere else.
*
* Stack states are movable, but not copyable.
*/
stack_state(stack_state &&st);
/** @brief Destroy the stack state. */
~stack_state();
stack_state &operator=(stack_state const &) = delete;
/** @brief Move-assign the stack state somewhere else.
*
* Stack states are move assignable, but not copy assignable.
*/
stack_state &operator=(stack_state &&);
/** @brief Get the pointer to the topmost (current) level. */
node const *get() const;
private:
state &p_state;
node *p_node;
};
/** @brief Represents a Cubescript error. /** @brief Represents a Cubescript error.
* *
* This is a standard error that can be thrown by either the Cubescript APIs * This is a standard error that can be thrown by either the Cubescript APIs
@ -86,7 +31,21 @@ private:
* which is reused for each error raised from that thread. * which is reused for each error raised from that thread.
*/ */
struct LIBCUBESCRIPT_EXPORT error { struct LIBCUBESCRIPT_EXPORT error {
friend struct state; /** @brief A node in the call stack.
*
* The nodes are indexed. The bottommost node has index 1, the topmost
* node has index N (where N is the number of levels the call stack has).
*
* There can be a gap in the stack (i.e. the bottommost node will have
* index 1 and the one above it greater than 2). The gap is controlled
* by the value of the `dbgalias` cubescript variable at the time of
* creation of the error (the stack list will contain at most N nodes).
*/
struct stack_node {
stack_node const *next; /**< @brief Next level. */
struct ident const *id; /**< @brief The ident of this level. */
std::size_t index; /**< @brief The level index. */
};
error() = delete; error() = delete;
error(error const &) = delete; error(error const &) = delete;
@ -94,24 +53,27 @@ struct LIBCUBESCRIPT_EXPORT error {
/** @brief Errors are move constructible. */ /** @brief Errors are move constructible. */
error(error &&v): error(error &&v):
p_errbeg{v.p_errbeg}, p_errend{v.p_errend}, p_errbeg{v.p_errbeg}, p_errend{v.p_errend},
p_stack{std::move(v.p_stack)} p_stack{std::move(v.p_stack)}, p_state{v.p_state}
{} {}
/** @brief Construct an error using a string. */ /** @brief Construct an error using a string. */
error(state &cs, std::string_view msg); error(state &cs, std::string_view msg);
/** @brief Destroy the error. */
~error();
/** @brief Get a view of the error message. */ /** @brief Get a view of the error message. */
std::string_view what() const { std::string_view what() const {
return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)}; return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)};
} }
/** @brief Get a reference to the call stack state. */ /** @brief Get a reference to the call stack state. */
stack_state &stack() { stack_node *stack() {
return p_stack; return p_stack;
} }
/** @brief Get a reference to the call stack state. */ /** @brief Get a reference to the call stack state. */
stack_state const &stack() const { stack_node const *stack() const {
return p_stack; return p_stack;
} }
private: private:
@ -120,7 +82,8 @@ private:
error(state &cs, char const *errbeg, char const *errend); error(state &cs, char const *errbeg, char const *errend);
char const *p_errbeg, *p_errend; char const *p_errbeg, *p_errend;
stack_state p_stack; stack_node *p_stack;
state *p_state;
}; };
} /* namespace cubescript */ } /* namespace cubescript */

View File

@ -293,9 +293,8 @@ inline R unescape_string(R writer, std::string_view str) {
* @return `writer` after writing into it * @return `writer` after writing into it
*/ */
template<typename R> template<typename R>
inline R print_stack(R writer, stack_state const &st) { inline R print_stack(R writer, typename error::stack_node const *nd) {
char buf[32] = {0}; char buf[32] = {0};
auto nd = st.get();
std::size_t pindex = 1; std::size_t pindex = 1;
while (nd) { while (nd) {
auto name = nd->id->name(); auto name = nd->id->name();

View File

@ -8,56 +8,26 @@
namespace cubescript { namespace cubescript {
LIBCUBESCRIPT_EXPORT stack_state::stack_state( static typename error::stack_node *save_stack(state &cs) {
state &cs, node *nd
):
p_state{cs}, p_node{nd}
{}
LIBCUBESCRIPT_EXPORT stack_state::stack_state(stack_state &&st):
p_state{st.p_state}, p_node{st.p_node}
{
st.p_node = nullptr;
}
LIBCUBESCRIPT_EXPORT stack_state::~stack_state() {
size_t len = 0;
for (node const *nd = p_node; nd; nd = nd->next) {
++len;
}
state_p{p_state}.ts().istate->destroy_array(p_node, len);
}
LIBCUBESCRIPT_EXPORT stack_state &stack_state::operator=(stack_state &&st) {
p_node = st.p_node;
st.p_node = nullptr;
return *this;
}
LIBCUBESCRIPT_EXPORT stack_state::node const *stack_state::get() const {
return p_node;
}
static stack_state save_stack(state &cs) {
auto &ts = state_p{cs}.ts(); auto &ts = state_p{cs}.ts();
builtin_var *dalias = ts.istate->ivar_dbgalias; builtin_var *dalias = ts.istate->ivar_dbgalias;
auto dval = std::clamp( auto dval = std::clamp(
dalias->value().get_integer(), integer_type(0), integer_type(1000) dalias->value().get_integer(), integer_type(0), integer_type(1000)
); );
if (!dval) { if (!dval) {
return stack_state{cs, nullptr}; return nullptr;
} }
int total = 0, depth = 0; int total = 0, depth = 0;
for (ident_link *l = ts.callstack; l; l = l->next) { for (ident_link *l = ts.callstack; l; l = l->next) {
total++; total++;
} }
if (!total) { if (!total) {
return stack_state{cs, nullptr}; return nullptr;
} }
stack_state::node *st = ts.istate->create_array<stack_state::node>( auto *st = ts.istate->create_array<typename error::stack_node>(
std::min(total, dval) std::min(total, dval)
); );
stack_state::node *ret = st, *nd = st; typename error::stack_node *ret = st, *nd = st;
++st; ++st;
for (ident_link *l = ts.callstack; l; l = l->next) { for (ident_link *l = ts.callstack; l; l = l->next) {
++depth; ++depth;
@ -76,11 +46,19 @@ static stack_state save_stack(state &cs) {
nd->next = nullptr; nd->next = nullptr;
} }
} }
return stack_state{cs, ret}; return ret;
}
LIBCUBESCRIPT_EXPORT error::~error() {
std::size_t slen = 0;
for (stack_node const *nd = p_stack; nd; nd = nd->next) {
++slen;
}
state_p{*p_state}.ts().istate->destroy_array(p_stack, slen);
} }
LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg): LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg):
p_errbeg{}, p_errend{}, p_stack{cs} p_errbeg{}, p_errend{}, p_state{&cs}
{ {
char *sp; char *sp;
char *buf = state_p{cs}.ts().request_errbuf(msg.size(), sp); char *buf = state_p{cs}.ts().request_errbuf(msg.size(), sp);
@ -93,7 +71,7 @@ LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg):
LIBCUBESCRIPT_EXPORT error::error( LIBCUBESCRIPT_EXPORT error::error(
state &cs, char const *errbeg, char const *errend state &cs, char const *errbeg, char const *errend
): p_errbeg{errbeg}, p_errend{errend}, p_stack{cs} { ): p_errbeg{errbeg}, p_errend{errend}, p_state{&cs} {
p_stack = save_stack(cs); p_stack = save_stack(cs);
} }

View File

@ -84,7 +84,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
result = args[0].get_code().call(cs); result = args[0].get_code().call(cs);
} catch (error const &e) { } catch (error const &e) {
result.set_string(e.what(), cs); result.set_string(e.what(), cs);
if (e.stack().get()) { if (e.stack()) {
charbuf buf{cs}; charbuf buf{cs};
print_stack(std::back_inserter(buf), e.stack()); print_stack(std::back_inserter(buf), e.stack());
tback.set_string(buf.str(), cs); tback.set_string(buf.str(), cs);

View File

@ -253,7 +253,7 @@ static bool do_call(cs::state &cs, std::string_view line, bool file = false) {
std::printf( std::printf(
"%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data() "%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data()
); );
if (e.stack().get()) { if (e.stack()) {
std::string str; std::string str;
cs::print_stack(std::back_inserter(str), e.stack()); cs::print_stack(std::back_inserter(str), e.stack());
std::printf("%s\n", str.data()); std::printf("%s\n", str.data());