From 7ee41a4b7181a0f677cd3894d2b4d554cc87835f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 26 Nov 2025 00:32:37 -0500 Subject: [PATCH] xo-interpreter: + expression sequences --- .../include/xo/expression/Sequence.hpp | 4 + .../interpreter/VirtualSchematikaMachine.hpp | 5 + .../include/xo/interpreter/VsmInstr.hpp | 4 + .../include/xo/interpreter/VsmStackFrame.hpp | 11 +- .../interpreter/VirtualSchematikaMachine.cpp | 121 +++++++++++++++++- .../src/interpreter/VsmStackFrame.cpp | 15 +++ xo-object/include/xo/object/Integer.hpp | 2 + 7 files changed, 158 insertions(+), 4 deletions(-) diff --git a/xo-expression/include/xo/expression/Sequence.hpp b/xo-expression/include/xo/expression/Sequence.hpp index c713eb3d..d8105999 100644 --- a/xo-expression/include/xo/expression/Sequence.hpp +++ b/xo-expression/include/xo/expression/Sequence.hpp @@ -17,6 +17,10 @@ namespace xo { expr_v_(xv) {} static rp make(const std::vector> & xv) { return new Sequence(xv); } + /** downcast from Expression **/ + static bp from(bp x) { + return bp::from(x); + } std::size_t size() const { return expr_v_.size(); } const rp & operator[](std::size_t i) const { return expr_v_[i]; } diff --git a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp index 419e9ca9..91e40312 100644 --- a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp +++ b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp @@ -96,6 +96,11 @@ namespace xo { /** continue after establish value of test expression **/ void do_complete_ifexpr_op(); + /** interprete sequence **/ + void eval_sequence_op(); + /** continue after establishing value for a sequence element **/ + void do_complete_sequence_op(); + /** goto error state with message @p err **/ void report_error(const std::string & err); diff --git a/xo-interpreter/include/xo/interpreter/VsmInstr.hpp b/xo-interpreter/include/xo/interpreter/VsmInstr.hpp index 1bc8e394..1f82fd7c 100644 --- a/xo-interpreter/include/xo/interpreter/VsmInstr.hpp +++ b/xo-interpreter/include/xo/interpreter/VsmInstr.hpp @@ -37,6 +37,10 @@ namespace xo { **/ complete_ifexpr, + /** execute remainder of expression sequence + **/ + complete_sequence, + /** choose branch of if-expression + continue * * stack: frame with diff --git a/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp b/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp index cd166e0b..c6efc699 100644 --- a/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp +++ b/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp @@ -34,13 +34,22 @@ namespace xo { #endif /** create new stack frame using allocator @p mm, - * with parent frame @p p; new frame contains values @p s0, @p s1 + * with parent frame @p p; new frame contains values @p s0 **/ static gp push1(gc::IAlloc * mm, gp p, gp s0, const VsmInstr * cont); + /** create new stack frame using allocator @p mm, + * with parent frame @p p; new frame contains values @p s0, @p s1 + **/ + static gp push2(gc::IAlloc * mm, + gp p, + gp s0, + gp s1, + const VsmInstr * cont); + /** reflect VsmStackFrame object representation **/ static void reflect_self(); diff --git a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp index 63d8d537..53ce2c17 100644 --- a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp +++ b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp @@ -3,11 +3,13 @@ #include "VirtualSchematikaMachine.hpp" #include "VsmInstr.hpp" #include "ExpressionBoxed.hpp" -#include "xo/expression/ConstantInterface.hpp" +#include "xo/expression/Constant.hpp" #include "xo/expression/DefineExpr.hpp" #include "xo/expression/AssignExpr.hpp" #include "xo/expression/Variable.hpp" #include "xo/expression/IfExpr.hpp" +#include "xo/expression/Sequence.hpp" +#include "xo/object/Integer.hpp" #include "xo/object/Boolean.hpp" #include "xo/alloc/GC.hpp" @@ -24,6 +26,7 @@ namespace xo { using xo::gc::GC; + using xo::obj::Integer; using xo::obj::Boolean; namespace scm { @@ -50,6 +53,12 @@ namespace xo { * - top stack frame contains {ifexpr, cont} **/ static VsmInstr complete_ifexpr_op; + + /** proceed to next element of sequence-expr. + * - opcode is Opcode::complete_sequence + * - top stack fram contains {seq, next, cont} + */ + static VsmInstr complete_sequence_op; }; VsmInstr @@ -64,6 +73,9 @@ namespace xo { VsmInstr VsmOps::complete_ifexpr_op{VsmInstr::Opcode::complete_ifexpr, "complete-ifexpr"}; + VsmInstr + VsmOps::complete_sequence_op{VsmInstr::Opcode::complete_sequence, "complete-sequence"}; + // ----- VirtualSchematikaMachineFlyweight ----- VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, @@ -192,12 +204,16 @@ namespace xo { this->eval_ifexpr_op(); break; + case exprtype::sequence: + log && log("eval -> sequence"); + this->eval_sequence_op(); + break; + case exprtype::invalid: case exprtype::primitive: case exprtype::apply: case exprtype::lambda: - case exprtype::sequence: case exprtype::convert: case exprtype::n_expr: this->pc_ = nullptr; @@ -218,6 +234,10 @@ namespace xo { this->do_complete_ifexpr_op(); break; + case Opcode::complete_sequence: + this->do_complete_sequence_op(); + break; + case Opcode::N_Opcode: assert(false); break; @@ -490,7 +510,12 @@ namespace xo { if (test_value->value()) { this->expr_ = ifexpr->when_true(); } else { - this->expr_ = ifexpr->when_false(); + if (ifexpr->when_false()) { + this->expr_ = ifexpr->when_false(); + } else { + /* 1-sided if-expr; evaluate to false */ + this->expr_ = Constant::make(false); + } } this->stack_ = sp0->parent(); @@ -507,6 +532,96 @@ namespace xo { } } + void + VirtualSchematikaMachine::eval_sequence_op() + { + using xo::scm::Sequence; + + scope log(XO_DEBUG(true)); + + gc::IAlloc * mm = flyweight_.object_mm_; + + /** must promote bp -> gp **/ + gp seq_boxed = ExpressionBoxed::make(mm, expr_); + bp seq = Sequence::from(expr_); + + assert(seq.get()); + assert(env_.get()); + + this->pc_ = &VsmOps::eval_op; + + if (seq->size() == 0) { + /* for 0-size sequence, invent an expression */ + this->expr_ = Constant::make(false); + } else { + this->expr_ = (*seq)[0]; + } + + if (seq->size() > 1) { + /* remainder */ + + gp next = Integer::make(mm, 1); + + /* when control arrives at .cont_ will have: + * .value_ -> result of evaluating last expr in seq + */ + this->stack_ = VsmStackFrame::push2(mm, stack_, seq_boxed, next, cont_); + + /* .stack_: + * frame + * [0] = seq (boxed sequence) + * [1] = next (index of next seq member to evaluate) + * .. + */ + + this->cont_ = &VsmOps::complete_sequence_op; + } else { + /* sequence completes when expr_ evaluated + * -> proceed with o.g. cont_ + */ + } + } + + void + VirtualSchematikaMachine::do_complete_sequence_op() + { + using xo::scm::Sequence; + + scope log(XO_DEBUG(true)); + + /* - stack: top frame has 2 slots: + * [0] : seq (boxed Sequence) + * [1] : next (index of next seq element to eval + */ + + assert(value_.get()); + assert(stack_.get()); + + gp sp0 = this->stack_; + + assert(sp0->size() == 2); + + bp seq = Sequence::from(ExpressionBoxed::from((*sp0)[0])->contents()); + gp next_obj = Integer::from((*sp0)[1]); + size_t i_next = next_obj->value(); + + assert(i_next < seq->size()); + + this->pc_ = &VsmOps::eval_op; + this->expr_ = (*seq)[i_next]; + + if (i_next + 1 == seq->size()) { + /* last member of sequence -> tail call optimization */ + this->stack_ = sp0->parent(); + this->cont_ = sp0->continuation(); + } else { + /* we can modify next_obj in place, + * since it's unique to frame sp0 + */ + next_obj->assign_value(i_next + 1); + this->cont_ = &VsmOps::complete_sequence_op; + } + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-interpreter/src/interpreter/VsmStackFrame.cpp b/xo-interpreter/src/interpreter/VsmStackFrame.cpp index e12bf6b9..b189745f 100644 --- a/xo-interpreter/src/interpreter/VsmStackFrame.cpp +++ b/xo-interpreter/src/interpreter/VsmStackFrame.cpp @@ -47,6 +47,21 @@ namespace xo { return retval; } + gp + VsmStackFrame::push2(gc::IAlloc * mm, + gp p, + gp s0, + gp s1, + const VsmInstr * cont) + { + gp retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 2, cont); + + (*retval)[0] = s0; + (*retval)[1] = s1; + + return retval; + } + TaggedPtr VsmStackFrame::self_tp() const { diff --git a/xo-object/include/xo/object/Integer.hpp b/xo-object/include/xo/object/Integer.hpp index 73049a20..48756ea9 100644 --- a/xo-object/include/xo/object/Integer.hpp +++ b/xo-object/include/xo/object/Integer.hpp @@ -25,6 +25,8 @@ namespace xo { int_type value() const { return value_; } + void assign_value(int_type x) { value_ = x; } + // inherited from Object.. virtual TaggedPtr self_tp() const final override; virtual void display(std::ostream & os) const final override;