Files
tdesktop/cmake/external/glib/cppgir/tools/genbase.cpp
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
init
2026-02-16 15:50:16 +03:00

223 lines
6.8 KiB
C++

#include "genbase.hpp"
#include <map>
static std::string
qualify(const std::string &ns, const std::string &cpptype, int flags)
{
if (cpptype.find(':') == cpptype.npos && !cpptype.empty() &&
!(flags & TYPE_BASIC))
return ns + "::" + cpptype;
return cpptype;
}
GeneratorBase::GeneratorBase(GeneratorContext &_ctx, const std::string _ns)
: ctx(_ctx), ns(_ns)
{}
std::string
GeneratorBase::qualify(const std::string &cpptype, int flags) const
{
return ::qualify(ns, cpptype, flags);
}
void
GeneratorBase::parse_typeinfo(
const std::string &girname, TypeInfo &result) const
{
auto ti = ctx.repo.lookup(girname);
if (ti && ti->info)
result = *ti->info;
}
GeneratorBase::ArgInfo
GeneratorBase::parse_arginfo(const pt::ptree &node, ArgInfo *routput) const
{
ArgInfo lresult;
ArgInfo &result = routput ? *routput : lresult;
const pt::ptree *pntype{};
std::string kind;
// try most likely in turn
for (auto &&v : {EL_TYPE, EL_ARRAY, EL_VARARGS}) {
const auto &ntypeo = node.get_child_optional(v);
if (ntypeo.is_initialized()) {
kind = v;
pntype = &ntypeo.get();
}
}
if (kind.empty() || !pntype)
throw skip("type info not found");
if (kind == EL_VARARGS)
throw skip("varargs not supported", skip::OK);
auto &ntype = *pntype;
bool discard_element = false;
// no name for array
if (kind == EL_ARRAY) {
result.flags = TYPE_ARRAY;
result.length = get_attribute<int>(ntype, AT_LENGTH, -10);
result.zeroterminated = get_attribute<int>(ntype, AT_ZERO_TERMINATED, 1);
result.fixedsize = get_attribute<int>(ntype, AT_FIXED_SIZE, 0);
if (result.length < 0 && !result.zeroterminated && !result.fixedsize)
throw skip("inconsistent array info");
auto name = get_name(ntype, std::nothrow);
// could be GBytes, etc
if (name.size()) {
// transform to plain argument if not ignored
// FIXME maybe custom wrappers might be more convenient ??
if (ctx.match_ignore.matches(ns, EL_RECORD, {name}))
throw skip(name + " array not supported", skip::OK);
// fresh state and discard element info processing
result = ArgInfo{};
discard_element = true;
parse_typeinfo(name, result);
}
} else {
parse_typeinfo(get_name(ntype), result);
}
// should be present (but not so for signal)
// though const info seems to be missing in array case
result.ctype = get_attribute(ntype, AT_CTYPE, "");
// special case where const is preserved for the cpp type
if (result.girname == "gpointer" && is_const(result.ctype))
parse_typeinfo("gconstpointer", result);
// handle element type info
int i = 0;
for (const auto &n : ntype) {
if (n.first == "type" && !discard_element) {
ArgTypeInfo &ti = i == 0 ? result.first : result.second;
auto elname = get_name(n.second);
parse_typeinfo(elname, ti);
if (!ti.flags)
throw skip("container element not supported", skip::OK);
// probably not, but give it a shot
ti.ctype = get_attribute(n.second, AT_CTYPE, "");
// avoid specialized bool vector
if (ti.cpptype == "bool")
ti.cpptype = "gboolean";
// some char arrays (e.g. g_regex* parameters) specify utf8 element type
// along with ctype char rather than char*
// so discard utf8 in that case and go for a plain array
if (kind == EL_ARRAY && elname == "utf8" && ti.ctype == "gchar")
parse_typeinfo(ti.ctype, ti);
++i;
}
}
// sanity checks
if ((result.flags & (TYPE_ARRAY | TYPE_LIST))) {
if (i != 1)
throw skip("inconsistent list element info");
if (result.flags & TYPE_ARRAY) {
// NOTE apparently both are possible, see e.g. g_shell_parse_arg*
// in that case it is handled zeroterminated
// and the size param becomes a regular one
if (result.zeroterminated) {
result.length = -1;
result.fixedsize = 0;
}
// 1 pointer level more than the basic type
result.pdepth = ((result.first.flags & TYPE_CLASS) ? 1 : 0) + 1;
}
} else if (result.flags & TYPE_MAP) {
if (i != 2)
throw skip("inconsistent map element info");
} else {
if (i != 0)
throw skip("inconsistent type info");
}
return result;
}
std::string
GeneratorBase::make_ctype(
const ArgInfo &info, const std::string &direction, bool callerallocates)
{
std::string result;
bool out = !(direction == DIR_IN || direction == DIR_RETURN);
if (info.flags & TYPE_ARRAY) {
auto ret = info.first.argtype + GI_PTR;
if (out && !callerallocates)
ret += GI_PTR;
result = ret;
} else if (info.flags & TYPE_CALLBACK) {
result = info.cpptype + "::cfunction_type";
} else {
if (!out || callerallocates) {
result = info.argtype;
} else {
result = info.argtype + GI_PTR;
}
}
return (is_const(info.ctype) ? std::string("const ") : EMPTY) + result;
}
void
GeneratorBase::track_dependency(DepsSet &deps, const ArgInfo &info) const
{
auto track = [&](const std::string &cpptype, int flags) {
// other items (e.g. enums) are included before anyway
if (flags & TYPE_CLASS && !(flags & (TYPE_BASIC | TYPE_TYPEDEF))) {
// always track scoped
assert(is_qualified(cpptype));
deps.insert({"", cpptype});
if (flags & TYPE_BOXED)
deps.insert({"", cpptype + GI_SUFFIX_REF});
}
};
if (!(info.flags & TYPE_CONTAINER)) {
track(info.cpptype, info.flags);
} else {
track(info.first.cpptype, info.first.flags);
if (info.flags & TYPE_MAP)
track(info.second.cpptype, info.second.flags);
}
}
bool
GeneratorBase::check_suppression(const std::string &ns, const std::string &kind,
const std::string &name) const
{
// always generate
ctx.suppressions.insert(ctx.match_sup.format(ns, kind, name));
return ctx.match_sup.matches(ns, kind, {name});
}
std::string
GeneratorBase::make_wrap_format(const ArgInfo &info,
const std::string &transfer, const std::string &outtype)
{
std::string fmts;
auto format = "{}";
if (info.flags & TYPE_CLASS) {
fmts = fmt::format(GI_NS_SCOPED + "wrap ({}, {})", format,
get_transfer_parameter(transfer));
} else if (info.flags & TYPE_ENUM) {
fmts = GI_NS_SCOPED + "wrap ({})";
} else if (info.flags & (TYPE_LIST | TYPE_ARRAY | TYPE_MAP)) {
assert(!outtype.empty());
fmts = fmt::format(GI_NS_SCOPED + "wrap_to<{}>({}, {})", outtype, format,
get_transfer_parameter(transfer));
} else {
fmts = format;
}
return fmts;
}
std::string
GeneratorBase::get_transfer_parameter(const std::string &transfer, bool _type)
{
std::map<std::string, std::string> m{
{TRANSFER_NOTHING, "transfer_none"},
{TRANSFER_FULL, "transfer_full"},
{TRANSFER_CONTAINER, "transfer_container"},
};
auto it = m.find(transfer);
if (it == m.end())
throw std::runtime_error("invalid transfer " + transfer);
return GI_NS_SCOPED + it->second + (_type ? "_t" : "");
}