xo-interpreter: ObjectConverter + VirtualSchmatikaMachineFlyweight
This commit is contained in:
parent
3956635920
commit
37b132821f
6 changed files with 187 additions and 20 deletions
|
|
@ -9,6 +9,12 @@
|
|||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @brief state that may be shared across VirtualSchematikaMachine instances **/
|
||||
struct VirtualSchematikaMachineFlyweight {
|
||||
/** convert TaggedPtr->Object **/
|
||||
ObjectConverter object_converter_;
|
||||
};
|
||||
|
||||
/** @class VirtualSchematikaMachine
|
||||
* @brief Virtual machine implementing a Schematika interpreter
|
||||
*
|
||||
|
|
@ -34,7 +40,7 @@ namespace xo {
|
|||
/** execute vsm instruction @p pc
|
||||
* Note: may possibly be able to replace with just opcode
|
||||
**/
|
||||
void execute_vsm(const VsmInstr * pc);
|
||||
void execute_one(const VsmInstr * pc);
|
||||
|
||||
/** implementation class; contains instruction implementations **/
|
||||
friend class VsmOps;
|
||||
|
|
@ -58,6 +64,9 @@ namespace xo {
|
|||
* (Perhaps replace with VsmInstr::Opcode ?)
|
||||
**/
|
||||
const VsmInstr * cont_ = nullptr;
|
||||
|
||||
/** possibly-shared data **/
|
||||
VirtualSchemtikaMachineFlyweight flyweight_;
|
||||
};
|
||||
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
/** continue after completing a VSM instruction;
|
||||
* achieve by jumping to continuation.
|
||||
**/
|
||||
//#define VSM_CONTINUE() this->pc_ = this->cont_; return;
|
||||
#define VSM_CONTINUE() this->pc_ = this->cont_; return;
|
||||
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -34,15 +34,28 @@ namespace xo {
|
|||
VirtualSchematikaMachine::VirtualSchematikaMachine()
|
||||
{}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::run()
|
||||
{
|
||||
for (const VsmInstr * pc = pc_; pc; pc = pc_)
|
||||
this->execute_vsm(pc);
|
||||
this->execute_one(pc);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::execute_vsm(const VsmInstr * instr)
|
||||
VirtualSchematikaMachine::execute_one(const VsmInstr * instr)
|
||||
{
|
||||
using Opcode = VsmInstr::Opcode;
|
||||
|
||||
|
|
@ -60,8 +73,11 @@ namespace xo {
|
|||
/* generally speaking: opcode will be 1:1 with extypes */
|
||||
|
||||
switch (expr_->extype()) {
|
||||
case exprtype::invalid:
|
||||
case exprtype::constant:
|
||||
this->constant_op();
|
||||
break;
|
||||
|
||||
case exprtype::invalid:
|
||||
case exprtype::primitive:
|
||||
case exprtype::define:
|
||||
case exprtype::assign:
|
||||
|
|
@ -88,20 +104,12 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<gp<Object>,
|
||||
SchematikaError>
|
||||
VirtualSchematikaMachine::eval(bp<Expression> expr)
|
||||
void
|
||||
VirtualSchematikaMachine::constant_op()
|
||||
{
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr.promote();
|
||||
this->cont_ = &VsmOps::halt_op;
|
||||
|
||||
this->run();
|
||||
|
||||
return std::make_pair(this->value_, this->error_);
|
||||
this->value_ = expr_->value_tp();
|
||||
}
|
||||
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
112
xo-object/include/xo/object/ObjectConverter.hpp
Normal file
112
xo-object/include/xo/object/ObjectConverter.hpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/** @file ObjectConverter.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Object.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
//#include "xo/reflect/TaggedPtr.hpp"
|
||||
#include "xo/reflect/TypeDrivenMap.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace obj {
|
||||
struct Converter {
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using ConvertToObjectFn = gp<Object> (*)(gc::IAlloc *, const TaggedPtr &);
|
||||
|
||||
public:
|
||||
explicit Converter(ConvertToObjectFn f) : cvt_to_object_{f} {}
|
||||
|
||||
/** convert tagged pointer @p tp to new object,
|
||||
* allocated via @p mm.
|
||||
*
|
||||
* Conversion will typically be for some specific type;
|
||||
* see @ref ObjectConverter
|
||||
**/
|
||||
ConvertToObjectFn cvt_to_object_;
|
||||
};
|
||||
|
||||
/** @class ObjectConverter
|
||||
* @brief Conversion to/from Object
|
||||
*
|
||||
* For some instance of type T:
|
||||
*
|
||||
* @code
|
||||
* ObjectConverter & converters = ...;
|
||||
* T x = ...;
|
||||
* TaggedPtr tp = Reflect::make_tp(&x);
|
||||
* TypeId tid = tp.td()->id();
|
||||
*
|
||||
* const Converter * cvt = converters.cvt_.lookup(tid);
|
||||
*
|
||||
* if (cvt) {
|
||||
* // cvt is a converter for T instances
|
||||
* gp<Object> obj = (*(cvt->cvt_to_object_))(mm,
|
||||
* @endcode
|
||||
**/
|
||||
class ObjectConverter {
|
||||
public:
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
/** sets up standard conversions **/
|
||||
ObjectConverter();
|
||||
|
||||
/** establish conversion: use @p fn to convert values of type @tparam T. **/
|
||||
template <typename T>
|
||||
void establish_conversion(Converter::ConvertToObjectFn fn);
|
||||
|
||||
/** convert @p x to object.
|
||||
* return converted object; if allocated, using only memory from @p mm.
|
||||
* return nullptr if no converter available, and @p throw_flag not set.
|
||||
* throw exception if no converter available, and @p throw_flag set.
|
||||
**/
|
||||
template <typename T>
|
||||
gp<Object> to_object(IAlloc * mm, const T & x, bool throw_flag);
|
||||
|
||||
private:
|
||||
/** expandable type-driven conversion table.
|
||||
**/
|
||||
xo::reflect::TypeDrivenMap<Converter> cvt_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
ObjectConverter::establish_conversion(Converter::ConvertToObjectFn fn)
|
||||
{
|
||||
using xo::reflect::TypeDescrW;
|
||||
using xo::reflect::Reflect;
|
||||
|
||||
TypeDescrW td = Reflect::require<T>();
|
||||
Converter * cvt = cvt_.require(td);
|
||||
|
||||
*cvt = Converter(fn);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gp<xo::Object>
|
||||
ObjectConverter::to_object(IAlloc * mm, const T & x, bool throw_flag)
|
||||
{
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
TaggedPtr x_tp = Reflect::make_tp(&x);
|
||||
Converter * cvt = cvt_.lookup(x_tp.td());
|
||||
|
||||
if (cvt) {
|
||||
return (cvt->cvt_to_object_)(mm, x_tp);
|
||||
} else {
|
||||
if (throw_flag) {
|
||||
throw std::runtime_error(tostr("no object-converter available for instance of type",
|
||||
xtag("id", x_tp.td()->id()),
|
||||
xtag("name", x_tp.td()->short_name())));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end ObjectConverter.hpp */
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
set(SELF_LIB xo_object)
|
||||
set(SELF_SRCS
|
||||
ObjectConverter.cpp
|
||||
Boolean.cpp
|
||||
String.cpp
|
||||
List.cpp
|
||||
|
|
|
|||
34
xo-object/src/object/ObjectConverter.cpp
Normal file
34
xo-object/src/object/ObjectConverter.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/** @file ObjectConverter.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#include "ObjectConverter.hpp"
|
||||
#include "Integer.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::TaggedPtr;
|
||||
using xo::gc::IAlloc;
|
||||
|
||||
namespace obj {
|
||||
namespace {
|
||||
template <typename T>
|
||||
gp<Object>
|
||||
int_to_object(IAlloc * mm, const TaggedPtr & src)
|
||||
{
|
||||
T * native = src.recover_native<T>();
|
||||
|
||||
assert(native);
|
||||
|
||||
return Integer::make(mm, *native);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectConverter::ObjectConverter()
|
||||
{
|
||||
this->establish_conversion<std::int32_t>(&int_to_object<std::int32_t>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end ObjectConverter.cpp */
|
||||
|
|
@ -14,21 +14,24 @@ namespace xo {
|
|||
template<typename Value>
|
||||
class TypeDrivenMap {
|
||||
public:
|
||||
Value const * lookup(TypeId id) const { return this->lookup_slot(id); }
|
||||
TypeDrivenMap() = default;
|
||||
|
||||
const Value * lookup(TypeId id) const { return this->lookup_slot(id); }
|
||||
const Value * lookup(TypeDescr td) { return this->lookup_slot(td->id()); }
|
||||
|
||||
Value * require(TypeId id) { return this->require_slot(id); }
|
||||
Value * require(TypeDescr td) { return this->require_slot(td->id()); }
|
||||
|
||||
private:
|
||||
Value const * lookup_slot(TypeId id) const {
|
||||
if (this->contents_v_.size() <= id.id())
|
||||
const Value * lookup_slot(TypeId id) const {
|
||||
if (contents_v_.size() <= id.id())
|
||||
return nullptr;
|
||||
|
||||
return &(this->contents_v_[id.id()]);
|
||||
} /*lookup_slot*/
|
||||
|
||||
Value * require_slot(TypeId id) {
|
||||
if (this->contents_v_.size() <= id.id())
|
||||
if (contents_v_.size() <= id.id())
|
||||
this->contents_v_.resize(id.id() + 1);
|
||||
|
||||
return &(this->contents_v_[id.id()]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue