xo-interpreter2 stack: wrap TokenizerError as DRuntimeError

Also fix _read_eval_print() to report them!
This commit is contained in:
Roland Conybeare 2026-03-27 11:16:28 -04:00
commit 6189e631f3
7 changed files with 69 additions and 30 deletions

View file

@ -27,17 +27,15 @@ namespace xo {
VsmResult() = default;
explicit VsmResult(obj<AGCObject> value) : result_{value} {}
explicit VsmResult(TokenizerError err) : result_{err} {}
bool is_value() const { return std::holds_alternative<obj<AGCObject>>(result_); }
bool is_tk_error() const { return std::holds_alternative<TokenizerError>(result_); }
bool is_eval_error() const;
bool is_value() const { return result_; }
bool is_error() const;
const obj<AGCObject> * value() const { return std::get_if<obj<AGCObject>>(&result_); }
obj<AGCObject> & value_ref() { return std::get<obj<AGCObject>>(result_); }
const obj<AGCObject> * value() const { return &result_; }
obj<AGCObject> & value_ref() { return result_; }
/** result of evaluating first expression encountered in input **/
std::variant<obj<AGCObject>, TokenizerError> result_;
obj<AGCObject> result_;
};
/** vsm result + reamining span **/
@ -270,7 +268,9 @@ namespace xo {
obj<AAllocator> aux_mm_;
/** allocator (likely DX1Collector or similar) for
* expressions and values. Schemaatika reader will use this also
* expressions and values. Schemaatika reader will use this also.
*
* Allocations must represent a type that supports GCObject.
**/
abox<AAllocator> mm_;

View file

@ -60,15 +60,9 @@ namespace xo {
namespace scm {
bool
VsmResult::is_eval_error() const
VsmResult::is_error() const
{
if (std::holds_alternative<obj<AGCObject>>(result_)) {
auto err = obj<AGCObject,DRuntimeError>::from(*(this->value()));
return err;
} else {
return false;
}
return (*this->value() && obj<AGCObject,DRuntimeError>::from(*(this->value())));
}
namespace {
@ -191,18 +185,39 @@ namespace xo {
reader_.reset_result();
auto [expr, remaining, error1]
auto [expr, remaining, tk_error]
= reader_.read_expr(input, eof);
if (!expr) {
/* tokenizer error */
if (tk_error.is_error()) {
// tokenizer error -> convert to runtime error
return VsmResultExt(VsmResult(error1), remaining);
DString * src = DString::from_view(mm_.to_op(), tk_error.src_function());
DString * msg = tk_error.report_to_string(mm_.to_op());
auto error = obj<AGCObject,DRuntimeError>(DRuntimeError::_make(mm_.to_op(), src, msg));
{
obj<APrintable> error_pr
= FacetRegistry::instance().variant<APrintable,AGCObject>(error);
ppconfig ppc;
ppstate_standalone pps(&cout, 0, &ppc);
pps.prettyn(error_pr);
}
return VsmResultExt(VsmResult(error), remaining);
} else {
// incomplete input
return VsmResultExt(VsmResult(), remaining);
}
}
// here: have obtained complete input expression
VsmResult evalresult = this->start_eval(expr);
if (evalresult.is_tk_error()) {
if (evalresult.is_error()) {
// TODO: print error here
return VsmResultExt(evalresult, remaining);
@ -210,19 +225,21 @@ namespace xo {
assert(evalresult.is_value());
obj<AGCObject> * p_value = std::get_if<obj<AGCObject>>(&(evalresult.result_));
obj<AGCObject> value = evalresult.result_;
assert(p_value);
assert(value);
obj<APrintable> value_pr
= FacetRegistry::instance().variant<APrintable,AGCObject>(*p_value);
{
obj<APrintable> value_pr
= FacetRegistry::instance().variant<APrintable,AGCObject>(value);
// pretty_toplevel(value_pr, &cout, ppconfig());
ppconfig ppc;
ppstate_standalone pps(&cout, 0, &ppc);
pps.prettyn(value_pr);
// pretty_toplevel(value_pr, &cout, ppconfig());
ppconfig ppc;
ppstate_standalone pps(&cout, 0, &ppc);
pps.prettyn(value_pr);
}
return VsmResultExt(VsmResult(*p_value), remaining);
return VsmResultExt(VsmResult(value), remaining);
}
const VsmResult &

View file

@ -230,7 +230,7 @@ namespace xo {
*p_input = res.remaining_;
return !res.is_tk_error() && !res.is_eval_error();
return !res.is_error();
}
void

View file

@ -6,6 +6,7 @@ include(CMakeFindDependencyMacro)
# must coordinate with xo_dependency() calls
# in src/tokenizer2/CMakeLists.txt
#
find_dependency(xo_stringtable2)
find_dependency(xo_arena)
find_dependency(indentlog)

View file

@ -8,6 +8,8 @@
#include "TkInputState.hpp"
#include "tokentype.hpp"
#include "span.hpp"
#include <xo/stringtable2/String.hpp>
#include <xo/alloc2/Allocator.hpp>
#include <iomanip>
namespace xo {
@ -19,6 +21,7 @@ namespace xo {
**/
class TokenizerError {
public:
using AAllocator = xo::mm::AAllocator;
using CharT = char;
using span_type = xo::mm::span<const CharT>;
@ -89,6 +92,9 @@ namespace xo {
/** Print human-oriented error report on @p os. **/
void report(std::ostream & os) const;
/** Similar to report, but capture as string, allocated from @p mm **/
DString * report_to_string(obj<AAllocator> mm) const;
///@}
private:

View file

@ -11,6 +11,7 @@ set(SELF_SRCS
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
# deps must coordinate with xo-tokenizer/cmake/xo_tokenizer2Config.cmake.in
xo_dependency(${SELF_LIB} xo_stringtable2)
xo_dependency(${SELF_LIB} xo_arena)
xo_dependency(${SELF_LIB} indentlog)

View file

@ -54,6 +54,20 @@ namespace xo {
}
}
DString *
TokenizerError::report_to_string(obj<AAllocator> dest_mm) const
{
// FIXME:
// using heap here for scratch space.
// Would prefer to checkpoint + realloc.
std::stringstream ss;
this->report(ss);
return DString::from_str(dest_mm, ss.str());
}
} /*namespace scm*/
} /*namespace xo*/