xo-interpreter: + toplevel env in VSM
This commit is contained in:
parent
57ef654a55
commit
56a1c3bc75
11 changed files with 218 additions and 18 deletions
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "ArenaAlloc.hpp"
|
||||
#include "GcStatistics.hpp"
|
||||
#include "Object.hpp"
|
||||
#include "xo/callback/UpCallbackSet.hpp"
|
||||
#include "xo/indentlog/print/array.hpp"
|
||||
#include <vector>
|
||||
|
|
@ -154,6 +155,9 @@ namespace xo {
|
|||
**/
|
||||
static up<GC> make(const Config & config);
|
||||
|
||||
/** runtime downcast **/
|
||||
static GC * from(IAlloc * mm);
|
||||
|
||||
const Config & config() const { return config_; }
|
||||
std::uint8_t nursery_polarity() const { return nursery_polarity_; }
|
||||
std::uint8_t tenured_polarity() const { return tenured_polarity_; }
|
||||
|
|
@ -230,6 +234,15 @@ namespace xo {
|
|||
* from @c *addr
|
||||
**/
|
||||
void add_gc_root(Object ** addr);
|
||||
/** reverse the effect of previous call to @ref add_gc_root **/
|
||||
void remove_gc_root(Object ** addr);
|
||||
|
||||
/** convenience wrapper **/
|
||||
template <typename T>
|
||||
void add_gc_root_dwim(gp<T> * p) { this->add_gc_root(reinterpret_cast<Object**>(p->ptr_address())); }
|
||||
template <typename T>
|
||||
void remove_gc_root_dwim(gp<T> * p) { this->remove_gc_root(reinterpret_cast<Object**>(p->ptr_address())); }
|
||||
|
||||
/** may optionally use this to observe GC copy phase.
|
||||
* Will be invoked once _per surviving object_, so not cheap.
|
||||
* Intended for GC visualization.
|
||||
|
|
|
|||
|
|
@ -132,11 +132,15 @@ namespace xo {
|
|||
up<GC>
|
||||
GC::make(const Config & config)
|
||||
{
|
||||
//GC * gc = new GC(config);
|
||||
|
||||
return std::make_unique<GC>(config);
|
||||
}
|
||||
|
||||
GC *
|
||||
GC::from(IAlloc * mm)
|
||||
{
|
||||
return dynamic_cast<GC *>(mm);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
GC::name() const
|
||||
{
|
||||
|
|
@ -390,6 +394,19 @@ namespace xo {
|
|||
gc_root_v_.push_back(addr);
|
||||
}
|
||||
|
||||
void
|
||||
GC::remove_gc_root(Object ** addr)
|
||||
{
|
||||
/* Multithreaded GC not supported */
|
||||
|
||||
assert(!this->gc_in_progress());
|
||||
|
||||
auto new_end_ix = std::remove(gc_root_v_.begin(), gc_root_v_.end(), addr);
|
||||
|
||||
/* erase now-unused slots */
|
||||
gc_root_v_.erase(new_end_ix, gc_root_v_.end());
|
||||
}
|
||||
|
||||
auto
|
||||
GC::add_gc_copy_callback(up<GcCopyCallback> fn) -> CallbackId
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace xo {
|
|||
|
||||
if (ix == global_map_.end()) {
|
||||
/* not found */
|
||||
return bp<Variable>::from_native(nullptr);
|
||||
return bp<Variable>();
|
||||
}
|
||||
|
||||
return ix->second;
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "xo/alloc/Object.hpp"
|
||||
#include "xo/refcnt/Refcounted.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
class Variable; // see xo::scm::Variable in xo/expression/Variable.hpp
|
||||
|
||||
/** @class Env
|
||||
* @brief runtime environment, holding variable bindings for schematika interpreter
|
||||
*
|
||||
|
|
@ -18,6 +21,19 @@ namespace xo {
|
|||
**/
|
||||
class Env : public Object {
|
||||
public:
|
||||
/** true iff @p vname is present in Symtab for innermost environment **/
|
||||
virtual bool local_contains_var(const std::string & vname) const = 0;
|
||||
|
||||
/** require storage for variable @p v.
|
||||
* will also establish binding path.
|
||||
*
|
||||
* Intended for introducing a new variable,
|
||||
* replacing any previous variable with the same name.
|
||||
*
|
||||
* Beware of invalidating type correctness
|
||||
**/
|
||||
virtual void establish_var(bp<Variable> v) = 0;
|
||||
|
||||
//gp<Object> lookup_symbol(const std::string & name) const;
|
||||
};
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ namespace xo {
|
|||
|
||||
gc::IAlloc * get_mm() const { return mm_; }
|
||||
|
||||
// inherited from Env..
|
||||
virtual bool local_contains_var(const std::string & vname) const final override;
|
||||
virtual void establish_var(bp<Variable> var) final override;
|
||||
|
||||
// inherited from Object..
|
||||
virtual TaggedPtr self_tp() const final override;
|
||||
virtual void display(std::ostream & os) const final override;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace xo {
|
|||
* @brief Represent a single runtime stack frame for a Schematika function
|
||||
*
|
||||
* LocalEnv intended to be used for interpreted functions.
|
||||
*
|
||||
*
|
||||
* Compiled functions will still likely have stack frames, but need not use the
|
||||
* @ref LocalEnv class
|
||||
*
|
||||
|
|
@ -89,6 +89,15 @@ namespace xo {
|
|||
gp<Object> operator[](std::size_t i) const { return slot_v_[i]; }
|
||||
gp<Object> & operator[](std::size_t i) { return slot_v_[i]; }
|
||||
|
||||
// inherited from Env..
|
||||
|
||||
virtual bool local_contains_var(const std::string & vname) const final override;
|
||||
|
||||
/** LocalEnv policy is that variable can be established once only.
|
||||
* For example function arguments must all have distinct names
|
||||
**/
|
||||
virtual void establish_var(bp<Variable> v) final override;
|
||||
|
||||
// inherited from Object..
|
||||
virtual TaggedPtr self_tp() const final override;
|
||||
virtual void display(std::ostream & os) const final override;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "VsmInstr.hpp"
|
||||
#include "SchematikaError.hpp"
|
||||
#include "Env.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/object/ObjectConverter.hpp"
|
||||
#include "xo/alloc/Object.hpp"
|
||||
|
|
@ -12,10 +13,13 @@ namespace xo {
|
|||
namespace scm {
|
||||
/** @brief state that may be shared across VirtualSchematikaMachine instances **/
|
||||
struct VirtualSchematikaMachineFlyweight {
|
||||
explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm);
|
||||
explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
||||
gp<Env> env);
|
||||
|
||||
/** memory allocator for interpreter operation. **/
|
||||
gc::IAlloc * object_mm_ = nullptr;
|
||||
/** global environment **/
|
||||
gp<Env> toplevel_env_;
|
||||
/** convert TaggedPtr->Object **/
|
||||
xo::obj::ObjectConverter object_converter_;
|
||||
};
|
||||
|
|
@ -29,17 +33,30 @@ namespace xo {
|
|||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
public:
|
||||
VirtualSchematikaMachine(IAlloc * mm);
|
||||
VirtualSchematikaMachine(IAlloc * mm, gp<Env> toplevel_env);
|
||||
~VirtualSchematikaMachine();
|
||||
|
||||
/** evaluate expression @p expr.
|
||||
* borrows calling thread until completion
|
||||
* return [value, error]. error ignored unless value is nullptr.
|
||||
* conversely when value is nullptr, error gives details of original
|
||||
* error.
|
||||
*
|
||||
* Evaluate schematika expression @p expr in environment @p env
|
||||
**/
|
||||
std::pair<gp<Object>, SchematikaError> eval(bp<Expression> expr);
|
||||
std::pair<gp<Object>, SchematikaError> eval(bp<Expression> expr, gp<Env> env);
|
||||
|
||||
/** evaluate expression @p expr in toplevel environment **/
|
||||
std::pair<gp<Object>, SchematikaError> toplevel_eval(bp<Expression> expr);
|
||||
|
||||
private:
|
||||
/** Not moveable or copyable.
|
||||
* One constraint is member variables added to flyweight_.object_mm_
|
||||
* as GC roots, with no provision for unwinding later.
|
||||
**/
|
||||
VirtualSchematikaMachine(const VirtualSchematikaMachine &) = delete;
|
||||
VirtualSchematikaMachine(VirtualSchematikaMachine &&) = delete;
|
||||
|
||||
/** borrow calling thread to run schematika machine
|
||||
* indefinitely, or until null continuation
|
||||
**/
|
||||
|
|
@ -67,6 +84,8 @@ namespace xo {
|
|||
|
||||
/** expression **/
|
||||
rp<Expression> expr_;
|
||||
/** holds bindings for all schematika variables **/
|
||||
gp<Env> env_;
|
||||
|
||||
/** non-error result value from eval() / apply() **/
|
||||
gp<Object> value_;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,40 @@ namespace xo {
|
|||
symtab_{symtab}
|
||||
{}
|
||||
|
||||
bool
|
||||
GlobalEnv::local_contains_var(const std::string & vname) const
|
||||
{
|
||||
return symtab_->lookup_local(vname).get();
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEnv::establish_var(bp<Variable> var)
|
||||
{
|
||||
// Warning: altering declared type for an already-existing variable
|
||||
// invalidates any type checking that relied on that variable.
|
||||
//
|
||||
// Ignoring this problem for now.
|
||||
//
|
||||
// Actual solution might look like:
|
||||
// - keep track of which functions/defs depend on each global variable.
|
||||
// - invalidate any jit / types for such variables.
|
||||
// - maybe use seqno's to track
|
||||
// - re-check / re-complie
|
||||
// - need to admit invalid states.
|
||||
// suppose have mutually recursive functions f(), g()
|
||||
// want ability to modify type signatures separately
|
||||
//
|
||||
// Alternatives:
|
||||
// - forbid changing type of an already-established variable
|
||||
// Actually: can't even change values if we intend supporting dependent types
|
||||
// - quietly number variables so new definitions shadow old ones but don't
|
||||
// affect previously-encountered expressions
|
||||
|
||||
this->symtab_->require_global(var->name(), var);
|
||||
|
||||
this->slot_map_[var->name()] = gp<Object>();
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
GlobalEnv::self_tp() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,6 +44,24 @@ namespace xo {
|
|||
slot_v_{mm, n}
|
||||
{}
|
||||
|
||||
bool
|
||||
LocalEnv::local_contains_var(const std::string & vname) const
|
||||
{
|
||||
assert(symtab_.get());
|
||||
|
||||
return symtab_->lookup_local(vname);
|
||||
}
|
||||
|
||||
void
|
||||
LocalEnv::establish_var(bp<Variable> v)
|
||||
{
|
||||
assert(v);
|
||||
|
||||
throw std::runtime_error(tostr("LocalEnv::establish_var:"
|
||||
" inserting new variables not supported for LocalEnv",
|
||||
xtag("v.name", v->name())));
|
||||
}
|
||||
|
||||
TaggedPtr
|
||||
LocalEnv::self_tp() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "Schematika.hpp"
|
||||
#include "VirtualSchematikaMachine.hpp"
|
||||
#include "GlobalEnv.hpp"
|
||||
#include "xo/reader/reader.hpp"
|
||||
#include <replxx.hxx>
|
||||
#include <ostream>
|
||||
|
|
@ -26,7 +27,8 @@ namespace xo {
|
|||
* rather than VirtualSchematikaMachine to own allocator
|
||||
* to preserve option to share it
|
||||
**/
|
||||
Impl(const Config & config, up<IAlloc> mm) : config_{config}, vsm_{mm.get()}, mm_{std::move(mm)} {}
|
||||
Impl(const Config & config, up<IAlloc> mm, gp<Env> toplevel_env) :
|
||||
config_{config}, vsm_{mm.get(), toplevel_env}, mm_{std::move(mm)} {}
|
||||
|
||||
/** create instance + allocator **/
|
||||
static up<Impl> make(const Config & cfg);
|
||||
|
|
@ -59,8 +61,10 @@ namespace xo {
|
|||
Schematika::Impl::make(const Config & cfg)
|
||||
{
|
||||
up<IAlloc> mm = GC::make(cfg.gc_config_);
|
||||
rp<GlobalSymtab> symtab = GlobalSymtab::make_empty();
|
||||
gp<Env> env = GlobalEnv::make_empty(mm.get(), symtab);
|
||||
|
||||
return std::make_unique<Impl>(cfg, std::move(mm));
|
||||
return std::make_unique<Impl>(cfg, std::move(mm), env);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -180,7 +184,7 @@ namespace xo {
|
|||
//pps.prettyn(expr);
|
||||
|
||||
// TODO:
|
||||
auto [ value, scm_error ] = this->vsm_.eval(expr);
|
||||
auto [ value, scm_error ] = this->vsm_.toplevel_eval(expr);
|
||||
|
||||
if (scm_error.is_error()) {
|
||||
/* print error */
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "VirtualSchematikaMachine.hpp"
|
||||
#include "VsmInstr.hpp"
|
||||
#include "xo/expression/ConstantInterface.hpp"
|
||||
#include "xo/alloc/GC.hpp"
|
||||
|
||||
/** continue after completing a VSM instruction;
|
||||
* achieve by jumping to continuation.
|
||||
|
|
@ -14,6 +15,8 @@
|
|||
#define VSM_ERROR(msg) report_error(msg); return;
|
||||
|
||||
namespace xo {
|
||||
using xo::gc::GC;
|
||||
|
||||
namespace scm {
|
||||
struct VsmOps {
|
||||
/** halt virtual scheme machine.
|
||||
|
|
@ -36,21 +39,60 @@ namespace xo {
|
|||
|
||||
// ----- VirtualSchematikaMachineFlyweight -----
|
||||
|
||||
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm) :
|
||||
object_mm_{mm}
|
||||
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm,
|
||||
gp<Env> env) :
|
||||
object_mm_{mm},
|
||||
toplevel_env_{env}
|
||||
{}
|
||||
|
||||
// ----- VirtualSchematikaMachine -----
|
||||
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm) : flyweight_{mm}
|
||||
{}
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm, gp<Env> env) : flyweight_{mm, env}
|
||||
{
|
||||
// gc roots
|
||||
gc::GC * gc = GC::from(mm);
|
||||
|
||||
if (gc) {
|
||||
assert((gc->gc_in_progress() == false) && "cannot add roots while GC running");
|
||||
|
||||
gc->add_gc_root_dwim(&env_);
|
||||
gc->add_gc_root_dwim(&value_);
|
||||
} else {
|
||||
// Want to support VSM with arena-allocator-only;
|
||||
// if only for unit testing.
|
||||
}
|
||||
|
||||
// TODO: install builtin primitives here
|
||||
}
|
||||
|
||||
VirtualSchematikaMachine::~VirtualSchematikaMachine()
|
||||
{
|
||||
gc::GC * gc = GC::from(flyweight_.object_mm_);
|
||||
|
||||
if (gc) {
|
||||
assert((gc->gc_in_progress() == false) && "cannot remove roots while GC running");
|
||||
|
||||
gc->remove_gc_root_dwim(&env_);
|
||||
gc->remove_gc_root_dwim(&value_);
|
||||
} else {
|
||||
// nothing to do in arena-only mode
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<gp<Object>,
|
||||
SchematikaError>
|
||||
VirtualSchematikaMachine::eval(bp<Expression> expr)
|
||||
VirtualSchematikaMachine::toplevel_eval(bp<Expression> expr)
|
||||
{
|
||||
return this->eval(expr, this->env_);
|
||||
}
|
||||
|
||||
std::pair<gp<Object>,
|
||||
SchematikaError>
|
||||
VirtualSchematikaMachine::eval(bp<Expression> expr, gp<Env> env)
|
||||
{
|
||||
this->pc_ = &VsmOps::eval_op;
|
||||
this->expr_ = expr.promote();
|
||||
this->env_ = env;
|
||||
this->cont_ = &VsmOps::halt_op;
|
||||
|
||||
this->run();
|
||||
|
|
@ -101,7 +143,7 @@ namespace xo {
|
|||
case exprtype::n_expr:
|
||||
this->pc_ = nullptr;
|
||||
this->value_ = nullptr;
|
||||
this->error_ = SchematikaError(tostr("execute_vsm: not implmented",
|
||||
this->error_ = SchematikaError(tostr("execute_vsm: not implemented",
|
||||
xtag("extype", expr_->extype())));
|
||||
this->cont_ = nullptr;
|
||||
break;
|
||||
|
|
@ -129,10 +171,10 @@ namespace xo {
|
|||
void
|
||||
VirtualSchematikaMachine::constant_op()
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
using xo::scm::ConstantInterface;
|
||||
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
bp<ConstantInterface> expr = ConstantInterface::from(expr_);
|
||||
|
||||
assert(expr);
|
||||
|
|
@ -153,6 +195,30 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
// placeholder: primitive_op
|
||||
|
||||
#ifdef NOT_YET
|
||||
void
|
||||
VirtualSchematikaMachine::define_op()
|
||||
{
|
||||
using xo::scm::DefineExpr;
|
||||
|
||||
bp<DefineExpr> expr = DefineExpr::from(expr_);
|
||||
|
||||
assert(expr);
|
||||
|
||||
// note: establish lhs_var first, to allow for recursion, for example:
|
||||
// def fact(n: i64) { if (n == 0) then 1; else n * fact(n-1); }
|
||||
|
||||
/** remembers promised variable type **/
|
||||
env_->establish_var(expr->lhs_variable());
|
||||
|
||||
/* lhs_var
|
||||
* rhs
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue