diff --git a/include/xo/expression/Apply.hpp b/include/xo/expression/Apply.hpp index b6db3a0c..1ed06e6b 100644 --- a/include/xo/expression/Apply.hpp +++ b/include/xo/expression/Apply.hpp @@ -63,6 +63,15 @@ namespace xo { return n; } + virtual ref::rp xform_layer(TransformFn xform_fn) override { + this->fn_ = fn_->xform_layer(xform_fn); + + for (auto & arg : argv_) + arg = arg->xform_layer(xform_fn); + + return xform_fn(this); + } + virtual void attach_envs(ref::brw p) override { fn_->attach_envs(p); diff --git a/include/xo/expression/Constant.hpp b/include/xo/expression/Constant.hpp index 50f4c2ba..ffc15967 100644 --- a/include/xo/expression/Constant.hpp +++ b/include/xo/expression/Constant.hpp @@ -56,6 +56,10 @@ namespace xo { return 1; } + virtual ref::rp xform_layer(TransformFn xform_fn) override { + return xform_fn(this); + } + virtual void display(std::ostream & os) const override { os << "short_name()) diff --git a/include/xo/expression/Expression.hpp b/include/xo/expression/Expression.hpp index d23a412e..84248555 100644 --- a/include/xo/expression/Expression.hpp +++ b/include/xo/expression/Expression.hpp @@ -35,7 +35,10 @@ namespace xo { **/ class Expression : public ref::Refcount { public: - using VisitFn = std::function)>; + using VisitFn = std::function + )>; + using TransformFn = std::function + (ref::brw)>; using TypeDescr = xo::reflect::TypeDescr; public: @@ -58,6 +61,9 @@ namespace xo { **/ virtual std::size_t visit_preorder(VisitFn visitor_fn) = 0; + /** traverse ast @ref visit_preorder but do not visit Lambdas **/ + virtual ref::rp xform_layer(TransformFn visitor_fn) = 0; + /** attach an environment to each lambda expression X in this subtree, * that will: * - resolve names matching X's arguments (formal parameters) to diff --git a/include/xo/expression/IfExpr.hpp b/include/xo/expression/IfExpr.hpp index fc8204a7..8091481e 100644 --- a/include/xo/expression/IfExpr.hpp +++ b/include/xo/expression/IfExpr.hpp @@ -60,12 +60,21 @@ namespace xo { visitor_fn(this); + n += this->test_->visit_preorder(visitor_fn); n += this->when_true_->visit_preorder(visitor_fn); n += this->when_false_->visit_preorder(visitor_fn); return n; } + virtual ref::rp xform_layer(TransformFn xform_fn) override { + this->test_ = this->test_->xform_layer(xform_fn); + this->when_true_ = this->when_true_->xform_layer(xform_fn); + this->when_false_= this->when_false_->xform_layer(xform_fn); + + return xform_fn(this); + } + virtual void attach_envs(ref::brw p) override { test_->attach_envs(p); when_true_->attach_envs(p); diff --git a/include/xo/expression/Lambda.hpp b/include/xo/expression/Lambda.hpp index 619913a1..18039982 100644 --- a/include/xo/expression/Lambda.hpp +++ b/include/xo/expression/Lambda.hpp @@ -68,6 +68,11 @@ namespace xo { return n; } + virtual ref::rp xform_layer(TransformFn /*xform_fn*/) override { + /* a layer is bounded by lambdas, don't enter them */ + return this; + } + virtual void attach_envs(ref::brw p) override { local_env_->assign_parent(p); } diff --git a/include/xo/expression/PrimitiveInterface.hpp b/include/xo/expression/PrimitiveInterface.hpp index c52eb979..70080607 100644 --- a/include/xo/expression/PrimitiveInterface.hpp +++ b/include/xo/expression/PrimitiveInterface.hpp @@ -57,6 +57,10 @@ namespace xo { return 1; } + virtual ref::rp xform_layer(TransformFn xform_fn) override { + return xform_fn(this); + } + virtual void attach_envs(ref::brw /*p*/) override {} private: diff --git a/include/xo/expression/Variable.hpp b/include/xo/expression/Variable.hpp index 3f45677e..713da66f 100644 --- a/include/xo/expression/Variable.hpp +++ b/include/xo/expression/Variable.hpp @@ -43,6 +43,10 @@ namespace xo { return 1; } + virtual ref::rp xform_layer(TransformFn xform_fn) override { + return xform_fn(this); + } + virtual void attach_envs(ref::brw /*p*/) override; virtual void display(std::ostream & os) const override; diff --git a/src/expression/Lambda.cpp b/src/expression/Lambda.cpp index 2f84b178..b2e4d1f3 100644 --- a/src/expression/Lambda.cpp +++ b/src/expression/Lambda.cpp @@ -4,6 +4,7 @@ #include "xo/reflect/TypeDescr.hpp" #include "xo/reflect/function/FunctionTdx.hpp" #include "xo/indentlog/print/vector.hpp" +#include namespace xo { using xo::reflect::TypeDescrBase; @@ -25,10 +26,12 @@ namespace xo { **/ std::vector arg_td_v; - arg_td_v.reserve(argv.size()); + { + arg_td_v.reserve(argv.size()); - for (const auto & arg : argv) { - arg_td_v.push_back(arg->valuetype()); + for (const auto & arg : argv) { + arg_td_v.push_back(arg->valuetype()); + } } auto function_info @@ -85,6 +88,30 @@ namespace xo { } ss << ")"; + /* regularize local_env+body: make sure exactly one instance + * (i.e. with object identity) of a Variable appears + * within one layer of a lambda body. + * + * Here 'layer' means excluding appearance in any nested lambdas + * (i.e. whether or not such appearance would resolve to the same + * memory location). + * + * Motivation is to unify Variables that would use the same + * binding_path to resolve their runtime location. + */ + { + std::map> var_map; + + for (const auto & arg : local_env_->argv()) { + /* each arg name can appear at most once + * in a particular lambda's parameter list + */ + assert(var_map.find(arg->name()) == var_map.end()); + + var_map[arg->name()] = arg; + } + } + this->type_str_ = ss.str(); this->free_var_set_ = this->calc_free_variables();