166 lines
6.4 KiB
C++
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 */
|