xo-expression2/xo-interpreter/src/interpreter/GlobalEnv.cpp

127 lines
3.9 KiB
C++

/** @file GlobalEnv.cpp **/
#include "GlobalEnv.hpp"
#include "xo/reflect/Reflect.hpp"
namespace xo {
using xo::reflect::Reflect;
using xo::reflect::TaggedPtr;
namespace scm {
gp<GlobalEnv>
GlobalEnv::make_empty(gc::IAlloc * mm, const rp<GlobalSymtab> & symtab)
{
/* by design: GlobalEnv and GlobalEnv.slot_map_ are heap-allocated */
return new GlobalEnv(mm, symtab);
}
GlobalEnv::GlobalEnv(const GlobalEnv & x)
: mm_{x.mm_},
symtab_{x.symtab_},
slot_map_{std::make_unique<map_type>(*x.slot_map_)}
{
}
GlobalEnv::GlobalEnv(gc::IAlloc * mm,
const rp<GlobalSymtab> & symtab) : mm_{mm},
symtab_{symtab},
slot_map_{std::make_unique<map_type>()}
{}
bool
GlobalEnv::local_contains_var(const std::string & vname) const
{
return symtab_->lookup_local(vname).get();
}
gp<Object> *
GlobalEnv::lookup_slot(const std::string & vname)
{
scope log(XO_DEBUG(true), xtag("name", vname));
assert(slot_map_.get());
auto ix = slot_map_->find(vname);
if (ix == slot_map_->end()) {
return nullptr;
} else {
log && log("binding found", xtag("vname", vname));
return &(ix->second);
}
}
gp<Object> *
GlobalEnv::establish_var(bp<Variable> var)
{
scope log(XO_DEBUG(true), xtag("name", var->name()), xtag("type", var->valuetype()));
// 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);
gp<Object> &slot = (*this->slot_map_)[var->name()];
/* discard any pre-existing value, we're redefining a variable */
slot = gp<Object>();
return &slot;
}
TaggedPtr
GlobalEnv::self_tp() const
{
return Reflect::make_tp(const_cast<GlobalEnv *>(this));
}
void
GlobalEnv::display(std::ostream & os) const
{
os << "<global-env" << xtag("n", slot_map_->size()) << ">";
}
std::size_t
GlobalEnv::_shallow_size() const
{
return sizeof(GlobalEnv);
}
Object *
GlobalEnv::_shallow_copy(gc::IAlloc * mm) const
{
Cpof cpof(mm, this);
return new (cpof) GlobalEnv(*this);
}
std::size_t
GlobalEnv::_forward_children(gc::IAlloc * gc)
{
for (auto & ix : *slot_map_) {
Object::_forward_inplace(ix.second, gc);
}
return _shallow_size();
}
} /*namespace scm*/
} /*namespace xo*/
/* end GlobalEnv.cpp */