xo-reader2/xo-reader/src/reader/reader.cpp

166 lines
6.4 KiB
C++

/* @file reader.cpp */
#include "reader.hpp"
namespace xo {
namespace scm {
reader::reader(const rp<GlobalSymtab> & toplevel_symtab, bool debug_flag) :
tokenizer_{debug_flag},
parser_{toplevel_symtab, debug_flag}
{}
void
reader::begin_interactive_session() {
parser_.begin_interactive_session();
}
reader_result
reader::end_interactive_session() {
return this->read_expr(span_type(nullptr, nullptr), true /*eof*/);
}
void
reader::begin_translation_unit() {
parser_.begin_translation_unit();
}
reader_result
reader::end_translation_unit() {
return this->read_expr(span_type(nullptr, nullptr), true /*eof*/);
}
reader_result
reader::read_expr(const span_type & input_arg, bool eof_flag)
{
scope log(XO_DEBUG(this->debug_flag()));
span_type input = input_arg;
/* input text-span consumed by this call.
* Always comprises some number (possibly 0)
* of complete tokens, along with any leading
* whitespace.
*
* expr_span may also begin and end part way through
* distinct input lines
*/
span_type expr_span = input.prefix(0ul);
while (!input.empty()) {
/* each loop iteration reads one token */
/* read one token from input.
* tokenizer stashes one line at a time, but used_span only
* reports in used_span the portion representing the first token.
*/
auto [tk, used_span, error1]
= this->tokenizer_.scan(input, eof_flag);
log && log(xtag("consumed", used_span));
log && log(xtag("input.pre", input));
expr_span += used_span;
if (tk.is_valid()) {
log && log("input_state.current_line", tokenizer_.input_state().current_line());
/* forward just-read token to parser */
auto parser_result = this->parser_.include_token(tk);
log && log("after parser.include_token");
log && log("input_state.current_line", tokenizer_.input_state().current_line());
if (parser_result.is_expression()) {
log && log(xtag("outcome", "victory!"),
xtag("expr", parser_result.result_expr()));
rp<Expression> result_expr = parser_result.result_expr();
this->parser_.reset_result();
/* token completes an expression -> victory */
return reader_result(parser_result.result_expr(),
expr_span, parser_.stack_size(), reader_error());
} else if (parser_result.is_error()) {
/* 1. parser detected error.
* 2. tokenizer_.input_state().current_pos refers to position just after offending token
* 3. error_pos here is 0 because error detected at token boundary
*/
reader_error error2(parser_result.error_src_function(),
parser_result.error_description(),
tokenizer_.input_state().rewind(tk.text().size()),
0 /*error_pos*/);
std::cout << "parser error pre-report:" << std::endl;
error2.report(std::cout);
return reader_result(nullptr, expr_span, parser_.stack_size(), error2);
} else {
/* token did not complete an expression
* (e.g. token for '[')
*
* input span may contain more tokens -> iterate
*/
}
} else /*invalid token*/ {
if (error1.is_error()) {
/* tokenizer detected an error */
std::cout << "tokenizer error pre-report:" << std::endl;
error1.report(std::cout);
return reader_result(nullptr, expr_span, parser_.stack_size(),
reader_error(error1.src_function(),
error1.error_description(),
error1.input_state(),
error1.error_pos()));
} else if (used_span.size() > 0) {
/* control here on reaching the last token in input line;
* used_span will be the entire line
*/
} else {
/* control should not come here: invalid token with no error
*/
assert(input.empty());
break;
}
}
input = input.after_prefix(used_span);
}
/* control here: either
* 1. input.empty (perhaps ate some whitespace, ok)
* 2. missing or incomplete token (ok unless eof)
*/
if (eof_flag) {
if (parser_.has_incomplete_expr()) {
throw std::runtime_error
("reader::read_expr"
": eof reached with incomplete expression");
}
if (tokenizer_.has_prefix()) {
throw std::runtime_error
("reader::read_expr"
": unintelligible input recognized at eof");
}
}
log && log(xtag("outcome", "noop"),
xtag("parser.stack_size", parser_.stack_size()));
return reader_result(nullptr, expr_span, parser_.stack_size(), reader_error());
}
void
reader::reset_to_idle_toplevel()
{
this->tokenizer_.discard_current_line();
this->parser_.reset_to_idle_toplevel();
}
} /*namespace scm*/
} /*namespace xo*/
/* end reader.cpp */