reader reports tokenizer errors through normal return
This commit is contained in:
parent
c0587aa4fb
commit
781adeb0d3
10 changed files with 149 additions and 20 deletions
|
|
@ -40,6 +40,8 @@ namespace xo {
|
|||
void push_envframe(const rp<LocalEnv> & x);
|
||||
rp<LocalEnv> pop_envframe();
|
||||
|
||||
void reset_to_toplevel() { stack_.resize(1); }
|
||||
|
||||
/** relative to top-of-stack.
|
||||
* 0 -> top (last in), z-1 -> bottom (first in)
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ namespace xo {
|
|||
void push_exprstate(std::unique_ptr<exprstate> exs);
|
||||
std::unique_ptr<exprstate> pop_exprstate();
|
||||
|
||||
void reset_to_toplevel();
|
||||
|
||||
/** relative to top-of-stack.
|
||||
* 0 -> top (last in), z-1 -> bottom (first in)
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ namespace xo {
|
|||
* $varname(n) : $typename(n)) [-> $typename[ret]]
|
||||
* body-expr
|
||||
* [ end $functionname ]
|
||||
* literal-expr = integer-literal
|
||||
* literal-expr = boolean-literal
|
||||
* | integer-literal
|
||||
* | fp-literal
|
||||
* | string-literal
|
||||
* | symbol-literal
|
||||
|
|
@ -211,6 +212,13 @@ namespace xo {
|
|||
**/
|
||||
rp<Expression> include_token(const token_type & tk);
|
||||
|
||||
/** reset to starting parsing state.
|
||||
* use this after encountering an error, to avoid cascade of
|
||||
* spurious secondary errors.. particularly important when
|
||||
* invoked asa part of a REPL.
|
||||
**/
|
||||
void reset_to_idle_toplevel();
|
||||
|
||||
/** print human-readable representation on stream @p os **/
|
||||
void print(std::ostream & os) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "reader_error.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/expression/pretty_expression.hpp"
|
||||
#include "xo/tokenizer/tokenizer.hpp"
|
||||
|
|
@ -19,8 +20,8 @@ namespace xo {
|
|||
using Expression = xo::ast::Expression;
|
||||
using span_type = span<const char>;
|
||||
|
||||
reader_result(rp<Expression> expr, span_type rem, std::size_t psz)
|
||||
: expr_{std::move(expr)}, rem_{rem}, parser_stack_size_{psz} {}
|
||||
reader_result(rp<Expression> expr, span_type rem, std::size_t psz, const reader_error & error)
|
||||
: expr_{std::move(expr)}, rem_{rem}, parser_stack_size_{psz}, error_{error} {}
|
||||
|
||||
/** true if reader parsed a complete expression **/
|
||||
bool expr_complete() const { return expr_.get(); }
|
||||
|
|
@ -37,6 +38,9 @@ namespace xo {
|
|||
* will be zero whenever @ref expr_ is non-null
|
||||
**/
|
||||
std::size_t parser_stack_size_ = 0;
|
||||
|
||||
/** error description, whenever .error_.is_error() is true **/
|
||||
reader_error error_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -53,7 +57,7 @@ namespace xo {
|
|||
*
|
||||
* for (auto rem = input; !rem.empty();) {
|
||||
* // res: (parsed-expr, used)
|
||||
* auto res = rdr.read_expr(rem, eof);
|
||||
* auto [expres = rdr.read_expr(rem, eof);
|
||||
*
|
||||
* if (res.first) {
|
||||
* // do something with res.first (parsed expr)
|
||||
|
|
@ -112,6 +116,13 @@ namespace xo {
|
|||
**/
|
||||
reader_result read_expr(const span_type & input, bool eof);
|
||||
|
||||
/** reset to known starting point after encountering an error.
|
||||
* - remainder of stashed current line.
|
||||
* Necesary for well-formatted error reporting.
|
||||
* - current parsing state
|
||||
**/
|
||||
void reset_to_idle_toplevel();
|
||||
|
||||
private:
|
||||
/** tokenizer: text -> tokens **/
|
||||
tokenizer_type tokenizer_;
|
||||
|
|
|
|||
53
include/xo/reader/reader_error.hpp
Normal file
53
include/xo/reader/reader_error.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* reader_error.hpp
|
||||
*
|
||||
* Author: Roland Conybeare, Jul 2025
|
||||
*/
|
||||
|
||||
#include "xo/tokenizer/tokenizer_error.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class reader_error {
|
||||
public:
|
||||
using input_state_type = typename tokenizer_error<char>::input_state_type;
|
||||
|
||||
public:
|
||||
/** default ctor represents a not-an-error sentinel object **/
|
||||
reader_error() = default;
|
||||
/** construct to capture parsing error context
|
||||
* @
|
||||
**/
|
||||
reader_error(const char * src_function,
|
||||
const char * error_description,
|
||||
const input_state_type & input_state,
|
||||
size_t error_pos)
|
||||
: tk_error_{src_function, error_description, input_state, error_pos}
|
||||
{}
|
||||
|
||||
const tokenizer_error<char> & tk_error() const { return tk_error_; }
|
||||
|
||||
/** true, except for sentinel not-an-error object **/
|
||||
bool is_error() const { return tk_error_.is_error(); }
|
||||
/** false, except for object in sentinel state **/
|
||||
bool is_not_an_error() const { return tk_error_.is_not_an_error(); }
|
||||
|
||||
const char * src_function() const { return tk_error_.src_function(); }
|
||||
|
||||
/** print error representation to stream @p os. Intended for parser/tokenizer
|
||||
* diagnostics. For Schematika errors prefer @ref report
|
||||
**/
|
||||
void print(std::ostream & os) const { tk_error_.print(os); }
|
||||
|
||||
/** print human-oriented error report on @p os. **/
|
||||
void report(std::ostream & os) const { tk_error_.report(os); }
|
||||
|
||||
private:
|
||||
/** for parser-level errors, will still use this for
|
||||
* {src function, error description, input state and error pos}
|
||||
**/
|
||||
tokenizer_error<char> tk_error_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* end reader_error.hpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue