/** @file readerreplxx.cpp **/ #include #include #include #include #include #include #include #include #include #include #include #include // for isatty // presumeably replxx assumes input is a tty // bool replxx_getline(bool interactive, bool is_at_toplevel, replxx::Replxx & rx, const char ** p_input) { using namespace std; char const * prompt = ""; if (interactive) { prompt = ((is_at_toplevel) ? "> " : ". "); } const char * input_cstr = rx.input(prompt); bool retval = (input_cstr != nullptr); if (retval) *p_input = input_cstr; if (input_cstr) rx.history_add(input_cstr); return retval; } void welcome(std::ostream & os) { using namespace std; os << "read-eval-print loop for schematika expressions" << endl; os << " ctrl-a/ctrl-e beginning/end of line" << endl; os << " ctrl-u delete entire line" << endl; os << " ctrl-k delete to end of line" << endl; os << " meta- backward delete word" << endl; os << " |meta-p previous command from history" << endl; os << " |meta-n next command from history" << endl; os << " / page through history faster" << endl; os << " ctrl-s/ctrl-r forward/backward history search" << endl; os << endl; } namespace { using xo::scm::SchematikaReader; using xo::scm::AExpression; using xo::print::APrintable; using xo::print::ppstate_standalone; using xo::print::ppconfig; using xo::facet::FacetRegistry; using xo::facet::obj; using xo::xtag; using xo::scope; using std::cout; using std::endl; /** body of read-parse-print loop * * true -> no errors; * false -> reader encountered error **/ bool reader_seq(SchematikaReader * p_reader, SchematikaReader::span_type * p_input, bool eof, bool debug_flag) { scope log(XO_DEBUG(debug_flag)); if (!p_input || p_input->empty()) return true; auto [expr, remaining, error] = p_reader->read_expr(*p_input, eof); obj expr_pr; if (expr) { expr_pr = FacetRegistry::instance().variant(expr); assert(expr_pr); } if (log) { if (expr_pr) { log(xtag("expr", expr_pr)); } log(xtag("remaining", remaining)); log(xtag("error", error)); } if (expr) { ppconfig ppc; ppstate_standalone pps(&cout, 0, &ppc); pps.prettyn(expr_pr); *p_input = remaining; return true; } else if (error.is_error()) { cout << "parsing error (detected in " << error.src_function() << "): " << endl; error.report(cout); /* discard stashed remainder of input line * (for nicely-formatted errors) */ p_reader->reset_to_idle_toplevel(); return false; } else { *p_input = remaining; /* partial expression or whitespace input, no error */ return true; } } } int main() { using namespace replxx; using xo::scm::SchematikaReader; using xo::scm::ReaderConfig; using xo::mm::AAllocator; using xo::mm::DX1Collector; using xo::mm::CollectorConfig; using xo::mm::DArena; using xo::facet::with_facet; using xo::facet::obj; using xo::S_reader2_tag; using xo::InitSubsys; using xo::Subsystem; using xo::scope; using namespace std; bool interactive = isatty(STDIN_FILENO); InitSubsys::require(); Subsystem::initialize_all(); Replxx rx; rx.set_max_history_size(1000); rx.history_load("repl_history.txt"); // rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous"); // rx.bind_key_internal(Replxx::KEY::control('n'), "history_next"); constexpr bool c_debug_flag = false; scope log(XO_DEBUG(c_debug_flag)); CollectorConfig x1_config = (CollectorConfig() .with_size(4*1024*1024)); DX1Collector x1(x1_config); obj expr_alloc = with_facet::mkobj(&x1); // accepting defaults too ReaderConfig rdr_config; { rdr_config.reader_debug_flag_ = true; //rdr_config.parser_debug_flag_ = true; //rdr_config.tk_debug_flag_ = true; } SchematikaReader rdr(rdr_config, expr_alloc); using span_type = SchematikaReader::span_type; welcome(cerr); rdr.begin_interactive_session(); bool eof = false; const char * input_str = nullptr; span_type input; while (replxx_getline(interactive, rdr.is_at_toplevel(), rx, &input_str)) { if (input_str && *input_str) { input = span_type::from_cstr(input_str); while (!input.empty() && reader_seq(&rdr, &input, false /*eof*/, c_debug_flag)) { ; } /* here: either: * 1. input.empty() or * 2. error encountered */ } } /* reminder: eof can complete at most one token */ reader_seq(&rdr, &input, true /*eof*/, c_debug_flag); rx.history_save("repl_history.txt"); } /* end readerreplxx.cpp */