diff --git a/include/cubescript/cubescript/error.hh b/include/cubescript/cubescript/error.hh index f0fa8f4..00f30f5 100644 --- a/include/cubescript/cubescript/error.hh +++ b/include/cubescript/cubescript/error.hh @@ -40,9 +40,12 @@ struct LIBCUBESCRIPT_EXPORT error { * 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). + * + * When getting the stack state, it will be represented as a span with + * the first element being the topmost node and the last element being + * the bottommost (index 1). */ 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. */ }; @@ -51,10 +54,12 @@ struct LIBCUBESCRIPT_EXPORT error { error(error const &) = delete; /** @brief Errors are move constructible. */ - error(error &&v): - p_errbeg{v.p_errbeg}, p_errend{v.p_errend}, - p_stack{std::move(v.p_stack)}, p_state{v.p_state} - {} + error(error &&v); + + error &operator=(error const &) = delete; + + /** @brief Errors are move assignable. */ + error &operator=(error &&v); /** @brief Construct an error using a string. */ error(state &cs, std::string_view msg); @@ -63,26 +68,18 @@ struct LIBCUBESCRIPT_EXPORT error { ~error(); /** @brief Get a view of the error message. */ - std::string_view what() const { - return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)}; - } + std::string_view what() const; - /** @brief Get a reference to the call stack state. */ - stack_node *stack() { - return p_stack; - } + /** @brief Get the call stack state at the point of error. */ + span_type stack() const; - /** @brief Get a reference to the call stack state. */ - stack_node const *stack() const { - return p_stack; - } private: friend struct error_p; error(state &cs, char const *errbeg, char const *errend); char const *p_errbeg, *p_errend; - stack_node *p_stack; + stack_node *p_sbeg, *p_send; state *p_state; }; diff --git a/src/cs_error.cc b/src/cs_error.cc index ec1f30a..919cd17 100644 --- a/src/cs_error.cc +++ b/src/cs_error.cc @@ -2,28 +2,35 @@ #include #include +#include #include "cs_thread.hh" #include "cs_error.hh" namespace cubescript { -static typename error::stack_node *save_stack(state &cs) { +static void save_stack( + state &cs, typename error::stack_node *&sbeg, + typename error::stack_node *&send +) { auto &ts = state_p{cs}.ts(); builtin_var *dalias = ts.istate->ivar_dbgalias; auto dval = std::size_t(std::clamp( dalias->value().get_integer(), integer_type(0), integer_type(1000) )); if (!dval) { - return nullptr; + sbeg = send = nullptr; + return; } std::size_t depth = 0; std::size_t total = ts.callstack.size(); if (!total) { - return nullptr; + sbeg = send = nullptr; + return; } + auto slen = std::min(total, dval); auto *st = static_cast(ts.istate->alloc( - nullptr, 0, sizeof(typename error::stack_node) * std::min(total, dval) + nullptr, 0, sizeof(typename error::stack_node) * slen )); typename error::stack_node *ret = st, *nd = st; ++st; @@ -32,27 +39,41 @@ static typename error::stack_node *save_stack(state &cs) { ++depth; if (depth < dval) { new (nd) typename error::stack_node{ - nullptr, lev.id, total - depth + 1 + lev.id, total - depth + 1 }; if (i == 0) { break; } - nd->next = st; nd = st++; } else if (i == 0) { - new (nd) typename error::stack_node{nullptr, lev.id, 1}; + new (nd) typename error::stack_node{lev.id, 1}; break; } } - return ret; + sbeg = ret; + send = ret + slen; +} + +LIBCUBESCRIPT_EXPORT error::error(error &&v): + p_errbeg{v.p_errbeg}, p_errend{v.p_errend}, + p_sbeg{v.p_sbeg}, p_send{v.p_send}, p_state{v.p_state} +{ + v.p_sbeg = v.p_send = nullptr; +} + +LIBCUBESCRIPT_EXPORT error &error::operator=(error &&v) { + std::swap(p_errbeg, v.p_errbeg); + std::swap(p_errend, v.p_errend); + std::swap(p_sbeg, v.p_sbeg); + std::swap(p_send, v.p_send); + std::swap(p_state, v.p_state); + return *this; } 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); + state_p{*p_state}.ts().istate->destroy_array( + p_sbeg, std::size_t(p_send - p_sbeg) + ); } LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg): @@ -64,13 +85,23 @@ LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg): buf[msg.size()] = '\0'; p_errbeg = sp; p_errend = buf + msg.size(); - p_stack = save_stack(cs); + save_stack(cs, p_sbeg, p_send); } LIBCUBESCRIPT_EXPORT error::error( state &cs, char const *errbeg, char const *errend ): p_errbeg{errbeg}, p_errend{errend}, p_state{&cs} { - p_stack = save_stack(cs); + save_stack(cs, p_sbeg, p_send); +} + +std::string_view error::what() const { + return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)}; +} + +span_type error::stack() const { + return span_type{ + p_sbeg, std::size_t(p_send - p_sbeg) + }; } } /* namespace cubescript */ diff --git a/src/lib_base.cc b/src/lib_base.cc index 5759853..437f25b 100644 --- a/src/lib_base.cc +++ b/src/lib_base.cc @@ -84,19 +84,18 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) { auto tb = any_value{}; val.set_string(e.what(), cs); ts.get_astack(ra).set_alias(ra, ts, val); - if (auto *snd = e.stack(); snd) { + if (auto nds = e.stack(); !nds.empty()) { auto bc = args[4].get_code(); if (!bc.empty()) { alias_local ist{cs, args[2].get_ident(cs)}; alias_local vst{cs, args[3].get_ident(cs)}; any_value idv{}; - while (snd) { - idv.set_integer(integer_type(snd->index)); + for (auto &nd: nds) { + idv.set_integer(integer_type(nd.index)); ist.set(idv); - idv.set_string(snd->id.name().data(), cs); + idv.set_string(nd.id.name().data(), cs); vst.set(idv); bc.call(cs); - snd = snd->next; } } } diff --git a/tools/repl.cc b/tools/repl.cc index 557c677..656e5f1 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -254,13 +254,13 @@ static bool do_call(cs::state &cs, std::string_view line, bool file = false) { "%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data() ); std::size_t pindex = 1; - for (auto *nd = e.stack(); nd; nd = nd->next) { + for (auto &nd: e.stack()) { std::printf(" "); - if ((nd->index == 1) && (pindex > 2)) { + if ((nd.index == 1) && (pindex > 2)) { std::printf(".."); } - pindex = nd->index; - std::printf("%zu) %s\n", nd->index, nd->id.name().data()); + pindex = nd.index; + std::printf("%zu) %s\n", nd.index, nd.id.name().data()); } return false; }