155 lines
5 KiB
C++
155 lines
5 KiB
C++
/* @file Lambda.cpp */
|
|
|
|
#include "Lambda.hpp"
|
|
#include "xo/reflect/TypeDescr.hpp"
|
|
#include "xo/reflect/function/FunctionTdx.hpp"
|
|
#include "xo/indentlog/print/vector.hpp"
|
|
#include <map>
|
|
|
|
namespace xo {
|
|
using xo::reflect::TypeDescrBase;
|
|
using xo::reflect::FunctionTdxInfo;
|
|
using xo::ref::rp;
|
|
using std::stringstream;
|
|
|
|
namespace ast {
|
|
rp<Lambda>
|
|
Lambda::make(const std::string & name,
|
|
const std::vector<rp<Variable>> & argv,
|
|
const ref::rp<Expression> & body)
|
|
{
|
|
using xo::reflect::FunctionTdx;
|
|
|
|
/** assemble function type.
|
|
*
|
|
* NOTE: need this to be unique!
|
|
**/
|
|
|
|
std::vector<TypeDescr> 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<LocalEnv> env = LocalEnv::make(argv);
|
|
|
|
rp<Lambda> 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<std::string>
|
|
Lambda::calc_free_variables() const
|
|
{
|
|
std::set<std::string> 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<LocalEnv> & local_env,
|
|
const ref::rp<Expression> & 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<std::string, rp<Variable>> 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;
|
|
}
|
|
|
|
body_ = body_->xform_layer
|
|
([&var_map](ref::brw<Expression> x) -> ref::rp<Expression>
|
|
{
|
|
if (x->extype() == exprtype::variable) {
|
|
ref::brw<Variable> var = Variable::from(x);
|
|
|
|
auto ix = var_map.find(var->name());
|
|
if (ix == var_map.end()) {
|
|
/* add to var_map */
|
|
|
|
var_map[var->name()] = var.get();
|
|
|
|
return var.get();
|
|
} else {
|
|
/* substitute already-encountered var_map[] member */
|
|
return ix->second;
|
|
}
|
|
} else {
|
|
return x.get();
|
|
}
|
|
});
|
|
}
|
|
|
|
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 << "<Lambda"
|
|
<< xtag("name", name_)
|
|
<< xtag("argv", local_env_->argv())
|
|
<< xtag("body", body_)
|
|
<< ">";
|
|
} /*display*/
|
|
} /*namespace ast*/
|
|
} /*namespace xo*/
|
|
|
|
|
|
/* end Lambda.cpp */
|