#include <ctype.h>
#include <algorithm>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include "template_cpp.h"
#include "isl_config.h"
std::string TupleKind::to_string() const
{
return name;
}
std::vector<std::string> TupleKind::params() const
{
return { };
}
TupleKindPtr TupleKind::apply(const Substitution &subs,
const TupleKindPtr &self) const
{
if (subs.count(name) != 0)
return subs.at(name);
return self;
}
static TupleKindPtr apply(const TupleKindPtr tuple, const Substitution &subs)
{
return tuple->apply(subs, tuple);
}
TupleKindPtr TupleKind::left() const
{
return TupleKindPtr();
}
TupleKindPtr TupleKind::right() const
{
return TupleKindPtr();
}
struct Fixed {
};
TupleKindPtr::TupleKindPtr(Fixed) : Base(std::make_shared<TupleKind>(""))
{
}
static TupleKindPtr Ctx{Fixed()};
static TupleKindPtr Integer{Fixed()};
static TupleKindPtr Str{Fixed()};
static TupleKindPtr Res{Fixed()};
static TupleKindPtr Anonymous("Anonymous");
static TupleKindPtr Leaf("Leaf");
static TupleKindPtr Domain("Domain");
static TupleKindPtr Domain2("Domain2");
static TupleKindPtr Domain3("Domain3");
static TupleKindPtr Range("Range");
static TupleKindPtr Range2("Range2");
static TupleKindPtr Range3("Range3");
struct ProperTupleKind : public TupleKind {
ProperTupleKind(const std::string &name) : TupleKind(name) {}
virtual std::vector<std::string> params() const override;
};
std::vector<std::string> ProperTupleKind::params() const
{
if (Anonymous.get() == this)
return { };
return { name };
}
TupleKindPtr::TupleKindPtr(const std::string &name) :
Base(std::make_shared<ProperTupleKind>(name))
{
}
struct Pair : public TupleKind {
Pair(const TupleKindPtr &tuple1, const TupleKindPtr &tuple2) :
TupleKind(""), tuple1(tuple1), tuple2(tuple2) {}
virtual std::string to_string() const override;
virtual std::vector<std::string> params() const override;
virtual TupleKindPtr apply(const Substitution &match,
const TupleKindPtr &self) const override;
virtual TupleKindPtr left() const override;
virtual TupleKindPtr right() const override;
const TupleKindPtr tuple1;
const TupleKindPtr tuple2;
};
std::string Pair::to_string() const
{
return std::string("pair<") + tuple1->to_string() + ", " +
tuple2->to_string() + ">";
}
static void combine(std::vector<std::string> &vec1,
const std::vector<std::string> &vec2)
{
for (const auto &s : vec2)
if (std::find(vec1.begin(), vec1.end(), s) == vec1.end())
vec1.emplace_back(s);
}
std::vector<std::string> Pair::params() const
{
auto names1 = tuple1->params();
auto names2 = tuple2->params();
combine(names1, names2);
return names1;
}
TupleKindPtr Pair::apply(const Substitution &subs, const TupleKindPtr &self)
const
{
return TupleKindPtr(::apply(tuple1, subs), ::apply(tuple2, subs));
}
TupleKindPtr Pair::left() const
{
return tuple1;
}
TupleKindPtr Pair::right() const
{
return tuple2;
}
TupleKindPtr::TupleKindPtr(const TupleKindPtr &left, const TupleKindPtr &right)
: Base(std::make_shared<Pair>(left, right))
{
}
bool Kind::is_anon() const
{
return size() != 0 && back() == Anonymous;
}
bool Kind::is_set() const
{
return size() == 1;
}
bool Kind::is_anon_set() const
{
return is_set() && is_anon();
}
std::vector<std::string> Kind::params() const
{
std::vector<std::string> params;
for (const auto &tuple : *this)
combine(params, tuple->params());
return params;
}
Kind Kind::apply(const Substitution &subs) const
{
Kind applied;
for (const auto &tuple : *this)
applied.emplace_back(::apply(tuple, subs));
return applied;
}
struct Signature {
Kind ret;
std::vector<Kind> args;
std::vector<std::string> params() const;
Signature apply(const Substitution &match) const;
};
std::vector<std::string> Signature::params() const
{
std::vector<std::string> params;
for (const auto &arg : args)
combine(params, arg.params());
combine(params, ret.params());
return params;
}
Signature Signature::apply(const Substitution &subs) const
{
std::vector<Kind> applied_args;
for (const auto &arg : args)
applied_args.emplace_back(arg.apply(subs));
return { ret.apply(subs), applied_args };
}
static Substitution param_renamer(const std::vector<std::string> ¶ms,
const std::string &prefix)
{
Substitution renamer;
int n = 0;
for (const auto &name : params) {
auto suffix = std::to_string(++n);
auto arg_name = prefix + suffix;
auto arg = TupleKindPtr(arg_name);
if (name == Leaf->name)
generator::die("Leaf cannot be renamed");
renamer.emplace(name, arg);
}
return renamer;
}
static bool contains(const std::vector<std::string> &v, const std::string &el)
{
return find(v.begin(), v.end(), el) != v.end();
}
static std::vector<std::string> intersect(const std::vector<std::string> &v1,
const std::vector<std::string> &v2)
{
std::vector<std::string> intersection;
for (const auto &el : v1)
if (contains(v2, el))
intersection.push_back(el);
return intersection;
}
static Substitution shared_param_renamer(const Signature &sig, const Kind &kind)
{
return param_renamer(intersect(sig.params(), kind.params()), "Arg");
}
static Signature un_params = { { }, { { } } };
static Signature un_set = { { Domain }, { { Domain } } };
static Signature un_map = { { Domain, Range }, { { Domain, Range } } };
static std::vector<Signature> un_op = { un_params, un_set, un_map };
static std::vector<Signature> fn_un_op = { un_set, un_map };
static Signature bin_params = { { }, { { }, { } } };
static Signature bin_set = { { Domain }, { { Domain }, { Domain } } };
static Signature bin_map =
{ { Domain, Range }, { { Domain, Range }, { Domain, Range } } };
static std::vector<Signature> bin_op = { bin_params, bin_set, bin_map };
static std::vector<Signature> fn_bin_op = { bin_set, bin_map };
static Signature bin_set_params = { { Domain }, { { Domain }, { } } };
static Signature bin_map_params =
{ { Domain, Range }, { { Domain, Range }, { } } };
static Signature bin_map_domain =
{ { Domain, Range }, { { Domain, Range }, { Domain } } };
static Signature bin_map_range =
{ { Domain, Range }, { { Domain, Range }, { Range } } };
static Signature bin_map_domain_wrapped_domain =
{ { { Domain, Domain2 }, Range },
{ { { Domain, Domain2 }, Range }, { Domain } } };
static Signature bin_map_range_wrapped_domain =
{ { Domain, { Range, Range2 } },
{ { Domain, { Range, Range2 } }, { Range } } };
static Signature bin_params_anon = { { }, { { }, { Anonymous } } };
static Signature bin_set_anon = { { Domain }, { { Domain }, { Anonymous } } };
static Signature bin_map_anon =
{ { Domain, Range }, { { Domain, Range }, { Anonymous } } };
static std::vector<Signature> bin_op_anon =
{ bin_params_anon, bin_set_anon, bin_map_anon };
static Signature ter_params_int_int =
{ { }, { { }, { Integer }, { Integer } } };
static Signature ter_set_int_int =
{ { Domain }, { { Domain }, { Integer }, { Integer } } };
static Signature ter_map_int_int =
{ { Domain, Range }, { { Domain, Range }, { Integer }, { Integer } } };
static std::vector<Signature> ter_int_int =
{ ter_params_int_int, ter_set_int_int, ter_map_int_int };
static Signature ter_set =
{ { Domain }, { { Domain }, { Domain }, { Domain } } };
static Signature ter_map =
{ { Domain, Range },
{ { Domain, Range }, { Domain, Range }, { Domain, Range } } };
static std::vector<Signature> fn_ter_op = { ter_set, ter_map };
static Signature update_set = { { Domain2 }, { { Leaf }, { Anonymous } } };
static Signature update_domain =
{ { Domain2, Range }, { { Leaf, Range }, { Anonymous } } };
static Signature update_range =
{ { Domain, Range2 }, { { Domain, Leaf }, { Anonymous } } };
static std::vector<Signature> min_max = { un_set, bin_set, un_map, bin_map };
static Signature to_set = { { Domain }, { { }, { Integer } } };
static Signature add_range = { { Domain, Range }, { { Domain }, { Integer } } };
static Signature to_set_named =
{ { Domain }, { { }, { Anonymous }, { Integer } } };
static Signature add_range_named =
{ { Domain, Range }, { { Domain }, { Anonymous }, { Integer } } };
static Signature set_forward = { { Range }, { { Domain }, { Domain, Range } } };
static Signature domain_forward =
{ { Domain2, Range }, { { Domain, Range }, { Domain, Domain2 } } };
static Signature range_forward =
{ { Domain, Range2 }, { { Domain, Range }, { Range, Range2 } } };
static Signature set_backward =
{ { Domain2 }, { { Domain }, { Domain2, Domain } } };
static Signature domain_backward =
{ { Domain2, Range }, { { Domain, Range }, { Domain2, Domain } } };
static Signature range_backward =
{ { Domain, Range2 }, { { Domain, Range }, { Range2, Range } } };
static Signature domain_wrapped_domain_backward =
{ { { Domain3, Domain2 }, Range },
{ { { Domain, Domain2 }, Range }, { Domain3, Domain } } };
static Signature bind_set = { { }, { { Domain }, { Domain } } };
static Signature bind_domain = { { Range }, { { Domain, Range }, { Domain } } };
static Signature bind_range = { { Domain }, { { Domain, Range }, { Range } } };
static Signature bind_domain_wrapped_domain =
{ { Range2, Range }, { { { Domain2, Range2 }, Range }, { Domain2 } } };
static Signature each_params = { { Res }, { { }, { Res }, { } } };
static Signature each_set = { { Res }, { { Domain }, { Res }, { Domain } } };
static Signature each_map =
{ { Res }, { { Domain, Range }, { Res }, { Domain, Range } } };
static std::vector<Signature> each = { each_params, each_set, each_map };
static Signature each_scc_params =
{ { Res }, { { }, { Res }, { }, { }, { Res }, { } } };
static Signature each_scc_set =
{ { Res }, { { Domain },
{ Res }, { Domain }, { Domain },
{ Res }, { Domain } } };
static Signature each_scc_map =
{ { Res }, { { Domain, Range },
{ Res }, { Domain, Range }, { Domain, Range },
{ Res }, { Domain, Range } } };
static std::vector<Signature> each_scc =
{ each_scc_params, each_scc_set, each_scc_map };
static Signature map_from_range_and_domain =
{ { Domain, Range }, { { Range }, { Domain } } };
static Signature set_from_params = { { Domain }, { { }, { Domain } } };
static Signature map_from_domain_and_range =
{ { Domain, Range }, { { Domain }, { Range } } };
static std::vector<Signature> from_domain =
{ set_from_params, map_from_domain_and_range };
static Signature anonymous_set_from_params = { { Anonymous }, { { } } };
static Signature anonymous_map_from_domain =
{ { Domain, Anonymous }, { { Domain } } };
static std::vector<Signature> anonymous_from_domain =
{ anonymous_set_from_params, anonymous_map_from_domain };
static Signature anonymous_set_from_params_bin_anon =
{ { Anonymous }, { { }, { Anonymous } } };
static Signature anonymous_map_from_domain_bin_anon =
{ { Domain, Anonymous }, { { Domain }, { Anonymous } } };
static std::vector<Signature> anonymous_from_domain_bin_anon = {
anonymous_set_from_params_bin_anon,
anonymous_map_from_domain_bin_anon
};
static Signature set_to_map = { { Domain, Domain }, { { Domain } } };
static Signature domain = { { Domain }, { { Domain, Range } } };
static Signature range = { { Range }, { { Domain, Range } } };
static Signature transformation_domain = { { Domain }, { { Domain, Domain } } };
static Signature set_params = { { }, { { Domain } } };
static Signature map_params = { { }, { { Domain, Range } } };
static std::vector<Signature> fn_domain = { domain, set_params };
static Signature set_reverse =
{ { { Range, Domain } }, { { { Domain, Range } } } };
static Signature map_reverse = { { Range, Domain }, { { Domain, Range } } };
static Signature map_domain_reverse =
{ { { Domain2, Domain }, Range }, { { { Domain, Domain2 }, Range } } };
static Signature map_range_reverse =
{ { Domain, { Range2, Range } }, { { Domain, { Range, Range2 } } } };
static Signature set_product =
{ { { Domain, Range } }, { { Domain }, { Range } } };
static Signature map_product =
{ { { Domain, Domain2 }, { Range, Range2 } },
{ { Domain, Range }, { Domain2, Range2 } } };
static Signature domain_product =
{ { { Domain, Domain2 }, Range },
{ { Domain, Range }, { Domain2, Range } } };
static Signature range_product =
{ { Domain, { Range, Range2 } },
{ { Domain, Range }, { Domain, Range2 } } };
static Signature domain_factor_domain =
{ { Domain, Range }, { { { Domain, Domain2 }, Range } } };
static Signature domain_factor_range =
{ { Domain2, Range }, { { { Domain, Domain2 }, Range } } };
static Signature range_factor_domain =
{ { Domain, Range }, { { Domain, { Range, Range2 } } } };
static Signature range_factor_range =
{ { Domain, Range2 }, { { Domain, { Range, Range2 } } } };
static Signature curry =
{ { Domain, { Range, Range2 } },
{ { { Domain, Range }, Range2 } } };
static Signature uncurry =
{ { { Domain, Range }, Range2 },
{ { Domain, { Range, Range2 } } } };
static Signature wrap = { { { Domain, Range } }, { { Domain, Range } } };
static Signature unwrap = { { Domain, Range }, { { { Domain, Range } } } };
static Signature domain_map =
{ { { Domain, Range }, Domain }, { { Domain, Range } } };
static Signature range_map =
{ { { Domain, Range }, Range }, { { Domain, Range } } };
static Signature map_cmp =
{ { Domain, Domain }, { { Domain, Domain }, { Domain, Range } } };
static Signature set_join =
{ { Domain }, { { Domain, Range }, { Domain, Range } } };
static Signature anonymize_nested_domain =
{ { Anonymous, Range2 }, { { { Domain, Range }, Range2 } } };
static Signature anonymize_nested_range =
{ { Domain, Anonymous }, { { Domain, { Range, Range2 } } } };
static Signature replace_nested_domain =
{ { Domain2, Range2 },
{ { { Domain, Range }, Range2 }, { Anonymous} } };
static Signature replace_nested_range =
{ { Domain, Range3 }, { { Domain, { Range, Range2 } }, { Anonymous} } };
static std::vector<Signature> flatten_domain =
{ anonymize_nested_domain, replace_nested_domain };
static std::vector<Signature> flatten_range =
{ anonymize_nested_range, replace_nested_range };
static Signature set_at_set =
{ { Domain }, { { Domain }, { Integer }, { Anonymous } } };
static Signature set_at_map =
{ { Domain, Range },
{ { Domain, Range }, { Integer }, { Domain, Anonymous } } };
static std::vector<Signature> set_at = { set_at_set, set_at_map };
static Signature to_list_set = { { Anonymous }, { { Domain } } };
static Signature to_list_map = { { Domain, Anonymous }, { { Domain, Range } } };
static Signature ctx_params = { { }, { { Ctx } } };
static Signature ctx_set = { { Domain }, { { Ctx } } };
static Signature ctx_map = { { Domain, Range }, { { Ctx } } };
struct larger_infix {
bool operator()(const std::string &x, const std::string &y) const {
if (x.length() > y. length())
return true;
return x < y;
}
};
typedef std::map<std::string, std::vector<Signature>, larger_infix> infix_map;
typedef std::map<std::string, infix_map> infix_map_map;
static const infix_map_map static_methods {
{ "unit",
{ { "space", { ctx_params } } }
},
{ "empty",
{
{ "union_set", { ctx_params, ctx_set } },
{ "union_map", { ctx_map } },
{ "union_pw_multi_aff", { ctx_set, ctx_map } },
}
},
{ "universe",
{
{ "set", { un_params, un_set } },
{ "map", { un_map } },
}
},
};
static std::vector<Signature> range_op = { un_set, range };
static std::vector<Signature> bin_val = { bin_set, bin_map_range };
static const std::unordered_map<std::string, std::vector<Signature>>
member_methods {
{ "add", bin_op },
{ "add_constant", bin_val },
{ "add_named_tuple", { to_set_named, add_range_named } },
{ "add_param", bin_op_anon },
{ "add_unnamed_tuple", { to_set, add_range } },
{ "apply", { set_forward, range_forward } },
{ "apply_domain", { domain_forward } },
{ "apply_range", { range_forward } },
{ "as", un_op },
{ "as_map", { un_map } },
{ "as_union_map", { un_map } },
{ "as_set", { un_set } },
{ "bind", { bind_set, bind_range } },
{ "bind_domain", { bind_domain } },
{ "bind_range", { bind_range } },
{ "bind_domain_wrapped_domain",
{ bind_domain_wrapped_domain } },
{ "ceil", fn_un_op },
{ "coalesce", un_op },
{ "cond", fn_ter_op },
{ "constant", range_op },
{ "curry", { curry } },
{ "deltas", { transformation_domain } },
{ "detect_equalities", un_op },
{ "domain", fn_domain },
{ "domain_factor_domain",
{ domain_factor_domain } },
{ "domain_factor_range",
{ domain_factor_range } },
{ "domain_map", { domain_map } },
{ "domain_product", { domain_product } },
{ "domain_reverse", { map_domain_reverse } },
{ "drop", ter_int_int },
{ "drop_all_params", un_op },
{ "drop_unused_params", un_op },
{ "eq_at", { map_cmp } },
{ "every", each },
{ "extract", bin_op },
{ "flatten_domain", flatten_domain },
{ "flatten_range", flatten_range },
{ "floor", fn_un_op },
{ "foreach", each },
{ "foreach_scc", each_scc },
{ "ge_set", { set_join } },
{ "gt_set", { set_join } },
{ "gist", bin_op },
{ "gist_domain", { bin_map_domain } },
{ "gist_params", { bin_set_params, bin_map_params } },
{ "identity", { un_map, set_to_map } },
{ "identity_on_domain", { set_to_map } },
{ "indicator_function", anonymous_from_domain },
{ "insert_domain", { map_from_range_and_domain } },
{ "intersect", bin_op },
{ "intersect_params", { bin_set_params, bin_map_params } },
{ "intersect_domain", { bin_map_domain } },
{ "intersect_domain_wrapped_domain",
{ bin_map_domain_wrapped_domain } },
{ "intersect_range", { bin_map_range } },
{ "intersect_range_wrapped_domain",
{ bin_map_range_wrapped_domain } },
{ "lattice_tile", { un_set } },
{ "le_set", { set_join } },
{ "lt_set", { set_join } },
{ "lex_le_at", { map_cmp } },
{ "lex_lt_at", { map_cmp } },
{ "lex_ge_at", { map_cmp } },
{ "lex_gt_at", { map_cmp } },
{ "lexmin", fn_un_op },
{ "lexmax", fn_un_op },
{ "list", { to_list_set, to_list_map } },
{ "lower_bound", fn_bin_op },
{ "map_from_set", { set_to_map } },
{ "max", min_max },
{ "max_val", range_op },
{ "max_multi_val", range_op },
{ "min", min_max },
{ "min_val", range_op },
{ "min_multi_val", range_op },
{ "mod", bin_val },
{ "on_domain", from_domain },
{ "neg", fn_un_op },
{ "offset", fn_un_op },
{ "param_on_domain", anonymous_from_domain_bin_anon },
{ "params", { set_params, map_params } },
{ "plain_multi_val_if_fixed",
{ un_set } },
{ "preimage", { set_backward } },
{ "preimage_domain", { domain_backward } },
{ "preimage_domain_wrapped_domain",
{ domain_wrapped_domain_backward } },
{ "preimage_range", { range_backward } },
{ "product", { set_product, map_product } },
{ "project_out_param", bin_op_anon },
{ "project_out_all_params",
un_op },
{ "pullback", { domain_backward, bind_domain } },
{ "range", { range } },
{ "range_factor_domain",
{ range_factor_domain } },
{ "range_factor_range", { range_factor_range } },
{ "range_lattice_tile", { un_map } },
{ "range_map", { range_map } },
{ "range_product", { range_product } },
{ "range_reverse", { map_range_reverse } },
{ "range_simple_fixed_box_hull",
{ un_map } },
{ "reverse", { map_reverse } },
{ "scale", bin_val },
{ "scale_down", bin_val },
{ "set_at", set_at },
{ "set_domain_tuple", { update_domain } },
{ "set_range_tuple", { update_set, update_range } },
{ "simple_fixed_box_hull",
{ un_set } },
{ "sub", fn_bin_op },
{ "subtract", bin_op },
{ "subtract_domain", { bin_map_domain } },
{ "subtract_range", { bin_map_range } },
{ "translation", { set_to_map } },
{ "to", un_op },
{ "unbind_params", { set_from_params } },
{ "unbind_params_insert_domain",
{ map_from_range_and_domain } },
{ "uncurry", { uncurry } },
{ "union_add", fn_bin_op },
{ "unite", bin_op },
{ "universe", un_op },
{ "unwrap", { unwrap } },
{ "upper_bound", fn_bin_op },
{ "wrap", { wrap } },
{ "wrapped_reverse", { set_reverse } },
{ "zero", fn_un_op },
{ "zero_on_domain", { anonymous_map_from_domain } },
};
static Signature from_list_set = { { Domain }, { { Domain }, { Anonymous } } };
static Signature from_list_map =
{ { Domain, Range }, { { Domain, Range }, { Domain, Anonymous } } };
static Signature from_list_map_union =
{ { Domain, Range }, { { Range }, { Domain, Anonymous } } };
static const infix_map_map special_member_methods {
{ "gist",
{ { "aff", { bin_set_params, bin_map_domain } } }
},
{ "multi_union_pw_aff",
{ { "space", { from_list_set, from_list_map_union } } }
},
{ "size",
{ { "fixed_box", range_op } },
},
{ "space",
{
{ "multi_union", range_op },
{ "union", { un_params, set_params, map_params } },
}
},
};
static Kind params{};
static Kind set_type{ Domain };
static Kind set_anon{ Anonymous };
static Kind map_type{ Domain, Range };
static Kind map_anon{ Domain, Anonymous };
static const std::unordered_map<std::string, std::vector<Kind>> base_kinds {
{ "space", { params, set_type, map_type } },
{ "set", { params, set_type } },
{ "point", { params, set_type } },
{ "map", { map_type } },
{ "aff", { set_anon, map_anon } },
{ "fixed_box", { set_type, map_type } },
{ "val", { set_anon } },
{ "id", { set_anon } },
};
static const std::unordered_set<std::string> type_prefixes {
"basic",
"multi",
"pw",
"union",
};
static std::string drop_list(const std::string &type)
{
size_t pos = type.rfind('_');
if (pos == std::string::npos)
return type;
if (type.substr(pos + 1) == "list")
return type.substr(0, pos);
return type;
}
static std::string base_type(const std::string &type)
{
auto base = type;
size_t pos;
base = drop_list(base);
while (base_kinds.count(base) == 0 &&
(pos = base.find('_')) != std::string::npos &&
type_prefixes.count(base.substr(0, pos)) != 0) {
base = base.substr(pos + 1);
}
return base;
}
static std::map<Kind, Kind> anon_to_named {
{ set_anon, set_type },
{ map_anon, map_type },
};
static std::vector<Kind> add_name(const std::vector<Kind> &tuples)
{
std::vector<Kind> named;
for (const auto &tuple : tuples)
named.emplace_back(anon_to_named.at(tuple));
return named;
}
static std::vector<Kind> lookup_class_tuples(const std::string &name)
{
std::string base = base_type(name);
if (base_kinds.count(base) == 0)
return { };
if (name.find("multi_") != std::string::npos)
return add_name(base_kinds.at(base));
return base_kinds.at(base);
}
void template_cpp_generator::add_template_class(const isl_class &clazz,
const std::string &name, const std::vector<Kind> &class_tuples)
{
auto isl_namespace = cpp_type_printer().isl_namespace();
auto super = isl_namespace + name;
template_classes.emplace(name,
template_class{name, super, clazz, class_tuples});
}
template_cpp_generator::template_cpp_generator(clang::SourceManager &SM,
std::set<clang::RecordDecl *> &exported_types,
std::set<clang::FunctionDecl *> exported_functions,
std::set<clang::FunctionDecl *> functions) :
cpp_generator(SM, exported_types, exported_functions,
functions)
{
for (const auto &kvp : classes) {
const auto &clazz = kvp.second;
std::string name = type2cpp(clazz);
const auto &class_tuples = lookup_class_tuples(name);
if (class_tuples.empty())
continue;
add_template_class(clazz, name, class_tuples);
}
}
void template_cpp_generator::foreach_template_class(
const std::function<void(const template_class &)> &fn) const
{
for (const auto &kvp : template_classes)
fn(kvp.second);
}
void template_cpp_generator::print_forward_declarations(std::ostream &os)
{
foreach_template_class([&os] (const template_class &template_class) {
auto name = template_class.class_name;
os << "\n";
os << "template <typename...>\n";
os << "struct " << name << ";\n";
if (!template_class.is_anon())
return;
if (template_class.is_anon_set())
return;
os << "\n";
os << "template <typename...Ts>\n";
os << "using " << name << "_on = "
<< name << "<Ts..., Anonymous>;\n";
});
}
void template_cpp_generator::print_friends(std::ostream &os)
{
foreach_template_class([&os] (const template_class &template_class) {
os << " template <typename...>\n";
os << " friend struct " << template_class.class_name << ";\n";
});
}
static void print_template_arg(std::ostream &os, const std::string &arg)
{
os << "typename " << arg;
}
static void print_template_arg(std::ostream &os, const TupleKindPtr &kind)
{
os << kind->to_string();
}
template <typename List>
static void print_pure_template_args(std::ostream &os, const List &args)
{
for (size_t i = 0; i < args.size(); ++i) {
if (i != 0)
os << ", ";
print_template_arg(os, args[i]);
}
}
template <typename List>
static void print_template_args(std::ostream &os, const List &args)
{
os << "<";
print_pure_template_args(os, args);
os << ">";
}
static void print_template(std::ostream &os,
const std::vector<std::string> ¶ms)
{
os << "template ";
print_template_args(os, params);
os << "\n";
}
static void print_non_empty_template(std::ostream &os,
const std::vector<std::string> ¶ms)
{
if (params.size() > 0)
print_template(os, params);
}
static void print_bare_template_type(std::ostream &os, const std::string &type,
const Kind &kind)
{
os << type;
print_template_args(os, kind);
}
struct specialization {
struct template_class &template_class;
Kind kind;
const std::string &base_name() const;
const std::string &class_name() const;
};
const std::string &specialization::base_name() const
{
return template_class.super_name;
}
const std::string &specialization::class_name() const
{
return template_class.class_name;
}
struct specialization_printer {
specialization_printer(std::ostream &os,
template_cpp_generator &generator) :
os(os), generator(generator) {}
virtual void print_class(const specialization &instance) const = 0;
void print_classes() const;
std::ostream &os;
template_cpp_generator &generator;
};
void specialization_printer::print_classes() const
{
for (auto &kvp : generator.template_classes) {
auto &template_class = kvp.second;
const auto &class_tuples = template_class.class_tuples;
for (size_t i = 0; i < class_tuples.size(); ++i)
print_class({ template_class, class_tuples[i] });
}
}
struct template_cpp_generator::class_printer :
public cpp_generator::class_printer {
class_printer(const specialization &instance,
const specialization_printer &instance_printer,
bool is_declaration);
void print_return_type(const Method &method, const Kind &kind)
const;
void print_method_template_arguments(const Signature &sig);
void print_method_header(const Method &method, const Signature &sig);
bool print_special_method(const Method &method,
const infix_map_map &special_methods);
void print_static_method(const Method &method);
void print_constructor(const Method &method);
bool is_return_kind(const Method &method, const Kind &return_kind);
void add_specialization(const Kind &kind);
bool print_matching_method(const Method &method, const Signature &sig,
const Kind &match_arg);
bool print_matching_method(const Method &method, const Signature &sig);
void print_matching_method(const Method &method,
const std::vector<Signature> &signatures);
void print_at_method(const Method &method);
bool print_special_member_method(const Method &method);
bool print_type_named_member_method(const Method &method);
bool print_member_method_with_name(const Method &method,
const std::string &name);
void print_member_method(const Method &method);
void print_any_method(const Method &method);
virtual void print_method(const Method &method) override;
virtual void print_method(const ConversionMethod &method) override;
virtual void print_method_sig(const Method &method,
const Signature &sig, bool deleted) = 0;
virtual bool want_descendent_overloads(const function_set &methods)
override;
void print_all_methods();
const specialization &instance;
template_cpp_generator &generator;
};
template_cpp_generator::class_printer::class_printer(
const specialization &instance,
const specialization_printer &instance_printer,
bool is_declaration) :
cpp_generator::class_printer(instance_printer.os,
instance.template_class.clazz, instance_printer.generator,
is_declaration),
instance(instance), generator(instance_printer.generator)
{
}
struct template_cpp_type_printer : public cpp_type_printer {
template_cpp_type_printer() {}
std::string base(const std::string &type, const Kind &kind) const;
virtual Kind kind(int arg) const = 0;
virtual std::string qualified(int arg, const std::string &cpp_type)
const override;
};
std::string template_cpp_type_printer::base(const std::string &type,
const Kind &kind) const
{
std::ostringstream ss;
ss << "typed::";
print_bare_template_type(ss, type, kind);
return ss.str();
}
std::string template_cpp_type_printer::qualified(int arg,
const std::string &cpp_type) const
{
if (cpp_type == "ctx")
return cpp_type_printer::qualified(arg, cpp_type);
return base(cpp_type, kind(arg));
}
struct template_cpp_kind_type_printer : public template_cpp_type_printer {
template_cpp_kind_type_printer(const Kind &kind) :
template_cpp_type_printer(), fixed_kind(kind) {}
virtual Kind kind(int arg) const override;
const Kind &fixed_kind;
};
Kind template_cpp_kind_type_printer::kind(int arg) const
{
return fixed_kind;
}
struct template_cpp_arg_type_printer : public template_cpp_type_printer {
template_cpp_arg_type_printer(const Signature &sig) :
template_cpp_type_printer(), sig(sig) {}
virtual Kind kind(int arg) const override;
const Signature &sig;
};
Kind template_cpp_arg_type_printer::kind(int arg) const
{
int n_args = sig.args.size();
if (arg < 0)
return sig.ret;
if (arg >= n_args)
generator::die("argument out of bounds");
return sig.args[arg];
}
struct template_method_type_printer : public template_cpp_arg_type_printer {
template_method_type_printer(const Signature &sig,
const Kind &class_kind) :
template_cpp_arg_type_printer(sig),
class_kind(class_kind) {}
virtual std::string class_type(const std::string &cpp_name)
const override;
const Kind &class_kind;
};
std::string template_method_type_printer::class_type(
const std::string &cpp_name) const
{
return base(cpp_name, class_kind);
}
void template_cpp_generator::class_printer::print_return_type(
const Method &method, const Kind &return_kind) const
{
template_cpp_kind_type_printer printer(return_kind);
os << printer.return_type(method);
}
template <typename T>
static void drop_initial(std::vector<T> &v, size_t n)
{
v.erase(v.begin(), v.begin() + n);
}
void template_cpp_generator::class_printer::print_method_template_arguments(
const Signature &sig)
{
std::vector<std::string> class_params, method_params;
class_params = instance.kind.params();
method_params = class_params;
combine(method_params, sig.params());
if (class_params.size() == method_params.size())
return;
drop_initial(method_params, class_params.size());
if (declarations)
os << " ";
print_template(os, method_params);
}
void template_cpp_generator::class_printer::print_method_header(
const Method &method, const Signature &sig)
{
template_method_type_printer type_printer(sig, instance.kind);
print_method_template_arguments(sig);
cpp_generator::class_printer::print_method_header(method,
type_printer);
}
bool template_cpp_generator::class_printer::want_descendent_overloads(
const function_set &methods)
{
return true;
}
void template_cpp_generator::class_printer::print_all_methods()
{
print_constructors();
print_methods();
}
struct template_cpp_generator::method_decl_printer :
public template_cpp_generator::class_printer {
method_decl_printer(const specialization &instance,
const struct specialization_printer &instance_printer) :
class_printer(instance, instance_printer, true) {}
virtual void print_method_sig(const Method &method,
const Signature &sig, bool deleted) override;
virtual void print_get_method(FunctionDecl *fd) override;
};
void template_cpp_generator::method_decl_printer::print_method_sig(
const Method &method, const Signature &sig, bool deleted)
{
print_method_header(method, sig);
if (deleted)
os << " = delete";
os << ";\n";
}
static int total_params(const Method &method)
{
int n = method.num_params();
for (const auto &callback : method.callbacks) {
auto callback_type = callback->getType();
auto proto = generator::extract_prototype(callback_type);
n += proto->getNumArgs() - 1;
n -= 1;
}
return n;
}
static Signature instance_sig(const Method &method,
const specialization &instance)
{
std::vector<Kind> args(total_params(method));
args[0] = instance.kind;
return { instance.kind, args };
}
void template_cpp_generator::method_decl_printer::print_get_method(
FunctionDecl *fd)
{
Method method(clazz, fd, clazz.base_method_name(fd));
print_method_sig(method, instance_sig(method, instance), true);
}
struct template_cpp_generator::method_impl_printer :
public template_cpp_generator::class_printer {
method_impl_printer(const specialization &instance,
const struct specialization_printer &instance_printer) :
class_printer(instance, instance_printer, false) {}
void print_callback_method_body(const Method &method,
const Signature &sig);
void print_method_body(const Method &method, const Signature &sig);
void print_constructor_body(const Method &method, const Signature &sig);
virtual void print_method_sig(const Method &method,
const Signature &sig, bool deleted) override;
virtual void print_get_method(FunctionDecl *fd) override;
};
void template_cpp_generator::method_impl_printer::print_constructor_body(
const Method &method, const Signature &sig)
{
const auto &base_name = instance.base_name();
os << " : " << base_name;
method.print_cpp_arg_list(os, [&] (int i, int arg) {
os << method.fd->getParamDecl(i)->getName().str();
});
os << "\n";
os << "{\n";
os << "}\n";
}
static void print_callback_args(std::ostream &os,
const FunctionProtoType *callback, const cpp_type_printer &type_printer,
int shift,
const std::function<void(const std::string &type,
const std::string &name)> &print_arg)
{
auto n_arg = callback->getNumArgs() - 1;
Method::print_arg_list(os, 0, n_arg, [&] (int i) {
auto type = callback->getArgType(i);
auto name = "arg" + std::to_string(i);
auto cpptype = type_printer.param(shift + i, type);
print_arg(cpptype, name);
return false;
});
}
static void print_callback_lambda(std::ostream &os, ParmVarDecl *callback,
const Signature &sig, int shift)
{
auto callback_type = callback->getType();
auto callback_name = callback->getName().str();
auto proto = generator::extract_prototype(callback_type);
os << " auto lambda_" << callback_name << " = [&] ";
print_callback_args(os, proto, cpp_type_printer(), shift,
[&] (const std::string &type, const std::string &name) {
os << type << " " << name;
});
os << " {\n";
os << " return " << callback_name;
print_callback_args(os, proto, template_cpp_arg_type_printer(sig),
shift,
[&] (const std::string &type, const std::string &name) {
os << type << "(" << name << ")";
});
os << ";\n";
os << " };\n";
}
static void print_callback_lambdas(std::ostream &os, const Method &method,
const Signature &sig)
{
int shift;
if (method.num_params() != 1 + 2 * method.callbacks.size())
generator::die("callbacks are assumed to be only arguments");
shift = 2;
for (const auto &callback : method.callbacks) {
print_callback_lambda(os, callback, sig, shift);
shift += generator::prototype_n_args(callback->getType());
}
}
void template_cpp_generator::method_impl_printer::print_callback_method_body(
const Method &method, const Signature &sig)
{
const auto &base_name = instance.base_name();
auto return_type = method.fd->getReturnType();
if (!is_isl_bool(return_type) && !is_isl_stat(return_type))
die("only isl_bool and isl_stat return types are supported");
os << "{\n";
print_callback_lambdas(os, method, sig);
os << " return ";
os << base_name << "::" << method.name;
method.print_cpp_arg_list(os, [&] (int i, int arg) {
auto param = method.fd->getParamDecl(i);
if (generator::is_callback(param->getType()))
os << "lambda_";
os << param->getName().str();
});
os << ";\n";
os << "}\n";
}
void template_cpp_generator::method_impl_printer::print_method_body(
const Method &method, const Signature &sig)
{
const auto &base_name = instance.base_name();
os << "{\n";
os << " auto res = ";
os << base_name << "::" << method.name;
method.print_cpp_arg_list(os, [&] (int i, int arg) {
os << method.fd->getParamDecl(i)->getName().str();
});
os << ";\n";
os << " return ";
print_return_type(method, sig.ret);
os << "(res);\n";
os << "}\n";
}
void template_cpp_generator::method_impl_printer::print_method_sig(
const Method &method, const Signature &sig, bool deleted)
{
if (deleted)
return;
os << "\n";
print_non_empty_template(os, instance.kind.params());
print_method_header(method, sig);
os << "\n";
if (method.kind == Method::Kind::constructor)
print_constructor_body(method, sig);
else if (method.callbacks.size() != 0)
print_callback_method_body(method, sig);
else
print_method_body(method, sig);
}
void template_cpp_generator::method_impl_printer::print_get_method(
FunctionDecl *fd)
{
}
void template_cpp_generator::class_printer::print_static_method(
const Method &method)
{
print_special_method(method, static_methods);
}
static Signature params_from_str = { { }, { { Ctx }, { Str } } };
static Signature set_from_str = { { Domain }, { { Ctx }, { Str } } };
static Signature map_from_str = { { Domain, Range }, { { Ctx }, { Str } } };
static std::vector<Signature> from_str =
{ params_from_str, set_from_str, map_from_str };
static Signature int_from_si = { { Anonymous }, { { Ctx }, { Integer } } };
static Signature alloc_params = { { }, { { Ctx }, { Integer } } };
static Signature alloc_set = { { Domain }, { { Ctx }, { Integer } } };
static Signature alloc_map = { { Domain, Range }, { { Ctx }, { Integer } } };
static std::vector<Signature> constructor_sig = {
un_params,
un_set,
un_map,
from_list_set,
from_list_map,
};
static const std::unordered_map<std::string, std::vector<Signature>>
special_constructors {
{ "alloc", { alloc_params, alloc_set, alloc_map } },
{ "int_from_si", { int_from_si } },
{ "read_from_str", from_str },
};
void template_cpp_generator::class_printer::print_constructor(
const Method &method)
{
if (special_constructors.count(method.name) != 0) {
const auto &sigs = special_constructors.at(method.name);
return print_matching_method(method, sigs);
}
print_matching_method(method, constructor_sig);
}
bool template_class::is_anon() const
{
return class_tuples[0].is_anon();
}
bool template_class::is_anon_set() const
{
return class_tuples.size() == 1 && class_tuples[0].is_anon_set();
}
static bool update_sub_base(Substitution &sub, const TupleKindPtr &general,
const TupleKindPtr &specific)
{
auto name = general->name;
if (sub.count(name) != 0 && sub.at(name) != specific)
return false;
sub.emplace(name, specific);
return true;
}
static bool update_sub(Substitution &sub, const TupleKindPtr &general,
const TupleKindPtr &specific)
{
if (general->left() && !specific->left())
return false;
if (general->left())
return update_sub(sub, general->left(), specific->left()) &&
update_sub(sub, general->right(), specific->right());
if (general == Anonymous && specific != Anonymous)
return false;
if (general == Leaf && specific->left())
return false;
return update_sub_base(sub, general, specific);
}
static std::pair<bool, Substitution> specializer(const Kind &general,
const Kind &specific)
{
Substitution specializer;
if (general.size() != specific.size())
return { false, Substitution() };
for (size_t i = 0; i < general.size(); ++i) {
auto general_tuple = general[i];
if (!update_sub(specializer, general[i], specific[i]))
return { false, Substitution() };
}
return { true, specializer };
}
static bool equivalent(const Kind &kind1, const Kind &kind2)
{
return specializer(kind1, kind2).first &&
specializer(kind2, kind1).first;
}
void template_class::add_specialization(const Kind &kind)
{
for (const auto &special : class_tuples)
if (equivalent(special, kind))
return;
class_tuples.emplace_back(kind);
}
struct plain_cpp_type_printer : public cpp_type_printer {
plain_cpp_type_printer() {}
virtual std::string qualified(int arg, const std::string &cpp_type)
const override;
};
std::string plain_cpp_type_printer::qualified(int arg,
const std::string &cpp_type) const
{
return cpp_type;
}
static std::string plain_type(QualType type)
{
return plain_cpp_type_printer().param(-1, type);
}
static std::string plain_return_type(const Method &method)
{
return plain_type(method.fd->getReturnType());
}
static const Kind &matching_kind(const Method &method, const Signature &sig)
{
if (method.kind == Method::Kind::member_method)
return sig.args[0];
else
return sig.ret;
}
static bool has_kind(const template_class &template_class, const Kind &kind)
{
if (template_class.is_anon() && !kind.is_anon())
return false;
for (const auto &class_tuple : template_class.class_tuples)
if (class_tuple.size() == kind.size())
return true;
return false;
}
bool template_cpp_generator::class_printer::is_return_kind(
const Method &method, const Kind &return_kind)
{
const auto &template_classes = generator.template_classes;
auto return_type = plain_return_type(method);
if (template_classes.count(return_type) == 0)
return return_kind.params().size() == 0;
return has_kind(template_classes.at(return_type), return_kind);
}
static bool assignable(const TupleKindPtr &kind)
{
return kind != Anonymous && kind != Leaf;
}
static Substitution assign(const TupleKindPtr &kind1, const TupleKindPtr &kind2)
{
Substitution res;
if (assignable(kind1) || kind1 == kind2)
res.emplace(kind1->name, kind2);
return res;
}
static Substitution compose(const Substitution &first,
const Substitution &second)
{
Substitution res = second;
for (const auto &kvp : first)
res.emplace(kvp.first, apply(kvp.second, second));
return res;
}
static Substitution compute_unifier(const TupleKindPtr &kind1,
const TupleKindPtr &kind2);
static Substitution combine_unifiers(const TupleKindPtr &kind1,
const TupleKindPtr &kind2, const Substitution &unifier)
{
auto k1 = apply(kind1, unifier);
auto k2 = apply(kind2, unifier);
auto u = compute_unifier(k1, k2);
if (u.size() == 0)
return Substitution();
return compose(unifier, u);
}
static Substitution compute_pair_unifier(const TupleKindPtr &kind1,
const TupleKindPtr &kind2)
{
auto unifier_left = compute_unifier(kind1->left(), kind2->left());
if (unifier_left.size() == 0)
return Substitution();
return combine_unifiers(kind1->right(), kind2->right(), unifier_left);
}
static Substitution compute_unifier(const TupleKindPtr &kind1,
const TupleKindPtr &kind2)
{
if (kind1->left() && !kind2->left())
return assign(kind2, kind1);
if (!kind1->left() && kind2->left())
return assign(kind1, kind2);
if (!kind1->left() && !kind2->left()) {
if (assignable(kind1))
return assign(kind1, kind2);
else
return assign(kind2, kind1);
}
return compute_pair_unifier(kind1, kind2);
}
static Substitution compute_unifier(const Kind &kind1, const Kind &kind2)
{
Substitution unifier;
if (kind1.size() != kind2.size())
return Substitution();
for (size_t i = 0; i < kind1.size(); ++i)
unifier = combine_unifiers(kind1[i], kind2[i], unifier);
return unifier;
}
static std::pair<bool, Kind> unify(const Kind &general, const Kind &specific)
{
if (specializer(specific, general).first) {
return { true, general };
} else {
auto rename = param_renamer(specific.params(), "T");
auto renamed = specific.apply(rename);
auto unifier = compute_unifier(general, renamed);
if (unifier.size() == 0)
return { false, { } };
return { true, general.apply(unifier) };
}
}
void template_cpp_generator::class_printer::add_specialization(
const Kind &kind)
{
auto maybe_unified = unify(kind, instance.kind);
if (!maybe_unified.first)
return;
instance.template_class.add_specialization(maybe_unified.second);
}
static bool param_is_anon(const Method &method, int i)
{
ParmVarDecl *param = method.get_param(i);
QualType type = param->getOriginalType();
if (cpp_generator::is_isl_type(type)) {
const auto &name = type->getPointeeType().getAsString();
const auto &cpp = cpp_generator::type2cpp(name);
const auto &tuples = lookup_class_tuples(cpp);
if (tuples.empty())
return true;
return tuples[0].is_anon();
}
return true;
}
static Signature specialize_anonymous_arg(const Signature &sig,
const Kind &arg_kind, const Kind &instance_kind)
{
const auto &subs = compute_unifier(arg_kind.back(), Anonymous);
const auto &specialized_instance = instance_kind.apply(subs);
if (!specializer(specialized_instance, instance_kind).first)
return sig;
return sig.apply(subs);
}
static Signature specialize_anonymous_args(const Signature &sig,
const Method &method, const Kind &instance_kind)
{
auto specialized_sig = sig;
method.on_cpp_arg_list([&] (int i, int arg) {
const auto &arg_kind = sig.args[arg];
if (arg_kind.is_anon())
return;
if (!param_is_anon(method, i))
return;
specialized_sig = specialize_anonymous_arg(specialized_sig,
arg_kind, instance_kind);
});
return specialized_sig;
}
bool template_cpp_generator::class_printer::print_matching_method(
const Method &method, const Signature &sig, const Kind &match_arg)
{
auto rename = shared_param_renamer(sig, instance.kind);
auto renamed_arg = match_arg.apply(rename);
auto maybe_specializer = specializer(renamed_arg, instance.kind);
if (maybe_specializer.first) {
const auto &specializer = maybe_specializer.second;
auto specialized_sig = sig.apply(rename).apply(specializer);
specialized_sig = specialize_anonymous_args(specialized_sig,
method, instance.kind);
if (!is_return_kind(method, specialized_sig.ret))
return false;
print_method_sig(method, specialized_sig, false);
} else {
add_specialization(match_arg);
}
return maybe_specializer.first;
}
static bool first_arg_is_ctx(const Method &method)
{
return generator::first_arg_is_isl_ctx(method.fd);
}
static bool first_kind_is_ctx(const Signature &sig)
{
return sig.args[0].size() > 0 && sig.args[0][0] == Ctx;
}
bool template_cpp_generator::class_printer::print_matching_method(
const Method &method, const Signature &sig)
{
auto match_arg = matching_kind(method, sig);
int n_args = sig.args.size();
if (match_arg.size() != instance.kind.size())
return false;
if (n_args != total_params(method))
return false;
if (n_args > 0 && first_arg_is_ctx(method) != first_kind_is_ctx(sig))
return false;
return print_matching_method(method, sig, match_arg);
}
void template_cpp_generator::class_printer::print_matching_method(
const Method &method, const std::vector<Signature> &signatures)
{
auto any = false;
for (const auto &sig : signatures)
if (print_matching_method(method, sig))
any = true;
if (!any)
print_method_sig(method, instance_sig(method, instance), true);
}
static Signature select_set = { { Anonymous }, { { Domain }, { Integer } } };
static Signature select_map =
{ { Domain, Anonymous }, { { Domain, Range }, { Integer } } };
static std::vector<Signature> at_select = { select_set, select_map };
static Signature bin_set_int = { { Domain }, { { Domain }, { Integer } } };
static Signature bin_map_int =
{ { Domain, Range }, { { Domain, Range }, { Integer } } };
static std::vector<Signature> at_keep = { bin_set_int, bin_map_int };
void template_cpp_generator::class_printer::print_at_method(
const Method &method)
{
auto anon = instance.template_class.is_anon();
auto return_type = plain_return_type(method);
auto return_class = generator.template_classes.at(return_type);
if (!anon && return_class.is_anon())
return print_matching_method(method, at_select);
else
return print_matching_method(method, at_keep);
}
static bool contains(const std::string &s, const std::string &sub)
{
return s.find(sub) != std::string::npos;
}
bool template_cpp_generator::class_printer::print_special_method(
const Method &method, const infix_map_map &special_methods)
{
if (special_methods.count(method.name) == 0)
return false;
for (const auto &kvp : special_methods.at(method.name)) {
if (!contains(instance.template_class.class_name, kvp.first))
continue;
print_matching_method(method, kvp.second);
return true;
}
return false;
}
bool template_cpp_generator::class_printer::print_special_member_method(
const Method &method)
{
return print_special_method(method, special_member_methods);
}
bool template_cpp_generator::class_printer::print_type_named_member_method(
const Method &method)
{
if (generator.template_classes.count(method.name) == 0)
return false;
print_matching_method(method, constructor_sig);
return true;
}
bool template_cpp_generator::class_printer::print_member_method_with_name(
const Method &method, const std::string &name)
{
if (member_methods.count(name) == 0)
return false;
print_matching_method(method, member_methods.at(name));
return true;
}
static std::string drop_occurrence(const std::string &str,
const std::string &sub)
{
auto res = str;
auto pos = str.find(sub);
if (pos != std::string::npos)
res.erase(pos, sub.length());
return res;
}
static std::string drop_underscore_occurrence(const std::string &str,
const std::string &sub)
{
auto res = drop_occurrence(str, sub + "_");
if (res != str)
return res;
return drop_occurrence(res, std::string("_") + sub);
}
const std::string name_without_return(const Method &method)
{
auto return_infix = plain_return_type(method);
return drop_underscore_occurrence(method.name, return_infix);
}
const std::string callback_name(const Method &method)
{
if (method.callbacks.size() == 0)
return method.name;
auto type = method.callbacks.at(0)->getType();
auto callback = cpp_generator::extract_prototype(type);
auto arg_type = plain_type(callback->getArgType(0));
return generator::drop_suffix(method.name, "_" + arg_type);
}
void template_cpp_generator::class_printer::print_member_method(
const Method &method)
{
if (method.name == "at")
return print_at_method(method);
if (print_special_member_method(method))
return;
if (print_type_named_member_method(method))
return;
if (print_member_method_with_name(method, method.name))
return;
if (print_member_method_with_name(method, name_without_return(method)))
return;
if (print_member_method_with_name(method, callback_name(method)))
return;
}
void template_cpp_generator::class_printer::print_any_method(
const Method &method)
{
switch (method.kind) {
case Method::Kind::static_method:
print_static_method(method);
break;
case Method::Kind::constructor:
print_constructor(method);
break;
case Method::Kind::member_method:
print_member_method(method);
break;
}
}
void template_cpp_generator::class_printer::print_method(const Method &method)
{
print_any_method(NoCopyMethod(method));
}
void template_cpp_generator::class_printer::print_method(
const ConversionMethod &method)
{
print_any_method(method);
}
struct template_cpp_generator::class_decl_printer :
public specialization_printer
{
class_decl_printer(std::ostream &os,
template_cpp_generator &generator) :
specialization_printer(os, generator) {}
void print_arg_subclass_constructor(const specialization &instance,
const std::vector<std::string> ¶ms) const;
void print_super_constructor(const specialization &instance) const;
virtual void print_class(const specialization &instance) const override;
};
void template_cpp_generator::class_decl_printer::print_arg_subclass_constructor(
const specialization &instance,
const std::vector<std::string> ¶ms) const
{
const auto &class_name = instance.class_name();
auto rename = param_renamer(params, "Arg");
auto derived = instance.kind.apply(rename);
os << " template ";
os << "<";
print_pure_template_args(os, derived.params());
os << ",\n";
os << " typename std::enable_if<\n";
for (size_t i = 0; i < params.size(); ++i) {
if (i != 0)
os << " &&\n";
os << " std::is_base_of<"
<< params[i] << ", "
<< rename.at(params[i])->params()[0] << ">{}";
}
os << ",\n";
os << " bool>::type = true>";
os << "\n";
os << " " << class_name << "(const ";
print_bare_template_type(os, class_name, derived);
os << " &obj) : " << instance.base_name() << "(obj) {}\n";
}
void template_cpp_generator::class_decl_printer::print_super_constructor(
const specialization &instance) const
{
bool hide = !instance.kind.is_anon_set();
const auto &base_name = instance.base_name();
const auto &arg_name = hide ? "base" : base_name;
if (hide) {
os << " private:\n";
os << " template <typename base,\n";
os << " typename std::enable_if<\n";
os << " std::is_same<base, " << base_name
<< ">{}, bool>::type = true>\n";
}
os << " " << instance.class_name()
<< "(const " << arg_name << " &obj) : "
<< base_name << "(obj) {}\n";
if (hide)
os << " public:\n";
os << " static " << instance.class_name() << " from"
<< "(const " << base_name << " &obj) {\n";
os << " return " << instance.class_name() << "(obj);\n";
os << " }\n";
}
void template_cpp_generator::class_decl_printer::print_class(
const specialization &instance) const
{
const auto &class_name = instance.class_name();
auto params = instance.kind.params();
os << "\n";
print_template(os, params);
os << "struct ";
print_bare_template_type(os, class_name, instance.kind);
os << " : public " << instance.base_name() << " {\n";
generator.print_friends(os);
os << "\n";
os << " " << class_name << "() = default;\n";
if (params.size() != 0)
print_arg_subclass_constructor(instance, params);
print_super_constructor(instance);
method_decl_printer(instance, *this).print_all_methods();
os << "};\n";
}
struct template_cpp_generator::class_impl_printer :
public specialization_printer
{
class_impl_printer(std::ostream &os,
template_cpp_generator &generator) :
specialization_printer(os, generator) {}
virtual void print_class(const specialization &instance) const override;
};
void template_cpp_generator::class_impl_printer::print_class(
const specialization &instance) const
{
method_impl_printer(instance, *this).print_all_methods();
}
void template_cpp_generator::generate()
{
ostream &os = std::cout;
os << "\n";
print_forward_declarations(os);
class_decl_printer(os, *this).print_classes();
class_impl_printer(os, *this).print_classes();
}