xo-interpreter: handle define-expressions.
This commit is contained in:
parent
f98d1345d3
commit
fb5c43dc85
16 changed files with 523 additions and 53 deletions
|
|
@ -97,6 +97,8 @@ namespace xo {
|
|||
|
||||
/** memory allocator for objects. Likely this will be a GC instance,
|
||||
* but simple arena also supported.
|
||||
*
|
||||
* Load-bearing for .assign_member()
|
||||
**/
|
||||
static gc::IAlloc * mm;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
using xo::log_level;
|
||||
using xo::scm::Schematika;
|
||||
|
||||
Schematika::Config cfg;
|
||||
cfg.vsm_log_level_ = log_level::verbose;
|
||||
Schematika scm = Schematika::make(cfg);
|
||||
|
||||
scm.interactive_repl();
|
||||
|
|
|
|||
50
xo-interpreter/include/xo/interpreter/CVector.hpp
Normal file
50
xo-interpreter/include/xo/interpreter/CVector.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/** @file CVector.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/alloc/IAlloc.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** gc-only vector.
|
||||
* Used in both LocalEnv and VsmStackFrame
|
||||
**/
|
||||
template <typename ElementType>
|
||||
class CVector {
|
||||
public:
|
||||
using value_type = ElementType;
|
||||
|
||||
public:
|
||||
CVector(gc::IAlloc * mm, std::size_t n)
|
||||
: n_{n}, v_{nullptr}
|
||||
{
|
||||
if (n_ > 0) {
|
||||
std::byte * mem = mm->alloc(n_ * sizeof(ElementType));
|
||||
this->v_ = new (mem) ElementType[n];
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t size() const { return n_; }
|
||||
|
||||
ElementType operator[](std::size_t i) const { return v_[i]; }
|
||||
ElementType & operator[](std::size_t i) { return v_[i]; }
|
||||
|
||||
friend class LocalEnv;
|
||||
friend class VsmStackFrame;
|
||||
|
||||
private:
|
||||
/** number of elements in @ref v_ **/
|
||||
std::size_t n_ = 0;
|
||||
/** contiguous array of pointers **/
|
||||
ElementType * v_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end CVector.hpp */
|
||||
43
xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp
Normal file
43
xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/** @file ExpressionBoxed.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/alloc/Object.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class ExpressionBoxed
|
||||
* @brief xo::scm::Expression, adapted to xo::Object interface
|
||||
**/
|
||||
class ExpressionBoxed : public Object {
|
||||
public:
|
||||
explicit ExpressionBoxed(bp<Expression> c);
|
||||
|
||||
/** create boxed version of @p c, using allocator @p mm **/
|
||||
static gp<ExpressionBoxed> make(gc::IAlloc * mm,
|
||||
bp<Expression> c);
|
||||
|
||||
const rp<Expression> & contents() const { return contents_; }
|
||||
|
||||
// inherited from Object
|
||||
virtual TaggedPtr self_tp() const final override;
|
||||
virtual void display(std::ostream & os) const final override;
|
||||
virtual std::size_t _shallow_size() const final override;
|
||||
virtual Object * _shallow_copy(gc::IAlloc * mm) const final override;
|
||||
virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override;
|
||||
|
||||
private:
|
||||
/** reference-counted Expression pointer
|
||||
*
|
||||
* NOTE correctness requires finalization support in xo::gc::GC
|
||||
**/
|
||||
rp<Expression> contents_;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end ExpressionBoxed.hpp */
|
||||
|
|
@ -35,7 +35,7 @@ namespace xo {
|
|||
virtual void display(std::ostream & os) const final override;
|
||||
virtual std::size_t _shallow_size() const final override;
|
||||
virtual Object * _shallow_copy(gc::IAlloc * mm) const final override;
|
||||
virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override;
|
||||
virtual std::size_t _forward_children(gc::IAlloc * mm) final override;
|
||||
|
||||
private:
|
||||
GlobalEnv(const GlobalEnv & x);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/** @file LocalEnv.hpp **/
|
||||
|
||||
#include "Env.hpp"
|
||||
#include "CVector.hpp"
|
||||
#include "xo/alloc/IAlloc.hpp"
|
||||
#include "xo/expression/LocalSymtab.hpp"
|
||||
#include <cstddef>
|
||||
|
|
@ -8,36 +9,6 @@
|
|||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** gc-only vector
|
||||
**/
|
||||
template <typename ElementType>
|
||||
class CVector {
|
||||
public:
|
||||
using value_type = ElementType;
|
||||
|
||||
public:
|
||||
CVector(gc::IAlloc * mm, std::size_t n)
|
||||
: n_{n}, v_{nullptr}
|
||||
{
|
||||
if (n_ > 0) {
|
||||
std::byte * mem = mm->alloc(n_ * sizeof(ElementType));
|
||||
this->v_ = new (mem) ElementType[n];
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t size() const { return n_; }
|
||||
|
||||
ElementType operator[](std::size_t i) const { return v_[i]; }
|
||||
ElementType & operator[](std::size_t i) { return v_[i]; }
|
||||
|
||||
friend class LocalEnv;
|
||||
private:
|
||||
/** number of elements in @ref v_ **/
|
||||
std::size_t n_ = 0;
|
||||
/** contiguous array of pointers **/
|
||||
ElementType * v_ = nullptr;
|
||||
};
|
||||
|
||||
/** @class LocalEnv
|
||||
* @brief Represent a single runtime stack frame for a Schematika function
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ namespace xo {
|
|||
|
||||
/** garbage collector configuration **/
|
||||
gc::Config gc_config_;
|
||||
|
||||
/** control schematika vsm logging **/
|
||||
log_level vsm_log_level_;
|
||||
};
|
||||
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "VsmInstr.hpp"
|
||||
#include "VsmStackFrame.hpp"
|
||||
#include "SchematikaError.hpp"
|
||||
#include "Env.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
|
|
@ -14,7 +15,8 @@ namespace xo {
|
|||
/** @brief state that may be shared across VirtualSchematikaMachine instances **/
|
||||
struct VirtualSchematikaMachineFlyweight {
|
||||
explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
||||
gp<Env> env);
|
||||
gp<Env> env,
|
||||
log_level log_level);
|
||||
|
||||
/** memory allocator for interpreter operation. **/
|
||||
gc::IAlloc * object_mm_ = nullptr;
|
||||
|
|
@ -22,6 +24,8 @@ namespace xo {
|
|||
gp<Env> toplevel_env_;
|
||||
/** convert TaggedPtr->Object **/
|
||||
xo::obj::ObjectConverter object_converter_;
|
||||
/** control logging level. higher values -> more logging **/
|
||||
log_level log_level_;
|
||||
};
|
||||
|
||||
/** @class VirtualSchematikaMachine
|
||||
|
|
@ -33,7 +37,7 @@ namespace xo {
|
|||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
public:
|
||||
VirtualSchematikaMachine(IAlloc * mm, gp<Env> toplevel_env);
|
||||
VirtualSchematikaMachine(IAlloc * mm, gp<Env> toplevel_env, log_level log_level);
|
||||
~VirtualSchematikaMachine();
|
||||
|
||||
/** evaluate expression @p expr.
|
||||
|
|
@ -64,12 +68,25 @@ namespace xo {
|
|||
|
||||
/** 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
|
||||
* - value_ output
|
||||
* - error_ output
|
||||
**/
|
||||
void execute_one();
|
||||
|
||||
/** interpret literal constant expression **/
|
||||
void eval_constant_op();
|
||||
|
||||
/** interpret define expression **/
|
||||
void eval_define_op();
|
||||
|
||||
/** continue after establishing value fo rhs of define exprsssion **/
|
||||
void do_defexpr_assign_op();
|
||||
|
||||
/** goto error state with message @p err **/
|
||||
void report_error(const std::string & err);
|
||||
|
||||
|
|
@ -82,19 +99,38 @@ namespace xo {
|
|||
**/
|
||||
const VsmInstr * pc_ = nullptr;
|
||||
|
||||
/** expression **/
|
||||
/** register to hold Schematika expression to drive @ref execute_one.
|
||||
*
|
||||
* caller saves!
|
||||
**/
|
||||
rp<Expression> expr_;
|
||||
/** holds bindings for all schematika variables **/
|
||||
/** holds bindings for all schematika variables, to drive @ref execute_one.
|
||||
* execute_one will not save this
|
||||
*
|
||||
* caller saves!
|
||||
**/
|
||||
gp<Env> env_;
|
||||
|
||||
/** non-error result value from eval() / apply() **/
|
||||
/** 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() **/
|
||||
/** 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,15 @@ namespace xo {
|
|||
**/
|
||||
eval,
|
||||
|
||||
/** assign to variable + continue
|
||||
*
|
||||
* stack: frame with:
|
||||
* [0] lhs : variable to assign
|
||||
* [1] cont : continuation after assignment
|
||||
* ... maybe other vsm state that must be saved
|
||||
**/
|
||||
defexpr_assign,
|
||||
|
||||
N_Opcode
|
||||
};
|
||||
|
||||
|
|
|
|||
75
xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp
Normal file
75
xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/** @file VsmStackFrame.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VsmInstr.hpp"
|
||||
#include "CVector.hpp"
|
||||
#include "xo/alloc/Object.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @class VsmStackFrame
|
||||
* @brief Virtual Schematika Machine stack frame
|
||||
*
|
||||
* Intending to use the "cheney on the MTA" strategy,
|
||||
* i.e. allocate frames using GC's bump allocator.
|
||||
*
|
||||
* Parallels LocalEnv, but VSM implementation isn't reflected
|
||||
**/
|
||||
class VsmStackFrame : public Object {
|
||||
public:
|
||||
VsmStackFrame(gc::IAlloc * mm, gp<VsmStackFrame> p, std::size_t n, const VsmInstr * cont);
|
||||
|
||||
#ifdef NOT_YET
|
||||
/** create frame using allocator @p mm,
|
||||
* with parent @p p and exactly @p n_slot object pointers.
|
||||
**/
|
||||
static gp<VsmStackFrame> make(gc::IAlloc * mm,
|
||||
gp<VsmStackFrame> p,
|
||||
const VsmInstr * cont,
|
||||
std::size_t n_slot);
|
||||
#endif
|
||||
|
||||
/** create new stack frame using allocator @p mm,
|
||||
* with parent frame @p p; new frame contains values @p s0, @p s1
|
||||
**/
|
||||
static gp<VsmStackFrame> push1(gc::IAlloc * mm,
|
||||
gp<VsmStackFrame> p,
|
||||
gp<Object> s0,
|
||||
const VsmInstr * cont);
|
||||
|
||||
|
||||
/** reflect VsmStackFrame object representation **/
|
||||
static void reflect_self();
|
||||
|
||||
gp<VsmStackFrame> parent() const { return parent_; }
|
||||
std::size_t size() const { return slot_v_.size(); }
|
||||
const VsmInstr * continuation() const { return cont_; }
|
||||
|
||||
gp<Object> operator[](std::size_t i) const { return slot_v_[i]; }
|
||||
gp<Object> & operator[](std::size_t i) { return slot_v_[i]; }
|
||||
|
||||
// inherited from Object..
|
||||
virtual TaggedPtr self_tp() const final override;
|
||||
virtual void display(std::ostream & os) const final override;
|
||||
virtual std::size_t _shallow_size() const final override;
|
||||
virtual Object * _shallow_copy(gc::IAlloc *) const final override;
|
||||
virtual std::size_t _forward_children(gc::IAlloc *) final override;
|
||||
|
||||
private:
|
||||
/** parent stack frame **/
|
||||
gp<VsmStackFrame> parent_;
|
||||
|
||||
/** stored state **/
|
||||
CVector<gp<Object>> slot_v_;
|
||||
|
||||
/** proceed to this continuation when popping this frame **/
|
||||
const VsmInstr * cont_ = nullptr;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end VsmStackFrame.hpp */
|
||||
|
|
@ -8,6 +8,8 @@ set(SELF_SRCS
|
|||
GlobalEnv.cpp
|
||||
VirtualSchematikaMachine.cpp
|
||||
VsmInstr.cpp
|
||||
VsmStackFrame.cpp
|
||||
ExpressionBoxed.cpp
|
||||
)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
|
|
|||
59
xo-interpreter/src/interpreter/ExpressionBoxed.cpp
Normal file
59
xo-interpreter/src/interpreter/ExpressionBoxed.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/** @file ExpressionBoxed.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#include "ExpressionBoxed.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
namespace scm {
|
||||
ExpressionBoxed::ExpressionBoxed(bp<Expression> c) : contents_{c.promote()}
|
||||
{}
|
||||
|
||||
gp<ExpressionBoxed>
|
||||
ExpressionBoxed::make(gc::IAlloc * mm,
|
||||
bp<Expression> c)
|
||||
{
|
||||
return new (MMPtr(mm)) ExpressionBoxed(c);
|
||||
}
|
||||
|
||||
|
||||
TaggedPtr
|
||||
ExpressionBoxed::self_tp() const
|
||||
{
|
||||
return Reflect::make_tp(const_cast<ExpressionBoxed *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
ExpressionBoxed::display(std::ostream & os) const
|
||||
{
|
||||
os << contents_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ExpressionBoxed::_shallow_size() const
|
||||
{
|
||||
return sizeof(ExpressionBoxed);
|
||||
}
|
||||
|
||||
Object *
|
||||
ExpressionBoxed::_shallow_copy(gc::IAlloc * mm) const
|
||||
{
|
||||
Cpof cpof(mm, this);
|
||||
|
||||
return new (cpof) ExpressionBoxed(*this);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ExpressionBoxed::_forward_children(gc::IAlloc *)
|
||||
{
|
||||
return _shallow_size();
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end ExpressionBoxed.cpp */
|
||||
|
|
@ -101,7 +101,7 @@ namespace xo {
|
|||
{
|
||||
Cpof cpof(mm, this);
|
||||
|
||||
size_t z = size();
|
||||
size_t z = this->size();
|
||||
|
||||
LocalEnv * copy = new (cpof) LocalEnv(cpof.mm_, parent_, symtab_, z);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ namespace xo {
|
|||
* to preserve option to share it
|
||||
**/
|
||||
Impl(const Config & config, up<IAlloc> mm, gp<Env> toplevel_env) :
|
||||
config_{config}, vsm_{mm.get(), toplevel_env}, mm_{std::move(mm)} {}
|
||||
config_{config},
|
||||
vsm_{mm.get(), toplevel_env, config.vsm_log_level_},
|
||||
mm_{std::move(mm)} {}
|
||||
|
||||
/** create instance + allocator **/
|
||||
static up<Impl> make(const Config & cfg);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
#include "VirtualSchematikaMachine.hpp"
|
||||
#include "VsmInstr.hpp"
|
||||
#include "ExpressionBoxed.hpp"
|
||||
#include "xo/expression/ConstantInterface.hpp"
|
||||
#include "xo/expression/DefineExpr.hpp"
|
||||
#include "xo/expression/Variable.hpp"
|
||||
#include "xo/alloc/GC.hpp"
|
||||
|
||||
/** continue after completing a VSM instruction;
|
||||
|
|
@ -14,6 +17,8 @@
|
|||
**/
|
||||
#define VSM_ERROR(msg) report_error(msg); return;
|
||||
|
||||
|
||||
|
||||
namespace xo {
|
||||
using xo::gc::GC;
|
||||
|
||||
|
|
@ -29,6 +34,12 @@ namespace xo {
|
|||
* - expression in register @ref expr_
|
||||
**/
|
||||
static VsmInstr eval_op;
|
||||
|
||||
/** assign variable after evaluating rhs of a define-expression
|
||||
* - opcode is Opcode::defexpr_assign
|
||||
* - top stack frame contains {lhs, cont}
|
||||
*/
|
||||
static VsmInstr defexpr_assign_op;
|
||||
};
|
||||
|
||||
VsmInstr
|
||||
|
|
@ -37,18 +48,27 @@ namespace xo {
|
|||
VsmInstr
|
||||
VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"};
|
||||
|
||||
VsmInstr
|
||||
VsmOps::defexpr_assign_op{VsmInstr::Opcode::defexpr_assign, "defexpr-assign"};
|
||||
|
||||
// ----- VirtualSchematikaMachineFlyweight -----
|
||||
|
||||
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
||||
gp<Env> env) :
|
||||
gp<Env> env,
|
||||
log_level ll) :
|
||||
object_mm_{mm},
|
||||
toplevel_env_{env}
|
||||
toplevel_env_{env},
|
||||
log_level_{ll}
|
||||
{}
|
||||
|
||||
// ----- VirtualSchematikaMachine -----
|
||||
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm, gp<Env> env) : flyweight_{mm, env}
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm,
|
||||
gp<Env> env,
|
||||
log_level ll) : flyweight_{mm, env, ll}
|
||||
{
|
||||
this->env_ = env;
|
||||
|
||||
// gc roots
|
||||
gc::GC * gc = GC::from(mm);
|
||||
|
||||
|
|
@ -90,10 +110,13 @@ namespace xo {
|
|||
SchematikaError>
|
||||
VirtualSchematikaMachine::eval(bp<Expression> expr, gp<Env> env)
|
||||
{
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr.promote();
|
||||
this->env_ = env;
|
||||
this->cont_ = &VsmOps::halt_op;
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr.promote();
|
||||
this->env_ = env;
|
||||
this->stack_ = nullptr;
|
||||
this->value_ = nullptr;
|
||||
this->error_ = SchematikaError();
|
||||
this->cont_ = &VsmOps::halt_op;
|
||||
|
||||
this->run();
|
||||
|
||||
|
|
@ -110,6 +133,9 @@ namespace xo {
|
|||
void
|
||||
VirtualSchematikaMachine::execute_one()
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
log && log("stack", stack_);
|
||||
|
||||
using Opcode = VsmInstr::Opcode;
|
||||
|
||||
switch (pc_->opcode()) {
|
||||
|
|
@ -123,6 +149,8 @@ namespace xo {
|
|||
|
||||
case Opcode::eval:
|
||||
{
|
||||
log && log("eval");
|
||||
|
||||
/* generally speaking: opcode will be 1:1 with extypes */
|
||||
|
||||
switch (expr_->extype()) {
|
||||
|
|
@ -130,9 +158,14 @@ namespace xo {
|
|||
this->eval_constant_op();
|
||||
break;
|
||||
|
||||
|
||||
case exprtype::define:
|
||||
this->eval_define_op();
|
||||
break;
|
||||
|
||||
case exprtype::invalid:
|
||||
case exprtype::primitive:
|
||||
case exprtype::define:
|
||||
|
||||
case exprtype::assign:
|
||||
case exprtype::apply:
|
||||
case exprtype::lambda:
|
||||
|
|
@ -151,6 +184,10 @@ namespace xo {
|
|||
}
|
||||
break;
|
||||
|
||||
case Opcode::defexpr_assign:
|
||||
this->do_defexpr_assign_op();
|
||||
break;
|
||||
|
||||
case Opcode::N_Opcode:
|
||||
assert(false);
|
||||
break;
|
||||
|
|
@ -197,29 +234,60 @@ namespace xo {
|
|||
|
||||
// placeholder: primitive_op
|
||||
|
||||
#ifdef NOT_YET
|
||||
void
|
||||
VirtualSchematikaMachine::define_op()
|
||||
VirtualSchematikaMachine::eval_define_op()
|
||||
{
|
||||
using xo::scm::DefineExpr;
|
||||
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
auto mm = flyweight_.object_mm_;
|
||||
|
||||
bp<DefineExpr> expr = DefineExpr::from(expr_);
|
||||
|
||||
assert(expr);
|
||||
assert(env_.get());
|
||||
|
||||
// note: expecting nested define to have expanded iteself into
|
||||
// applying a lambda
|
||||
|
||||
// note: establish lhs_var first, to allow for recursion, for example:
|
||||
// def fact(n: i64) { if (n == 0) then 1; else n * fact(n-1); }
|
||||
|
||||
/** remembers promised variable type **/
|
||||
env_->establish_var(expr->lhs_variable());
|
||||
this->env_->establish_var(expr->lhs_variable());
|
||||
|
||||
/** must promote rp<Expression> -> gp<ExpressionBoxed> **/
|
||||
gp<ExpressionBoxed> lhs_0 = ExpressionBoxed::make(mm, expr->lhs_variable());
|
||||
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr->rhs();
|
||||
|
||||
/* lhs_var
|
||||
* rhs
|
||||
/* when control arrives at .cont_, will have:
|
||||
* .value_ -> result of evaluating expr->rhs()
|
||||
*/
|
||||
|
||||
this->stack_ = VsmStackFrame::push1(mm, this->stack_, lhs_0, cont_);
|
||||
this->cont_ = &VsmOps::defexpr_assign_op;
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::do_defexpr_assign_op()
|
||||
{
|
||||
/*
|
||||
* - value: contains result of evaluating rhs of define
|
||||
* - stack: top frame has 1 slot, holds variable to receive assignment
|
||||
*/
|
||||
assert(value_.get());
|
||||
assert(stack_.get());
|
||||
|
||||
gp<VsmStackFrame> sp0 = this->stack_;
|
||||
|
||||
//this->value_ = this->value_; // preserve value from rhs of defexpr
|
||||
|
||||
this->stack_ = sp0->parent();
|
||||
this->pc_ = this->cont_ = sp0->continuation();
|
||||
}
|
||||
#endif
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
148
xo-interpreter/src/interpreter/VsmStackFrame.cpp
Normal file
148
xo-interpreter/src/interpreter/VsmStackFrame.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/** @file VsmStackFrame.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Nov 2025
|
||||
**/
|
||||
|
||||
#include "VsmStackFrame.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
#include "xo/reflect/StructReflector.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::StructReflector;
|
||||
using xo::reflect::TypeDescrW;
|
||||
using xo::reflect::TaggedPtr;
|
||||
using xo::reflect::TypeDescrExtra;
|
||||
using xo::reflect::EstablishTypeDescr;
|
||||
using xo::reflect::StlVectorTdx;
|
||||
|
||||
namespace scm {
|
||||
namespace {
|
||||
// TOOD: move into CVector
|
||||
|
||||
std::size_t
|
||||
slot_array_size(std::size_t n) {
|
||||
return n * sizeof(gp<Object>);
|
||||
}
|
||||
}
|
||||
|
||||
VsmStackFrame::VsmStackFrame(gc::IAlloc * mm,
|
||||
gp<VsmStackFrame> p,
|
||||
std::size_t n,
|
||||
const VsmInstr * cont) : parent_{p},
|
||||
slot_v_{mm, n},
|
||||
cont_{cont}
|
||||
{}
|
||||
|
||||
gp<VsmStackFrame>
|
||||
VsmStackFrame::push1(gc::IAlloc * mm,
|
||||
gp<VsmStackFrame> p,
|
||||
gp<Object> s0,
|
||||
const VsmInstr * cont)
|
||||
{
|
||||
gp<VsmStackFrame> retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 1, cont);
|
||||
|
||||
(*retval)[0] = s0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
VsmStackFrame::self_tp() const
|
||||
{
|
||||
return Reflect::make_tp(const_cast<VsmStackFrame *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
VsmStackFrame::display(std::ostream & os) const
|
||||
{
|
||||
os << "<vsm-stack-frame"
|
||||
<< xtag("n", slot_v_.size());
|
||||
|
||||
#ifdef NOT_YET
|
||||
for (std::size_t i = 0, n = n_slot(); i < n; ++i) {
|
||||
char buf[24];
|
||||
snprintf(buf, sizeof(buf), "v[%lu]", i);
|
||||
|
||||
os << xtag(buf, lookup(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
os << ">";
|
||||
}
|
||||
|
||||
std::size_t
|
||||
VsmStackFrame::_shallow_size() const
|
||||
{
|
||||
std::size_t retval = sizeof(VsmStackFrame);
|
||||
|
||||
retval += gc::IAlloc::with_padding(slot_array_size(slot_v_.size()));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Object *
|
||||
VsmStackFrame::_shallow_copy(gc::IAlloc * mm) const
|
||||
{
|
||||
Cpof cpof(mm, this);
|
||||
|
||||
size_t n = this->size();
|
||||
|
||||
VsmStackFrame * copy = new (cpof) VsmStackFrame(cpof.mm_, parent_, n, cont_);
|
||||
|
||||
void * v_dest = copy->slot_v_.v_;
|
||||
|
||||
if (slot_v_.v_) {
|
||||
::memcpy(v_dest, slot_v_.v_, slot_array_size(n));
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
for (size_t i = 0, n = n_slot_; i < n; ++i) {
|
||||
copy->v_[i] = v_[i];
|
||||
}
|
||||
#endif
|
||||
return copy;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
VsmStackFrame::_forward_children(gc::IAlloc * gc)
|
||||
{
|
||||
Object::_forward_inplace(parent_, gc);
|
||||
|
||||
for (std::size_t i = 0, n = slot_v_.size(); i < n; ++i) {
|
||||
Object::_forward_inplace((*this)[i], gc);
|
||||
}
|
||||
|
||||
return _shallow_size();
|
||||
}
|
||||
|
||||
void
|
||||
VsmStackFrame::reflect_self()
|
||||
{
|
||||
StructReflector<VsmStackFrame> sr;
|
||||
|
||||
if (sr.is_incomplete() ) {
|
||||
/* reflect CVector<gp<Object>>.
|
||||
* duplicates similar code in LocalEnv::reflect_self()
|
||||
*/
|
||||
using VectorType = CVector<gp<Object>>;
|
||||
|
||||
/* custom reflection for array of Object pointers.
|
||||
* Can use StlVectorTdx here, treating CVector<T> as a vector
|
||||
* via .size() and .operator[] members
|
||||
*/
|
||||
std::unique_ptr<TypeDescrExtra> tdx1
|
||||
= std::make_unique<StlVectorTdx<VectorType>>();
|
||||
TypeDescrW td1
|
||||
= EstablishTypeDescr::establish<VectorType>();
|
||||
td1->assign_tdextra(Reflect::get_final_invoker<VectorType>(),
|
||||
std::move(tdx1));
|
||||
|
||||
REFLECT_MEMBER(sr, parent);
|
||||
REFLECT_MEMBER(sr, slot_v);
|
||||
}
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end VsmStackFrame.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue