init
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
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
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
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
172
cmake/external/glib/cppgir/tools/common.hpp
vendored
Normal file
172
cmake/external/glib/cppgir/tools/common.hpp
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
#ifndef COMMON_HPP
|
||||
#define COMMON_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
const char GI_PTR = '*';
|
||||
const std::string GI_SUFFIX_REF = "_Ref";
|
||||
const std::string GI_SUFFIX_CF_CTYPE = "_CF_CType";
|
||||
const std::string GI_SUFFIX_CB_TRAIT = "_CB_Trait";
|
||||
|
||||
const std::string GIR_GOBJECT("GObject.Object");
|
||||
const std::string GIR_GINITIALLYUNOWNED("GObject.InitiallyUnowned");
|
||||
const std::string GIR_GVARIANT("GLib.Variant");
|
||||
const std::string GIR_VOID("none");
|
||||
const std::string GIR_GDESTROYNOTIFY("GLib.DestroyNotify");
|
||||
|
||||
const std::string GDESTROYNOTIFY("GDestroyNotify");
|
||||
const std::string CPP_VOID("void");
|
||||
const std::string GIR_SUFFIX(".gir");
|
||||
|
||||
const std::string PT_ATTR("<xmlattr>");
|
||||
const std::string GI_NS("gi");
|
||||
const std::string GI_NS_INTERNAL("internal");
|
||||
const std::string GI_NS_IMPL("impl");
|
||||
const std::string GI_NS_ARGS("callargs");
|
||||
const std::string GI_SCOPE("::");
|
||||
const std::string GI_NS_SCOPED("gi::");
|
||||
const std::string GI_NS_DETAIL_SCOPED("gi::detail::");
|
||||
const std::string GI_REPOSITORY_NS("repository");
|
||||
const std::string GI_INLINE("GI_INLINE_DECL");
|
||||
const std::string GI_CLASS_IMPL_BEGIN("GI_CLASS_IMPL_BEGIN");
|
||||
const std::string GI_CLASS_IMPL_END("GI_CLASS_IMPL_END");
|
||||
const std::string GI_DISABLE_DEPRECATED_WARN_BEGIN(
|
||||
"GI_DISABLE_DEPRECATED_WARN_BEGIN");
|
||||
const std::string GI_DISABLE_DEPRECATED_WARN_END(
|
||||
"GI_DISABLE_DEPRECATED_WARN_END");
|
||||
const std::string EMPTY;
|
||||
|
||||
const std::string EL_REPOSITORY("repository");
|
||||
const std::string EL_CINCLUDE("c:include");
|
||||
const std::string EL_ALIAS("alias");
|
||||
const std::string EL_ENUM("enumeration");
|
||||
const std::string EL_FLAGS("bitfield");
|
||||
const std::string EL_MEMBER("member");
|
||||
const std::string EL_CONST("constant");
|
||||
const std::string EL_OBJECT("class");
|
||||
const std::string EL_INTERFACE("interface");
|
||||
const std::string EL_RECORD("record");
|
||||
const std::string EL_CALLBACK("callback");
|
||||
|
||||
const std::string EL_FUNCTION("function");
|
||||
const std::string EL_CONSTRUCTOR("constructor");
|
||||
const std::string EL_METHOD("method");
|
||||
const std::string EL_VIRTUAL_METHOD("virtual-method");
|
||||
const std::string EL_FIELD("field");
|
||||
const std::string EL_PROPERTY("property");
|
||||
const std::string EL_SIGNAL("glib:signal");
|
||||
|
||||
const std::string EL_RETURN("return-value");
|
||||
const std::string EL_PARAMETERS("parameters");
|
||||
const std::string EL_INSTANCE_PARAMETER("instance-parameter");
|
||||
const std::string EL_PARAMETER("parameter");
|
||||
|
||||
const std::string EL_TYPE("type");
|
||||
const std::string EL_ARRAY("array");
|
||||
const std::string EL_VARARGS("varargs");
|
||||
const std::string EL_IMPLEMENTS("implements");
|
||||
|
||||
const std::string AT_SHARED_LIBRARY("shared-library");
|
||||
const std::string AT_DEPRECATED("deprecated");
|
||||
const std::string AT_INTROSPECTABLE("introspectable");
|
||||
const std::string AT_FOREIGN("foreign");
|
||||
const std::string AT_SHADOWS("shadows");
|
||||
const std::string AT_SHADOWED_BY("shadowed-by");
|
||||
const std::string AT_DISGUISED("disguised");
|
||||
const std::string AT_MOVED_TO("moved-to");
|
||||
const std::string AT_VERSION("version");
|
||||
|
||||
const std::string AT_NAME("name");
|
||||
const std::string AT_TRANSFER("transfer-ownership");
|
||||
const std::string AT_DIRECTION("direction");
|
||||
const std::string AT_CLOSURE("closure");
|
||||
const std::string AT_DESTROY("destroy");
|
||||
const std::string AT_SCOPE("scope");
|
||||
const std::string AT_NULLABLE("nullable");
|
||||
const std::string AT_OPTIONAL("optional");
|
||||
const std::string AT_ALLOW_NONE("allow-none");
|
||||
const std::string AT_CALLER_ALLOCATES("caller-allocates");
|
||||
const std::string AT_GLIB_GET_TYPE("glib:get-type");
|
||||
const std::string AT_GLIB_FUNDAMENTAL("glib:fundamental");
|
||||
const std::string AT_GLIB_TYPE_STRUCT("glib:type-struct");
|
||||
const std::string AT_GLIB_IS_TYPE_STRUCT_FOR("glib:is-gtype-struct-for");
|
||||
|
||||
const std::string AT_PARENT("parent");
|
||||
|
||||
const std::string AT_LENGTH("length");
|
||||
const std::string AT_ZERO_TERMINATED("zero-terminated");
|
||||
const std::string AT_FIXED_SIZE("fixed-size");
|
||||
|
||||
const std::string AT_THROWS("throws");
|
||||
const std::string AT_CTYPE("c:type");
|
||||
const std::string AT_CIDENTIFIER("c:identifier");
|
||||
|
||||
const std::string TRANSFER_NOTHING("none");
|
||||
const std::string TRANSFER_FULL("full");
|
||||
const std::string TRANSFER_CONTAINER("container");
|
||||
|
||||
const std::string SCOPE_NOTIFIED("notified");
|
||||
const std::string SCOPE_ASYNC("async");
|
||||
const std::string SCOPE_CALL("call");
|
||||
|
||||
const std::string DIR_IN("in");
|
||||
const std::string DIR_OUT("out");
|
||||
const std::string DIR_INOUT("inout");
|
||||
const std::string DIR_RETURN("return");
|
||||
|
||||
const std::string AT_READABLE("readable");
|
||||
const std::string AT_WRITABLE("writable");
|
||||
const std::string AT_PRIVATE("private");
|
||||
} // namespace
|
||||
|
||||
enum class Log { NONE, ERROR, WARNING, INFO, DEBUG, LOG };
|
||||
|
||||
extern Log _loglevel;
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
logger(Log level, const T &m)
|
||||
{
|
||||
static std::string lvl[] = {"NONE", "ERROR", "WARN", "INFO", "DEBUG", "LOG"};
|
||||
if (level <= _loglevel)
|
||||
std::cerr << lvl[(int)level] << " " << m << std::endl;
|
||||
}
|
||||
|
||||
template<typename T, typename ARG, typename... ARGS>
|
||||
void
|
||||
logger(Log level, const T &m, ARG &&arg, ARGS &&...args)
|
||||
{
|
||||
logger(level,
|
||||
fmt::format(m, std::forward<ARG>(arg), std::forward<ARGS>(args)...));
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_qualified(const std::string &name)
|
||||
{
|
||||
return (name.find(':') != name.npos) || (name.find('.') != name.npos);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
toupper(const std::string &s)
|
||||
{
|
||||
auto c = s;
|
||||
for (auto &ch : c)
|
||||
ch = std::toupper(ch);
|
||||
return c;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
tolower(const std::string &s)
|
||||
{
|
||||
auto c = s;
|
||||
for (auto &ch : c)
|
||||
ch = std::tolower(ch);
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif // COMMON_HPP
|
||||
514
cmake/external/glib/cppgir/tools/cppgir.cpp
vendored
Normal file
514
cmake/external/glib/cppgir/tools/cppgir.cpp
vendored
Normal file
@@ -0,0 +1,514 @@
|
||||
#include "common.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "genbase.hpp"
|
||||
#include "genns.hpp"
|
||||
#include "repository.hpp"
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
// thanks go to glib
|
||||
#define GI_STRINGIFY(macro_or_string) GI_STRINGIFY_ARG(macro_or_string)
|
||||
#define GI_STRINGIFY_ARG(contents) #contents
|
||||
|
||||
#ifndef DEFAULT_IGNORE_FILE
|
||||
// embed ignore data
|
||||
#include "ignore.hpp"
|
||||
static std::string GI_DEFAULT_IGNORE;
|
||||
#else
|
||||
static const char *GI_DATA_IGNORE = "";
|
||||
static std::string GI_DEFAULT_IGNORE{GI_STRINGIFY(DEFAULT_IGNORE_FILE)};
|
||||
#endif
|
||||
|
||||
static const char PATH_SEP = '/';
|
||||
static const std::string GIR_SUBDIR{"gir-1.0"};
|
||||
|
||||
Log _loglevel = Log::WARNING;
|
||||
|
||||
class Generator
|
||||
{
|
||||
GeneratorContext &ctx_;
|
||||
std::vector<std::string> girdirs_;
|
||||
// processes ns (ns: ns header)
|
||||
std::map<std::string, std::string> processed_;
|
||||
|
||||
public:
|
||||
Generator(GeneratorContext &_ctx, const std::vector<std::string> &girdirs)
|
||||
: ctx_(_ctx), girdirs_(girdirs)
|
||||
{}
|
||||
|
||||
std::string find_in_dir(const fs::path p, const std::string &ns) const
|
||||
{
|
||||
std::string result;
|
||||
fs::error_code ec;
|
||||
// check if in this directory
|
||||
if (!fs::is_directory(p, ec))
|
||||
return "";
|
||||
|
||||
auto f = p / (ns + GIR_SUFFIX);
|
||||
std::vector<fs::directory_entry> dirs;
|
||||
for (auto &&entry : fs::directory_iterator(p, ec)) {
|
||||
if (fs::is_directory(entry, ec)) {
|
||||
dirs.emplace_back(entry);
|
||||
} else if (f == entry) {
|
||||
// exact match
|
||||
result = f.native();
|
||||
} else {
|
||||
// non-version match
|
||||
auto ename = entry.path().filename().native();
|
||||
auto s = ns.size();
|
||||
if (ename.substr(0, s) == ns && ename.size() > s && ename[s] == '-')
|
||||
result = entry.path().native();
|
||||
}
|
||||
}
|
||||
// check dirs
|
||||
while (!dirs.empty() && result.empty()) {
|
||||
result = find_in_dir(dirs.back(), ns);
|
||||
dirs.pop_back();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string find(const std::string &ns) const
|
||||
{
|
||||
for (auto &&d : girdirs_) {
|
||||
auto res = find_in_dir(fs::path(d), ns);
|
||||
if (!res.empty())
|
||||
return res;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// gir might be:
|
||||
// + a GIR filename
|
||||
// + or a GIR namespace (ns-version)
|
||||
// + or a GIR namespace (no version appended)
|
||||
void generate(const std::string &gir, bool recurse)
|
||||
{
|
||||
fs::path f(gir);
|
||||
fs::error_code ec;
|
||||
auto path = fs::exists(f, ec) ? gir : find(gir);
|
||||
if (path.empty())
|
||||
throw std::runtime_error("could not find GIR for " + gir);
|
||||
// avoid reading if possible
|
||||
if (processed_.count(gir))
|
||||
return;
|
||||
auto genp = NamespaceGenerator::new_(ctx_, path);
|
||||
auto &gen = *genp;
|
||||
// normalize namespace
|
||||
auto &&ns = gen.get_ns();
|
||||
// prevent duplicate processing
|
||||
if (processed_.count(ns))
|
||||
return;
|
||||
// generate deps
|
||||
auto &&deps = gen.get_dependencies();
|
||||
std::vector<std::string> headers;
|
||||
if (recurse) {
|
||||
for (auto &&d : deps) {
|
||||
generate(d, recurse);
|
||||
// should be available now
|
||||
headers.emplace_back(processed_[d]);
|
||||
}
|
||||
}
|
||||
// now generate this one
|
||||
// also mark processed and retain ns header file
|
||||
processed_[ns] = gen.process_tree(headers);
|
||||
}
|
||||
};
|
||||
|
||||
static std::string
|
||||
wrap(const char *s)
|
||||
{
|
||||
std::string res;
|
||||
if (s)
|
||||
res = s;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
die(const std::string &desc, const std::string &msg = "")
|
||||
{
|
||||
std::cout << msg << std::endl << std::endl;
|
||||
std::cout << desc << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::string
|
||||
make_subdir(const std::string &dir, const std::string &subdir)
|
||||
{
|
||||
auto result = dir;
|
||||
if (subdir.size()) {
|
||||
assert(subdir.front() != PATH_SEP);
|
||||
if (result.back() != PATH_SEP)
|
||||
result += PATH_SEP;
|
||||
result += subdir;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
addsplit(std::vector<std::string> &target, const std::string &src,
|
||||
const std::string &suffix = "", const std::string &seps = ":")
|
||||
{
|
||||
std::vector<std::string> tmp;
|
||||
boost::split(tmp, src, boost::is_any_of(seps));
|
||||
for (auto &&d : tmp) {
|
||||
if (d.size()) {
|
||||
target.emplace_back(make_subdir(d, suffix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace options
|
||||
{
|
||||
using OptionParseFunc = std::function<bool(const char *)>;
|
||||
|
||||
struct Option
|
||||
{
|
||||
std::string arg;
|
||||
OptionParseFunc func;
|
||||
};
|
||||
|
||||
Option
|
||||
make_parser(bool *val)
|
||||
{
|
||||
auto h = [val](const char *v) {
|
||||
// no arg for command-line option, set to true in that case
|
||||
*val = v ? atoi(v) : true;
|
||||
return true;
|
||||
};
|
||||
return {"", h};
|
||||
}
|
||||
|
||||
Option
|
||||
make_parser(int *val)
|
||||
{
|
||||
auto h = [val](const char *nextarg) {
|
||||
try {
|
||||
*val = std::stoi(nextarg);
|
||||
return true;
|
||||
} catch (const std::exception &exc) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return {"number", h};
|
||||
}
|
||||
|
||||
Option
|
||||
make_parser(std::string *val)
|
||||
{
|
||||
auto h = [val](const char *nextarg) {
|
||||
*val = nextarg;
|
||||
return true;
|
||||
};
|
||||
return {"arg", h};
|
||||
}
|
||||
|
||||
} // namespace options
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
using namespace options;
|
||||
|
||||
// env/options targets
|
||||
int debug_level{};
|
||||
std::string fpath_ignore;
|
||||
std::string fpath_suppress{};
|
||||
std::string fpath_gen_suppress;
|
||||
std::string output_dir;
|
||||
bool doclass{};
|
||||
bool dofullclass{};
|
||||
bool use_dl{};
|
||||
bool use_expected{};
|
||||
bool const_method{};
|
||||
bool output_top{};
|
||||
int call_args{-1};
|
||||
bool basic_collection{};
|
||||
bool dump_ignore{};
|
||||
std::string gir_path;
|
||||
|
||||
std::string helpdesc;
|
||||
struct OptionData
|
||||
{
|
||||
std::string opt;
|
||||
std::string var;
|
||||
const char *desc;
|
||||
Option option{};
|
||||
};
|
||||
std::vector<OptionData> descs = {
|
||||
{"help", "", "produce help message"},
|
||||
{"debug", "GI_DEBUG", "debug level", make_parser(&debug_level)},
|
||||
{"ignore", "GI_IGNORE", "colon separated ignore files",
|
||||
make_parser(&fpath_ignore)},
|
||||
{"suppression", "GI_SUPPRESSION", "colon separated suppression files",
|
||||
make_parser(&fpath_suppress)},
|
||||
{"gen-suppression", "G_GEN_SUPPRESSION", "generate suppression file",
|
||||
make_parser(&fpath_gen_suppress)},
|
||||
{"output", "GI_OUTPUT", "output directory", make_parser(&output_dir)},
|
||||
{"gir-path", "GI_GIR_PATH", "colon separated GIR search path",
|
||||
make_parser(&gir_path)},
|
||||
{"class", "GI_CLASS", "generate class implementation",
|
||||
make_parser(&doclass)},
|
||||
{"class-full", "GI_CLASS_FULL", "generate fallback class methods",
|
||||
make_parser(&dofullclass)},
|
||||
{"dl", "GI_DL", "use dynamic dlopen/dlsym rather than static link",
|
||||
make_parser(&use_dl)},
|
||||
{"expected", "GI_EXPECTED", "use expected<> return rather than exception",
|
||||
make_parser(&use_expected)},
|
||||
{"const-method", "GI_CONST_METHOD", "generate const methods",
|
||||
make_parser(&const_method)},
|
||||
{"output-top", "GI_OUTPUT_TOP",
|
||||
"generate convenience wrappers in output dir",
|
||||
make_parser(&output_top)},
|
||||
{"call-args", "GI_CALL_ARGS",
|
||||
"(if >= 0) min #optional arguments to enable a CallArgs variant",
|
||||
make_parser(&call_args)},
|
||||
{"basic-collection", "GI_BASIC_COLLECTION",
|
||||
"also generate collection for input collection of basic type",
|
||||
make_parser(&basic_collection)},
|
||||
};
|
||||
|
||||
// optionally dump embedded ignore
|
||||
if (*GI_DATA_IGNORE) {
|
||||
descs.push_back({"dump-ignore", "", "dump embedded ignore data",
|
||||
make_parser(&dump_ignore)});
|
||||
}
|
||||
|
||||
std::map<std::string, OptionData *> descs_index;
|
||||
|
||||
// first collect settings from environment
|
||||
for (auto &e : descs) {
|
||||
// build index
|
||||
descs_index[e.opt] = &e;
|
||||
// check env var
|
||||
if (!e.var.empty() && e.option.func) {
|
||||
if (auto v = getenv(e.var.c_str())) {
|
||||
e.option.func(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non-option argument analogue
|
||||
auto gir_top = wrap(getenv("GI_GIR"));
|
||||
|
||||
// into settings
|
||||
std::vector<std::string> girs, ignore_files, suppress_files;
|
||||
std::vector<std::string> girdirs;
|
||||
|
||||
// collect ignore files
|
||||
auto fpath_ignore_env = std::move(fpath_ignore);
|
||||
// suppress files
|
||||
auto fpath_suppress_env = std::move(fpath_suppress);
|
||||
// GIR path
|
||||
auto gir_path_env = std::move(gir_path);
|
||||
|
||||
{ // basic command line processing
|
||||
// assemble help description
|
||||
auto tmpl = (R"|(
|
||||
{} [options] girs...
|
||||
|
||||
Supported options and environment variables
|
||||
(specify 0 or 1 as environment variable value for a boolean switch):
|
||||
|
||||
)|");
|
||||
helpdesc = fmt::format(tmpl, argv[0]);
|
||||
for (auto &entry : std::as_const(descs)) {
|
||||
std::string var = entry.var;
|
||||
var = !var.empty() ? fmt::format("[{}] ", var) : var;
|
||||
helpdesc += fmt::format(" --{:<25}{}{}\n",
|
||||
entry.opt + ' ' + entry.option.arg, var, entry.desc);
|
||||
}
|
||||
if (!GI_DEFAULT_IGNORE.empty()) {
|
||||
helpdesc +=
|
||||
fmt::format("\nDefault ignore files:\n{}\n", GI_DEFAULT_IGNORE);
|
||||
}
|
||||
|
||||
// simple command line processing
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string opt = argv[i];
|
||||
if (opt == "-h" || opt == "--help")
|
||||
return die(helpdesc);
|
||||
if (opt.size() > 2 && opt.find("--") == 0) {
|
||||
auto oi = descs_index.find(opt.substr(2));
|
||||
if (oi != descs_index.end()) {
|
||||
assert(oi->second);
|
||||
auto &option = *oi->second;
|
||||
assert(option.option.func);
|
||||
char *nextarg = nullptr;
|
||||
if (!option.option.arg.empty()) {
|
||||
if (i + 1 >= argc) {
|
||||
return die(helpdesc, opt + "; missing argument");
|
||||
} else {
|
||||
nextarg = argv[i + 1];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
logger(Log::LOG,
|
||||
fmt::format("processing option {} {}", opt, wrap(nextarg)));
|
||||
if (!option.option.func(nextarg))
|
||||
return die(helpdesc, opt + "; invalid argument " + nextarg);
|
||||
} else {
|
||||
return die(helpdesc, "unknown option " + opt);
|
||||
}
|
||||
} else if (!opt.empty() && opt[0] == '-') {
|
||||
return die(helpdesc, "unknown option " + opt);
|
||||
} else {
|
||||
girs.push_back(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_ignore) {
|
||||
std::cout << GI_DATA_IGNORE << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// collect some more files
|
||||
addsplit(ignore_files, fpath_ignore);
|
||||
addsplit(suppress_files, fpath_suppress);
|
||||
addsplit(girdirs, gir_path);
|
||||
|
||||
// add env specified
|
||||
addsplit(ignore_files, fpath_ignore_env);
|
||||
addsplit(suppress_files, fpath_suppress_env);
|
||||
addsplit(girdirs, gir_path_env);
|
||||
|
||||
// level
|
||||
if (debug_level > 0)
|
||||
_loglevel = (Log)debug_level;
|
||||
|
||||
// system default
|
||||
{
|
||||
// gobject-introspection considers XDG_DATA_HOME first
|
||||
// (essentially g_get_user_data_dir)
|
||||
auto xdg_data_home = wrap(getenv("XDG_DATA_HOME"));
|
||||
if (xdg_data_home.empty()) {
|
||||
xdg_data_home = wrap(getenv("HOME"));
|
||||
if (!xdg_data_home.empty()) {
|
||||
if (xdg_data_home.back() != PATH_SEP)
|
||||
xdg_data_home += PATH_SEP;
|
||||
xdg_data_home += fmt::format(".local{}share", PATH_SEP);
|
||||
}
|
||||
}
|
||||
std::vector<std::string> default_gir_dirs;
|
||||
if (!xdg_data_home.empty())
|
||||
default_gir_dirs.push_back(xdg_data_home);
|
||||
// gobject-introspection uses XDG_DATA_DIRS next
|
||||
// (essentially g_get_system_data_dirs)
|
||||
auto xdg_data_dirs = wrap(getenv("XDG_DATA_DIRS"));
|
||||
addsplit(default_gir_dirs, xdg_data_dirs);
|
||||
// g_get_system_data_dirs optionally falls back to fixed /usr[/local] now
|
||||
// but that would then precede custom paths, which is a bit unfortunate
|
||||
// so, instead, consider those only as the very last resort (below)
|
||||
for (auto &d : default_gir_dirs) {
|
||||
girdirs.push_back(make_subdir(d, GIR_SUBDIR));
|
||||
}
|
||||
}
|
||||
|
||||
// extra GIR paths that gobject-introspection considers
|
||||
#ifdef GI_GIR_DIR
|
||||
girdirs.push_back(GI_STRINGIFY(GI_GIR_DIR));
|
||||
#endif
|
||||
#ifdef GI_DATA_DIR
|
||||
girdirs.push_back(GI_STRINGIFY(GI_DATA_DIR));
|
||||
#endif
|
||||
#ifdef DEFAULT_GIRPATH
|
||||
// optional (hard) fallback
|
||||
addsplit(girdirs, GI_STRINGIFY(DEFAULT_GIRPATH), GIR_SUBDIR);
|
||||
#endif
|
||||
|
||||
for (auto &&d : girdirs)
|
||||
logger(Log::DEBUG, "extending GIR path " + d);
|
||||
|
||||
// system default
|
||||
if (!GI_DEFAULT_IGNORE.empty())
|
||||
addsplit(ignore_files, GI_DEFAULT_IGNORE);
|
||||
|
||||
// collect girs to process
|
||||
addsplit(girs, gir_top);
|
||||
|
||||
// sanity check
|
||||
if (output_dir.empty())
|
||||
return die(helpdesc, "missing output directory");
|
||||
if (girs.empty())
|
||||
return die(helpdesc, "nothing to process");
|
||||
|
||||
// check for now
|
||||
if (girdirs.empty())
|
||||
return die(helpdesc, "empty search path");
|
||||
|
||||
// at least the standard ignore file is required
|
||||
// or things will go wrong
|
||||
int cnt = 0;
|
||||
fs::error_code ec;
|
||||
for (auto &f : ignore_files)
|
||||
cnt += fs::exists(f, ec);
|
||||
|
||||
if (cnt == 0 && !GI_DEFAULT_IGNORE.empty())
|
||||
return die(helpdesc, "required default ignore file location not specified");
|
||||
|
||||
// HACKety hack; extract some other config from ignore files
|
||||
// (avoids coming up with another separate config file for now)
|
||||
std::map<std::string, std::string> custom_c_types;
|
||||
auto custom = [&custom_c_types](const std::string &line) {
|
||||
if (line.find("#!ctype:") == 0) {
|
||||
std::vector<std::string> tmp;
|
||||
addsplit(tmp, line);
|
||||
if (tmp.size() == 3) {
|
||||
custom_c_types[tmp[1]] = tmp[2];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto match_ignore = Matcher(ignore_files, GI_DATA_IGNORE, custom);
|
||||
auto match_suppress = Matcher(suppress_files);
|
||||
|
||||
// now let's start
|
||||
GeneratorOptions options;
|
||||
options.rootdir = output_dir;
|
||||
options.classimpl = doclass;
|
||||
options.classfull = dofullclass;
|
||||
options.dl = use_dl;
|
||||
options.expected = use_expected;
|
||||
options.const_method = const_method;
|
||||
options.output_top = output_top;
|
||||
options.call_args = call_args;
|
||||
options.basic_collection = basic_collection;
|
||||
|
||||
logger(Log::INFO, "generating to directory {}", options.rootdir);
|
||||
|
||||
auto repo = Repository::new_(custom_c_types);
|
||||
std::set<std::string> suppressions;
|
||||
GeneratorContext ctx{
|
||||
options, *repo, match_ignore, match_suppress, suppressions};
|
||||
Generator gen(ctx, girdirs);
|
||||
try {
|
||||
for (auto &&g : girs)
|
||||
gen.generate(g, true);
|
||||
|
||||
// write suppression
|
||||
if (fpath_gen_suppress.size()) {
|
||||
std::vector<std::string> sup(suppressions.begin(), suppressions.end());
|
||||
sort(sup.begin(), sup.end());
|
||||
logger(Log::INFO, "writing {} suppressions to {}", sup.size(),
|
||||
fpath_gen_suppress);
|
||||
|
||||
std::ofstream fsup(fpath_gen_suppress);
|
||||
for (auto &&v : sup)
|
||||
fsup << v << std::endl;
|
||||
}
|
||||
} catch (std::runtime_error &ex) {
|
||||
logger(Log::ERROR, ex.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
25
cmake/external/glib/cppgir/tools/format.hpp
vendored
Normal file
25
cmake/external/glib/cppgir/tools/format.hpp
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FORMAT_HPP
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// available as of gcc-13
|
||||
// also requires/checks the above guard on C++20
|
||||
|
||||
#include <format>
|
||||
#include <string_view>
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template<typename... Args>
|
||||
inline std::string
|
||||
format(std::string_view format, Args &&...args)
|
||||
{
|
||||
return std::vformat(format, std::make_format_args(args...));
|
||||
}
|
||||
} // namespace fmt
|
||||
|
||||
#else
|
||||
// use original fmtlib
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
#endif // FORMAT_HPP
|
||||
13
cmake/external/glib/cppgir/tools/fs.hpp
vendored
Normal file
13
cmake/external/glib/cppgir/tools/fs.hpp
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef FS_HPP
|
||||
#define FS_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
using namespace std::filesystem;
|
||||
using error_code = std::error_code;
|
||||
} // namespace fs
|
||||
|
||||
#endif // FS_HPP
|
||||
2153
cmake/external/glib/cppgir/tools/function.cpp
vendored
Normal file
2153
cmake/external/glib/cppgir/tools/function.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
128
cmake/external/glib/cppgir/tools/function.hpp
vendored
Normal file
128
cmake/external/glib/cppgir/tools/function.hpp
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef FUNCTION_HPP
|
||||
#define FUNCTION_HPP
|
||||
|
||||
#include "genbase.hpp"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ElementFunction
|
||||
{
|
||||
// type of function; method, etc
|
||||
std::string kind;
|
||||
// GIR name
|
||||
std::string name;
|
||||
// otherwise descriptive name (e.g. original C name)
|
||||
std::string c_id;
|
||||
// expression defining function
|
||||
std::string functionexp;
|
||||
bool throws{};
|
||||
// represents symbol in lib
|
||||
// (which can be linked to or dlsym'ed)
|
||||
bool lib_symbol{};
|
||||
std::string shadows;
|
||||
};
|
||||
|
||||
// parameter data
|
||||
constexpr static const int INDEX_DEFAULT = -10;
|
||||
struct FunctionParameter
|
||||
{
|
||||
std::string name;
|
||||
GeneratorBase::ArgInfo tinfo{};
|
||||
// deduced C type
|
||||
std::string ptype;
|
||||
bool instance{};
|
||||
std::string direction;
|
||||
std::string transfer{TRANSFER_NOTHING};
|
||||
// index
|
||||
int closure{INDEX_DEFAULT}, destroy{INDEX_DEFAULT};
|
||||
int callerallocates{};
|
||||
std::string scope;
|
||||
bool optional{};
|
||||
bool nullable{};
|
||||
};
|
||||
using Parameter = FunctionParameter;
|
||||
|
||||
// info defining function to construct declaration/definition
|
||||
// (some parts not relevant for signal/callback)
|
||||
struct FunctionDefinition
|
||||
{
|
||||
// return (and optionally additional outputs)
|
||||
struct Output
|
||||
{
|
||||
// cpp type of output
|
||||
std::string type;
|
||||
// expression (value of output)
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct ArgTrait
|
||||
{
|
||||
// transfer (original attribute)
|
||||
std::string transfer;
|
||||
// inout parameter
|
||||
bool inout{};
|
||||
// applicable/relevant arguments (indexed as usual; see below)
|
||||
// usually only 1 (to 1)
|
||||
// for callback; function, userdata[, destroy]
|
||||
// for sized arrays; data, size
|
||||
// (other containers only need 1 and handled as usual)
|
||||
std::vector<int> args;
|
||||
// custom type trait
|
||||
std::string custom{};
|
||||
};
|
||||
|
||||
// GIR name (empty if not valid)
|
||||
std::string name;
|
||||
// statements preceding wrapped call (excluding final ;)
|
||||
std::vector<std::string> pre_call;
|
||||
// idem, post call
|
||||
std::vector<std::string> post_call;
|
||||
// assembled outputs (first one is return value, if any, could be empty)
|
||||
std::vector<Output> cpp_outputs;
|
||||
// parts that make up the C call (...)
|
||||
// indexed by param number (instance = -1)
|
||||
std::map<int, std::string> c_call;
|
||||
// parts that make up the ( ... ) decl/def
|
||||
// (similarly indexed/sorted)
|
||||
std::map<int, std::string> cpp_decl;
|
||||
// callee; trait info of (callback) parameters
|
||||
// (lowest one is for return; always present)
|
||||
// (except if fallback virtual method)
|
||||
std::map<int, ArgTrait> arg_traits;
|
||||
// extra parameters in a callee (= cb) declaration not present in callforward
|
||||
// (to deal with cb sized array output0
|
||||
std::map<int, std::string> cpp_decl_extra;
|
||||
// function (expression) to call
|
||||
std::string c_callee;
|
||||
// format with single placeholder for call (constructed based on all above)
|
||||
std::string ret_format;
|
||||
// parts used for callforward generation of callback type
|
||||
// (callforward = C++ signature which then calls a C function)
|
||||
// (callback = C signature which then calls a C++ function)
|
||||
// typedef of C function to call
|
||||
std::string cf_ctype;
|
||||
// (derived) C signature (without instance parameter if virtual method)
|
||||
std::string c_sig;
|
||||
};
|
||||
|
||||
std::string make_arg_traits(
|
||||
const std::map<int, FunctionDefinition::ArgTrait> &traits,
|
||||
const std::string &c_sig);
|
||||
|
||||
FunctionDefinition process_element_function(GeneratorContext &_ctx,
|
||||
const std::string _ns, const pt::ptree::value_type &entry,
|
||||
std::ostream &out, std::ostream &impl, const std::string &klass,
|
||||
const std::string &klasstype, GeneratorBase::DepsSet &deps,
|
||||
std::ostream *call_args, bool allow_deprecated);
|
||||
|
||||
FunctionDefinition process_element_function(GeneratorContext &_ctx,
|
||||
const std::string _ns, const ElementFunction &func,
|
||||
const std::vector<Parameter> ¶ms, std::ostream &out, std::ostream &impl,
|
||||
const std::string &klass, const std::string &klasstype,
|
||||
GeneratorBase::DepsSet &deps);
|
||||
|
||||
#endif // FUNCTION_HPP
|
||||
222
cmake/external/glib/cppgir/tools/genbase.cpp
vendored
Normal file
222
cmake/external/glib/cppgir/tools/genbase.cpp
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
#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" : "");
|
||||
}
|
||||
115
cmake/external/glib/cppgir/tools/genbase.hpp
vendored
Normal file
115
cmake/external/glib/cppgir/tools/genbase.hpp
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
#ifndef GENBASE_HPP
|
||||
#define GENBASE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "genutils.hpp"
|
||||
#include "repository.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
struct GeneratorOptions
|
||||
{
|
||||
// dir in which to generate
|
||||
std::string rootdir;
|
||||
// generate implementation classes
|
||||
bool classimpl;
|
||||
// generate fallback methods (for class implementation)
|
||||
bool classfull;
|
||||
// use dlopen/dlsym for generated call
|
||||
bool dl;
|
||||
// use expected<> return iso exception throwing
|
||||
bool expected;
|
||||
// generate const methods
|
||||
bool const_method;
|
||||
// generate top-level helpers in rootdir
|
||||
bool output_top;
|
||||
// min number of non-required function arguments
|
||||
// that triggers generation a CallArgs variant
|
||||
int call_args;
|
||||
// also generate collection signature for input collection of basic type
|
||||
bool basic_collection;
|
||||
};
|
||||
|
||||
struct GeneratorContext
|
||||
{
|
||||
GeneratorOptions &options;
|
||||
Repository &repo;
|
||||
const Matcher &match_ignore;
|
||||
const Matcher &match_sup;
|
||||
// generated during processing
|
||||
std::set<std::string> &suppressions;
|
||||
};
|
||||
|
||||
class GeneratorBase
|
||||
{
|
||||
protected:
|
||||
GeneratorContext &ctx;
|
||||
std::string ns;
|
||||
const std::string indent = " ";
|
||||
|
||||
public:
|
||||
GeneratorBase(GeneratorContext &_ctx, const std::string _ns);
|
||||
|
||||
struct ArgTypeInfo : public TypeInfo
|
||||
{
|
||||
// c:type as parsed from type element
|
||||
// (no const info for array or filename arg)
|
||||
// (empty for void, and possibly property or signal)
|
||||
std::string ctype;
|
||||
|
||||
// return CppType or reference CppType (if non-owning boxed transfer)
|
||||
std::string cppreftype(const std::string transfer) const
|
||||
{
|
||||
if ((flags & TYPE_BOXED) && transfer != TRANSFER_FULL)
|
||||
return cpptype + GI_SUFFIX_REF;
|
||||
// string case
|
||||
if ((flags & TYPE_CLASS) && (flags & TYPE_BASIC) &&
|
||||
transfer != TRANSFER_FULL)
|
||||
return cpptype + "_v";
|
||||
return cpptype;
|
||||
}
|
||||
};
|
||||
|
||||
// the above along with info on contained element
|
||||
// (as provided typically within <type> element in parameter or so)
|
||||
// * first only relevant for array, lists and maps
|
||||
// * second only for maps
|
||||
// * first and second do not have ctype info
|
||||
// * in case of array, no cpptype info on primary
|
||||
// * in case of (GS)List etc, primary specifies the particular type
|
||||
struct ArgInfo : public ArgTypeInfo
|
||||
{
|
||||
// container element types
|
||||
ArgTypeInfo first, second;
|
||||
// array
|
||||
int length = -1;
|
||||
bool zeroterminated = false;
|
||||
int fixedsize = 0;
|
||||
};
|
||||
|
||||
std::string qualify(const std::string &cpptype, int flags) const;
|
||||
|
||||
void parse_typeinfo(const std::string &girname, TypeInfo &result) const;
|
||||
|
||||
// if routput != nullptr, also place result in output
|
||||
// (possibly a partial one if exception is thrown)
|
||||
ArgInfo parse_arginfo(
|
||||
const pt::ptree &node, ArgInfo *routput = nullptr) const;
|
||||
|
||||
static std::string make_ctype(
|
||||
const ArgInfo &info, const std::string &direction, bool callerallocates);
|
||||
|
||||
// set of (ns, dep), where dep = [struct|class ]type
|
||||
using DepsSet = std::set<std::pair<std::string, std::string>>;
|
||||
void track_dependency(DepsSet &deps, const ArgInfo &info) const;
|
||||
|
||||
static std::string make_wrap_format(const ArgInfo &info,
|
||||
const std::string &transfer, const std::string &outtype = {});
|
||||
|
||||
static std::string get_transfer_parameter(
|
||||
const std::string &transfer, bool _type = false);
|
||||
|
||||
bool check_suppression(const std::string &ns, const std::string &kind,
|
||||
const std::string &name) const;
|
||||
};
|
||||
#endif // GENBASE_HPP
|
||||
1741
cmake/external/glib/cppgir/tools/genns.cpp
vendored
Normal file
1741
cmake/external/glib/cppgir/tools/genns.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
25
cmake/external/glib/cppgir/tools/genns.hpp
vendored
Normal file
25
cmake/external/glib/cppgir/tools/genns.hpp
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef GENNS_HPP
|
||||
#define GENNS_HPP
|
||||
|
||||
struct GeneratorContext;
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class NamespaceGenerator
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<NamespaceGenerator> new_(
|
||||
GeneratorContext &ctx, const std::string &filename);
|
||||
|
||||
virtual ~NamespaceGenerator() {}
|
||||
|
||||
virtual std::string get_ns() const = 0;
|
||||
|
||||
virtual std::vector<std::string> get_dependencies() const = 0;
|
||||
|
||||
virtual std::string process_tree(
|
||||
const std::vector<std::string> &dep_headers) = 0;
|
||||
};
|
||||
|
||||
#endif // GENNS_HPP
|
||||
31
cmake/external/glib/cppgir/tools/genutils.cpp
vendored
Normal file
31
cmake/external/glib/cppgir/tools/genutils.cpp
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "genutils.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
static std::set<std::string> reserved{"alignas", "alignof", "and", "and_eq",
|
||||
"asm", "atomic_cancel", "atomic_commit", "atomic_noexcept", "auto",
|
||||
"bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t",
|
||||
"char32_t", "class", "compl", "concept", "const", "constexpr", "const_cast",
|
||||
"continue", "co_await", "co_return", "co_yield", "decltype", "default",
|
||||
"delete", "do", "double", "dynamic_cast", "else", "enum", "explicit",
|
||||
"export", "extern", "false", "float", "for", "friend", "goto", "if",
|
||||
"import", "inline", "int", "long", "module", "mutable", "namespace", "new",
|
||||
"noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
|
||||
"private", "protected", "public", "register", "reflexpr",
|
||||
"reinterpret_cast", "requires", "return", "short", "signed", "sizeof",
|
||||
"static", "static_assert", "static_cast", "struct", "switch",
|
||||
"synchronized", "template", "this", "thread_local", "throw", "true", "try",
|
||||
"typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
|
||||
"void", "volatile", "wchar_t", "while", "xor", "xor_eq"};
|
||||
|
||||
std::string
|
||||
unreserve(const std::string &s, bool force)
|
||||
{
|
||||
auto res(s);
|
||||
if (!s.empty() && isdigit(s[0]))
|
||||
res.insert(res.begin(), '_');
|
||||
else if (reserved.find(s) != reserved.end() || toupper(s) == s || force)
|
||||
res += "_";
|
||||
return res;
|
||||
}
|
||||
192
cmake/external/glib/cppgir/tools/genutils.hpp
vendored
Normal file
192
cmake/external/glib/cppgir/tools/genutils.hpp
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
#ifndef GENUTILS_HPP
|
||||
#define GENUTILS_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class skip : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
static const int TODO = 0;
|
||||
static const int OK = 0;
|
||||
static const int INVALID = 1;
|
||||
static const int IGNORE = 2;
|
||||
int cause;
|
||||
|
||||
skip(const std::string &reason, int _cause = INVALID)
|
||||
: std::runtime_error(reason), cause(_cause)
|
||||
{}
|
||||
};
|
||||
|
||||
class ScopeGuard
|
||||
{
|
||||
private:
|
||||
std::function<void()> cleanup_;
|
||||
|
||||
public:
|
||||
ScopeGuard(std::function<void()> &&cleanup) : cleanup_(std::move(cleanup)) {}
|
||||
|
||||
~ScopeGuard() noexcept(false)
|
||||
{
|
||||
#if __cplusplus >= 201703L
|
||||
auto pending = std::uncaught_exceptions();
|
||||
#else
|
||||
auto pending = std::uncaught_exception();
|
||||
#endif
|
||||
try {
|
||||
cleanup_();
|
||||
} catch (...) {
|
||||
if (!pending)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NamespaceGuard
|
||||
{
|
||||
typedef std::vector<std::string> ns_list;
|
||||
|
||||
private:
|
||||
ns_list ns_;
|
||||
std::ostream &out_;
|
||||
|
||||
void push(const ns_list &ns)
|
||||
{
|
||||
for (auto &&v : ns) {
|
||||
out_ << "namespace " << v << " {" << std::endl << std::endl;
|
||||
ns_.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
NamespaceGuard(std::ostream &_out) : out_(_out) {}
|
||||
|
||||
void push(const std::string &ns, bool autodetect = true)
|
||||
{
|
||||
if (ns_.empty() && autodetect) {
|
||||
ns_list l{GI_NS, GI_REPOSITORY_NS};
|
||||
if (ns == GI_NS)
|
||||
l.pop_back();
|
||||
else if (ns != GI_REPOSITORY_NS)
|
||||
l.push_back(ns);
|
||||
push(l);
|
||||
} else {
|
||||
push(ns_list{ns});
|
||||
}
|
||||
}
|
||||
|
||||
void pop(int count = -1)
|
||||
{
|
||||
while (!ns_.empty() && (count > 0 || count < 0)) {
|
||||
out_ << "} // namespace";
|
||||
if (ns_.back().size())
|
||||
out_ << ' ' << ns_.back();
|
||||
out_ << std::endl << std::endl;
|
||||
ns_.pop_back();
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
~NamespaceGuard() { pop(); }
|
||||
};
|
||||
|
||||
class Matcher
|
||||
{
|
||||
std::regex pattern_;
|
||||
|
||||
static std::vector<std::string> readfile(std::istream &input)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
for (std::string line; std::getline(input, line);) {
|
||||
result.emplace_back(line);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
Matcher(const std::vector<std::string> &paths,
|
||||
const std::string &patterns = {},
|
||||
const std::function<void(const std::string &)> &custom = {})
|
||||
{
|
||||
std::set<std::string> lines;
|
||||
for (auto &fpath : paths) {
|
||||
if (fpath.size()) {
|
||||
std::ifstream input(fpath);
|
||||
auto flines = readfile(input);
|
||||
logger(Log::DEBUG, "read {} lines from {}", flines.size(), fpath);
|
||||
std::copy(
|
||||
flines.begin(), flines.end(), std::inserter(lines, lines.begin()));
|
||||
}
|
||||
}
|
||||
if (patterns.size()) {
|
||||
std::istringstream iss(patterns);
|
||||
auto flines = readfile(iss);
|
||||
logger(Log::DEBUG, "read {} data lines", flines.size());
|
||||
std::copy(
|
||||
flines.begin(), flines.end(), std::inserter(lines, lines.begin()));
|
||||
}
|
||||
|
||||
std::string lpatterns;
|
||||
for (auto &&l : lines) {
|
||||
if (!l.empty() && l[0] != '#') {
|
||||
// combine all expressions into 1 expression
|
||||
// so we only need to call once to check for matching
|
||||
lpatterns += (lpatterns.size() ? "|" : "") + l;
|
||||
} else if (custom && l.size() > 2 && l[0] == '#' && l[1] == '!') {
|
||||
custom(l);
|
||||
}
|
||||
}
|
||||
if (lpatterns.size())
|
||||
pattern_ = std::regex(lpatterns, std::regex::optimize);
|
||||
}
|
||||
|
||||
static std::string format(const std::string &first, const std::string &second,
|
||||
const std::string name)
|
||||
{
|
||||
return first + ":" + second + ":" + name;
|
||||
}
|
||||
|
||||
bool matches(const std::string &first, const std::string &second,
|
||||
const std::vector<std::string> &options) const
|
||||
{
|
||||
for (auto &&c : options) {
|
||||
// assemble string to match
|
||||
auto find = format(first, second, c);
|
||||
if (std::regex_match(find, pattern_))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool
|
||||
is_const(const std::string &ctype)
|
||||
{
|
||||
return (ctype.find("const ") != ctype.npos) || ctype == "gconstpointer";
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_volatile(const std::string &ctype)
|
||||
{
|
||||
return ctype.find("volatile ") != ctype.npos;
|
||||
}
|
||||
|
||||
inline int
|
||||
get_pointer_depth(const std::string &ctype)
|
||||
{
|
||||
int pointer = ctype.find("gpointer") != ctype.npos ||
|
||||
ctype.find("gconstpointer") != ctype.npos;
|
||||
// note that things like const gchar* const* are also possible
|
||||
return std::count(ctype.begin(), ctype.end(), GI_PTR) + !!pointer;
|
||||
}
|
||||
|
||||
// check if @s is somehow special
|
||||
// and mangle it a bit if so
|
||||
std::string unreserve(const std::string &s, bool force = false);
|
||||
|
||||
#endif // GENUTILS_HPP
|
||||
10
cmake/external/glib/cppgir/tools/ignore.hpp.in
vendored
Normal file
10
cmake/external/glib/cppgir/tools/ignore.hpp.in
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef IGNORE_HPP
|
||||
#define IGNORE_HPP
|
||||
|
||||
static const char *GI_DATA_IGNORE = R"|(
|
||||
@CPPGIR_IGNORE@
|
||||
@CPPGIR_UNIX_IGNORE@
|
||||
@CPPGIR_WIN_IGNORE@
|
||||
)|";
|
||||
|
||||
#endif // IGNORE_HPP
|
||||
341
cmake/external/glib/cppgir/tools/repository.cpp
vendored
Normal file
341
cmake/external/glib/cppgir/tools/repository.cpp
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
#include "repository.hpp"
|
||||
|
||||
#include "genutils.hpp"
|
||||
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
static std::set<std::string> basic_types{"gchar", "guchar", "gshort", "gushort",
|
||||
"gint", "guint", "glong", "gulong", "gssize", "gsize", "gintptr",
|
||||
"guintptr", "gpointer", "gconstpointer", "gboolean", "gint8", "gint16",
|
||||
"guint8", "guint16", "gint32", "guint32", "gint64", "guint64", "gfloat",
|
||||
"gdouble", "GType", "utf8", "filename", "gi::cstring", "gunichar",
|
||||
"dev_t", "gid_t", "pid_t", "socklen_t", "uid_t"};
|
||||
|
||||
class RepositoryPriv : public Repository
|
||||
{
|
||||
public:
|
||||
// holds info collected from GIRs indexed by entry's (qualified) name
|
||||
// (which should be unique within a namespace)
|
||||
std::unordered_map<key_type, mapped_type> index;
|
||||
// active ns
|
||||
std::string ns;
|
||||
// ODR check
|
||||
mutable std::unordered_map<std::string, std::string> type_index;
|
||||
// substitutes for missing c:type
|
||||
subst_c_types c_types;
|
||||
|
||||
RepositoryPriv(subst_c_types m) : c_types(std::move(m))
|
||||
{
|
||||
// make basic types known
|
||||
for (auto &&girname : basic_types) {
|
||||
auto cpptype = girname;
|
||||
auto ctype = girname;
|
||||
int flags = 0;
|
||||
|
||||
flags |= TYPE_BASIC;
|
||||
if (girname == "utf8" || girname == "filename" ||
|
||||
girname == "gi::cstring") {
|
||||
flags |= TYPE_CLASS;
|
||||
ctype = "char*";
|
||||
cpptype = "gi::cstring";
|
||||
} else {
|
||||
flags |= TYPE_VALUE;
|
||||
if (girname == "gboolean")
|
||||
cpptype = "bool";
|
||||
}
|
||||
auto argtype =
|
||||
(girname.find("pointer") != girname.npos) ? "void*" : ctype;
|
||||
index.emplace(
|
||||
girname, mapped_type{nullptr, std::make_unique<TypeInfo>(girname,
|
||||
cpptype, ctype, argtype, flags)});
|
||||
}
|
||||
// void case
|
||||
index.emplace(GIR_VOID,
|
||||
mapped_type{nullptr, std::make_unique<TypeInfo>(GIR_VOID, CPP_VOID,
|
||||
EMPTY, CPP_VOID, TYPE_BASIC)});
|
||||
|
||||
// other special and pre-defined cases
|
||||
std::vector<std::tuple<std::string, std::string, std::string, int>> pre{
|
||||
{std::make_tuple("GLib.List", "GList", "GList", TYPE_LIST)},
|
||||
{std::make_tuple("GLib.SList", "GSList", "GSList", TYPE_LIST)},
|
||||
{std::make_tuple(
|
||||
"GLib.HashTable", "GHashTable", "GHashTable", TYPE_MAP)},
|
||||
{std::make_tuple("GObject.Value", "GObject::Value", "GValue",
|
||||
TYPE_CLASS | TYPE_BOXED)},
|
||||
{std::make_tuple(
|
||||
"GLib.Error", "GLib::Error", "GError", TYPE_CLASS | TYPE_BOXED)},
|
||||
// avoid namespace mishap
|
||||
{std::make_tuple("GObject.Object", "GObject::Object", "GObject",
|
||||
TYPE_CLASS | TYPE_OBJECT)},
|
||||
// pretend is like object
|
||||
{std::make_tuple("GObject.ParamSpec", "GObject::ParamSpec",
|
||||
"GParamSpec", TYPE_CLASS)}};
|
||||
for (auto &&e : pre) {
|
||||
// qualify argtype to avoid name conflicts
|
||||
auto ti = std::make_unique<TypeInfo>(std::get<0>(e), std::get<1>(e),
|
||||
std::get<2>(e), GI_SCOPE + std::get<2>(e) + "*",
|
||||
std::get<3>(e) | TYPE_PREDEFINED);
|
||||
auto girname = ti->girname;
|
||||
index.emplace(girname, mapped_type{nullptr, std::move(ti)});
|
||||
}
|
||||
auto ti =
|
||||
std::make_unique<TypeInfo>("GLib.DestroyNotify", "GLib::DestroyNotify",
|
||||
GDESTROYNOTIFY, GDESTROYNOTIFY, TYPE_CALLBACK | TYPE_PREDEFINED);
|
||||
auto girname = ti->girname;
|
||||
index.emplace(girname, mapped_type{nullptr, std::move(ti)});
|
||||
}
|
||||
};
|
||||
|
||||
// C++ on the outside, C trick on the inside
|
||||
static const RepositoryPriv &
|
||||
get_self(const Repository *t)
|
||||
{
|
||||
return *static_cast<const RepositoryPriv *>(t);
|
||||
}
|
||||
static RepositoryPriv &
|
||||
get_self(Repository *t)
|
||||
{
|
||||
return *static_cast<RepositoryPriv *>(t);
|
||||
}
|
||||
|
||||
// set namespace used for unqualified girname
|
||||
void
|
||||
Repository::set_ns(const std::string _ns)
|
||||
{
|
||||
auto &self = get_self(this);
|
||||
self.ns = _ns;
|
||||
}
|
||||
|
||||
// qualify girname, optionally wrt relative base
|
||||
std::string
|
||||
Repository::qualify(const std::string &girname, const std::string &base) const
|
||||
{
|
||||
auto &&self = get_self(this);
|
||||
if (girname.find('.') == girname.npos) {
|
||||
auto bns = self.ns;
|
||||
if (base.size()) {
|
||||
auto pos = base.find('.');
|
||||
if (pos == base.npos)
|
||||
return girname;
|
||||
bns = base.substr(0, pos);
|
||||
}
|
||||
return bns + '.' + girname;
|
||||
}
|
||||
return girname;
|
||||
}
|
||||
|
||||
void
|
||||
Repository::add(const key_type &girname, const mapped_type::tree_type &n)
|
||||
{
|
||||
auto &&self = get_self(this);
|
||||
auto qualified = qualify(girname);
|
||||
auto it = self.index.find(qualified);
|
||||
bool registered = false;
|
||||
|
||||
if (girname.empty()) {
|
||||
// should not make it here
|
||||
assert(false);
|
||||
} else if (it != self.index.end()) {
|
||||
auto &e = it->second;
|
||||
// merge in tree data for predefined
|
||||
if (e.info && (e.info->flags & TYPE_PREDEFINED)) {
|
||||
e.tree = std::make_unique<mapped_type::tree_type>(n);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
fmt::format("duplicate name {} [{}]", girname, qualified));
|
||||
}
|
||||
} else {
|
||||
// examine node/type
|
||||
// NOTE not every entry/node represents a type (and therefore has !=
|
||||
// flags) consider e.g. a constant or function
|
||||
int flags = 0;
|
||||
auto &el = n.first;
|
||||
auto &node = n.second;
|
||||
auto ctype = get_attribute(node, AT_CTYPE, "");
|
||||
|
||||
// base identification
|
||||
if (el == EL_RECORD) {
|
||||
flags |= TYPE_CLASS | TYPE_BOXED;
|
||||
} else if (el == EL_OBJECT || el == EL_INTERFACE) {
|
||||
flags |= TYPE_CLASS | TYPE_OBJECT;
|
||||
} else if (el == EL_ENUM || el == EL_FLAGS) {
|
||||
flags |= TYPE_ENUM | TYPE_VALUE;
|
||||
} else if (el == EL_ALIAS) {
|
||||
// adopt flags of typedef'ed one
|
||||
// need not be a primitive one (e.g. GtkAllocation = GdkRectangle)
|
||||
auto btype = node.get(EL_TYPE + '.' + PT_ATTR + '.' + AT_NAME, "");
|
||||
auto ti = lookup(btype);
|
||||
flags = ti && ti->info ? ti->info->flags : 0;
|
||||
// also consider as sort-of predefined (at least if we know about
|
||||
// it)
|
||||
if (flags)
|
||||
flags |= TYPE_TYPEDEF;
|
||||
} else if (el == EL_CALLBACK) {
|
||||
flags |= TYPE_CALLBACK;
|
||||
}
|
||||
if (flags) {
|
||||
// check if registered
|
||||
auto gettype = get_attribute(n.second, AT_GLIB_GET_TYPE, "");
|
||||
if (gettype.size())
|
||||
registered = true;
|
||||
}
|
||||
|
||||
bool keep_node = false;
|
||||
bool keep_info = flags != 0;
|
||||
if (flags & TYPE_CLASS) {
|
||||
keep_node = true;
|
||||
// additional checks
|
||||
auto class_struct = get_attribute(node, AT_GLIB_IS_TYPE_STRUCT_FOR, "");
|
||||
if (class_struct.size()) {
|
||||
// is not a valid type, but keep some info around for later
|
||||
// lookup
|
||||
flags = 0;
|
||||
keep_info = true;
|
||||
} else if (flags & TYPE_BOXED) {
|
||||
keep_node = false;
|
||||
}
|
||||
// e.g. GParamSpec (several), variant
|
||||
auto fundamental = get_attribute<int>(node, AT_GLIB_FUNDAMENTAL, 0);
|
||||
// GVariant is marked this way
|
||||
auto gtype = get_attribute(node, AT_GLIB_GET_TYPE, "");
|
||||
if (fundamental || gtype == "intern") {
|
||||
flags = -1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// filter some more
|
||||
auto disguised = get_attribute<int>(node, AT_DISGUISED, 0);
|
||||
// also never mind if it is designed opaque/disguised
|
||||
// lots of private stuff, but also possibly type structs
|
||||
// (some at least, in case of opaque struct)
|
||||
if (disguised)
|
||||
flags = -1;
|
||||
// cairo is notable foreign example
|
||||
// structs are typically opaque, with custom _create, _copy,
|
||||
// _destroy
|
||||
// TODO for now filter all, perhaps not so later
|
||||
// (and then only filter by ignore and allow custom declaration of
|
||||
// above functions in the boxed system)
|
||||
auto foreign = get_attribute<int>(node, AT_FOREIGN, 0);
|
||||
if (foreign && !registered)
|
||||
flags = -1;
|
||||
}
|
||||
|
||||
// special fundamental case
|
||||
// partly prepared, mostly generated
|
||||
if (qualified == GIR_GVARIANT) {
|
||||
keep_node = false;
|
||||
keep_info = true;
|
||||
flags = TYPE_CLASS;
|
||||
}
|
||||
|
||||
// always check
|
||||
auto movedto = get_attribute(node, AT_MOVED_TO, "");
|
||||
if (!movedto.empty())
|
||||
flags = -1;
|
||||
|
||||
if (flags == -1) {
|
||||
logger(Log::DEBUG, "ignoring GIR {} {}", el, qualified);
|
||||
} else {
|
||||
logger(Log::LOG, "registering GIR {} {} {}", el, qualified, flags);
|
||||
|
||||
// convert GIR qualification to namespace qualification
|
||||
static const std::regex re_qualify("\\.", std::regex::optimize);
|
||||
// enum cpptype is unreserve'd in type definition
|
||||
auto cpptype = std::regex_replace(
|
||||
(flags & TYPE_ENUM) ? qualify(unreserve(girname)) : qualified,
|
||||
re_qualify, "::");
|
||||
assert(!(flags & TYPE_CLASS) || is_qualified(cpptype));
|
||||
|
||||
// in rare cases c:type is missing for a record/class
|
||||
// (e.g. GtkSnapshot = alias of Gdk type)
|
||||
// use an override substitute type
|
||||
if ((flags & TYPE_CLASS) && ctype.empty()) {
|
||||
auto sit = self.c_types.find(qualified);
|
||||
if (sit != self.c_types.end()) {
|
||||
ctype = sit->second;
|
||||
logger(Log::INFO, "{} using substitute c:type {}", qualified, ctype);
|
||||
}
|
||||
}
|
||||
|
||||
// always top-level qualify ctype to avoid ns ambiguity
|
||||
if (ctype.size())
|
||||
ctype = GI_SCOPE + ctype;
|
||||
auto argtype = ctype;
|
||||
if ((flags & TYPE_CLASS) && argtype.size())
|
||||
argtype += GI_PTR;
|
||||
|
||||
std::unique_ptr<mapped_type::tree_type> xmlinfo;
|
||||
// node only needed for class type
|
||||
// (only a small part of node is needed later on,
|
||||
// but let's simply keep all of it)
|
||||
if (keep_node)
|
||||
xmlinfo = std::make_unique<mapped_type::tree_type>(n);
|
||||
|
||||
mapped_type entry = {
|
||||
std::move(xmlinfo), keep_info ? std::make_unique<TypeInfo>(qualified,
|
||||
cpptype, ctype, argtype, flags)
|
||||
: nullptr};
|
||||
it = std::get<0>(
|
||||
self.index.emplace(std::move(qualified), std::move(entry)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Repository::discard(const key_type &girname)
|
||||
{
|
||||
auto &&self = get_self(this);
|
||||
auto qualified = qualify(girname);
|
||||
logger(Log::LOG, "discarding girname {}", qualified);
|
||||
if (!self.index.erase(qualified))
|
||||
logger(Log::WARNING, "discarded unknown girname {}", qualified);
|
||||
}
|
||||
|
||||
const Repository::mapped_type::tree_type &
|
||||
Repository::tree(const std::string &girname) const
|
||||
{
|
||||
auto &&self = get_self(this);
|
||||
auto &index = self.index;
|
||||
// only used by class types
|
||||
auto it = index.find(qualify(girname));
|
||||
if (it == index.end() || !it->second.tree)
|
||||
throw std::runtime_error("no node info for " + girname);
|
||||
return *it->second.tree;
|
||||
}
|
||||
|
||||
const Repository::mapped_type *
|
||||
Repository::lookup(const std::string &girname) const
|
||||
{
|
||||
auto &&self = get_self(this);
|
||||
auto &index = self.index;
|
||||
// also consider non-qualified for basic types
|
||||
auto it = index.find(girname);
|
||||
if (it == index.end())
|
||||
it = index.find(qualify(girname));
|
||||
if (it != index.end())
|
||||
return &it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string
|
||||
Repository::check_odr(const std::string &cpptype, const std::string &ctype)
|
||||
{
|
||||
if (!ctype.empty()) {
|
||||
auto &&self = get_self(this);
|
||||
auto ret = self.type_index.insert({ctype, cpptype});
|
||||
if (!ret.second && ret.first->second != cpptype) {
|
||||
return ret.first->second;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<Repository>
|
||||
Repository::new_(subst_c_types m)
|
||||
{
|
||||
return std::make_shared<RepositoryPriv>(std::move(m));
|
||||
}
|
||||
126
cmake/external/glib/cppgir/tools/repository.hpp
vendored
Normal file
126
cmake/external/glib/cppgir/tools/repository.hpp
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef REPOSITORY_HPP
|
||||
#define REPOSITORY_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
// ptree helpers
|
||||
template<typename T = std::string, typename... Args>
|
||||
static T
|
||||
get_attribute(const pt::ptree &node, const std::string &attr, Args... args)
|
||||
{
|
||||
static auto prefix = PT_ATTR + '.';
|
||||
return node.get<T>(prefix + attr, args...);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_name(const pt::ptree &node)
|
||||
{
|
||||
return get_attribute(node, AT_NAME);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_name(const pt::ptree &node, std::nothrow_t)
|
||||
{
|
||||
return get_attribute(node, AT_NAME, "");
|
||||
}
|
||||
|
||||
enum TYPE_TRAITS {
|
||||
// basic/fundamental glib defined type
|
||||
TYPE_BASIC = 1 << 0,
|
||||
// type passed by value (integral, enum, etc)
|
||||
TYPE_VALUE = 1 << 1,
|
||||
// enum, bitfield type
|
||||
TYPE_ENUM = 1 << 2,
|
||||
// class type (string, object, record)
|
||||
TYPE_CLASS = 1 << 3,
|
||||
// gobject
|
||||
TYPE_OBJECT = 1 << 4,
|
||||
// boxed
|
||||
TYPE_BOXED = 1 << 5,
|
||||
// callback
|
||||
TYPE_CALLBACK = 1 << 6,
|
||||
// containers
|
||||
TYPE_ARRAY = 1 << 7,
|
||||
TYPE_LIST = 1 << 8,
|
||||
TYPE_MAP = 1 << 9,
|
||||
TYPE_CONTAINER = TYPE_ARRAY | TYPE_LIST | TYPE_MAP,
|
||||
TYPE_VARARGS = 1 << 10,
|
||||
// predefined
|
||||
TYPE_PREDEFINED = 1 << 11,
|
||||
// typedef (no forward class declare)
|
||||
TYPE_TYPEDEF = 1 << 12
|
||||
};
|
||||
|
||||
// some info on (argument) type
|
||||
struct TypeInfo
|
||||
{
|
||||
TypeInfo() = default;
|
||||
TypeInfo(const std::string &_gir, const std::string &_cpp,
|
||||
const std::string &_c, const std::string &_argtype, int _flags)
|
||||
: girname(_gir), cpptype(_cpp), dtype(_c), argtype(_argtype),
|
||||
flags(_flags), pdepth(flags & (TYPE_CLASS | TYPE_CONTAINER) ? 1 : 0)
|
||||
{}
|
||||
// always qualified (if not predefined glib type)
|
||||
std::string girname;
|
||||
// always qualified (see below) as it might be used in class context
|
||||
// (so to avoid lookup conflicts with parent classes in other ns,
|
||||
// e.g. injected-class-name)
|
||||
std::string cpptype;
|
||||
// c:type taken from class/record definition
|
||||
std::string dtype;
|
||||
// c type as used in argument (no cv qualification)
|
||||
std::string argtype;
|
||||
// combination of flags above
|
||||
int flags = 0;
|
||||
// number of pointer indirections
|
||||
int pdepth = 0;
|
||||
};
|
||||
|
||||
class Repository
|
||||
{
|
||||
Repository() = default;
|
||||
friend class RepositoryPriv;
|
||||
|
||||
Repository(const Repository &other) = delete;
|
||||
Repository &operator=(const Repository &other) = delete;
|
||||
|
||||
public:
|
||||
typedef std::map<std::string, std::string> subst_c_types;
|
||||
typedef std::string key_type;
|
||||
struct mapped_type
|
||||
{
|
||||
typedef pt::ptree::value_type tree_type;
|
||||
std::unique_ptr<tree_type> tree;
|
||||
std::unique_ptr<TypeInfo> info;
|
||||
};
|
||||
|
||||
static std::shared_ptr<Repository> new_(subst_c_types m);
|
||||
|
||||
// set namespace used for unqualified girname
|
||||
void set_ns(const std::string _ns);
|
||||
|
||||
// qualify girname, optionally wrt relative base
|
||||
std::string qualify(
|
||||
const std::string &girname, const std::string &base = "") const;
|
||||
|
||||
void add(const key_type &girname, const mapped_type::tree_type &n);
|
||||
|
||||
void discard(const key_type &girname);
|
||||
|
||||
const mapped_type::tree_type &tree(const std::string &girname) const;
|
||||
|
||||
const mapped_type *lookup(const std::string &girname) const;
|
||||
|
||||
// check for duplicate definition for ctype
|
||||
// if ctype already claimed, returns non-empty claiming cpptype
|
||||
std::string check_odr(const std::string &cpptype, const std::string &ctype);
|
||||
};
|
||||
|
||||
#endif // REPOSITORY_HPP
|
||||
Reference in New Issue
Block a user