xo-reader: exprreplxx example program, now with line editing
This commit is contained in:
parent
dc6acaa18c
commit
0af7a50810
9 changed files with 170 additions and 11 deletions
|
|
@ -170,14 +170,18 @@ pkgs.mkShell {
|
|||
pkgs.graphviz
|
||||
pkgs.doxygen
|
||||
|
||||
|
||||
pkgs.llvmPackages_18.llvm.dev
|
||||
pkgs.libwebsockets
|
||||
pkgs.replxx
|
||||
pkgs.jsoncpp
|
||||
pkgs.eigen
|
||||
pkgs.cmake
|
||||
pkgs.catch2
|
||||
pkgs.zlib
|
||||
pkgs.unzip
|
||||
|
||||
pkgs.cmake
|
||||
pkgs.pkg-config
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
add_subdirectory(exprrepl)
|
||||
add_subdirectory(exprreplxx)
|
||||
|
|
|
|||
0
xo-reader/examples/exprrepl/expreplxx.cpp
Normal file
0
xo-reader/examples/exprrepl/expreplxx.cpp
Normal file
|
|
@ -4,18 +4,35 @@
|
|||
#include <iostream>
|
||||
#include <unistd.h> // for isatty
|
||||
|
||||
bool repl_getline(bool interactive, std::istream& in, std::ostream& out, std::string& input)
|
||||
bool repl_getline(bool interactive, std::size_t parser_stack_size, std::istream& in, std::ostream& out, std::string& input)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if (interactive) {
|
||||
out << "> ";
|
||||
if (parser_stack_size <= 1)
|
||||
out << "> ";
|
||||
else
|
||||
out << ". ";
|
||||
std::flush(out);
|
||||
}
|
||||
|
||||
bool retval = static_cast<bool>(std::getline(in, input));
|
||||
bool retval = static_cast<bool>(getline(in, input));
|
||||
|
||||
if (retval) {
|
||||
cerr << "got reval->true" << endl;
|
||||
|
||||
// interactive only: treat ^@ (C-RET) as ;RET
|
||||
if ((input.size() > 0) && ((*input.rbegin()) == '\0'))
|
||||
{
|
||||
cerr << "got ^@" << endl;
|
||||
|
||||
*input.rbegin() = ';';
|
||||
}
|
||||
|
||||
// want reader to see newline, it's syntax
|
||||
input.push_back('\n');
|
||||
} else {
|
||||
cerr << "got retval->false" << endl;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
|
@ -38,22 +55,24 @@ main() {
|
|||
bool eof = false;
|
||||
|
||||
span_type input;
|
||||
std::size_t parser_stack_size = 0;
|
||||
|
||||
while (repl_getline(interactive, cin, cout, input_str)) {
|
||||
while (repl_getline(interactive, parser_stack_size, cin, cout, input_str)) {
|
||||
input = span_type::from_string(input_str);
|
||||
|
||||
while (!input.empty()) {
|
||||
auto [expr, consumed] = rdr.read_expr(input, eof);
|
||||
auto [expr, consumed, psz] = rdr.read_expr(input, eof);
|
||||
|
||||
if (expr) {
|
||||
cout << expr << endl;
|
||||
}
|
||||
|
||||
input = input.after_prefix(consumed);
|
||||
parser_stack_size = psz;
|
||||
}
|
||||
}
|
||||
|
||||
auto [expr, _] = rdr.read_expr(input, true /*eof*/);
|
||||
auto [expr, _1, _2] = rdr.read_expr(input, true /*eof*/);
|
||||
|
||||
if (expr) {
|
||||
cout << expr << endl;
|
||||
|
|
|
|||
16
xo-reader/examples/exprreplxx/CMakeLists.txt
Normal file
16
xo-reader/examples/exprreplxx/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# xo-reader/example/exprreplxx/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_expression_replxx)
|
||||
set(SELF_SRCS exprreplxx.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_dependency(${SELF_EXE} xo_reader)
|
||||
xo_external_target_dependency(${SELF_EXE} replxx replxx::replxx)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${SELF_EXE} PUBLIC Threads::Threads)
|
||||
#xo_external_target_dependency(${SELF_EXE} Threads Threads::Threads)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
108
xo-reader/examples/exprreplxx/exprreplxx.cpp
Normal file
108
xo-reader/examples/exprreplxx/exprreplxx.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/** @file exprreplxx.cpp **/
|
||||
|
||||
#include "xo/reader/reader.hpp"
|
||||
#include <replxx.hxx>
|
||||
#include <iostream>
|
||||
#include <unistd.h> // for isatty
|
||||
|
||||
// presumeably replxx assumes input is a tty
|
||||
//
|
||||
bool replxx_getline(bool interactive, std::size_t parser_stack_size, replxx::Replxx & rx, std::string& input)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
char const * prompt = "";
|
||||
|
||||
if (interactive) {
|
||||
if (parser_stack_size <= 1)
|
||||
prompt = "> ";
|
||||
else
|
||||
prompt = ". ";
|
||||
}
|
||||
|
||||
const char * input_cstr = rx.input(prompt);
|
||||
|
||||
bool retval = (input_cstr != nullptr);
|
||||
|
||||
if (retval) {
|
||||
//cerr << "got reval->true" << endl;
|
||||
|
||||
input = input_cstr;
|
||||
|
||||
} else {
|
||||
//cerr << "got retval->false" << endl;
|
||||
}
|
||||
|
||||
rx.history_add(input);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
main() {
|
||||
using namespace replxx;
|
||||
using namespace xo::scm;
|
||||
using namespace std;
|
||||
|
||||
using span_type = xo::scm::span<const char>;
|
||||
|
||||
bool interactive = isatty(STDIN_FILENO);
|
||||
|
||||
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");
|
||||
|
||||
reader rdr;
|
||||
rdr.begin_interactive_session();
|
||||
|
||||
string input_str;
|
||||
|
||||
bool eof = false;
|
||||
|
||||
span_type input;
|
||||
std::size_t parser_stack_size = 0;
|
||||
|
||||
welcome(cerr);
|
||||
|
||||
while (replxx_getline(interactive, parser_stack_size, rx, input_str)) {
|
||||
input = span_type::from_string(input_str);
|
||||
|
||||
while (!input.empty()) {
|
||||
auto [expr, consumed, psz] = rdr.read_expr(input, eof);
|
||||
|
||||
if (expr) {
|
||||
cout << expr << endl;
|
||||
}
|
||||
|
||||
input = input.after_prefix(consumed);
|
||||
parser_stack_size = psz;
|
||||
}
|
||||
}
|
||||
|
||||
auto [expr, _1, _2] = rdr.read_expr(input, true /*eof*/);
|
||||
|
||||
if (expr) {
|
||||
cout << expr << endl;
|
||||
}
|
||||
|
||||
rx.history_save("repl_history.txt");
|
||||
}
|
||||
|
|
@ -156,6 +156,9 @@ namespace xo {
|
|||
**/
|
||||
parser();
|
||||
|
||||
/** true if parser is at top-level, i.e. ready for next top-level expression **/
|
||||
bool is_at_toplevel() const { return stack_size() == 0; }
|
||||
|
||||
/** for diagnostics: number of entries in parser stack **/
|
||||
std::size_t stack_size() const { return xs_stack_.size(); }
|
||||
/** for diagnostics: exprstatetype at level @p i
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@ namespace xo {
|
|||
using Expression = xo::ast::Expression;
|
||||
using span_type = span<const char>;
|
||||
|
||||
reader_result(rp<Expression> expr, span_type rem)
|
||||
: expr_{std::move(expr)}, rem_{rem} {}
|
||||
reader_result(rp<Expression> expr, span_type rem, std::size_t psz)
|
||||
: expr_{std::move(expr)}, rem_{rem}, parser_stack_size_{psz} {}
|
||||
|
||||
/** true if reader parsed a complete expression **/
|
||||
bool expr_complete() const { return expr_.get(); }
|
||||
|
||||
/** parsed schematica expression **/
|
||||
rp<Expression> expr_;
|
||||
|
|
@ -28,6 +31,11 @@ namespace xo {
|
|||
* This is the span returned in result of tokenizer<char>::scan()
|
||||
**/
|
||||
span_type rem_;
|
||||
|
||||
/** parser nesting level when this result delivered
|
||||
* will be zero whenever @ref expr_ is non-null
|
||||
**/
|
||||
std::size_t parser_stack_size_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ namespace xo {
|
|||
xtag("expr", expr));
|
||||
|
||||
/* token completes an expression -> victory */
|
||||
return reader_result(expr, expr_span);
|
||||
return reader_result(expr, expr_span, parser_.stack_size());
|
||||
} else {
|
||||
/* token did not complete an expression
|
||||
* (e.g. token for '[')
|
||||
|
|
@ -99,7 +99,7 @@ namespace xo {
|
|||
|
||||
log && log(xtag("outcome", "noop"));
|
||||
|
||||
return reader_result(nullptr, expr_span);
|
||||
return reader_result(nullptr, expr_span, parser_.stack_size());
|
||||
}
|
||||
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue