/* @file Lambda.cpp */ #include "Lambda.hpp" #include "xo/reflect/TypeDescr.hpp" #include "xo/reflect/function/FunctionTdx.hpp" #include "xo/indentlog/print/vector.hpp" #include namespace xo { using xo::reflect::TypeDescrBase; using xo::reflect::FunctionTdxInfo; using xo::ref::rp; using std::stringstream; namespace ast { rp Lambda::make(const std::string & name, const std::vector> & argv, const ref::rp & body) { using xo::reflect::FunctionTdx; /** assemble function type. * * NOTE: need this to be unique! **/ std::vector arg_td_v; { arg_td_v.reserve(argv.size()); for (const auto & arg : argv) { arg_td_v.push_back(arg->valuetype()); } } auto function_info = FunctionTdxInfo(body->valuetype(), arg_td_v, false /*!is_noexcept*/); TypeDescr lambda_td = TypeDescrBase::require_by_fn_info(function_info); rp env = LocalEnv::make(argv); rp retval = new Lambda(name, lambda_td, env, body); /* need two-phase construction b/c pointer cycle */ env->assign_origin(retval.get()); return retval; } /*make*/ std::set Lambda::calc_free_variables() const { std::set retval = body_->get_free_variables(); /* but remove formals. */ for (const auto & var : local_env_->argv()) retval.erase(var->name()); return retval; } /*calc_free_variables*/ Lambda::Lambda(const std::string & name, TypeDescr lambda_type, const rp & local_env, const ref::rp & body) : FunctionInterface(exprtype::lambda, lambda_type), name_{name}, body_{body}, local_env_{local_env} { stringstream ss; ss << "double"; ss << "("; for (std::size_t i = 0, n = this->n_arg(); i < n; ++i) { if (i > 0) ss << ","; ss << "double"; } 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(); body_->attach_envs(local_env_); } /*ctor*/ void Lambda::display(std::ostream & os) const { os << "argv()) << xtag("body", body_) << ">"; } /*display*/ } /*namespace ast*/ } /*namespace xo*/ /* end Lambda.cpp */