xo-expression2/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp

187 lines
6.8 KiB
C++

/** @file VirtualSchematikaMachine.hpp **/
#pragma once
#include "VsmInstr.hpp"
#include "VsmStackFrame.hpp"
#include "SchematikaError.hpp"
#include "GlobalEnv.hpp"
#include "xo/expression/Expression.hpp"
#include "xo/object/ObjectConverter.hpp"
#include "xo/alloc/Object.hpp"
namespace xo {
namespace scm {
/** @brief state that may be shared across VirtualSchematikaMachine instances **/
struct VirtualSchematikaMachineFlyweight {
explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
gp<GlobalEnv> env,
log_level log_level);
/** memory allocator for interpreter operation. **/
gc::IAlloc * object_mm_ = nullptr;
/** global environment **/
gp<GlobalEnv> toplevel_env_;
/** convert TaggedPtr->Object **/
xo::obj::ObjectConverter object_converter_;
/** control logging level. higher values -> more logging **/
log_level log_level_;
};
/** @class VirtualSchematikaMachine
* @brief Virtual machine implementing a Schematika interpreter
*
**/
class VirtualSchematikaMachine {
public:
using IAlloc = xo::gc::IAlloc;
public:
VirtualSchematikaMachine(IAlloc * mm, gp<GlobalEnv> toplevel_env, log_level log_level);
~VirtualSchematikaMachine();
gp<GlobalEnv> toplevel_env() const { return flyweight_.toplevel_env_; }
/** 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.
*
* Evaluate schematika expression @p expr in environment @p env
**/
std::pair<gp<Object>, SchematikaError> eval(bp<Expression> expr, gp<GlobalEnv> env);
/** evaluate expression @p expr in toplevel environment **/
std::pair<gp<Object>, SchematikaError> toplevel_eval(bp<Expression> expr);
private:
/** Not moveable or copyable.
* One constraint is member variables added to flyweight_.object_mm_
* as GC roots, with no provision for unwinding later.
**/
VirtualSchematikaMachine(const VirtualSchematikaMachine &) = delete;
VirtualSchematikaMachine(VirtualSchematikaMachine &&) = delete;
/** borrow calling thread to run schematika machine
* indefinitely, or until null continuation
**/
void run();
/** execute vsm instruction in program counter.
* Note: may possibly be able to replace with just opcode
*
* Registers:
* - expr_ input, caller saves
* - env_ input, caller saves
* - cont_ input, caller saves
* - stack_ input, caller saves
* - value_ output
* - error_ output
*
**/
void execute_one();
/* design note:
* - eval_xxx_op() methods are primary VSM transitions,
* in the sense that they begin a sequence of transitions to interpret a
* particular kind of expression
* - do_xxx_op() methods represent secondary VSM transitions,
* that continue an instruction sequence that was initiated by a preceding
* eval_xxx_op() method
*/
/** interpret literal constant expression **/
void eval_constant_op();
/** interpreter literal primitive expression
* (these appear implicitly as result of builtin operators like {+, ==, ..})
**/
void eval_primitive_op();
/** execute define expression (finished in do_complete_assign_op()) **/
void eval_define_op();
/** execute assign expression (finishes in do_complete_assign_op()) **/
void eval_assign_op();
/** continue after establishing value fo rhs of define exprsssion **/
void do_complete_assign_op();
/** interpret variable expression **/
void eval_variable_op();
/** interpret if-expression **/
void eval_ifexpr_op();
/** continue after establish value of test expression **/
void do_complete_ifexpr_op();
/** interpret sequence **/
void eval_sequence_op();
/** continue after establishing value for a sequence element **/
void do_complete_sequence_op();
/** interpret apply-expression (i.e. function call) **/
void eval_apply_op();
/** continue assembling args for a function call;
* transition to (interpretation of) called function once all arguments
* are evaluated.
**/
void do_complete_evalargs_op();
/** execute function application, given actuals in top stack frame **/
void apply_op();
/** goto error state with message @p err **/
void report_error(const std::string & err);
/** implementation class; contains instruction implementations **/
friend struct VsmOps;
private:
/** program counter.
* (Perhaps replace with VsmInstr::Opcode ?)
**/
const VsmInstr * pc_ = nullptr;
/** register to hold Schematika expression to drive @ref execute_one.
*
* caller saves!
**/
rp<Expression> expr_;
/** holds bindings for all schematika variables, to drive @ref execute_one.
* execute_one will not save this
*
* caller saves!
**/
gp<GlobalEnv> env_;
/** vsm stack. callee saves!
**/
gp<VsmStackFrame> stack_;
/** non-error result value from eval() / apply()
*
* output register: caller must save
**/
gp<Object> value_;
/** error result value from eval() / apply()
*
* output regisetr: caller must save
**/
SchematikaError error_;
/** continuation
* (Perhaps replace with VsmInstr::Opcode ?)
*
* input register: callee saves!
**/
const VsmInstr * cont_ = nullptr;
/** possibly-shared data **/
VirtualSchematikaMachineFlyweight flyweight_;
};
} /*namespace scm*/
} /*namespace xo*/
/* end VirtualSchematikaMachine.hpp */