xo-interpreter2: + skrepl (read eval print loop)
This commit is contained in:
parent
ce8663bcfa
commit
f26c05d64f
6 changed files with 268 additions and 12 deletions
|
|
@ -21,6 +21,7 @@ add_definitions(${PROJECT_CXX_FLAGS})
|
|||
# output targets
|
||||
|
||||
add_subdirectory(src/interpreter2)
|
||||
add_subdirectory(src/skrepl)
|
||||
add_subdirectory(utest)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -91,6 +91,11 @@ namespace xo {
|
|||
/** allocator for runtime errors **/
|
||||
obj<AAllocator> error_allocator() const noexcept;
|
||||
|
||||
/** true iff parser is at top-level -> does not contain
|
||||
* state for a incomplete/partial expression
|
||||
**/
|
||||
bool is_at_toplevel() const noexcept;
|
||||
|
||||
/** visit vsm-owned memory pools; call visitor(info) for each **/
|
||||
void visit_pools(const MemorySizeVisitor & visitor) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,12 @@ namespace xo {
|
|||
return error_mm_.to_op();
|
||||
}
|
||||
|
||||
bool
|
||||
VirtualSchematikaMachine::is_at_toplevel() const noexcept
|
||||
{
|
||||
return reader_.is_at_toplevel();
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::visit_pools(const MemorySizeVisitor & visitor) const
|
||||
{
|
||||
|
|
|
|||
13
xo-interpreter2/src/skrepl/CMakeLists.txt
Normal file
13
xo-interpreter2/src/skrepl/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# xo-interpreter2/src/repl/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE skrepl)
|
||||
set(SELF_SRCS skreplxx.cpp)
|
||||
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_dependency(${SELF_EXE} xo_interpreter2)
|
||||
xo_external_target_dependency(${SELF_EXE} replxx replxx::replxx)
|
||||
|
||||
# replxx requires this
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${SELF_EXE} PUBLIC Threads::Threads)
|
||||
|
||||
242
xo-interpreter2/src/skrepl/skreplxx.cpp
Normal file
242
xo-interpreter2/src/skrepl/skreplxx.cpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/** @file skreplxx.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Feb 2026
|
||||
**/
|
||||
|
||||
#include <xo/interpreter2/init_interpreter2.hpp>
|
||||
#include <xo/interpreter2/VirtualSchematikaMachine.hpp>
|
||||
#include <xo/alloc2/Arena.hpp>
|
||||
#include <xo/facet/FacetRegistry.hpp>
|
||||
#include <replxx.hxx>
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
using xo::scm::VirtualSchematikaMachine;
|
||||
using xo::scm::VsmResultExt;
|
||||
using xo::mm::AAllocator;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::DArena;
|
||||
using span_type = xo::mm::span<const char>;
|
||||
using xo::facet::FacetRegistry;
|
||||
using xo::facet::TypeRegistry;
|
||||
using std::cerr;
|
||||
|
||||
// presumeably replxx assumes input is a tty anyway?
|
||||
//
|
||||
bool replxx_getline(bool interactive,
|
||||
bool is_at_toplevel,
|
||||
replxx::Replxx & rx,
|
||||
span_type * p_input
|
||||
//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 = span_type::from_cstr(input_cstr);
|
||||
|
||||
if (input_cstr)
|
||||
rx.history_add(input_cstr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
welcome(std::ostream & os)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
os << "schematika repl" << 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;
|
||||
}
|
||||
|
||||
struct ReplConfig {
|
||||
ReplConfig() = default;
|
||||
|
||||
std::size_t max_history_size_ = 1000;
|
||||
std::string repl_history_fname_ = "skrepl_history.txt";
|
||||
bool debug_flag_ = false;
|
||||
};
|
||||
|
||||
struct AppConfig {
|
||||
using VsmConfig = xo::scm::VsmConfig;
|
||||
|
||||
//using ReaderConfig = xo::scm::ReaderConfig;
|
||||
//using X1CollectorConfig = xo::mm::X1CollectorConfig;
|
||||
//using ArenaConfig = xo::mm::ArenaConfig;
|
||||
|
||||
AppConfig(const ReplConfig & repl_cfg = ReplConfig(),
|
||||
const ArenaConfig & app_arena_cfg = ArenaConfig().with_name("skreplxx").with_size(16 * 1024),
|
||||
const VsmConfig & vsm_cfg = VsmConfig())
|
||||
: repl_config_{repl_cfg}, app_arena_config_{app_arena_cfg}, vsm_config_{vsm_cfg}
|
||||
{
|
||||
//rdr_config_.reader_debug_flag_ = true;
|
||||
//rdr_config.parser_debug_flag_ = true;
|
||||
//rdr_config.tk_debug_flag_ = true;
|
||||
}
|
||||
|
||||
ReplConfig repl_config_;
|
||||
ArenaConfig app_arena_config_;
|
||||
VsmConfig vsm_config_;
|
||||
//ReaderConfig rdr_config_;
|
||||
//X1CollectorConfig x1_config_ = (X1CollectorConfig().with_name("gc").with_size(4*1024*1024));
|
||||
//ArenaConfig fixed_config_ = (ArenaConfig().with_name("fixed").with_size(4*1024));
|
||||
};
|
||||
|
||||
struct App {
|
||||
//using AAllocator = xo::mm::AAllocator;
|
||||
//using DX1Collector = xo::mm::DX1Collector;
|
||||
//using X1CollectorConfig = xo::mm::X1CollectorConfig;
|
||||
//using DArena = xo::mm::DArena;
|
||||
//using ArenaConfig = xo::mm::ArenaConfig;
|
||||
using Replxx = replxx::Replxx;
|
||||
using span_type = VirtualSchematikaMachine::span_type;
|
||||
|
||||
App(const AppConfig & cfg = AppConfig())
|
||||
: repl_config_{cfg.repl_config_},
|
||||
app_arena_{cfg.app_arena_config_},
|
||||
vsm_{cfg.vsm_config_, obj<AAllocator,DArena>(&app_arena_)}
|
||||
{
|
||||
this->interactive_ = isatty(STDIN_FILENO);
|
||||
|
||||
rx_.set_max_history_size(repl_config_.max_history_size_);
|
||||
rx_.history_load(repl_config_.repl_history_fname_);
|
||||
// rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous");
|
||||
// rx.bind_key_internal(Replxx::KEY::control('n'), "history_next");
|
||||
}
|
||||
|
||||
/** borrows calling thread to run application **/
|
||||
void run();
|
||||
|
||||
private:
|
||||
void _init();
|
||||
void _start();
|
||||
void _repl();
|
||||
bool _read_eval_print(span_type * p_input, bool eof);
|
||||
|
||||
private:
|
||||
InitEvidence init_evidence_ = 0;
|
||||
ReplConfig repl_config_;
|
||||
bool interactive_ = false;
|
||||
Replxx rx_;
|
||||
///** collector/allocator for schematika expressions **/
|
||||
//DX1Collector x1_;
|
||||
///** e.g. for DArenaHashMap within global symtab **/
|
||||
//DArena fixed_;
|
||||
|
||||
/** arena with same lifetime as this application **/
|
||||
DArena app_arena_;
|
||||
/** schematika virtual machine **/
|
||||
VirtualSchematikaMachine vsm_;
|
||||
};
|
||||
|
||||
void
|
||||
App::run()
|
||||
{
|
||||
this->_init();
|
||||
this->_start();
|
||||
this->_repl();
|
||||
}
|
||||
|
||||
void
|
||||
App::_init()
|
||||
{
|
||||
// window to contorl size of registries ends as soon as we init other subsystems
|
||||
TypeRegistry::instance(1024);
|
||||
FacetRegistry::instance(1024);
|
||||
|
||||
InitEvidence init_evidence_ = (InitSubsys<S_interpreter2_tag>::require());
|
||||
|
||||
Subsystem::initialize_all();
|
||||
}
|
||||
|
||||
void
|
||||
App::_start()
|
||||
{
|
||||
welcome(cerr);
|
||||
|
||||
vsm_.begin_interactive_session();
|
||||
}
|
||||
|
||||
void
|
||||
App::_repl()
|
||||
{
|
||||
bool eof = false;
|
||||
span_type input;
|
||||
|
||||
// outer loop: fetch one line of interactive input
|
||||
while (replxx_getline(interactive_, vsm_.is_at_toplevel(), rx_, &input)) {
|
||||
|
||||
// inner lo9op: consume up to one expression at a time.
|
||||
while (!input.empty() && this->_read_eval_print(&input, false /*eof*/))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* here: either:
|
||||
* 1. input.empty() or
|
||||
* 2. error encountered
|
||||
*/
|
||||
}
|
||||
|
||||
/* reminder: eof can complete at most one token */
|
||||
this->_read_eval_print(&input, true /*eof*/);
|
||||
}
|
||||
|
||||
/** body of read-parse-print loop
|
||||
*
|
||||
* true -> no errors;
|
||||
* false -> reader encountered error
|
||||
**/
|
||||
bool
|
||||
App::_read_eval_print(span_type * p_input,
|
||||
bool eof)
|
||||
{
|
||||
scope log(XO_DEBUG(repl_config_.debug_flag_));
|
||||
|
||||
if (!p_input || p_input->empty())
|
||||
return true;
|
||||
|
||||
VsmResultExt res = vsm_.read_eval_print(*p_input, eof);
|
||||
|
||||
*p_input = res.remaining_;
|
||||
|
||||
return !res.is_tk_error() && !res.is_eval_error();
|
||||
}
|
||||
|
||||
} /*namespace xo*/
|
||||
|
||||
int
|
||||
main (int argc, char * argv[])
|
||||
{
|
||||
using xo::AppConfig;
|
||||
using xo::App;
|
||||
|
||||
AppConfig cfg;
|
||||
// [cmdline options here]
|
||||
|
||||
App app(cfg);
|
||||
|
||||
app.run();
|
||||
} /*main*/
|
||||
|
||||
/* end skreplxx.cpp */
|
||||
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#include <xo/interpreter2/init_interpreter2.hpp>
|
||||
#include <xo/interpreter2/VirtualSchematikaMachine.hpp>
|
||||
#include <xo/interpreter2/Closure.hpp>
|
||||
#include <xo/expression2/UniqueString.hpp>
|
||||
|
|
@ -12,18 +13,6 @@
|
|||
#include <xo/object2/RuntimeError.hpp>
|
||||
#include <xo/alloc2/Arena.hpp>
|
||||
#include <xo/facet/TypeRegistry.hpp>
|
||||
|
||||
#ifdef NOT_YET
|
||||
#include <xo/reader2/SchematikaParser.hpp>
|
||||
#include <xo/reader2/DDefineSsm.hpp>
|
||||
#include <xo/reader2/DExpectExprSsm.hpp>
|
||||
#include <xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp>
|
||||
#include <xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp>
|
||||
#endif
|
||||
#include <xo/interpreter2/init_interpreter2.hpp>
|
||||
#ifdef NOT_YET
|
||||
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
|
||||
#endif
|
||||
#include <xo/indentlog/print/hex.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue