diff --git a/xo-expression2/include/xo/expression2/DLambdaExpr.hpp b/xo-expression2/include/xo/expression2/DLambdaExpr.hpp index b21a37ce..30ed2b74 100644 --- a/xo-expression2/include/xo/expression2/DLambdaExpr.hpp +++ b/xo-expression2/include/xo/expression2/DLambdaExpr.hpp @@ -63,6 +63,7 @@ namespace xo { DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } size_type n_args() const noexcept { return local_symtab_->size(); } + obj body_expr() const noexcept { return body_expr_; } // get_free_variables() // visit_preorder() diff --git a/xo-interpreter2/CMakeLists.txt b/xo-interpreter2/CMakeLists.txt index ae8893a6..8a1b1b3c 100644 --- a/xo-interpreter2/CMakeLists.txt +++ b/xo-interpreter2/CMakeLists.txt @@ -104,16 +104,17 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- # note: manual target; generated code committed to git -xo_add_genfacetimpl( - TARGET xo-interpreter2-facetimpl-procedure-closure - FACET_PKG xo_procedure2 - FACET Procedure - REPR Closure - INPUT idl/IProcedure_DClosure.json5 - OUTPUT_HPP_DIR include/xo/interpreter2 - OUTPUT_IMPL_SUBDIR detail - OUTPUT_CPP_DIR src/interpreter2 -) +# +#xo_add_genfacetimpl( +# TARGET xo-interpreter2-facetimpl-procedure-closure +# FACET_PKG xo_procedure2 +# FACET Procedure +# REPR Closure +# INPUT idl/IProcedure_DClosure.json5 +# OUTPUT_HPP_DIR include/xo/interpreter2 +# OUTPUT_IMPL_SUBDIR detail +# OUTPUT_CPP_DIR src/interpreter2 +#) # note: manual target; generated code committed to git xo_add_genfacetimpl( diff --git a/xo-interpreter2/include/xo/interpreter2/Closure.hpp b/xo-interpreter2/include/xo/interpreter2/Closure.hpp index 5bbeb9b8..dc9272fe 100644 --- a/xo-interpreter2/include/xo/interpreter2/Closure.hpp +++ b/xo-interpreter2/include/xo/interpreter2/Closure.hpp @@ -6,7 +6,7 @@ #pragma once #include "DClosure.hpp" -#include "detail/IProcedure_DClosure.hpp" +//#include "detail/IProcedure_DClosure.hpp" #include "detail/IGCObject_DClosure.hpp" #include "detail/IPrintable_DClosure.hpp" diff --git a/xo-interpreter2/include/xo/interpreter2/DVsmApplyClosureFrame.hpp b/xo-interpreter2/include/xo/interpreter2/DVsmApplyClosureFrame.hpp index 185b818f..a98d5713 100644 --- a/xo-interpreter2/include/xo/interpreter2/DVsmApplyClosureFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DVsmApplyClosureFrame.hpp @@ -28,6 +28,16 @@ namespace xo { VsmInstr cont, DLocalEnv * env); + /** create instance, using memory from @p mm **/ + static DVsmApplyClosureFrame * make(obj mm, + obj stack, + VsmInstr cont, + DLocalEnv * env); + + obj stack() const { return stack_; } + VsmInstr cont() const { return cont_; } + DLocalEnv * local_env() const { return local_env_; } + /** gcobject facet **/ std::size_t shallow_size() const noexcept; DVsmApplyClosureFrame * shallow_copy(obj mm) const noexcept; diff --git a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp index b4b46de2..a5df3504 100644 --- a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp @@ -30,10 +30,10 @@ namespace xo { obj parent() const noexcept { return parent_; } VsmInstr cont() const noexcept { return cont_; } - obj fn() const noexcept { return fn_; } + obj fn() const noexcept { return fn_; } DArray * args() const noexcept { return args_; } - void assign_fn(obj x) { this->fn_ = x; } + void assign_fn(obj x) { this->fn_ = x; } std::size_t shallow_size() const noexcept; DVsmApplyFrame * shallow_copy(obj mm) const noexcept; @@ -51,9 +51,13 @@ namespace xo { * * note: when initially created, this will be unpopulated; * don't know correct value until we evaluate - * expression in head position + * expression in head position. + * + * Must exhibit either: + * 1. AProcedure facet (runs natively) + * 2. AVsmProcedure facet (requires schematika runtime) **/ - obj fn_; + obj fn_; /** evaluated arguments (to target procedure) **/ DArray * args_; }; diff --git a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp index 67307700..569d9d48 100644 --- a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp @@ -176,16 +176,28 @@ namespace xo { **/ void _do_evalargs_op(); + /** call closure @ref fn_ with arguments @ref args_ **/ + void _do_call_closure_op(); + /** call primitive @ref fn_ with arguments @ref args_ **/ + void _do_call_primitive_op(); + + /** restore registers from stack frame + * (specifically: local_env_, stack_, cont_) + * after invoking a schematika closure + **/ + void _do_applycoda_op(); + + private: /* * Some registers are preserved by evaluation: * stack_ * cont_ + * local_env_ * * Other registers not preserved * pc_ * expr_ - * local_env_ * fn_ * args_ * value_ @@ -244,8 +256,8 @@ namespace xo { DGlobalEnv * global_env_ = nullptr; private: - /** function to call **/ - obj fn_; + /** evaluated function to call **/ + obj fn_; /** evaluated argument list **/ DArray * args_; diff --git a/xo-interpreter2/include/xo/interpreter2/VsmInstr.hpp b/xo-interpreter2/include/xo/interpreter2/VsmInstr.hpp index ec836c4d..bdde3ab7 100644 --- a/xo-interpreter2/include/xo/interpreter2/VsmInstr.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VsmInstr.hpp @@ -19,12 +19,20 @@ namespace xo { static VsmInstr c_apply; static VsmInstr c_evalargs; + /** restore registers after calling a schematika closure **/ + static VsmInstr c_applycoda; + vsm_opcode opcode() const noexcept { return opcode_; } private: vsm_opcode opcode_; }; + inline bool + operator==(VsmInstr x, VsmInstr y) noexcept { + return x.opcode() == y.opcode(); + } + inline std::ostream & operator<<(std::ostream & os, VsmInstr x) { os << x.opcode(); diff --git a/xo-interpreter2/include/xo/interpreter2/VsmOpcode.hpp b/xo-interpreter2/include/xo/interpreter2/VsmOpcode.hpp index 2c58c04f..ec21b988 100644 --- a/xo-interpreter2/include/xo/interpreter2/VsmOpcode.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VsmOpcode.hpp @@ -28,6 +28,11 @@ namespace xo { **/ evalargs, + /** Coda to restore vsm registers (local_env, stack, cont) + * after invoking a closure + **/ + applycoda, + /** sentinel, counts number of opcodes **/ N, }; diff --git a/xo-interpreter2/src/interpreter2/CMakeLists.txt b/xo-interpreter2/src/interpreter2/CMakeLists.txt index 4a477874..1ddb3207 100644 --- a/xo-interpreter2/src/interpreter2/CMakeLists.txt +++ b/xo-interpreter2/src/interpreter2/CMakeLists.txt @@ -21,7 +21,6 @@ set(SELF_SRCS IPrintable_DVsmApplyClosureFrame.cpp DClosure.cpp - IProcedure_DClosure.cpp IGCObject_DClosure.cpp IPrintable_DClosure.cpp diff --git a/xo-interpreter2/src/interpreter2/DClosure.cpp b/xo-interpreter2/src/interpreter2/DClosure.cpp index 8aa7997b..53015068 100644 --- a/xo-interpreter2/src/interpreter2/DClosure.cpp +++ b/xo-interpreter2/src/interpreter2/DClosure.cpp @@ -36,6 +36,14 @@ namespace xo { DClosure::apply_nocheck(obj rcx, const DArray * args) { + // control here only if you try to invoke a closure + // as a procedure. + // + // May support this later, but requires + // nesting VSM (because call consumes c++ stack) + // + // typically prefer trampoline built into VSM + (void)args; scope log(XO_DEBUG(true)); @@ -45,23 +53,6 @@ namespace xo { log && log(xtag("vsm_rcx.data", (void*)vsm_rcx.data())); - // we already checked this stuff before calling apply_nocheck() - // assert (n_args == args->size()); - -#ifdef NOT_YET - auto local_env - = DLocalEnv::_make(vsm_rcx->allocator(), - env_, - lambda_->local_symtab(), - args); -#endif - - // plan: - // 1. push current local environment to vsm stack_ - // 2. set expr_ to lambda body - // 2. set pc_ to eval - // 3. set cont_ to restore local_env_ - auto err_mm = vsm_rcx->error_allocator(); diff --git a/xo-interpreter2/src/interpreter2/DVsmApplyClosureFrame.cpp b/xo-interpreter2/src/interpreter2/DVsmApplyClosureFrame.cpp index b7962ebd..6a86ce27 100644 --- a/xo-interpreter2/src/interpreter2/DVsmApplyClosureFrame.cpp +++ b/xo-interpreter2/src/interpreter2/DVsmApplyClosureFrame.cpp @@ -7,6 +7,7 @@ namespace xo { using xo::mm::AGCObject; + using xo::reflect::typeseq; namespace scm { @@ -18,6 +19,18 @@ namespace xo { local_env_{local_env} {} + DVsmApplyClosureFrame * + DVsmApplyClosureFrame::make(obj mm, + obj stack, + VsmInstr cont, + DLocalEnv * local_env) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DVsmApplyClosureFrame)); + + return new (mem) DVsmApplyClosureFrame(stack, cont, local_env); + } + std::size_t DVsmApplyClosureFrame::shallow_size() const noexcept { diff --git a/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp b/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp deleted file mode 100644 index b41c7be1..00000000 --- a/xo-interpreter2/src/interpreter2/IProcedure_DClosure.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/** @file IProcedure_DClosure.cpp - * - * Generated automagically from ingredients: - * 1. code generator: - * [xo-facet/codegen/genfacet] - * arguments: - * --input [idl/IProcedure_DClosure.json5] - * 2. jinja2 template for abstract facet .hpp file: - * [iface_facet_any.hpp.j2] - * 3. idl for facet methods - * [idl/IProcedure_DClosure.json5] -**/ - -#include "detail/IProcedure_DClosure.hpp" - -namespace xo { - namespace scm { - auto - IProcedure_DClosure::is_nary(const DClosure & self) noexcept -> bool - { - return self.is_nary(); - } - - auto - IProcedure_DClosure::n_args(const DClosure & self) noexcept -> std::int32_t - { - return self.n_args(); - } - - auto - IProcedure_DClosure::apply_nocheck(DClosure & self, obj rcx, const DArray * args) -> obj - { - return self.apply_nocheck(rcx, args); - } - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end IProcedure_DClosure.cpp */ diff --git a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp index 1242375a..8ff78ae0 100644 --- a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp +++ b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp @@ -6,6 +6,7 @@ #include "VirtualSchematikaMachine.hpp" #include "VsmApplyFrame.hpp" #include "VsmEvalArgsFrame.hpp" +#include "VsmApplyClosureFrame.hpp" #include "VsmRcx.hpp" #include "Closure.hpp" #include @@ -164,9 +165,9 @@ namespace xo { log && log(xtag("pc", pc_), xtag("cont", cont_)); - obj stack_pr - = (FacetRegistry::instance() - .try_variant(stack_)); + obj stack_pr = stack_.to_facet(); +// = (FacetRegistry::instance() +// .try_variant(stack_)); if (stack_pr) log && log(xtag("stack", stack_pr)); @@ -184,6 +185,9 @@ namespace xo { case vsm_opcode::evalargs: _do_evalargs_op(); break; + case vsm_opcode::applycoda: + _do_applycoda_op(); + break; } return true; @@ -370,10 +374,68 @@ namespace xo { // TODO: check argument types - this->value_ = VsmResult(fn_.apply_nocheck(rcx_.to_op(), args_)); - this->pc_ = cont_; + auto closure = obj::from(fn_); - return; + if (closure) { + _do_call_closure_op(); + return; + } else { + _do_call_closure_op(); + return; + } + } + + void + VirtualSchematikaMachine::_do_call_closure_op() + { + // We need to preserve registers while evaluating + // lambda body + + auto closure = obj::from(fn_); + + // TODO: for tail recursion: + // check whether stack_ already refers to a + // DVsmApplyClosureFrame instance, in which case + // we can just refer to it instead of pushing a new one + + if (cont_ == VsmInstr::c_applycoda) { + // we are making a tail call. + // No need to preserve (stack, cont, local_env), + // since continuation will restore on top of them + // frame top stackframe anyway + } else { + obj frame( + DVsmApplyClosureFrame::make(mm_.to_op(), + stack_, + cont_, + local_env_)); + + // push frame w/ saved vsm registers + this->stack_ = frame; + this->cont_ = VsmInstr::c_applycoda; + } + + auto lambda = closure->lambda(); + + auto local_env + = DLocalEnv::_make(mm_.to_op(), + local_env_, + lambda->local_symtab(), + args_); + + this->local_env_ = local_env; + this->expr_ = lambda->body_expr(); + this->pc_ = VsmInstr::c_eval; + } + + void + VirtualSchematikaMachine::_do_call_primitive_op() + { + auto fn = fn_.to_facet(); + + this->value_ = VsmResult(fn.apply_nocheck(rcx_.to_op(), args_)); + this->pc_ = cont_; } void @@ -434,10 +496,11 @@ namespace xo { = evalargs_frame->apply_expr(); if (i_arg == -1) { - auto fn = value.to_facet(); + bool is_native_fn = value.to_facet(); + bool is_closure = obj::from(value); - if (fn) { - apply_frame->assign_fn(fn); + if (is_native_fn || is_closure) { + apply_frame->assign_fn(value); i_arg = evalargs_frame->increment_arg(); @@ -493,6 +556,22 @@ namespace xo { assert(false); } + void + VirtualSchematikaMachine::_do_applycoda_op() + { + // see DVsmApplyClosureFrame + + auto frame = obj::from(stack_); + + assert(frame); + + this->stack_ = frame->stack(); + this->local_env_ = frame->local_env(); + this->pc_ = frame->cont(); + + // not implemented + assert(false); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-interpreter2/src/interpreter2/VsmInstr.cpp b/xo-interpreter2/src/interpreter2/VsmInstr.cpp index ddcc8c20..02ac8325 100644 --- a/xo-interpreter2/src/interpreter2/VsmInstr.cpp +++ b/xo-interpreter2/src/interpreter2/VsmInstr.cpp @@ -15,6 +15,7 @@ namespace xo { case vsm_opcode::eval: return "eval"; case vsm_opcode::apply: return "apply"; case vsm_opcode::evalargs: return "evalargs"; + case vsm_opcode::applycoda: return "applycoda"; case vsm_opcode::N: break; } @@ -33,6 +34,9 @@ namespace xo { VsmInstr VsmInstr::c_evalargs = VsmInstr(vsm_opcode::evalargs); + + VsmInstr + VsmInstr::c_applycoda = VsmInstr(vsm_opcode::applycoda); } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp b/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp index f945956e..1548aeaf 100644 --- a/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp +++ b/xo-interpreter2/src/interpreter2/interpreter2_register_facets.cpp @@ -59,9 +59,9 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); - FacetRegistry::register_impl(); - FacetRegistry::register_impl(); - FacetRegistry::register_impl(); +// FacetRegistry::register_impl(); +// FacetRegistry::register_impl(); +// FacetRegistry::register_impl(); // RuntimeContext // \- VsmRcx