xo-umbrella2/xo-reader2/src/reader2/ParserStateMachine.cpp
Roland Conybeare ec639ebb4b xo-interpreter2 stack: + reason arg to visit_gco_children()
Helps streamline DX1Collector in xo-gc/.
Want both forward and verify entry points for the same
representation.
2026-04-10 01:10:03 -04:00

942 lines
33 KiB
C++

/** @file ParserStateMachine.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include "ParserStateMachine.hpp"
#include "ParserStack.hpp"
#include "SyntaxStateMachine.hpp"
#include "ToplevelSeqSsm.hpp"
#include "DefineSsm.hpp"
#include <xo/numeric/NumericPrimitives.hpp>
#include <xo/procedure2/PrimitiveRegistry.hpp>
#include <xo/procedure2/SimpleRcx.hpp>
#include <xo/object2/array/IPrintable_DArray.hpp>
#include <xo/printable2/Printable.hpp>
#include <xo/alloc2/Collector.hpp>
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
#include <xo/facet/FacetRegistry.hpp>
#include <xo/indentlog/scope.hpp>
#include <xo/indentlog/print/tostr.hpp>
#include <xo/indentlog/print/tag.hpp>
#include <stdexcept>
namespace xo {
using xo::mm::ACollector;
using xo::mm::AAllocator;
using xo::mm::AGCObject;
using xo::print::APrintable;
using xo::reflect::TypeDescr;
using xo::facet::FacetRegistry;
using xo::facet::with_facet;
namespace scm {
namespace {
/** Create global environment and populate with builtin primitives.
* Get memory from @p mm, with symbol names in @p stringtable.
* Stash symbol names in @p global_symtab, which coordinates with
* new global environment.
* @p pm_install_flags controls which primitives to install
**/
obj<AGCObject,DGlobalEnv>
global_env_setup(StringTable & stringtable,
obj<AAllocator> mm,
DGlobalSymtab * global_symtab,
InstallFlags pm_install_flags)
{
scope log(XO_DEBUG(false));
DGlobalEnv * env = DGlobalEnv::_make(mm,
global_symtab);
// FUDGING this for now
obj<AAllocator> err_mm;
DSimpleRcx rcx(mm, err_mm, &stringtable);
InstallSink sink = ([env, rcx, &log]
(std::string_view name,
TypeDescr fn_td,
obj<AProcedure> pm,
InstallFlags flags)
{
(void)flags;
obj<AGCObject> pm_gco = pm.to_facet<AGCObject>();
const DUniqueString * sym
= rcx.stringtable()->intern(name);
log && log("upsert", xtag("sym", std::string_view(*sym)));
env->_upsert_value(rcx.allocator(),
sym,
fn_td,
pm_gco);
return true;
});
PrimitiveRegistry::instance()
.install_primitives(with_facet<ARuntimeContext>::mkobj(&rcx),
sink,
pm_install_flags);
return obj<AGCObject,DGlobalEnv>(env);
}
}
ParserStateMachine::ParserStateMachine(const ArenaConfig & config,
const ArenaHashMapConfig & symtab_var_config,
const ArenaHashMapConfig & symtab_type_config,
size_type max_stringtable_capacity,
InstallFlags pm_install_flags,
obj<AAllocator> expr_alloc,
obj<AAllocator> aux_alloc)
: stringtable_{max_stringtable_capacity},
parser_alloc_{DArena::map(config)},
expr_alloc_{expr_alloc},
aux_alloc_{aux_alloc},
global_symtab_{DGlobalSymtab::make(expr_alloc, aux_alloc,
symtab_var_config,
symtab_type_config)},
global_env_{global_env_setup(stringtable_,
expr_alloc_,
global_symtab_.data(),
pm_install_flags)},
debug_flag_{config.debug_flag_}
{
// see xo-numeric/ {SetupNumeric.cpp, NumericPrimitives.cpp}
// for setup of {_mul, _div, _sub, ...}
//
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_multiply_pm_name);
assert(name);
this->multiply_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_divide_pm_name);
assert(name);
this->divide_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_add_pm_name);
assert(name);
this->add_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_sub_pm_name);
assert(name);
this->subtract_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmpeq_pm_name);
assert(name);
this->cmpeq_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmpne_pm_name);
assert(name);
this->cmpne_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmplt_pm_name);
assert(name);
this->cmplt_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmple_pm_name);
assert(name);
this->cmple_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmpgt_pm_name);
assert(name);
this->cmpgt_binding_ = global_symtab_->lookup_binding(name);
}
{
const DUniqueString * name
= stringtable_.lookup(NumericPrimitives::c_cmpge_pm_name);
assert(name);
this->cmpge_binding_ = global_symtab_->lookup_binding(name);
}
}
ParserStateMachine::~ParserStateMachine()
{
obj<ACollector> gc = expr_alloc_.try_to_facet<ACollector>();
if (gc) {
scope log(XO_DEBUG(true), "remove_gc_root not implemented");
gc.remove_gc_root(&global_symtab_);
gc.remove_gc_root(&local_symtab_);
gc.remove_gc_root(&global_env_);
}
}
obj<AGCObject>
ParserStateMachine::multiply_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(multiply_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::divide_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(divide_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::add_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(add_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::subtract_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(subtract_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmpeq_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmpeq_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmpne_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmpne_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmplt_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmplt_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmple_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmple_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmpgt_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmpgt_binding_);
assert(retval);
return retval;
}
obj<AGCObject>
ParserStateMachine::cmpge_pm() const
{
obj<AGCObject> retval = global_env_->lookup_value(cmpge_binding_);
assert(retval);
return retval;
}
bool
ParserStateMachine::is_at_toplevel() const noexcept
{
/* top-level always has DToplevelSeqSsm */
ParserStack * s = stack_;
if (s) {
auto def = obj<ASyntaxStateMachine,DDefineSsm>::from(s->top());
if (def) {
/* carve-out for top-level DefineSsm: report 'at top-level' when
* that top-level DefineSsm is on the stack, so we detect
* this condition inside DefineSsm's event handling
*/
s = stack_->parent();
}
if (s && s->parent() == nullptr) {
auto top = obj<ASyntaxStateMachine,DToplevelSeqSsm>::from(s->top());
return top;
}
} else {
/** this isn't a normal operating state, still need a batch/interactive toplevel seq.
* just the same seems better to call it top-level
**/
return true;
}
return false;
}
bool
ParserStateMachine::has_incomplete_expr() const noexcept
{
scope log(XO_DEBUG(debug_flag_));
// don't count toplevel expression
ParserStack * s = stack_;
if (s) {
auto top = obj<ASyntaxStateMachine,DToplevelSeqSsm>::from(s->top());
return !top;
} else {
return false;
}
}
obj<ASyntaxStateMachine>
ParserStateMachine::top_ssm() const
{
return this->stack_->top();
}
void
ParserStateMachine::visit_pools(const MemorySizeVisitor & visitor) const
{
stringtable_.visit_pools(visitor);
parser_alloc_.visit_pools(visitor);
global_symtab_->visit_pools(visitor);
// not counting {expr_alloc_, fixed_alloc_}. We don't consider
// either to be owned by ParserStateMachine
}
void
ParserStateMachine::establish_toplevel_ssm(obj<ASyntaxStateMachine> ssm)
{
scope log(XO_DEBUG(debug_flag_));
assert(stack_ == nullptr);
DArena::Checkpoint ckp = parser_alloc_.checkpoint();
this->stack_ = ParserStack::push(nullptr /*stack*/, ckp, parser_alloc_, ssm);
this->parser_alloc_ckp_ = parser_alloc_.checkpoint();
}
void
ParserStateMachine::push_ssm(DArena::Checkpoint ckp, obj<ASyntaxStateMachine> ssm)
{
scope log(XO_DEBUG(debug_flag_));
// note: using parser_alloc_ for parser stack, since stacklike behavior
this->stack_ = ParserStack::push(stack_, ckp, parser_alloc_, ssm);
}
void
ParserStateMachine::pop_ssm()
{
scope log(XO_DEBUG(debug_flag_));
assert(this->stack_);
this->stack_ = ParserStack::pop(stack_, parser_alloc_);
}
const DUniqueString *
ParserStateMachine::intern_string(std::string_view str)
{
return stringtable_.intern(str);
}
const DUniqueString *
ParserStateMachine::gensym(std::string_view str)
{
return stringtable_.gensym(str);
}
DVarRef *
ParserStateMachine::lookup_varref(std::string_view symbolname)
{
scope log(XO_DEBUG(debug_flag_));
const DUniqueString * ustr = stringtable_.lookup(symbolname);
if (!ustr) {
// if we don't already know the symbol,
// -> can't be a valid variable reference
// (whether global or local)
return nullptr;
}
// TODO:
// 1. check global symtab
// 2. combine local+global symtab into indept struct
// 3. move lookup_varref implementation there.
//
if (local_symtab_) {
DLocalSymtab * symtab = local_symtab_.data();
// count #of nested scopes to cross, to reach symbol
//
int32_t link_count = 0;
while (symtab) {
Binding b = symtab->lookup_binding(ustr);
if (b.is_local()) {
assert(b.i_link() == 0);
DVariable * vardef = symtab->lookup_var(b);
assert(vardef);
/** ascii diagram here
**/
return DVarRef::make(expr_alloc_,
vardef,
link_count);
} else {
assert(b.is_null());
}
++link_count;
symtab = symtab->parent();
}
}
DVariable * vardef = global_symtab_->lookup_variable(ustr);
if (vardef) {
return DVarRef::make(expr_alloc_,
vardef,
0 /*link_count -- n/a for globals*/);
}
// symbol not found
return nullptr;
}
void
ParserStateMachine::push_local_symtab(DLocalSymtab * symtab)
{
this->local_symtab_ = obj<AGCObject,DLocalSymtab>(symtab);
}
void
ParserStateMachine::pop_local_symtab()
{
assert(local_symtab_);
this->local_symtab_ = obj<AGCObject,DLocalSymtab>(local_symtab_->parent());
}
void
ParserStateMachine::upsert_var(DVariable * var)
{
assert(global_symtab_);
global_symtab_->upsert_variable(this->expr_alloc(), var);
}
void
ParserStateMachine::reset_result()
{
this->result_ = ParserResult();
}
void
ParserStateMachine::clear_error_reset()
{
this->reset_result();
while (stack_ && stack_->parent())
stack_ = stack_->parent();
this->parser_alloc_.restore(parser_alloc_ckp_);
}
void
ParserStateMachine::on_parsed_symbol(std::string_view sym)
{
scope log(XO_DEBUG(debug_flag_), xtag("sym", sym));
assert(stack_);
this->stack_->top().on_parsed_symbol(sym, this);
}
void
ParserStateMachine::on_parsed_typedescr(TypeDescr td)
{
scope log(XO_DEBUG(debug_flag_), xtag("td", td));
assert(stack_);
this->stack_->top().on_parsed_typedescr(td, this);
}
void
ParserStateMachine::on_parsed_type(obj<AType> type)
{
scope log(XO_DEBUG(debug_flag_));
assert(stack_);
this->stack_->top().on_parsed_type(type, this);
}
void
ParserStateMachine::on_parsed_formal(const DUniqueString * sym,
TypeDescr td)
{
scope log(XO_DEBUG(debug_flag_), xtag("sym", std::string_view(*sym)), xtag("td", td));
assert(stack_);
this->stack_->top().on_parsed_formal(sym, td, this);
}
void
ParserStateMachine::on_parsed_formal_with_token(const DUniqueString * sym,
TypeDescr td,
const Token & tk)
{
scope log(XO_DEBUG(debug_flag_), xtag("sym", std::string_view(*sym)), xtag("td", td), xtag("tk", tk));
assert(stack_);
this->stack_->top().on_parsed_formal_with_token(sym, td, tk, this);
}
void
ParserStateMachine::on_parsed_formal_arglist(DArray * arglist)
{
scope log(XO_DEBUG(debug_flag_),
xtag("arglist", obj<APrintable,DArray>(arglist)));
assert(stack_);
this->stack_->top().on_parsed_formal_arglist(arglist, this);
}
void
ParserStateMachine::on_parsed_expression(obj<AExpression> expr)
{
scope log(XO_DEBUG(debug_flag_), xtag("expr", expr));
assert(stack_);
this->top_ssm().on_parsed_expression(expr, this);
}
void
ParserStateMachine::on_parsed_expression_with_token(obj<AExpression> expr,
const Token & tk)
{
scope log(XO_DEBUG(debug_flag_), xtag("expr", expr), xtag("tk", tk));
assert(stack_);
this->top_ssm().on_parsed_expression_with_token(expr, tk, this);
}
void
ParserStateMachine::on_quoted_literal(obj<AGCObject> lit)
{
this->top_ssm().on_quoted_literal(lit, this);
}
void
ParserStateMachine::on_token(const Token & tk)
{
scope log(XO_DEBUG(debug_flag_), xtag("tk", tk));
if (!stack_) {
// parsing stack should always have toplevel expression sequence
throw std::runtime_error(tostr("unexpected empty parsing stack",
xtag("token", tk),
xtag("help", "do it the same. but better!")
));
}
stack_->top().on_token(tk, this);
}
void
ParserStateMachine::capture_result(std::string_view ssm_name,
obj<AExpression> expr)
{
this->result_ = ParserResult::expression(ssm_name, expr);
}
void
ParserStateMachine::capture_error(std::string_view ssm_name,
const DString * errmsg)
{
if (result_.is_error()) {
/* in case one error triggers another, remmber just the first one */
} else {
this->result_ = ParserResult::error(ssm_name, errmsg);
}
}
void
ParserStateMachine::illegal_input_on_token(std::string_view ssm_name,
const Token & tk,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected token for parsing state",
xtag("token", tk),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_input_on_token"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_input_on_symbol(std::string_view ssm_name,
std::string_view sym,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected symbol for parsing state",
xtag("symbol", sym),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_input_on_symbol"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_input_on_typedescr(std::string_view ssm_name,
TypeDescr td,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected type-description for parsing state",
xtag("td", td),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_input_on_typedescr"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_input_on_type(std::string_view ssm_name,
obj<AType> type,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected type for parsing state",
xtag("type", type),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_input_on_type"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_parsed_formal(std::string_view ssm_name,
const DUniqueString * param_name,
TypeDescr param_type,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected formal",
xtag("param_name", std::string_view(*param_name)),
xtag("param_type", param_type),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_parsed_formal"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_parsed_formal_with_token(std::string_view ssm_name,
const DUniqueString * param_name,
TypeDescr param_type,
const Token & tk,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto errmsg_string = tostr("Unexpected formal",
xtag("param_name", std::string_view(*param_name)),
xtag("param_type", param_type),
xtag("tk", tk),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_parsed_formal"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_parsed_formal_arglist(std::string_view ssm_name,
DArray * arglist,
std::string_view expect_str)
{
obj<APrintable,DArray> arglist_pr(arglist);
auto errmsg_string = tostr("Unexpected formal arglist",
xtag("arglist", arglist_pr),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_parsed_formal_arglist"));
assert(expr_alloc_);
auto errmsg = DString::from_str(expr_alloc_, errmsg_string);
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_parsed_expression(std::string_view ssm_name,
obj<AExpression> expr,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
auto expr_pr = expr.to_facet<APrintable>();
//= FacetRegistry::instance().variant<APrintable,AExpression>(expr);
assert(expr_pr);
/** TODO
* problem here: we have pretty() support for obj<AExpression>,
* but not "ordinary printing" support. So expression doesn't get printed
**/
auto errmsg_string = tostr("Unexpected expression",
xtag("expr", expr_pr),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_parsed_expression"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_parsed_expression_with_token(std::string_view ssm_name,
obj<AExpression> expr,
const Token & tk,
std::string_view expect_str)
{
// TODO:
// - want to write error message using DArena
// - need something like log_streambuf and/or tostr() that's arena-aware
obj<APrintable> expr_pr
= FacetRegistry::instance().variant<APrintable,AExpression>(expr);
assert(expr_pr);
/** TODO
* problem here: we have pretty() support for obj<AExpression>,
* but not "ordinary printing" support. So expression doesn't get printed
**/
auto errmsg_string = tostr("Unexpected expression",
xtag("expr", expr_pr),
xtag("tk", tk),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_parsed_expression"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::illegal_quoted_literal(std::string_view ssm_name,
obj<AGCObject> lit,
std::string_view expect_str)
{
obj<APrintable> lit_pr
= FacetRegistry::instance().variant<APrintable,AGCObject>(lit);
/** TODO
* problem here: we have pretty() support for obj<AExpression>,
* but not "ordinary printing" support. So expression doesn't get printed
**/
auto errmsg_string = tostr("Unexpected quoted literal",
xtag("lit", lit_pr),
xtag("expecting", expect_str),
xtag("ssm", ssm_name),
xtag("via", "ParserStateMachine::illegal_quoted_literal"));
assert(expr_alloc_);
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
void
ParserStateMachine::error_unbound_variable(std::string_view ssm_name,
std::string_view sym)
{
auto errmsg_string = tostr("No binding for symbol",
xtag("symbol", sym),
xtag("ssm", ssm_name));
auto errmsg = DString::from_view(expr_alloc_,
std::string_view(errmsg_string));
this->capture_error(ssm_name, errmsg);
}
// ----- gc support -----
#ifdef OBSOLETE
void
ParserStateMachine::shallow_copy(obj<ACollector> gc) noexcept
{
(void)gc;
assert(false);
}
#endif
void
ParserStateMachine::visit_gco_children(VisitReason reason,
obj<AGCObjectVisitor> gc) noexcept
{
//scope log(XO_DEBUG(true));
assert(!stringtable_.is_gc_eligible());
assert(!parser_alloc_.is_gc_eligible());
//log && log("forward stack_", xtag("addr", stack_));
if (stack_) {
stack_->visit_gco_children(reason, gc);
}
// static_assert(!expr_alloc_.is_gc_eligible());
// static_assert(!aux_alloc_.is_gc_eligible());
//log && log("global_symtab_", xtag("addr", global_symtab_.data()));
gc.visit_child(reason, &global_symtab_);
//log && log("local_symtab_", xtag("addr", local_symtab_.data()));
gc.visit_child(reason, &local_symtab_);
//log && log("global_env_", xtag("addr", global_env_.data()));
gc.visit_child(reason, &global_env_);
//log && log("result_");
result_.visit_gco_children(reason, gc);
}
} /*namespace scm*/
} /*namespace xo*/
/* end ParserStateMachine.cpp */