xo-interpreter: handle assignment expressions

This commit is contained in:
Roland Conybeare 2025-11-25 14:31:05 -05:00
commit 7b49d3da88
7 changed files with 103 additions and 15 deletions

View file

@ -81,10 +81,12 @@ namespace xo {
/** interpret literal constant expression **/
void eval_constant_op();
/** interpret define expression **/
/** execute define expression (finished in do_complete_assign_op()) **/
void eval_define_op();
/** execute assign expression (finishes in do_complete_assign_op()) **/
void eval_assign_op();
/** continue after establishing value fo rhs of define exprsssion **/
void do_defexpr_assign_op();
void do_complete_assign_op();
/** interpret variable expression **/
void eval_variable_op();

View file

@ -32,7 +32,7 @@ namespace xo {
* [1] cont : continuation after assignment
* ... maybe other vsm state that must be saved
**/
defexpr_assign,
complete_assign,
N_Opcode
};

View file

@ -5,6 +5,7 @@
#include "ExpressionBoxed.hpp"
#include "xo/expression/ConstantInterface.hpp"
#include "xo/expression/DefineExpr.hpp"
#include "xo/expression/AssignExpr.hpp"
#include "xo/expression/Variable.hpp"
#include "xo/alloc/GC.hpp"
@ -35,11 +36,11 @@ namespace xo {
**/
static VsmInstr eval_op;
/** assign variable after evaluating rhs of a define-expression
/** assign variable after evaluating rhs of a define-expression or assign-expression
* - opcode is Opcode::defexpr_assign
* - top stack frame contains {lhs, cont}
*/
static VsmInstr defexpr_assign_op;
static VsmInstr complete_assign_op;
};
VsmInstr
@ -49,7 +50,7 @@ namespace xo {
VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"};
VsmInstr
VsmOps::defexpr_assign_op{VsmInstr::Opcode::defexpr_assign, "defexpr-assign"};
VsmOps::complete_assign_op{VsmInstr::Opcode::complete_assign, "complete-assign"};
// ----- VirtualSchematikaMachineFlyweight -----
@ -164,6 +165,11 @@ namespace xo {
this->eval_define_op();
break;
case exprtype::assign:
log && log("eval -> assign");
this->eval_assign_op();
break;
case exprtype::variable:
log && log("eval -> variable");
this->eval_variable_op();
@ -172,7 +178,6 @@ namespace xo {
case exprtype::invalid:
case exprtype::primitive:
case exprtype::assign:
case exprtype::apply:
case exprtype::lambda:
case exprtype::ifexpr:
@ -189,8 +194,8 @@ namespace xo {
}
break;
case Opcode::defexpr_assign:
this->do_defexpr_assign_op();
case Opcode::complete_assign:
this->do_complete_assign_op();
break;
case Opcode::N_Opcode:
@ -276,13 +281,65 @@ namespace xo {
/* .stack_:
* frame
* [0] = lhs_0 (boxed lhs Variable)
* ..
*/
this->cont_ = &VsmOps::defexpr_assign_op;
this->cont_ = &VsmOps::complete_assign_op;
}
void
VirtualSchematikaMachine::do_defexpr_assign_op()
VirtualSchematikaMachine::eval_assign_op()
{
using xo::scm::AssignExpr;
scope log(XO_DEBUG(true));
auto mm = flyweight_.object_mm_;
bp<AssignExpr> assign = AssignExpr::from(expr_);
assert(assign.get());
assert(env_.get());
assert(assign->lhs().get());
assert(assign->rhs().get());
/* verify slot exists, before we evaluate rhs */
gp<Object> * slot = env_->lookup_slot(assign->lhs()->name());
if (slot) {
/** must promote rp<Expression> -> gp<ExpressionBoxed> **/
gp<ExpressionBoxed> lhs = ExpressionBoxed::make(mm, assign->lhs());
this->pc_ = &VsmOps::eval_op;
this->expr_ = assign->rhs();
/* when control arrives at .cont_, will have:
* .value_ -> result of evaluating assign->rhs()
*/
this->stack_ = VsmStackFrame::push1(mm, this->stack_, lhs, cont_);
/* .stack_:
* frame
* [0] = lhs (boxed lhs Variable)
* ..
*/
this->cont_ = &VsmOps::complete_assign_op;
} else {
std::string err = tostr("no binding for lhs of assignment", xtag("name", assign->lhs()->name()));
this->value_ = nullptr;
this->error_ = SchematikaError(err);
/* note: poor man's exception */
this->pc_ = nullptr;
this->cont_ = nullptr;
}
}
void
VirtualSchematikaMachine::do_complete_assign_op()
{
scope log(XO_DEBUG(true));
@ -348,8 +405,6 @@ namespace xo {
/* note: poor man's exception */
this->pc_ = nullptr;
this->cont_ = nullptr;
this->pc_ = cont_;
}
}

View file

@ -172,6 +172,9 @@ namespace xo {
/** handle incoming '=' token **/
virtual void on_singleassign_token(const token_type & tk,
parserstatemachine * p_psm);
/** handle incoming ':=' token **/
virtual void on_assign_token(const token_type & tk,
parserstatemachine * p_psm);
/** handle incoming '(' token **/
virtual void on_leftparen_token(const token_type & tk,
parserstatemachine * p_psm);

View file

@ -97,7 +97,7 @@ namespace xo {
bp<Expression> expr2,
parserstatemachine * p_psm) const;
virtual const char * get_expect_str() const override;
virtual const char * get_expect_str() const final override;
virtual void on_expr(bp<Expression> expr,
parserstatemachine * p_psm) override;
@ -116,6 +116,8 @@ namespace xo {
parserstatemachine * p_psm) override;
virtual void on_singleassign_token(const token_type & tk,
parserstatemachine * p_psm) override;
virtual void on_assign_token(const token_type & tk,
parserstatemachine * p_psm) final override;
virtual void on_leftparen_token(const token_type & tk,
parserstatemachine * p_psm) override;
virtual void on_rightparen_token(const token_type & tk,
@ -129,7 +131,7 @@ namespace xo {
/* entry point for an infix operator token */
virtual void on_operator_token(const token_type & tk,
parserstatemachine * p_psm) override;
parserstatemachine * p_psm) final override;
virtual void on_bool_token(const token_type & tk,
parserstatemachine * p_psm) override;

View file

@ -216,6 +216,20 @@ namespace xo {
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
}
void
exprstate::on_assign_token(const token_type & tk,
parserstatemachine * p_psm)
{
constexpr bool c_debug_flag = true;
scope log(XO_DEBUG(c_debug_flag));
constexpr const char * c_self_name = "exprstate::on_assign_token";
const char * exp = get_expect_str();
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
}
void
exprstate::on_leftparen_token(const token_type & tk,
parserstatemachine * p_psm)
@ -445,6 +459,9 @@ namespace xo {
return;
case tokentype::tk_assign:
this->on_assign_token(tk, p_psm);
return;
case tokentype::tk_yields:
assert(false);
break;

View file

@ -434,6 +434,13 @@ namespace xo {
this->illegal_input_on_token(c_self_name, tk, exp, p_psm);
}
void
progress_xs::on_assign_token(const token_type & tk,
parserstatemachine * p_psm)
{
this->on_operator_token(tk, p_psm);
}
void
progress_xs::on_leftparen_token(const token_type & tk,
parserstatemachine * p_psm)
@ -573,6 +580,8 @@ namespace xo {
optype
tk2op(const tokentype & tktype) {
switch (tktype) {
case tokentype::tk_assign:
return optype::op_assign;
case tokentype::tk_plus:
return optype::op_add;
case tokentype::tk_minus: