From 61d41a229833c71134f8ed0427af2b232733c2dc Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 4 Feb 2026 16:26:19 -0500 Subject: [PATCH] xo-interpreter2: apply sequence now working in interpreter --- .../xo/interpreter2/DVsmApplyFrame.hpp | 2 + .../xo/interpreter2/DVsmEvalArgsFrame.hpp | 31 +++- .../interpreter2/VirtualSchematikaMachine.hpp | 21 ++- .../include/xo/interpreter2/VsmFrame.hpp | 4 +- .../src/interpreter2/DVsmEvalArgsFrame.cpp | 16 +- .../interpreter2/VirtualSchematikaMachine.cpp | 156 ++++++++++++++++-- .../utest/VirtualSchematikaMachine.test.cpp | 4 +- xo-object2/include/xo/object2/DArray.hpp | 3 +- 8 files changed, 203 insertions(+), 34 deletions(-) diff --git a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp index d947a8bc..c898c602 100644 --- a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp @@ -29,6 +29,8 @@ namespace xo { obj fn() const noexcept { return fn_; } DArray * args() const noexcept { return args_; } + void assign_fn(obj x) { this->fn_ = x; } + std::size_t shallow_size() const noexcept; DVsmApplyFrame * shallow_copy(obj mm) const noexcept; std::size_t forward_children(obj gc) noexcept; diff --git a/xo-interpreter2/include/xo/interpreter2/DVsmEvalArgsFrame.hpp b/xo-interpreter2/include/xo/interpreter2/DVsmEvalArgsFrame.hpp index a8ef0226..7131a001 100644 --- a/xo-interpreter2/include/xo/interpreter2/DVsmEvalArgsFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DVsmEvalArgsFrame.hpp @@ -5,16 +5,18 @@ #pragma once -#include "DVsmApplyFrame.hpp" +#include "VsmApplyFrame.hpp" +#include namespace xo { namespace scm { /** frame for executing an apply expression **/ - class DVsmEvalArgsFrame : public VsmFrame { + class DVsmEvalArgsFrame { public: using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; using ppindentinfo = xo::print::ppindentinfo; public: @@ -24,12 +26,21 @@ namespace xo { * old_cont = [xfer to called function] * **/ - DVsmEvalArgsFrame(obj old_parent, - VsmInstr old_cont); + DVsmEvalArgsFrame(DVsmApplyFrame * parent, + VsmInstr cont, + const DApplyExpr * apply_expr); static DVsmEvalArgsFrame * make(obj mm, - obj apply_frame, - VsmInstr old_cont); + DVsmApplyFrame * apply_frame, + VsmInstr old_cont, + const DApplyExpr * apply_expr); + + DVsmApplyFrame * parent() const noexcept { return parent_; } + VsmInstr cont() const noexcept { return cont_; } + const DApplyExpr * apply_expr() const noexcept { return apply_expr_; } + int32_t i_arg() const noexcept { return i_arg_; } + + int32_t increment_arg() { return ++i_arg_; } std::size_t shallow_size() const noexcept; DVsmEvalArgsFrame * shallow_copy(obj mm) const noexcept; @@ -38,6 +49,14 @@ namespace xo { bool pretty(const ppindentinfo & ppii) const; protected: + /** parent stack frame **/ + DVsmApplyFrame * parent_ = nullptr; + /** continuation after eval args completed (always VsmInstr::c_apply) **/ + VsmInstr cont_; + + /** expression being evaluated **/ + const DApplyExpr * apply_expr_ = nullptr; + /** next argument to be evaluated. -1 means function head **/ int32_t i_arg_ = -1; }; diff --git a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp index 78c2f3f7..774659eb 100644 --- a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp @@ -147,7 +147,14 @@ namespace xo { /** apply a function to evaluated arguments **/ void _do_apply_op(); - /** evaluate arguments on behalf of a function call **/ + /** evaluate arguments on behalf of a function call + * Require: + * - expression value in @ref value_ + * - stack: + * [0] VsmEvalArgsFrame + * [1] VsmApplyFrame + * ... + **/ void _do_evalargs_op(); private: @@ -159,6 +166,8 @@ namespace xo { * Other registers are not preserved * pc_ * expr_ + * fn_ + * args_ * value_ */ @@ -170,6 +179,11 @@ namespace xo { **/ box mm_; + /** runtime context for this vsm. + * For example, provides allocator to primitives + **/ + box rcx_; + // 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 @@ -186,6 +200,11 @@ namespace xo { /** expression register **/ obj expr_; + /** function to call **/ + obj fn_; + /** evaluated argument list **/ + DArray * args_; + /** result register **/ VsmResult value_; diff --git a/xo-interpreter2/include/xo/interpreter2/VsmFrame.hpp b/xo-interpreter2/include/xo/interpreter2/VsmFrame.hpp index f4cf5f1e..52a30761 100644 --- a/xo-interpreter2/include/xo/interpreter2/VsmFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VsmFrame.hpp @@ -20,9 +20,7 @@ namespace xo { VsmInstr cont) : parent_{parent}, cont_{cont} {} //obj parent() const noexcept { return parent_; } - VsmFrame * parent() const noexcept { - return reinterpret_cast(parent_.data()); - } + obj parent() const noexcept { return parent_; } VsmInstr cont() const noexcept { return cont_; } protected: diff --git a/xo-interpreter2/src/interpreter2/DVsmEvalArgsFrame.cpp b/xo-interpreter2/src/interpreter2/DVsmEvalArgsFrame.cpp index cb2b328e..01391cf2 100644 --- a/xo-interpreter2/src/interpreter2/DVsmEvalArgsFrame.cpp +++ b/xo-interpreter2/src/interpreter2/DVsmEvalArgsFrame.cpp @@ -14,22 +14,26 @@ namespace xo { // ----- VsmEvalArgsFrame ----- - DVsmEvalArgsFrame::DVsmEvalArgsFrame(obj old_parent, - VsmInstr old_cont) - : VsmFrame(old_parent, old_cont) + DVsmEvalArgsFrame::DVsmEvalArgsFrame(DVsmApplyFrame * parent, + VsmInstr cont, + const DApplyExpr * apply_expr) + : parent_{parent}, + cont_{cont}, + apply_expr_{apply_expr} {} DVsmEvalArgsFrame * DVsmEvalArgsFrame::make(obj mm, - obj apply_frame, - VsmInstr cont) + DVsmApplyFrame * apply_frame, + VsmInstr cont, + const DApplyExpr * apply_expr) { DVsmEvalArgsFrame * result = nullptr; void * mem = mm.alloc(typeseq::id(), sizeof(DVsmEvalArgsFrame)); - result = new (mem) DVsmEvalArgsFrame(apply_frame, cont); + result = new (mem) DVsmEvalArgsFrame(apply_frame, cont, apply_expr); assert(result); diff --git a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp index 22f9ed12..b32f6b24 100644 --- a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp +++ b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp @@ -8,6 +8,8 @@ #include "VsmEvalArgsFrame.hpp" #include #include +#include +#include #include #include #include @@ -26,9 +28,13 @@ namespace xo { namespace scm { + // NOTE: using heap for {DX1Collector, DSimpleRcx} instances + // (though allocation from explictly mmap'd memory) + // VirtualSchematikaMachine::VirtualSchematikaMachine(const VsmConfig & config) : config_{config}, mm_(box(new DX1Collector(config.x1_config_))), + rcx_(box(new DSimpleRcx(mm_.to_op()))), reader_{config.rdr_config_, mm_.to_op()} {} @@ -211,21 +217,23 @@ namespace xo { // assuming bump allocator: // - // DArray VsmApplyFrame VsmEvalArgsFrame - // v v v - // +----------------------+-------+------+----+--------+-------+------+-------+ - // | argument expressions | par x | cont | fn | args x | par x | cont | i_arg | - // +----------------------+-----|-+------+----+------|-+-----|-+------+-------+ - // ^ ^ | | | - // | \----------------------------------/ - // \ | / - // \-----------------------------------------------/ + // DArray VsmApplyFrame VsmEvalArgsFrame + // v v v + // +----------------------+-------+-------+----+--------+-------+-------+-------+ + // | argument expressions | par x | cont1 | fn | args x | par x | cont2 | i_arg | + // +----------------------+-----|-+-------+----+------|-+-----|-+-------+-------+ + // ^ ^ | | | + // | \-----------------------------------/ + // \ | / + // \------------------------------------------------/ // / // <---------------------------/ // // - VsmEvalArgsFrame: owned by VSM, state for evalargs loop // - VsmApplyFrame: owned by VSM, state for transferring control to called function // - DArray: contains evaluated args; owned by called primitive + // - cont2: always c_apply + // auto apply = obj::from(expr_); @@ -235,13 +243,13 @@ namespace xo { // TODO: check function signature - auto apply_frame - = obj - (DVsmApplyFrame::make(mm_.to_op(), stack_, cont_, args)); + DVsmApplyFrame * apply_frame + = DVsmApplyFrame::make(mm_.to_op(), stack_, cont_, args); auto evalargs_frame = obj - (DVsmEvalArgsFrame::make(mm_.to_op(), apply_frame, VsmInstr::c_apply)); + (DVsmEvalArgsFrame::make(mm_.to_op(), + apply_frame, VsmInstr::c_apply, apply.data())); this->stack_ = evalargs_frame; @@ -269,13 +277,131 @@ namespace xo { void VirtualSchematikaMachine::_do_apply_op() { - // not implemented - assert(false); + // rcx_ : runtime context + // fn_ : function to call + // args_ : array of arguments + + // TODO: check argument types + + this->value_ = fn_.apply_nocheck(rcx_.to_op(), args_); + this->pc_ = cont_; + + return; } void VirtualSchematikaMachine::_do_evalargs_op() { + scope log(XO_DEBUG(false)); + + if (!value_.is_value()) { + // error while evaluating function arg + + log.retroactively_enable(); + log && log("error in apply -> terminating app"); + + this->pc_ = VsmInstr::c_halt; + return; + } + + // here: nested evaluation succeeded + + // value of one of {fn, arg(i), ..} in fn(arg0 .. arg(n-1)) + // + obj value = *(value_.value()); + + // value_ in [i_arg] value_ + // . (if i_arg >= 0) . (if i_arg = -1) + // . . + // DArray . VsmApplyFrame . VsmEvalArgsFrame + // v v v v v + // +----------------------+-------+-------+----+--------+-------+-------+--------+-------+ + // | argument expressions | par o | cont1 | fn | args x | par o | cont2 | applyx | i_arg | + // +----------------------+-----|-+-------+----+------|-+-----|-+-------+--------+-------+ + // ^ ^ | | | + // | \-----------------------------------/ + // \ | / + // \------------------------------------------------/ + // / + // <---------------------------/ + // + // - VsmEvalArgsFrame: owned by VSM, state for evalargs loop + // - VsmApplyFrame: owned by VSM, state for transferring control to called function + // - DArray: contains evaluated args; owned by called primitive + + // - i_arg + // if -1: value_ register holds function + // if >=0: value_ register holds i'th function argument + // + + auto evalargs_frame + = obj::from(stack_); + + assert(evalargs_frame); + + int32_t i_arg = evalargs_frame->i_arg(); + + DVsmApplyFrame * apply_frame = evalargs_frame->parent(); + + const DApplyExpr * apply_expr + = evalargs_frame->apply_expr(); + + if (i_arg == -1) { + auto fn = value.to_facet(); + + if (fn) { + apply_frame->assign_fn(fn); + + i_arg = evalargs_frame->increment_arg(); + + // now i_arg is 0 -> evaluate that argument + + this->expr_ = apply_expr->arg(i_arg); + this->pc_ = VsmInstr::c_eval; + //this->cont_ = VsmInstra::c_evalargs; // redundant, since preserved + + return; + } else { + // error - function position must deliver something with AProcedure? + // or DClosure, but we'll get to that. + + log.retroactively_enable(); + log("expected procedure in function position -> terminate"); + + assert(false); + } + } else { + DArray * args = apply_frame->args(); + + log && log(xtag("i_arg", i_arg), xtag("n_arg", args->size()), xtag("cap", args->capacity())); + + args->push_back(value); + + i_arg = evalargs_frame->increment_arg(); + + if (i_arg == static_cast(apply_expr->n_args())) { + // all apply-arguments have been evaluated + // -> done with VsmEvalArgsFrame + // + + this->fn_ = apply_frame->fn(); + this->args_ = apply_frame->args(); + + this->stack_ = apply_frame->parent(); + this->pc_ = VsmInstr::c_apply; + this->cont_ = apply_frame->cont(); + + return; + + } else { + this->expr_ = apply_expr->arg(i_arg); + this->pc_ = VsmInstr::c_eval; + //this->cont_ = VsmInstra::c_evalargs; // redundant, since preserved + + return; + } + } + // not implemented assert(false); } diff --git a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp index 59104860..32cf7cab 100644 --- a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp +++ b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp @@ -166,10 +166,10 @@ namespace xo { log && log(xtag("res.tseq", res.value()->_typeseq())); - auto x = obj::from(*res.value()); + auto x = obj::from(*res.value()); REQUIRE(x); - REQUIRE(x.data()->value() == 1011); + REQUIRE(x.data()->value() == 1.570796325); REQUIRE(res.remaining_.size() == 1); REQUIRE(*res.remaining_.lo() == '\n'); diff --git a/xo-object2/include/xo/object2/DArray.hpp b/xo-object2/include/xo/object2/DArray.hpp index e95f67f6..c6f25221 100644 --- a/xo-object2/include/xo/object2/DArray.hpp +++ b/xo-object2/include/xo/object2/DArray.hpp @@ -68,7 +68,8 @@ namespace xo { requires (std::same_as> && ...) static DArray * array(obj mm, Args... args); - obj operator[](size_type index) const noexcept { return elts_[index]; } + const obj & operator[](size_type index) const noexcept { return elts_[index]; } + obj & operator[](size_type index) noexcept { return elts_[index]; } ///@} /** @defgroup darray-access acecss methods **/