xo-interpreter: + expression sequences
This commit is contained in:
parent
498dd6a54e
commit
7ee41a4b71
7 changed files with 158 additions and 4 deletions
|
|
@ -17,6 +17,10 @@ namespace xo {
|
||||||
expr_v_(xv) {}
|
expr_v_(xv) {}
|
||||||
|
|
||||||
static rp<Sequence> make(const std::vector<rp<Expression>> & xv) { return new Sequence(xv); }
|
static rp<Sequence> make(const std::vector<rp<Expression>> & xv) { return new Sequence(xv); }
|
||||||
|
/** downcast from Expression **/
|
||||||
|
static bp<Sequence> from(bp<Expression> x) {
|
||||||
|
return bp<Sequence>::from(x);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t size() const { return expr_v_.size(); }
|
std::size_t size() const { return expr_v_.size(); }
|
||||||
const rp<Expression> & operator[](std::size_t i) const { return expr_v_[i]; }
|
const rp<Expression> & operator[](std::size_t i) const { return expr_v_[i]; }
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,11 @@ namespace xo {
|
||||||
/** continue after establish value of test expression **/
|
/** continue after establish value of test expression **/
|
||||||
void do_complete_ifexpr_op();
|
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 **/
|
/** goto error state with message @p err **/
|
||||||
void report_error(const std::string & err);
|
void report_error(const std::string & err);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
complete_ifexpr,
|
complete_ifexpr,
|
||||||
|
|
||||||
|
/** execute remainder of expression sequence
|
||||||
|
**/
|
||||||
|
complete_sequence,
|
||||||
|
|
||||||
/** choose branch of if-expression + continue
|
/** choose branch of if-expression + continue
|
||||||
*
|
*
|
||||||
* stack: frame with
|
* stack: frame with
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,22 @@ namespace xo {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** create new stack frame using allocator @p mm,
|
/** 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<VsmStackFrame> push1(gc::IAlloc * mm,
|
static gp<VsmStackFrame> push1(gc::IAlloc * mm,
|
||||||
gp<VsmStackFrame> p,
|
gp<VsmStackFrame> p,
|
||||||
gp<Object> s0,
|
gp<Object> s0,
|
||||||
const VsmInstr * cont);
|
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<VsmStackFrame> push2(gc::IAlloc * mm,
|
||||||
|
gp<VsmStackFrame> p,
|
||||||
|
gp<Object> s0,
|
||||||
|
gp<Object> s1,
|
||||||
|
const VsmInstr * cont);
|
||||||
|
|
||||||
|
|
||||||
/** reflect VsmStackFrame object representation **/
|
/** reflect VsmStackFrame object representation **/
|
||||||
static void reflect_self();
|
static void reflect_self();
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
#include "VirtualSchematikaMachine.hpp"
|
#include "VirtualSchematikaMachine.hpp"
|
||||||
#include "VsmInstr.hpp"
|
#include "VsmInstr.hpp"
|
||||||
#include "ExpressionBoxed.hpp"
|
#include "ExpressionBoxed.hpp"
|
||||||
#include "xo/expression/ConstantInterface.hpp"
|
#include "xo/expression/Constant.hpp"
|
||||||
#include "xo/expression/DefineExpr.hpp"
|
#include "xo/expression/DefineExpr.hpp"
|
||||||
#include "xo/expression/AssignExpr.hpp"
|
#include "xo/expression/AssignExpr.hpp"
|
||||||
#include "xo/expression/Variable.hpp"
|
#include "xo/expression/Variable.hpp"
|
||||||
#include "xo/expression/IfExpr.hpp"
|
#include "xo/expression/IfExpr.hpp"
|
||||||
|
#include "xo/expression/Sequence.hpp"
|
||||||
|
#include "xo/object/Integer.hpp"
|
||||||
#include "xo/object/Boolean.hpp"
|
#include "xo/object/Boolean.hpp"
|
||||||
#include "xo/alloc/GC.hpp"
|
#include "xo/alloc/GC.hpp"
|
||||||
|
|
||||||
|
|
@ -24,6 +26,7 @@
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
using xo::gc::GC;
|
using xo::gc::GC;
|
||||||
|
using xo::obj::Integer;
|
||||||
using xo::obj::Boolean;
|
using xo::obj::Boolean;
|
||||||
|
|
||||||
namespace scm {
|
namespace scm {
|
||||||
|
|
@ -50,6 +53,12 @@ namespace xo {
|
||||||
* - top stack frame contains {ifexpr, cont}
|
* - top stack frame contains {ifexpr, cont}
|
||||||
**/
|
**/
|
||||||
static VsmInstr complete_ifexpr_op;
|
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
|
VsmInstr
|
||||||
|
|
@ -64,6 +73,9 @@ namespace xo {
|
||||||
VsmInstr
|
VsmInstr
|
||||||
VsmOps::complete_ifexpr_op{VsmInstr::Opcode::complete_ifexpr, "complete-ifexpr"};
|
VsmOps::complete_ifexpr_op{VsmInstr::Opcode::complete_ifexpr, "complete-ifexpr"};
|
||||||
|
|
||||||
|
VsmInstr
|
||||||
|
VsmOps::complete_sequence_op{VsmInstr::Opcode::complete_sequence, "complete-sequence"};
|
||||||
|
|
||||||
// ----- VirtualSchematikaMachineFlyweight -----
|
// ----- VirtualSchematikaMachineFlyweight -----
|
||||||
|
|
||||||
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
||||||
|
|
@ -192,12 +204,16 @@ namespace xo {
|
||||||
this->eval_ifexpr_op();
|
this->eval_ifexpr_op();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case exprtype::sequence:
|
||||||
|
log && log("eval -> sequence");
|
||||||
|
this->eval_sequence_op();
|
||||||
|
break;
|
||||||
|
|
||||||
case exprtype::invalid:
|
case exprtype::invalid:
|
||||||
case exprtype::primitive:
|
case exprtype::primitive:
|
||||||
|
|
||||||
case exprtype::apply:
|
case exprtype::apply:
|
||||||
case exprtype::lambda:
|
case exprtype::lambda:
|
||||||
case exprtype::sequence:
|
|
||||||
case exprtype::convert:
|
case exprtype::convert:
|
||||||
case exprtype::n_expr:
|
case exprtype::n_expr:
|
||||||
this->pc_ = nullptr;
|
this->pc_ = nullptr;
|
||||||
|
|
@ -218,6 +234,10 @@ namespace xo {
|
||||||
this->do_complete_ifexpr_op();
|
this->do_complete_ifexpr_op();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Opcode::complete_sequence:
|
||||||
|
this->do_complete_sequence_op();
|
||||||
|
break;
|
||||||
|
|
||||||
case Opcode::N_Opcode:
|
case Opcode::N_Opcode:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
@ -490,7 +510,12 @@ namespace xo {
|
||||||
if (test_value->value()) {
|
if (test_value->value()) {
|
||||||
this->expr_ = ifexpr->when_true();
|
this->expr_ = ifexpr->when_true();
|
||||||
} else {
|
} 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<bool>::make(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->stack_ = sp0->parent();
|
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<Sequence> -> gp<ExpressionBoxed> **/
|
||||||
|
gp<ExpressionBoxed> seq_boxed = ExpressionBoxed::make(mm, expr_);
|
||||||
|
bp<Sequence> 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<bool>::make(false);
|
||||||
|
} else {
|
||||||
|
this->expr_ = (*seq)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq->size() > 1) {
|
||||||
|
/* remainder */
|
||||||
|
|
||||||
|
gp<Integer> 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<VsmStackFrame> sp0 = this->stack_;
|
||||||
|
|
||||||
|
assert(sp0->size() == 2);
|
||||||
|
|
||||||
|
bp<Sequence> seq = Sequence::from(ExpressionBoxed::from((*sp0)[0])->contents());
|
||||||
|
gp<Integer> 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 scm*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,21 @@ namespace xo {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gp<VsmStackFrame>
|
||||||
|
VsmStackFrame::push2(gc::IAlloc * mm,
|
||||||
|
gp<VsmStackFrame> p,
|
||||||
|
gp<Object> s0,
|
||||||
|
gp<Object> s1,
|
||||||
|
const VsmInstr * cont)
|
||||||
|
{
|
||||||
|
gp<VsmStackFrame> retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 2, cont);
|
||||||
|
|
||||||
|
(*retval)[0] = s0;
|
||||||
|
(*retval)[1] = s1;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
TaggedPtr
|
TaggedPtr
|
||||||
VsmStackFrame::self_tp() const
|
VsmStackFrame::self_tp() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ namespace xo {
|
||||||
|
|
||||||
int_type value() const { return value_; }
|
int_type value() const { return value_; }
|
||||||
|
|
||||||
|
void assign_value(int_type x) { value_ = x; }
|
||||||
|
|
||||||
// inherited from Object..
|
// inherited from Object..
|
||||||
virtual TaggedPtr self_tp() const final override;
|
virtual TaggedPtr self_tp() const final override;
|
||||||
virtual void display(std::ostream & os) const final override;
|
virtual void display(std::ostream & os) const final override;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue