Add 'xo-expression/' from commit '5ac3c03a0c'
git-subtree-dir: xo-expression git-subtree-mainline:d0f5ccc1cegit-subtree-split:5ac3c03a0c
This commit is contained in:
commit
aecabbb144
46 changed files with 3241 additions and 0 deletions
72
xo-expression/src/expression/Apply.cpp
Normal file
72
xo-expression/src/expression/Apply.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* @file Apply.cpp */
|
||||
|
||||
#include "Apply.hpp"
|
||||
#include "Primitive.hpp"
|
||||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
rp<Apply>
|
||||
Apply::make(const rp<Expression> & fn,
|
||||
const std::vector<rp<Expression>> & argv)
|
||||
{
|
||||
/* extract result type from function type */
|
||||
TypeDescr fn_valuetype = fn->valuetype();
|
||||
|
||||
if (!fn_valuetype->is_function()) {
|
||||
throw std::runtime_error
|
||||
(tostr("Apply::make: found expression F in function position,"
|
||||
" with value-type FT where a function type expected",
|
||||
xtag("FT", fn_valuetype->short_name()),
|
||||
xtag("F", fn_valuetype)));
|
||||
}
|
||||
|
||||
TypeDescr fn_retval_type = fn_valuetype->fn_retval();
|
||||
|
||||
return new Apply(fn_retval_type, fn, argv);
|
||||
}
|
||||
|
||||
rp<Apply>
|
||||
Apply::make_add2_f64(const rp<Expression> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
{
|
||||
return Apply::make(Primitive_f64::make_add2_f64(),
|
||||
{lhs, rhs});
|
||||
}
|
||||
|
||||
rp<Apply>
|
||||
Apply::make_sub2_f64(const rp<Expression> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
{
|
||||
return Apply::make(Primitive_f64::make_sub2_f64(),
|
||||
{lhs, rhs});
|
||||
}
|
||||
|
||||
rp<Apply>
|
||||
Apply::make_mul2_f64(const rp<Expression> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
{
|
||||
return Apply::make(Primitive_f64::make_mul2_f64(),
|
||||
{lhs, rhs});
|
||||
}
|
||||
|
||||
rp<Apply>
|
||||
Apply::make_div2_f64(const rp<Expression> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
{
|
||||
return Apply::make(Primitive_f64::make_div2_f64(),
|
||||
{lhs, rhs});
|
||||
}
|
||||
|
||||
void
|
||||
Apply::display(std::ostream & os) const {
|
||||
os << "<Apply"
|
||||
<< xtag("fn", fn_)
|
||||
<< xtag("argv", argv_)
|
||||
<< ">";
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Apply.cpp */
|
||||
93
xo-expression/src/expression/AssignExpr.cpp
Normal file
93
xo-expression/src/expression/AssignExpr.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* file AssignExpr.cpp
|
||||
*
|
||||
* author: Roland Conybeare
|
||||
*/
|
||||
|
||||
#include "AssignExpr.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
rp<AssignExpr>
|
||||
AssignExpr::make(const rp<Variable> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
{
|
||||
return new AssignExpr(lhs, rhs);
|
||||
}
|
||||
|
||||
AssignExpr::AssignExpr(const rp<Variable> & lhs,
|
||||
const rp<Expression> & rhs)
|
||||
: Expression(exprtype::assign, rhs->valuetype()),
|
||||
lhs_{lhs}, rhs_{rhs}
|
||||
{
|
||||
this->free_var_set_ = this->calc_free_variables();
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
AssignExpr::calc_free_variables() const
|
||||
{
|
||||
std::set<std::string> retval = lhs_->get_free_variables();
|
||||
|
||||
std::set<std::string> tmp = rhs_->get_free_variables();
|
||||
|
||||
for (const auto & name : tmp)
|
||||
retval.insert(name);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
AssignExpr::get_free_variables() const {
|
||||
return free_var_set_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
AssignExpr::visit_preorder(VisitFn visitor_fn) {
|
||||
std::size_t n = 1;
|
||||
|
||||
visitor_fn(this);
|
||||
|
||||
n += lhs_->visit_preorder(visitor_fn);
|
||||
n += rhs_->visit_preorder(visitor_fn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
AssignExpr::visit_layer(VisitFn visitor_fn) {
|
||||
std::size_t n = 1;
|
||||
|
||||
visitor_fn(this);
|
||||
|
||||
n += lhs_->visit_layer(visitor_fn);
|
||||
n += rhs_->visit_layer(visitor_fn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
rp<Expression>
|
||||
AssignExpr::xform_layer(TransformFn xform_fn) {
|
||||
this->lhs_ = Variable::from(lhs_->xform_layer(xform_fn)).promote();
|
||||
this->rhs_ = rhs_->xform_layer(xform_fn);
|
||||
|
||||
return xform_fn(this);
|
||||
}
|
||||
|
||||
void
|
||||
AssignExpr::attach_envs(ref::brw<Environment> p) {
|
||||
lhs_->attach_envs(p);
|
||||
rhs_->attach_envs(p);
|
||||
}
|
||||
|
||||
void
|
||||
AssignExpr::display(std::ostream & os) const {
|
||||
os << "<Assign"
|
||||
<< xtag("lhs", lhs_)
|
||||
<< xtag("rhs", rhs_)
|
||||
<< ">";
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end AssignExpr.cpp */
|
||||
24
xo-expression/src/expression/CMakeLists.txt
Normal file
24
xo-expression/src/expression/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# expression/CMakeLists.txt
|
||||
|
||||
set(SELF_LIB xo_expression)
|
||||
set(SELF_SRCS
|
||||
GeneralizedExpression.cpp
|
||||
Expression.cpp
|
||||
DefineExpr.cpp
|
||||
AssignExpr.cpp
|
||||
Apply.cpp
|
||||
Lambda.cpp
|
||||
Variable.cpp
|
||||
IfExpr.cpp
|
||||
Sequence.cpp
|
||||
LocalEnv.cpp
|
||||
ConvertExpr.cpp
|
||||
Primitive.cpp
|
||||
)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
xo_dependency(${SELF_LIB} reflect)
|
||||
#xo_dependency(${SELF_LIB} indentlog)
|
||||
#xo_dependency(${SELF_LIB} subsys)
|
||||
|
||||
# end CMakeLists.txt
|
||||
53
xo-expression/src/expression/ConvertExpr.cpp
Normal file
53
xo-expression/src/expression/ConvertExpr.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* file ConvertExpr.cpp
|
||||
*
|
||||
* author: Roland Conybeare
|
||||
*/
|
||||
|
||||
#include "ConvertExpr.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
rp<ConvertExpr>
|
||||
ConvertExpr::make(TypeDescr dest_type,
|
||||
rp<Expression> arg)
|
||||
{
|
||||
return new ConvertExpr(dest_type,
|
||||
std::move(arg));
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
ConvertExpr::get_free_variables() const {
|
||||
if (this->arg_)
|
||||
return this->arg_->get_free_variables();
|
||||
else
|
||||
return std::set<std::string>();
|
||||
}
|
||||
|
||||
void
|
||||
ConvertExpr::display(std::ostream & os) const {
|
||||
os << "<Convert"
|
||||
<< xtag("dest_type", this->valuetype()->short_name())
|
||||
<< xtag("arg", arg_)
|
||||
<< ">";
|
||||
}
|
||||
|
||||
// ----- ConvertExprAccess -----
|
||||
|
||||
rp<ConvertExprAccess>
|
||||
ConvertExprAccess::make(TypeDescr dest_type,
|
||||
rp<Expression> arg)
|
||||
{
|
||||
return new ConvertExprAccess(dest_type,
|
||||
std::move(arg));
|
||||
}
|
||||
|
||||
rp<ConvertExprAccess>
|
||||
ConvertExprAccess::make_empty() {
|
||||
return new ConvertExprAccess(nullptr /*dest_type*/,
|
||||
nullptr /*arg*/);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end ConvertExpr.cpp */
|
||||
99
xo-expression/src/expression/DefineExpr.cpp
Normal file
99
xo-expression/src/expression/DefineExpr.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* file DefineExpr.cpp
|
||||
*
|
||||
* author: Roland Conybeare
|
||||
*/
|
||||
|
||||
#include "DefineExpr.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
rp<DefineExpr>
|
||||
DefineExpr::make(std::string lhs_name,
|
||||
rp<Expression> rhs)
|
||||
{
|
||||
TypeDescr rhs_valuetype = nullptr;
|
||||
|
||||
if (rhs)
|
||||
rhs_valuetype = rhs->valuetype();
|
||||
|
||||
return new DefineExpr(rhs_valuetype,
|
||||
std::move(lhs_name),
|
||||
std::move(rhs));
|
||||
} /*make*/
|
||||
|
||||
DefineExpr::DefineExpr(TypeDescr rhs_valuetype,
|
||||
std::string lhs_name,
|
||||
rp<Expression> rhs)
|
||||
: Expression(exprtype::define, rhs_valuetype),
|
||||
lhs_name_{std::move(lhs_name)},
|
||||
rhs_{std::move(rhs)}
|
||||
{
|
||||
this->free_var_set_ = this->calc_free_variables();
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
DefineExpr::calc_free_variables() const
|
||||
{
|
||||
std::set<std::string> retval;
|
||||
|
||||
if (rhs_)
|
||||
retval = rhs_->get_free_variables();
|
||||
|
||||
/* but remove this variable */
|
||||
if (!this->lhs_name().empty())
|
||||
retval.erase(this->lhs_name());
|
||||
|
||||
return retval;
|
||||
} /*calc_free_variables*/
|
||||
|
||||
void
|
||||
DefineExpr::display(std::ostream & os) const {
|
||||
os << "<Define"
|
||||
<< xtag("name", lhs_name_)
|
||||
<< xtag("rhs", rhs_)
|
||||
<< ">";
|
||||
} /*display*/
|
||||
|
||||
// ----- DefineExprAccess -----
|
||||
|
||||
rp<DefineExprAccess>
|
||||
DefineExprAccess::make(std::string lhs_name,
|
||||
rp<Expression> rhs)
|
||||
{
|
||||
TypeDescr rhs_valuetype = nullptr;
|
||||
|
||||
if (rhs)
|
||||
rhs_valuetype = rhs->valuetype();
|
||||
|
||||
return new DefineExprAccess(rhs_valuetype,
|
||||
std::move(lhs_name),
|
||||
std::move(rhs));
|
||||
}
|
||||
|
||||
rp<DefineExprAccess>
|
||||
DefineExprAccess::make_empty()
|
||||
{
|
||||
return new DefineExprAccess(nullptr /*rhs_valuetype*/,
|
||||
"" /*lhs_name*/,
|
||||
nullptr /*rhs*/);
|
||||
}
|
||||
|
||||
void
|
||||
DefineExprAccess::assign_rhs(const rp<Expression> & x)
|
||||
{
|
||||
assert(x);
|
||||
|
||||
this->rhs_ = x;
|
||||
|
||||
if (x) {
|
||||
this->assign_valuetype(x->valuetype());
|
||||
}
|
||||
|
||||
this->free_var_set_ = this->calc_free_variables();
|
||||
}
|
||||
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end DefineExpr.cpp */
|
||||
11
xo-expression/src/expression/Expression.cpp
Normal file
11
xo-expression/src/expression/Expression.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/* @file Expression.cpp */
|
||||
|
||||
#include "Expression.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Expression.cpp */
|
||||
14
xo-expression/src/expression/GeneralizedExpression.cpp
Normal file
14
xo-expression/src/expression/GeneralizedExpression.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* @file GeneralizedExpression.cpp */
|
||||
|
||||
#include "GeneralizedExpression.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
std::string
|
||||
GeneralizedExpression::display_string() const {
|
||||
return tostr(*this);
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end GeneralizedExpression.cpp */
|
||||
45
xo-expression/src/expression/IfExpr.cpp
Normal file
45
xo-expression/src/expression/IfExpr.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* @file IfExpr.cpp */
|
||||
|
||||
#include "IfExpr.hpp"
|
||||
#include "xo/indentlog/print/vector.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
rp<IfExpr>
|
||||
IfExpr::make(const rp<Expression> & test,
|
||||
const rp<Expression> & when_true,
|
||||
const rp<Expression> & when_false)
|
||||
{
|
||||
/** TODO: verify test returns _boolean_ type **/
|
||||
|
||||
if (when_true->valuetype() != when_false->valuetype()) {
|
||||
throw std::runtime_error
|
||||
(tostr("IfExpr::make:"
|
||||
" types {T1,T2} found for branches of if-expr"
|
||||
" where equal types expected",
|
||||
xtag("T1", when_true->valuetype()->canonical_name()),
|
||||
xtag("T2", when_false->valuetype()->canonical_name())));
|
||||
}
|
||||
|
||||
/* arbitrary choice here */
|
||||
auto ifexpr_type = when_true->valuetype();
|
||||
|
||||
return new IfExpr(ifexpr_type,
|
||||
test,
|
||||
when_true,
|
||||
when_false);
|
||||
} /*make*/
|
||||
|
||||
void
|
||||
IfExpr::display(std::ostream & os) const {
|
||||
os << "<IfExpr"
|
||||
<< xtag("test", test_)
|
||||
<< xtag("when_true", when_true_)
|
||||
<< xtag("when_false", when_false_)
|
||||
<< ">";
|
||||
} /*display*/
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end IfExpr.cpp */
|
||||
361
xo-expression/src/expression/Lambda.cpp
Normal file
361
xo-expression/src/expression/Lambda.cpp
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/* @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>
|
||||
#include <sstream>
|
||||
|
||||
namespace xo {
|
||||
using xo::reflect::TypeDescr;
|
||||
using xo::reflect::TypeDescrBase;
|
||||
using xo::reflect::FunctionTdxInfo;
|
||||
using std::stringstream;
|
||||
|
||||
namespace ast {
|
||||
TypeDescr
|
||||
Lambda::assemble_lambda_td(const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
{
|
||||
if (!body)
|
||||
return nullptr;
|
||||
|
||||
/** 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);
|
||||
|
||||
return lambda_td;
|
||||
}
|
||||
|
||||
std::string
|
||||
Lambda::assemble_type_str(TypeDescr lambda_td) {
|
||||
assert(lambda_td);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << lambda_td->fn_retval()->short_name()
|
||||
<< "(";
|
||||
|
||||
for (std::size_t i = 0, n = lambda_td->n_fn_arg(); i < n; ++i) {
|
||||
if (i > 0)
|
||||
ss << ",";
|
||||
ss << lambda_td->fn_arg(i)->short_name();
|
||||
}
|
||||
ss << ")";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
rp<Lambda>
|
||||
Lambda::make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
{
|
||||
using xo::reflect::FunctionTdx;
|
||||
|
||||
rp<LocalEnv> env = LocalEnv::make(argv);
|
||||
|
||||
TypeDescr lambda_td = assemble_lambda_td(argv, body);
|
||||
|
||||
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*/
|
||||
|
||||
std::map<std::string, rp<Variable>>
|
||||
Lambda::regularize_layer_vars()
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
this->body_
|
||||
= (body_->xform_layer
|
||||
([&var_map](ref::brw<Expression> x) -> 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, copy to ensure Variable
|
||||
* not shared with any other layer
|
||||
*/
|
||||
|
||||
var_map[var->name()] = Variable::copy(var);
|
||||
|
||||
return var.get();
|
||||
} else {
|
||||
/* substitute already-encountered var_map[] member */
|
||||
return ix->second.get();
|
||||
}
|
||||
} else {
|
||||
return x.get();
|
||||
}
|
||||
}));
|
||||
|
||||
return var_map;
|
||||
} /*regularize_layer_vars*/
|
||||
|
||||
void
|
||||
Lambda::complete_assembly_from_body() {
|
||||
if (body_) {
|
||||
TypeDescr lambda_td
|
||||
= assemble_lambda_td(this->local_env_->argv(), body_);
|
||||
|
||||
if (lambda_td)
|
||||
this->type_str_ = assemble_type_str(lambda_td);
|
||||
|
||||
this->layer_var_map_ = this->regularize_layer_vars();
|
||||
|
||||
this->free_var_set_ = this->calc_free_variables();
|
||||
|
||||
std::map<std::string, ref::brw<Lambda>> nested_lambda_map;
|
||||
{
|
||||
this->body_->visit_layer
|
||||
([&nested_lambda_map]
|
||||
(ref::brw<Expression> expr)
|
||||
{
|
||||
if (expr->extype() == exprtype::lambda) {
|
||||
ref::brw<Lambda> lm = Lambda::from(expr);
|
||||
|
||||
nested_lambda_map[lm->name()] = lm.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
this->nested_lambda_map_ = std::move(nested_lambda_map);
|
||||
|
||||
/* establish the set of captured local vars.
|
||||
* These are any formal parameters that appear free in
|
||||
* any layer of a nested lambda.
|
||||
*/
|
||||
std::set<std::string> captured_var_set;
|
||||
{
|
||||
for (const auto & ix : nested_lambda_map_) {
|
||||
std::set<std::string> nested_free_var_set
|
||||
= ix.second->get_free_variables();
|
||||
|
||||
for (const auto & jx : nested_free_var_set) {
|
||||
/* check whether variable *jx is one of this lambda's
|
||||
* formals
|
||||
*/
|
||||
auto bind = this->local_env_->lookup_local_binding(jx);
|
||||
|
||||
if (bind.i_link_ == 0) {
|
||||
/* yup, it's a formal parameter of this lambda */
|
||||
captured_var_set.insert(jx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->captured_var_set_ = std::move(captured_var_set);
|
||||
|
||||
/* in particular:
|
||||
* - establish binding path (intrusively) for each variable
|
||||
* assigns Variable::path_
|
||||
*/
|
||||
this->body_->attach_envs(local_env_);
|
||||
}
|
||||
}
|
||||
|
||||
Lambda::Lambda(const std::string & name,
|
||||
TypeDescr lambda_td,
|
||||
const rp<LocalEnv> & local_env,
|
||||
const rp<Expression> & body)
|
||||
: FunctionInterface(exprtype::lambda, lambda_td),
|
||||
name_{name},
|
||||
body_{body},
|
||||
local_env_{local_env}
|
||||
{
|
||||
#ifdef OBSOLETE
|
||||
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 << ")";
|
||||
#endif
|
||||
|
||||
if (lambda_td)
|
||||
this->type_str_ = assemble_type_str(lambda_td);
|
||||
|
||||
/* ensure variables are unique within layer for this lambda */
|
||||
this->layer_var_map_ = this->regularize_layer_vars();
|
||||
|
||||
this->free_var_set_ = this->calc_free_variables();
|
||||
|
||||
std::map<std::string, ref::brw<Lambda>> nested_lambda_map;
|
||||
{
|
||||
this->body_->visit_layer
|
||||
([&nested_lambda_map]
|
||||
(ref::brw<Expression> expr)
|
||||
{
|
||||
if (expr->extype() == exprtype::lambda) {
|
||||
ref::brw<Lambda> lm = Lambda::from(expr);
|
||||
|
||||
nested_lambda_map[lm->name()] = lm.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
this->nested_lambda_map_ = std::move(nested_lambda_map);
|
||||
|
||||
/* establish the set of captured local vars.
|
||||
* These are any formal parameters that appear free in
|
||||
* any layer of a nested lambda.
|
||||
*/
|
||||
std::set<std::string> captured_var_set;
|
||||
{
|
||||
for (const auto & ix : nested_lambda_map_) {
|
||||
std::set<std::string> nested_free_var_set
|
||||
= ix.second->get_free_variables();
|
||||
|
||||
for (const auto & jx : nested_free_var_set) {
|
||||
/* check whether variable *jx is one of this lambda's
|
||||
* formals
|
||||
*/
|
||||
auto bind = this->local_env_->lookup_local_binding(jx);
|
||||
|
||||
if (bind.i_link_ == 0) {
|
||||
/* yup, it's a formal parameter of this lambda */
|
||||
captured_var_set.insert(jx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->captured_var_set_ = std::move(captured_var_set);
|
||||
|
||||
/* in particular:
|
||||
* - establish binding path (intrusively) for each variable
|
||||
* assigns Variable::path_
|
||||
*/
|
||||
this->body_->attach_envs(local_env_);
|
||||
|
||||
} /*ctor*/
|
||||
|
||||
void
|
||||
Lambda::attach_envs(ref::brw<Environment> p) {
|
||||
local_env_->assign_parent(p);
|
||||
|
||||
/** establish a binding path for each variable **/
|
||||
}
|
||||
|
||||
void
|
||||
Lambda::display(std::ostream & os) const {
|
||||
os << "<Lambda"
|
||||
<< xtag("name", name_)
|
||||
<< xtag("argv", local_env_->argv())
|
||||
<< xtag("body", body_)
|
||||
<< ">";
|
||||
} /*display*/
|
||||
|
||||
// ----- Lambda Access -----
|
||||
|
||||
rp<LambdaAccess>
|
||||
LambdaAccess::make(const std::string & name,
|
||||
const std::vector<rp<Variable>> & argv,
|
||||
const rp<Expression> & body)
|
||||
{
|
||||
TypeDescr lambda_td = assemble_lambda_td(argv, body);
|
||||
rp<LocalEnv> env = LocalEnv::make(argv);
|
||||
|
||||
rp<LambdaAccess> retval
|
||||
= new LambdaAccess(name,
|
||||
lambda_td,
|
||||
env,
|
||||
body);
|
||||
|
||||
/* need two-phase construction b/c pointer cycle */
|
||||
env->assign_origin(retval.get());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
rp<LambdaAccess>
|
||||
LambdaAccess::make_empty()
|
||||
{
|
||||
return new LambdaAccess("" /*name*/,
|
||||
nullptr /*lambda_td*/,
|
||||
nullptr /*local_env*/,
|
||||
nullptr /*body*/);
|
||||
}
|
||||
|
||||
LambdaAccess::LambdaAccess(const std::string & name,
|
||||
TypeDescr lambda_td,
|
||||
const rp<LocalEnv> & local_env,
|
||||
const rp<Expression> & body)
|
||||
: Lambda(name, lambda_td, local_env, body)
|
||||
{}
|
||||
|
||||
void
|
||||
LambdaAccess::assign_body(const rp<Expression> & body) {
|
||||
this->body_ = body;
|
||||
|
||||
this->complete_assembly_from_body();
|
||||
}
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Lambda.cpp */
|
||||
44
xo-expression/src/expression/LocalEnv.cpp
Normal file
44
xo-expression/src/expression/LocalEnv.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* file LocalEnv.cpp
|
||||
*
|
||||
* author: Roland Conybeare
|
||||
*/
|
||||
|
||||
#include "LocalEnv.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
binding_path
|
||||
LocalEnv::lookup_local_binding(const std::string & vname) const
|
||||
{
|
||||
int j_slot = 0;
|
||||
for (const auto & arg : argv_) {
|
||||
if (arg->name() == vname)
|
||||
return { 0 /*i_link*/, j_slot };
|
||||
++j_slot;
|
||||
}
|
||||
|
||||
return { -2 /*i_link: sentinel*/, 0 };
|
||||
} /*lookup_local_binding*/
|
||||
|
||||
binding_path
|
||||
LocalEnv::lookup_binding(const std::string & vname) const
|
||||
{
|
||||
{
|
||||
auto local = this->lookup_local_binding(vname);
|
||||
|
||||
if (local.i_link_ == 0)
|
||||
return local;
|
||||
}
|
||||
|
||||
auto free = parent_env_->lookup_binding(vname);
|
||||
|
||||
if (free.i_link_ == -1)
|
||||
return free;
|
||||
else
|
||||
return { free.i_link_ + 1, free.j_slot_ };
|
||||
} /*lookup_binding*/
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end LocalEnv.cpp */
|
||||
89
xo-expression/src/expression/Primitive.cpp
Normal file
89
xo-expression/src/expression/Primitive.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* @file Primitive.cpp */
|
||||
|
||||
#include "Primitive.hpp"
|
||||
|
||||
extern "C" {
|
||||
double
|
||||
add2_f64(double x, double y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
double
|
||||
sub2_f64(double x, double y) {
|
||||
return x - y;
|
||||
}
|
||||
|
||||
double
|
||||
mul2_f64(double x, double y) {
|
||||
return x * y;
|
||||
}
|
||||
|
||||
double
|
||||
div2_f64(double x, double y) {
|
||||
return x / y;
|
||||
}
|
||||
}
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
auto
|
||||
Primitive_f64::make_add2_f64() -> rp<PrimitiveType>
|
||||
{
|
||||
static rp<PrimitiveType> s_retval;
|
||||
|
||||
if (!s_retval)
|
||||
s_retval = Primitive::make("add2_f64",
|
||||
&add2_f64,
|
||||
true /*explicit_symbol_def*/,
|
||||
llvmintrinsic::fp_add);
|
||||
|
||||
return s_retval;
|
||||
}
|
||||
|
||||
auto
|
||||
Primitive_f64::make_sub2_f64() -> rp<PrimitiveType>
|
||||
{
|
||||
static rp<PrimitiveType> s_retval;
|
||||
|
||||
if (!s_retval)
|
||||
s_retval = Primitive::make("sub2_f64",
|
||||
&sub2_f64,
|
||||
true /*explicit_symbol_def*/,
|
||||
llvmintrinsic::fp_sub);
|
||||
|
||||
return s_retval;
|
||||
}
|
||||
|
||||
auto
|
||||
Primitive_f64::make_mul2_f64() -> rp<PrimitiveType>
|
||||
{
|
||||
static rp<PrimitiveType> s_retval;
|
||||
|
||||
if (!s_retval)
|
||||
s_retval = Primitive::make("mul2_f64",
|
||||
&mul2_f64,
|
||||
true /*explicit_symbol_def*/,
|
||||
llvmintrinsic::fp_mul);
|
||||
|
||||
return s_retval;
|
||||
}
|
||||
|
||||
auto
|
||||
Primitive_f64::make_div2_f64() -> rp<PrimitiveType>
|
||||
{
|
||||
static rp<PrimitiveType> s_retval;
|
||||
|
||||
if (!s_retval)
|
||||
s_retval = Primitive::make("div2_f64",
|
||||
&div2_f64,
|
||||
true /*explicit_symbol_def*/,
|
||||
llvmintrinsic::fp_div);
|
||||
|
||||
return s_retval;
|
||||
}
|
||||
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Primitive.cpp */
|
||||
78
xo-expression/src/expression/Sequence.cpp
Normal file
78
xo-expression/src/expression/Sequence.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* @file Sequence.cpp */
|
||||
|
||||
#include "Sequence.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
std::set<std::string>
|
||||
Sequence::get_free_variables() const {
|
||||
std::set<std::string> retval;
|
||||
|
||||
for (const auto & x : expr_v_) {
|
||||
std::set<std::string> free_vars;
|
||||
free_vars = x->get_free_variables();
|
||||
|
||||
for (const auto & y : free_vars)
|
||||
retval.insert(y);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
Sequence::visit_preorder(VisitFn visitor_fn) {
|
||||
std::size_t n = 1;
|
||||
|
||||
visitor_fn(this);
|
||||
|
||||
for (const auto & x : expr_v_)
|
||||
n += x->visit_preorder(visitor_fn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
Sequence::visit_layer(VisitFn visitor_fn) {
|
||||
std::size_t n = 1;
|
||||
|
||||
visitor_fn(this);
|
||||
|
||||
for (const auto & x : expr_v_)
|
||||
n += x->visit_layer(visitor_fn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
rp<Expression>
|
||||
Sequence::xform_layer(TransformFn xform_fn) {
|
||||
for (std::size_t i = 0, n = expr_v_.size(); i < n; ++i) {
|
||||
expr_v_[i] = expr_v_[i]->xform_layer(xform_fn);
|
||||
}
|
||||
|
||||
return xform_fn(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sequence::attach_envs(ref::brw<Environment> p) {
|
||||
for (const auto & x : expr_v_)
|
||||
x->attach_envs(p);
|
||||
}
|
||||
|
||||
void
|
||||
Sequence::display(std::ostream & os) const {
|
||||
os << "<Sequence";
|
||||
std::size_t i = 0;
|
||||
for (const auto & x : expr_v_) {
|
||||
std::string i_str = tostr("[", i, "]");
|
||||
|
||||
os << xtag(i_str.c_str(), x);
|
||||
}
|
||||
|
||||
os << ">";
|
||||
}
|
||||
} /*namespace scm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Sequence.cpp */
|
||||
32
xo-expression/src/expression/Variable.cpp
Normal file
32
xo-expression/src/expression/Variable.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* @file Variable.cpp */
|
||||
|
||||
#include "Variable.hpp"
|
||||
#include "Environment.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ast {
|
||||
void
|
||||
Variable::attach_envs(ref::brw<Environment> e) {
|
||||
/** e makes accessible all enclosing lexical scopes **/
|
||||
if (this->path_.i_link_ == -2 /*sentinel*/) {
|
||||
this->path_ = e->lookup_binding(this->name_);
|
||||
} else {
|
||||
/* have already established binding for this Variable */
|
||||
}
|
||||
} /*attach_envs*/
|
||||
|
||||
void
|
||||
Variable::display(std::ostream & os) const {
|
||||
os << "<Variable"
|
||||
<< xtag("name", name_);
|
||||
if (this->valuetype())
|
||||
os << xtag("type", this->valuetype()->short_name());
|
||||
else
|
||||
os << xtag("type", "nullptr");
|
||||
os << ">";
|
||||
} /*display*/
|
||||
} /*namespace ast*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end Variable.cpp */
|
||||
14
xo-expression/src/expression/intrinsics.cpp
Normal file
14
xo-expression/src/expression/intrinsics.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* @file intrinsics.cpp */
|
||||
|
||||
#include "intrinsics.hpp"
|
||||
|
||||
/* FIXME: don't know how to mangle symbols yet,
|
||||
* so putting functions invoked from jit into global namespace
|
||||
*/
|
||||
extern "C"
|
||||
int32_t
|
||||
mul_i32(int32_t x, int32_t y) {
|
||||
return x * y;
|
||||
}
|
||||
|
||||
/* end intrinsics.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue