xo-interpreter: scaffold interpreter read-eval-print loop
This commit is contained in:
parent
f12b5c1172
commit
3956635920
7 changed files with 222 additions and 4 deletions
28
xo-interpreter/include/xo/interpreter/SchematikaError.hpp
Normal file
28
xo-interpreter/include/xo/interpreter/SchematikaError.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/** @file SchematikaError.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class SchematikaError {
|
||||
public:
|
||||
SchematikaError() = default;
|
||||
explicit SchematikaError(std::string x) : what_{std::move(x)} {}
|
||||
|
||||
const std::string & what() const { return what_; }
|
||||
|
||||
bool is_error() const { return !what_.empty(); }
|
||||
bool is_not_an_error() const { return what_.empty(); }
|
||||
|
||||
private:
|
||||
std::string what_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* end SchematikaError.hpp */
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "VsmInstr.hpp"
|
||||
#include "SchematikaError.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/alloc/Object.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
|
@ -14,12 +17,47 @@ namespace xo {
|
|||
public:
|
||||
VirtualSchematikaMachine();
|
||||
|
||||
/** evaluate expression @p expr.
|
||||
* borrows calling thread until completion
|
||||
* return [value, error]. error ignored unless value is nullptr.
|
||||
* conversely when value is nullptr, error gives details of original
|
||||
* error.
|
||||
**/
|
||||
std::pair<gp<Object>, SchematikaError> eval(bp<Expression> expr);
|
||||
|
||||
private:
|
||||
/** program counter **/
|
||||
/** borrow calling thread to run schematika machine
|
||||
* indefinitely, or until null continuation
|
||||
**/
|
||||
void run();
|
||||
|
||||
/** execute vsm instruction @p pc
|
||||
* Note: may possibly be able to replace with just opcode
|
||||
**/
|
||||
void execute_vsm(const VsmInstr * pc);
|
||||
|
||||
/** implementation class; contains instruction implementations **/
|
||||
friend class VsmOps;
|
||||
|
||||
private:
|
||||
/** program counter.
|
||||
* (Perhaps replace with VsmInstr::Opcode ?)
|
||||
**/
|
||||
const VsmInstr * pc_ = nullptr;
|
||||
|
||||
/** expression **/
|
||||
rp<Expression> expr_;
|
||||
|
||||
/** non-error result value from eval() / apply() **/
|
||||
gp<Object> value_;
|
||||
|
||||
/** error result value from eval() / apply() **/
|
||||
SchematikaError error_;
|
||||
|
||||
/** continuation
|
||||
* (Perhaps replace with VsmInstr::Opcode ?)
|
||||
**/
|
||||
const VsmInstr * cont_ = nullptr;
|
||||
};
|
||||
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
|
|
@ -16,9 +16,29 @@ namespace xo {
|
|||
class VsmInstr
|
||||
{
|
||||
public:
|
||||
using ActionFn = void (*)(VirtualSchematikaMachine * vm);
|
||||
enum class Opcode {
|
||||
/** Halt virtual schematika machine **/
|
||||
halt,
|
||||
|
||||
/** Evaluate a schematika expression.
|
||||
* See VirtualSchematikaMachine::eval()
|
||||
**/
|
||||
eval,
|
||||
|
||||
N_Opcode
|
||||
};
|
||||
|
||||
//using ActionFn = void (*)(VirtualSchematikaMachine * vm);
|
||||
|
||||
public:
|
||||
VsmInstr(Opcode opcode, std::string_view name);
|
||||
|
||||
Opcode opcode() const { return opcode_; }
|
||||
|
||||
private:
|
||||
/** unique opcode for this instruction **/
|
||||
Opcode opcode_;
|
||||
/** **/
|
||||
std::string_view name_;
|
||||
//ActionFn action_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ set(SELF_SRCS
|
|||
LocalEnv.cpp
|
||||
GlobalEnv.cpp
|
||||
VirtualSchematikaMachine.cpp
|
||||
VsmInstr.cpp
|
||||
)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
**/
|
||||
|
||||
#include "Schematika.hpp"
|
||||
#include "VirtualSchematikaMachine.hpp"
|
||||
#include "xo/reader/reader.hpp"
|
||||
#include <replxx.hxx>
|
||||
#include <ostream>
|
||||
|
|
@ -35,6 +36,8 @@ namespace xo {
|
|||
private:
|
||||
/** configuration **/
|
||||
Config config_;
|
||||
/** schematika interpreter **/
|
||||
VirtualSchematikaMachine vsm_;
|
||||
};
|
||||
|
||||
void
|
||||
|
|
@ -151,7 +154,23 @@ namespace xo {
|
|||
ppconfig ppc;
|
||||
ppstate_standalone pps(&cout, 0, &ppc);
|
||||
|
||||
pps.prettyn(expr);
|
||||
//pps.prettyn(expr);
|
||||
|
||||
// TODO:
|
||||
auto [ value, scm_error ] = this->vsm_.eval(expr);
|
||||
|
||||
if (scm_error.is_error()) {
|
||||
/* print error */
|
||||
|
||||
cout << "scm error: " << scm_error.what() << endl;
|
||||
cout << "top-level expression: " << expr << endl;
|
||||
} else {
|
||||
/* print value */
|
||||
|
||||
cout << "scm result:" << endl;
|
||||
pps.pretty(value);
|
||||
}
|
||||
|
||||
} else if (error.is_error()) {
|
||||
cout << "parsing error (detected in " << error.src_function() << "): " << endl << endl;
|
||||
error.report(cout);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,105 @@
|
|||
|
||||
#include "VsmInstr.hpp"
|
||||
|
||||
/** continue after completing a VSM instruction;
|
||||
* achieve by jumping to continuation.
|
||||
**/
|
||||
//#define VSM_CONTINUE() this->pc_ = this->cont_; return;
|
||||
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
struct VsmOps {
|
||||
/** halt virtual scheme machine.
|
||||
* This will cause innermost run() to return to its caller
|
||||
**/
|
||||
static VsmInstr halt_op;
|
||||
|
||||
/** evaluate an expression.
|
||||
* - opcode is Opcode::eval
|
||||
* - expression in register @ref expr_
|
||||
**/
|
||||
static VsmInstr eval_op;
|
||||
};
|
||||
|
||||
VsmInstr
|
||||
VsmOps::halt_op{VsmInstr::Opcode::halt, "halt"};
|
||||
|
||||
VsmInstr
|
||||
VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"};
|
||||
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine()
|
||||
{}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::run()
|
||||
{
|
||||
for (const VsmInstr * pc = pc_; pc; pc = pc_)
|
||||
this->execute_vsm(pc);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::execute_vsm(const VsmInstr * instr)
|
||||
{
|
||||
using Opcode = VsmInstr::Opcode;
|
||||
|
||||
switch (instr->opcode()) {
|
||||
|
||||
case Opcode::halt:
|
||||
{
|
||||
this->pc_ = nullptr;
|
||||
this->cont_ = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case Opcode::eval:
|
||||
{
|
||||
/* generally speaking: opcode will be 1:1 with extypes */
|
||||
|
||||
switch (expr_->extype()) {
|
||||
case exprtype::invalid:
|
||||
case exprtype::constant:
|
||||
case exprtype::primitive:
|
||||
case exprtype::define:
|
||||
case exprtype::assign:
|
||||
case exprtype::apply:
|
||||
case exprtype::lambda:
|
||||
case exprtype::variable:
|
||||
case exprtype::ifexpr:
|
||||
case exprtype::sequence:
|
||||
case exprtype::convert:
|
||||
case exprtype::n_expr:
|
||||
this->pc_ = nullptr;
|
||||
this->value_ = nullptr;
|
||||
this->error_ = SchematikaError(tostr("execute_vsm: not implmented",
|
||||
xtag("extype", expr_->extype())));
|
||||
this->cont_ = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Opcode::N_Opcode:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<gp<Object>,
|
||||
SchematikaError>
|
||||
VirtualSchematikaMachine::eval(bp<Expression> expr)
|
||||
{
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr.promote();
|
||||
this->cont_ = &VsmOps::halt_op;
|
||||
|
||||
this->run();
|
||||
|
||||
return std::make_pair(this->value_, this->error_);
|
||||
}
|
||||
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end VirtualSchematikaMachine.hpp */
|
||||
/* end VirtualSchematikaMachine.cpp */
|
||||
|
|
|
|||
16
xo-interpreter/src/interpreter/VsmInstr.cpp
Normal file
16
xo-interpreter/src/interpreter/VsmInstr.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/** @file VsmInstr.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#include "VsmInstr.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
VsmInstr::VsmInstr(Opcode opcode,
|
||||
std::string_view name) : opcode_{opcode}, name_{name}
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
/* end VsmInstr.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue