198 lines
6.2 KiB
C++
198 lines
6.2 KiB
C++
/** @file VirtualSchematikaMachine.hpp
|
|
*
|
|
* @author Roland Conybare, Jan 2026
|
|
**/
|
|
|
|
#pragma once
|
|
|
|
#include "VsmConfig.hpp"
|
|
#include "VsmInstr.hpp"
|
|
#include "VsmFrame.hpp"
|
|
#include <xo/reader2/SchematikaReader.hpp>
|
|
#include <xo/expression2/Expression.hpp>
|
|
#include <xo/gc/GCObject.hpp>
|
|
#include <xo/facet/box.hpp>
|
|
|
|
namespace xo {
|
|
namespace scm {
|
|
struct EvaluationError {
|
|
/** source location (in vsm implementation) at which error identified **/
|
|
std::string_view src_function_;
|
|
/** error description (allocated from ErrorArena) **/
|
|
std::string_view error_description_;
|
|
// TODO: info about location in schematika source
|
|
};
|
|
|
|
/** similar to @ref xo::scm::ReaderResult **/
|
|
struct VsmResult {
|
|
using AGCObject = xo::mm::AGCObject;
|
|
using span_type = xo::mm::span<const char>;
|
|
|
|
VsmResult() = default;
|
|
VsmResult(obj<AGCObject> value) : result_{value} {}
|
|
VsmResult(TokenizerError err) : result_{err} {}
|
|
|
|
bool is_value() const { return std::holds_alternative<obj<AGCObject>>(result_); }
|
|
bool is_tk_error() const { return std::holds_alternative<TokenizerError>(result_); }
|
|
bool is_eval_error() const { return std::holds_alternative<EvaluationError>(result_); }
|
|
|
|
const obj<AGCObject> * value() const { return std::get_if<obj<AGCObject>>(&result_); }
|
|
|
|
/** result of evaluating first expression encountered in input **/
|
|
std::variant<obj<AGCObject>, TokenizerError, EvaluationError> result_;
|
|
};
|
|
|
|
/** vsm result + reamining span **/
|
|
struct VsmResultExt : public VsmResult {
|
|
using span_type = VsmResult::span_type;
|
|
|
|
VsmResultExt() = default;
|
|
VsmResultExt(const VsmResult & result, span_type rem) : VsmResult{result}, remaining_{rem} {}
|
|
|
|
/** unconsumed portion of input **/
|
|
VsmResult::span_type remaining_;
|
|
};
|
|
|
|
/** @class VirtualSchematikaMachine
|
|
* @brief virtual machine for schematika
|
|
**/
|
|
class VirtualSchematikaMachine {
|
|
public:
|
|
// will be DArenaVector<obj<StackFrame>> probably
|
|
using Stack = void *;
|
|
using AAllocator = xo::mm::AAllocator;
|
|
using AGCObject = xo::mm::AGCObject;
|
|
using MemorySizeVisitor = xo::mm::MemorySizeVisitor;
|
|
using span_type = xo::mm::span<const char>;
|
|
|
|
public:
|
|
VirtualSchematikaMachine(const VsmConfig & config);
|
|
|
|
/** visit vsm-owned memory pools; call visitor(info) for each **/
|
|
void visit_pools(const MemorySizeVisitor & visitor) const;
|
|
|
|
/** begin interactive session. **/
|
|
void begin_interactive_session();
|
|
/** begin batch session **/
|
|
void begin_batch_session();
|
|
|
|
/** consume input @p input_cstr.
|
|
* Require: must first start interactive/batch session
|
|
**/
|
|
VsmResultExt read_eval_print(span_type input_span, bool eof);
|
|
|
|
/** evaluate expression @p expr
|
|
* Require: must first start interactive/batch session
|
|
**/
|
|
VsmResult start_eval(obj<AExpression> expr);
|
|
|
|
/** borrow calling thread to run indefinitely,
|
|
* until halt instruction
|
|
**/
|
|
void run();
|
|
|
|
/** execute vsm instruction in @ref pc_.
|
|
* @retval instruction count. 1 unless pc_ is halt.
|
|
**/
|
|
bool execute_one();
|
|
|
|
private:
|
|
/** Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_op();
|
|
|
|
/** evaluate a constant expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_constant_op();
|
|
|
|
/** evaluate a define-expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_define_op();
|
|
|
|
/** evaluate a lambda expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_lambda_op();
|
|
|
|
/** evaluate a variable expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_variable_op();
|
|
|
|
/** evaluate an apply expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_apply_op();
|
|
|
|
/** evaluate an if-else expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_if_else_op();
|
|
|
|
/** evaluate a sequence expression
|
|
* Require:
|
|
* - expression in @ref expr_
|
|
**/
|
|
void _do_eval_sequence_op();
|
|
|
|
/** apply a function to evaluated arguments **/
|
|
void _do_apply_op();
|
|
|
|
/** evaluate arguments on behalf of a function call **/
|
|
void _do_evalargs_op();
|
|
|
|
private:
|
|
/*
|
|
* Some registers are preserved by evaluation:
|
|
* stack_
|
|
* cont_
|
|
*
|
|
* Other registers are not preserved
|
|
* pc_
|
|
* expr_
|
|
* value_
|
|
*/
|
|
|
|
/** configuration **/
|
|
VsmConfig config_;
|
|
|
|
/** allocator (likely collector) for
|
|
* expressions and values
|
|
**/
|
|
box<AAllocator> mm_;
|
|
|
|
// consider separate allocator (which _may_ turn out to be the same)
|
|
// for VM stack. Only works for code that doesn't rely on fancy
|
|
// lexical scoping
|
|
|
|
/** reader: text -> expression **/
|
|
SchematikaReader reader_;
|
|
|
|
/** program counter **/
|
|
VsmInstr pc_ = VsmInstr::c_halt;
|
|
|
|
/** stack pointer **/
|
|
obj<AGCObject> stack_;
|
|
|
|
/** expression register **/
|
|
obj<AExpression> expr_;
|
|
|
|
/** result register **/
|
|
VsmResult value_;
|
|
|
|
/** continuation register **/
|
|
VsmInstr cont_ = VsmInstr::c_halt;
|
|
};
|
|
} /*namespace scm*/
|
|
} /*namespace xo*/
|
|
|
|
/* end VirtualSchematikaMachine.hpp */
|