Merge branch 'main' of github.com:rconybea/xo-umbrella2
This commit is contained in:
commit
de3b27629d
13 changed files with 220 additions and 17 deletions
|
|
@ -116,7 +116,7 @@ add_subdirectory(xo-expression)
|
|||
add_subdirectory(xo-pyexpression)
|
||||
add_subdirectory(xo-tokenizer)
|
||||
add_subdirectory(xo-reader)
|
||||
add_subdirectory(xo-symboltable)
|
||||
#add_subdirectory(xo-symboltable)
|
||||
add_subdirectory(xo-interpreter)
|
||||
add_subdirectory(xo-jit)
|
||||
add_subdirectory(xo-pyjit)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets
|
|||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
#add_subdirectory(example)
|
||||
add_subdirectory(example)
|
||||
add_subdirectory(utest)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
|
|
|||
1
xo-interpreter/example/CMakeLists.txt
Normal file
1
xo-interpreter/example/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(replxx)
|
||||
17
xo-interpreter/example/replxx/CMakeLists.txt
Normal file
17
xo-interpreter/example/replxx/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# xo-interpreter/example/replxx/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_interpreter_replxx)
|
||||
set(SELF_SRCS replxx.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_dependency(${SELF_EXE} xo_interpreter)
|
||||
# TODO: consider promoting to regular app
|
||||
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)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
140
xo-interpreter/example/replxx/replxx.cpp
Normal file
140
xo-interpreter/example/replxx/replxx.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/** @file replxx.cpp **/
|
||||
|
||||
#include "xo/reader/reader.hpp"
|
||||
#include <replxx.hxx>
|
||||
#include <iostream>
|
||||
#include <unistd.h> // for isatty
|
||||
|
||||
// similar helper in exprreplxx.cpp
|
||||
//
|
||||
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 = ". ";
|
||||
}
|
||||
|
||||
/* input_cstr: next line of input from replxx library */
|
||||
const char * input_cstr = rx.input(prompt);
|
||||
|
||||
bool retval = (input_cstr != nullptr);
|
||||
|
||||
if (retval) {
|
||||
/* got new input */
|
||||
input = input_cstr;
|
||||
}
|
||||
|
||||
rx.history_add(input);
|
||||
|
||||
input.push_back('\n');
|
||||
|
||||
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 xo::scm::Expression;
|
||||
using xo::print::ppconfig;
|
||||
using xo::print::ppstate_standalone;
|
||||
using xo::rp;
|
||||
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");
|
||||
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
reader rdr(c_debug_flag);
|
||||
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, error] = rdr.read_expr(input, eof);
|
||||
|
||||
if (expr) {
|
||||
ppconfig ppc;
|
||||
ppstate_standalone pps(&cout, 0, &ppc);
|
||||
|
||||
pps.prettyn(expr);
|
||||
} 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)
|
||||
*/
|
||||
rdr.reset_to_idle_toplevel();
|
||||
break;
|
||||
}
|
||||
|
||||
input = input.after_prefix(consumed);
|
||||
parser_stack_size = psz;
|
||||
}
|
||||
|
||||
/* here: input.empty() or error encountered */
|
||||
|
||||
}
|
||||
|
||||
auto [expr, _1, _2, error] = rdr.read_expr(input, true /*eof*/);
|
||||
|
||||
if (expr) {
|
||||
ppconfig ppc;
|
||||
ppstate_standalone pps(&cout, 0, &ppc);
|
||||
|
||||
pps.prettyn<rp<Expression>>(rp<Expression>(expr));
|
||||
} else if (error.is_error()) {
|
||||
cout << "parsing error (detected in " << error.src_function() << "): " << endl;
|
||||
error.report(cout);
|
||||
}
|
||||
|
||||
rx.history_save("repl_history.txt");
|
||||
}
|
||||
|
||||
/* end replxx.cpp */
|
||||
40
xo-interpreter/include/xo/interpreter/Schematika.hpp
Normal file
40
xo-interpreter/include/xo/interpreter/Schematika.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/** @file Schematika.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pramga once
|
||||
|
||||
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
||||
/** @class Schematika
|
||||
* @brief schematika interpreter state
|
||||
**/
|
||||
class Schematika {
|
||||
public:
|
||||
/** interactive read-eval-print loop.
|
||||
* Uses replxx to read from stdin.
|
||||
* If stdin is interactive, accepts line editing commands:
|
||||
* - ctrl-a goto beginning of line
|
||||
* - ctrl-e goto end of line
|
||||
* - ctrl-k delete to end of line
|
||||
* - meta-<bs> backwards delete word
|
||||
* - meta-p|<up> retrieve previous command from history
|
||||
* - meta-n|<down> retrieve next command from history
|
||||
* - <pgup>/<pgdown> page through history faster
|
||||
* - ctrl-s forward history search
|
||||
* - ctrl-r backward history search
|
||||
**/
|
||||
void interactive_repl();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p_impl_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* end Schematika.hpp */
|
||||
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
// presumeably replxx assumes input is a tty
|
||||
//
|
||||
bool replxx_getline(bool interactive, std::size_t parser_stack_size, replxx::Replxx & rx, std::string& input)
|
||||
bool replxx_getline(bool interactive,
|
||||
std::size_t parser_stack_size,
|
||||
replxx::Replxx & rx,
|
||||
std::string& input)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -58,7 +61,8 @@ welcome(std::ostream& os)
|
|||
}
|
||||
|
||||
int
|
||||
main() {
|
||||
main()
|
||||
{
|
||||
using namespace replxx;
|
||||
using namespace xo::scm;
|
||||
using xo::scm::Expression;
|
||||
|
|
|
|||
|
|
@ -165,7 +165,11 @@ namespace xo {
|
|||
**/
|
||||
explicit parser(bool debug_flag);
|
||||
|
||||
/** true if parser is at top-level, i.e. ready for next top-level expression **/
|
||||
bool debug_flag() const { return psm_.debug_flag(); }
|
||||
|
||||
/** 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 **/
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ namespace xo {
|
|||
public:
|
||||
explicit reader(bool debug_flag);
|
||||
|
||||
bool debug_flag() const { return parser_.debug_flag(); }
|
||||
|
||||
/** call once before calling .read_expr()
|
||||
* for a new interactive session
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -68,8 +68,7 @@ namespace xo {
|
|||
exprstate::on_def_token(const token_type & tk,
|
||||
parserstatemachine * p_psm)
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||
|
||||
log && log(xtag("exstype", p_psm->top_exprstate().exs_type()));
|
||||
|
||||
|
|
@ -357,8 +356,7 @@ namespace xo {
|
|||
exprstate::on_input(const token_type & tk,
|
||||
parserstatemachine * p_psm)
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||
log && log(xtag("tk", tk));
|
||||
log && log(xtag("state", *this));
|
||||
log && log(xtag("psm", p_psm));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace xo {
|
|||
|
||||
void
|
||||
exprstatestack::push_exprstate(std::unique_ptr<exprstate> exs) {
|
||||
constexpr bool c_debug_flag = true;
|
||||
constexpr bool c_debug_flag = false;
|
||||
scope log(XO_DEBUG(c_debug_flag),
|
||||
xtag("exs", exs.get()));
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ namespace xo {
|
|||
|
||||
std::unique_ptr<exprstate>
|
||||
exprstatestack::pop_exprstate() {
|
||||
constexpr bool c_debug_flag = true;
|
||||
constexpr bool c_debug_flag = false;
|
||||
scope log(XO_DEBUG(c_debug_flag),
|
||||
xtag("top.exstype", top_exprstate().exs_type()));
|
||||
|
||||
|
|
|
|||
|
|
@ -339,8 +339,7 @@ namespace xo {
|
|||
progress_xs::on_expr_with_semicolon(bp<Expression> expr,
|
||||
parserstatemachine * p_psm)
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||
|
||||
log && log(xtag("lhs", lhs_), xtag("op", op_type_), xtag("expr", expr));
|
||||
|
||||
|
|
@ -606,8 +605,7 @@ namespace xo {
|
|||
progress_xs::on_operator_token(const token_type & tk,
|
||||
parserstatemachine * p_psm)
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
scope log(XO_DEBUG(p_psm->debug_flag()));
|
||||
|
||||
constexpr const char * c_self_name = "progress_xs::on_operator_token";
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ namespace xo {
|
|||
reader_result
|
||||
reader::read_expr(const span_type & input_arg, bool eof)
|
||||
{
|
||||
constexpr bool c_debug_flag = true;
|
||||
scope log(XO_DEBUG(c_debug_flag));
|
||||
scope log(XO_DEBUG(this->debug_flag()));
|
||||
|
||||
span_type input = input_arg;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue