From 705406e039d122a12a8091aa2d69d94364c9ed69 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 25 Nov 2025 20:51:33 -0500 Subject: [PATCH] xo-interpreter: interpret if-expressions. not tested --- .../interpreter/VirtualSchematikaMachine.hpp | 5 + .../include/xo/interpreter/VsmInstr.hpp | 12 +- .../interpreter/VirtualSchematikaMachine.cpp | 105 +++++++++++++++++- xo-object/include/xo/object/Boolean.hpp | 1 + 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp index ea3b9d7b..419e9ca9 100644 --- a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp +++ b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp @@ -91,6 +91,11 @@ namespace xo { /** interpret variable expression **/ void eval_variable_op(); + /** interpret if-expression **/ + void eval_ifexpr_op(); + /** continue after establish value of test expression **/ + void do_complete_ifexpr_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 9044cd6a..1bc8e394 100644 --- a/xo-interpreter/include/xo/interpreter/VsmInstr.hpp +++ b/xo-interpreter/include/xo/interpreter/VsmInstr.hpp @@ -29,11 +29,19 @@ namespace xo { * * stack: frame with: * [0] lhs : variable to assign - * [1] cont : continuation after assignment - * ... maybe other vsm state that must be saved **/ complete_assign, + /** execute ifexpr branch, given + * result of test expression has been established + **/ + complete_ifexpr, + + /** choose branch of if-expression + continue + * + * stack: frame with + * [0] ifexpr : original if-expression + **/ N_Opcode }; diff --git a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp index 6cfd2a4c..63d8d537 100644 --- a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp +++ b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp @@ -7,6 +7,8 @@ #include "xo/expression/DefineExpr.hpp" #include "xo/expression/AssignExpr.hpp" #include "xo/expression/Variable.hpp" +#include "xo/expression/IfExpr.hpp" +#include "xo/object/Boolean.hpp" #include "xo/alloc/GC.hpp" /** continue after completing a VSM instruction; @@ -22,6 +24,7 @@ namespace xo { using xo::gc::GC; + using xo::obj::Boolean; namespace scm { struct VsmOps { @@ -37,10 +40,16 @@ namespace xo { static VsmInstr eval_op; /** assign variable after evaluating rhs of a define-expression or assign-expression - * - opcode is Opcode::defexpr_assign + * - opcode is Opcode::complete_assign * - top stack frame contains {lhs, cont} - */ + **/ static VsmInstr complete_assign_op; + + /** choose branch of if-expr after evaluating test condition. + * - opcode is Opcode::complete_ifexpr + * - top stack frame contains {ifexpr, cont} + **/ + static VsmInstr complete_ifexpr_op; }; VsmInstr @@ -52,6 +61,9 @@ namespace xo { VsmInstr VsmOps::complete_assign_op{VsmInstr::Opcode::complete_assign, "complete-assign"}; + VsmInstr + VsmOps::complete_ifexpr_op{VsmInstr::Opcode::complete_ifexpr, "complete-ifexpr"}; + // ----- VirtualSchematikaMachineFlyweight ----- VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, @@ -175,12 +187,16 @@ namespace xo { this->eval_variable_op(); break; + case exprtype::ifexpr: + log && log("eval -> ifexpr"); + this->eval_ifexpr_op(); + break; + case exprtype::invalid: case exprtype::primitive: case exprtype::apply: case exprtype::lambda: - case exprtype::ifexpr: case exprtype::sequence: case exprtype::convert: case exprtype::n_expr: @@ -198,6 +214,10 @@ namespace xo { this->do_complete_assign_op(); break; + case Opcode::complete_ifexpr: + this->do_complete_ifexpr_op(); + break; + case Opcode::N_Opcode: assert(false); break; @@ -408,6 +428,85 @@ namespace xo { } } + void + VirtualSchematikaMachine::eval_ifexpr_op() + { + using xo::scm::IfExpr; + + scope log(XO_DEBUG(true)); + + gc::IAlloc * mm = flyweight_.object_mm_; + + /** must promote bp -> gp **/ + gp ifexpr_boxed = ExpressionBoxed::make(mm, expr_); + bp ifexpr = IfExpr::from(expr_); + + assert(ifexpr.get()); + assert(env_.get()); + + this->pc_ = &VsmOps::eval_op; + this->expr_ = ifexpr->test(); + + + /* when control arrives at .cont_ will have: + * .value_ -> result of evaluating ifexpr->test() + */ + this->stack_ = VsmStackFrame::push1(mm, this->stack_, ifexpr_boxed, cont_); + + /* .stack_: + * frame + * [0] = ifexpr (boxed expression) + */ + + this->cont_ = &VsmOps::complete_ifexpr_op; + } + + void + VirtualSchematikaMachine::do_complete_ifexpr_op() + { + using xo::scm::IfExpr; + + scope log(XO_DEBUG(true)); + + /* + * - value: contains result of evaluating test condition of if-expr + * - stack: top frame has 1 slot, holds (boxed) if-expr itself + */ + assert(value_.get()); + assert(stack_.get()); + assert(env_.get()); + + gp test_value = gp::from(value_); + + if (test_value.get()) { + gp sp0 = this->stack_; + + bp ifexpr = IfExpr::from(ExpressionBoxed::from((*sp0)[0])->contents()); + + assert(ifexpr.get()); + + this->pc_ = &VsmOps::eval_op; + + if (test_value->value()) { + this->expr_ = ifexpr->when_true(); + } else { + this->expr_ = ifexpr->when_false(); + } + + this->stack_ = sp0->parent(); + this->cont_ = sp0->continuation(); + } else { + std::string err = tostr("expect boolean value for result of if-expr test", xtag("value", test_value)); + + this->value_ = nullptr; + this->error_ = SchematikaError(err); + + /* note: poor man's exception */ + this->pc_ = nullptr; + this->cont_ = nullptr; + } + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-object/include/xo/object/Boolean.hpp b/xo-object/include/xo/object/Boolean.hpp index 6bfa2585..8ace42db 100644 --- a/xo-object/include/xo/object/Boolean.hpp +++ b/xo-object/include/xo/object/Boolean.hpp @@ -16,6 +16,7 @@ namespace xo { static gp boolean_obj(bool x); static gp true_obj(); static gp false_obj(); + static gp from(gp x) { return gp::from(x); } bool value() const { return value_; }