215 lines
5.6 KiB
C++
215 lines
5.6 KiB
C++
/** @file readerreplxx.cpp **/
|
|
|
|
#include <xo/reader2/init_reader2.hpp>
|
|
#include <xo/reader2/SchematikaReader.hpp>
|
|
#include <xo/gc/DX1Collector.hpp>
|
|
#include <xo/gc/detail/IAllocator_DX1Collector.hpp>
|
|
#include <xo/alloc2/Allocator.hpp>
|
|
#include <xo/printable2/Printable.hpp>
|
|
#include <xo/facet/FacetRegistry.hpp>
|
|
#include <xo/facet/obj.hpp>
|
|
#include <xo/subsys/Subsystem.hpp>
|
|
#include <replxx.hxx>
|
|
#include <iostream>
|
|
#include <unistd.h> // 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-<bs> backward delete word" << endl;
|
|
os << " <up>|meta-p previous command from history" << endl;
|
|
os << " <down>|meta-n next command from history" << endl;
|
|
os << " <pgup>/<pgdown> 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<APrintable> expr_pr;
|
|
|
|
if (expr) {
|
|
expr_pr = FacetRegistry::instance().variant<APrintable,AExpression>(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<S_reader2_tag>::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<AAllocator> expr_alloc = with_facet<AAllocator>::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 */
|