function.cpp 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932
  1. #include "function.hpp"
  2. #include <boost/algorithm/string/join.hpp>
  3. #include <boost/range/adaptor/transformed.hpp>
  4. #include <boost/range/iterator.hpp>
  5. #include <map>
  6. namespace
  7. { // anonymous
  8. const int INDEX_RETURN{-5};
  9. const int INDEX_INSTANCE{-1};
  10. const int INDEX_CF{150};
  11. const int INDEX_ERROR{100};
  12. const std::string MOVE = "std::move";
  13. struct FunctionGenerator : public GeneratorBase
  14. {
  15. using Output = FunctionDefinition::Output;
  16. const ElementFunction &func;
  17. // duplicated from above
  18. const std::string &kind;
  19. const std::string &klass, &klasstype;
  20. // errors collected along the way (trigger abort)
  21. std::vector<std::string> errors;
  22. // collected dependencies
  23. std::set<std::string> &deps;
  24. // tweak debug level upon error
  25. bool ignored = false;
  26. bool introspectable = true;
  27. bool allow_deprecated = false;
  28. // also detect various function generation alternatives
  29. enum class opt_except {
  30. NOEXCEPT,
  31. THROW,
  32. EXPECTED,
  33. GERROR,
  34. DEFAULT = NOEXCEPT,
  35. ALT = GERROR
  36. };
  37. std::set<opt_except> do_except = {opt_except::DEFAULT};
  38. enum class opt_output { PARAM, TUPLE, DEFAULT = PARAM, ALT = TUPLE };
  39. std::set<opt_output> do_output = {opt_output::DEFAULT};
  40. enum class opt_nullable {
  41. PRESENT,
  42. DISCARD,
  43. DEFAULT = PRESENT,
  44. ALT = DISCARD
  45. };
  46. std::set<opt_nullable> do_nullable = {opt_nullable::DEFAULT};
  47. struct Options
  48. {
  49. opt_except except{};
  50. opt_output output{};
  51. opt_nullable nullable{};
  52. Options(opt_except _except, opt_output _output, opt_nullable _nullable)
  53. : except(_except), output(_output), nullable(_nullable)
  54. {}
  55. Options() {}
  56. };
  57. // global info
  58. // track callback's user_data
  59. int found_user_data = INDEX_DEFAULT;
  60. // const method
  61. bool const_method = false;
  62. // typical async method;
  63. // has GAsyncReadyCallback param with async scope
  64. std::string async_cb_wrapper;
  65. // indexed by GIR numbering (first non-instance parameter index 0)
  66. std::map<int, Parameter> paraminfo;
  67. // param numbers referenced by some other parameter
  68. std::set<int> referenced;
  69. // collects generated declaration and implementation
  70. std::ostringstream oss_decl, oss_impl;
  71. using FunctionData = FunctionDefinition;
  72. struct FunctionDataExtended : public FunctionDefinition
  73. {
  74. // (indexed as above)
  75. std::vector<decltype(cpp_decl)::mapped_type> cpp_decl_unfolded;
  76. FunctionDataExtended() = default;
  77. FunctionDataExtended(FunctionDefinition odef)
  78. : FunctionDefinition(std::move(odef))
  79. {
  80. auto &def = *this;
  81. // process decl map into plain list
  82. def.cpp_decl_unfolded.clear();
  83. for (auto &&e : def.cpp_decl)
  84. def.cpp_decl_unfolded.emplace_back(e.second);
  85. }
  86. };
  87. public:
  88. FunctionGenerator(GeneratorContext &_ctx, const std::string _ns,
  89. const ElementFunction &_func, const std::string &_klass,
  90. const std::string &_klasstype, std::set<std::string> &_deps,
  91. bool _allow_deprecated = false)
  92. : GeneratorBase(_ctx, _ns), func(_func), kind(func.kind), klass(_klass),
  93. klasstype(_klasstype), deps(_deps), allow_deprecated(_allow_deprecated)
  94. {
  95. assert(func.name.size());
  96. assert(func.kind.size());
  97. assert(func.c_id.size());
  98. assert(func.functionexp.size());
  99. }
  100. static bool ends_with(std::string const &value, std::string const &ending)
  101. {
  102. if (ending.size() > value.size())
  103. return false;
  104. return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
  105. };
  106. void handle_skip(const skip &ex)
  107. {
  108. // we tried but it went wrong ...
  109. if (errors.empty() && !introspectable) {
  110. errors.push_back("not introspectable");
  111. // ... so let's not complain about it
  112. ignored = true;
  113. }
  114. if (ex.cause == skip::INVALID) {
  115. auto level = ignored ? Log::DEBUG : Log::WARNING;
  116. if (check_suppression(ns, kind, func.c_id))
  117. level = Log::DEBUG;
  118. logger(level, "skipping {} {}; {}", kind, func.c_id, ex.what());
  119. } else if (ex.cause == skip::IGNORE) {
  120. ignored = true;
  121. }
  122. errors.push_back(ex.what());
  123. }
  124. bool check_errors()
  125. {
  126. // check errors
  127. if (errors.size()) {
  128. auto reason = ignored ? "IGNORE" : "SKIP";
  129. auto err = fmt::format(
  130. "// {}; {}", reason, boost::algorithm::join(errors, ", "));
  131. oss_decl << err << std::endl;
  132. // no impl for signals
  133. if (kind != EL_SIGNAL)
  134. oss_impl << err << std::endl;
  135. return true;
  136. }
  137. return false;
  138. }
  139. // all parameters should have ctype info except for signal case
  140. void check_ctype(const ArgInfo &info)
  141. {
  142. if (info.ctype.empty() && kind != EL_SIGNAL)
  143. throw skip("missing c:type info");
  144. }
  145. void collect_param(const pt::ptree::value_type &n, int &param_no)
  146. {
  147. // instance parameter not in cpp signature
  148. auto &el = n.first;
  149. bool instance = (el == EL_INSTANCE_PARAMETER);
  150. param_no += instance ? 0 : 1;
  151. // directly parse into target
  152. // so we always have minimal attributes for raw fallback
  153. auto &pinfo = paraminfo[param_no];
  154. pinfo.instance = instance;
  155. pinfo.name = unreserve(get_name(n.second), false);
  156. // gather a bunch of attributes
  157. pinfo.direction = get_attribute(n.second, AT_DIRECTION, DIR_IN);
  158. pinfo.transfer = get_attribute(n.second, AT_TRANSFER);
  159. pinfo.closure = get_attribute<int>(n.second, AT_CLOSURE, -10);
  160. pinfo.destroy = get_attribute<int>(n.second, AT_DESTROY, -10);
  161. pinfo.callerallocates =
  162. get_attribute<int>(n.second, AT_CALLER_ALLOCATES, 0);
  163. pinfo.scope = get_attribute(n.second, AT_SCOPE, "");
  164. bool allownone = get_attribute<bool>(n.second, AT_ALLOW_NONE, 0);
  165. // limited backwards compatbility for allow-none
  166. bool is_out = pinfo.direction.find(DIR_OUT) != pinfo.direction.npos;
  167. pinfo.optional =
  168. (is_out && allownone) || get_attribute<bool>(n.second, AT_OPTIONAL, 0);
  169. pinfo.nullable =
  170. (!is_out && allownone) || get_attribute<bool>(n.second, AT_NULLABLE, 0);
  171. // might fail
  172. parse_arginfo(n.second, &pinfo.tinfo);
  173. check_ctype(pinfo.tinfo);
  174. }
  175. void collect_node(const pt::ptree::value_type &entry)
  176. {
  177. auto &node = entry.second;
  178. // should be ignored in some cases
  179. try {
  180. auto deprecated = get_attribute<int>(node, AT_DEPRECATED, 0);
  181. if (ctx.match_ignore.matches(ns, kind, {func.name, func.c_id}))
  182. throw skip("marked ignore", skip::IGNORE);
  183. if (deprecated && !allow_deprecated)
  184. throw skip("deprecated", skip::IGNORE);
  185. // there are a few nice-to-have in this case (e.g. some _get_source)
  186. // so let's try anyway but not complain too much if it goes wrong
  187. auto intro = get_attribute<int>(node, AT_INTROSPECTABLE, 1);
  188. // except when renaming is at hand
  189. auto shadowed = get_attribute(node, AT_SHADOWED_BY, "");
  190. if (shadowed.size() && !intro)
  191. throw skip("not introspectable; shadowed-by " + shadowed, skip::IGNORE);
  192. // otherwise mark and try ...
  193. introspectable = intro;
  194. } catch (skip &ex) {
  195. handle_skip(ex);
  196. }
  197. try {
  198. auto &ret = node.get_child(EL_RETURN);
  199. // return value
  200. // always try to read minimal info (e.g. ctype)
  201. // as it might be needed for method fallback
  202. auto &pinfo = paraminfo[INDEX_RETURN];
  203. pinfo.direction = DIR_RETURN;
  204. // best effort for now, see also below
  205. pinfo.transfer = get_attribute(ret, AT_TRANSFER, TRANSFER_FULL);
  206. pinfo.nullable = get_attribute<bool>(ret, AT_NULLABLE, 0);
  207. parse_arginfo(ret, &pinfo.tinfo);
  208. // override constructor to return class instance
  209. if (kind == EL_CONSTRUCTOR)
  210. parse_typeinfo(klasstype, pinfo.tinfo);
  211. check_ctype(pinfo.tinfo);
  212. pinfo.transfer = pinfo.tinfo.cpptype == CPP_VOID
  213. ? TRANSFER_FULL
  214. : get_attribute(ret, AT_TRANSFER);
  215. } catch (skip &ex) {
  216. handle_skip(ex);
  217. }
  218. { // first pass to collect parameter info
  219. int param_no = INDEX_INSTANCE;
  220. auto params = node.get_child_optional(EL_PARAMETERS);
  221. if (params.is_initialized()) {
  222. for (auto &n : params.value()) {
  223. try {
  224. auto el = n.first;
  225. if (el == EL_PARAMETER || el == EL_INSTANCE_PARAMETER) {
  226. collect_param(n, param_no);
  227. }
  228. } catch (skip &ex) {
  229. handle_skip(ex);
  230. }
  231. }
  232. }
  233. }
  234. }
  235. // could be dropped if wrap/unwrap is made more casual about const-stuff
  236. // but on the other hand these checks catch some incorrect annotations
  237. // so some warning or discarding still has merit
  238. void verify_const_transfer(const ArgInfo &info, const std::string &transfer,
  239. const std::string &direction, bool /*wrap*/)
  240. {
  241. auto ctype = info.ctype;
  242. // never mind in case of signal
  243. if (kind == EL_SIGNAL)
  244. return;
  245. // note that const for parameter is not always picked up reliably
  246. // so if the ctype is const, it probably really is
  247. // (and so we might complain or warn)
  248. // but if the ctype is not const, the real one in function might
  249. // actually be (so we can't know for sure and then should not warn)
  250. // const and transfer full should not go together
  251. if (is_const(ctype) && transfer != TRANSFER_NOTHING) {
  252. auto level =
  253. check_suppression(ns, kind, func.c_id) ? Log::DEBUG : Log::WARNING;
  254. logger(level, "warning; {}; const transfer {} mismatch [{}]", func.c_id,
  255. transfer, direction);
  256. }
  257. #if 0
  258. if ((flags & TYPE_BASIC) && (flags & TYPE_CLASS)) {
  259. // string transfer none preferably unwraps to a const
  260. // but as mentioned above; this check is not reliable
  261. if (!wrap && !is_const (ctype) && transfer == TRANSFER_NOTHING)
  262. throw skip ("transfer none on non-const string");
  263. }
  264. #endif
  265. }
  266. bool process_param_in_callback(int param_no, const Parameter &pinfo,
  267. const Options & /*options*/, FunctionData &def, bool defaultable)
  268. {
  269. auto closure = pinfo.closure;
  270. auto scope = pinfo.scope;
  271. auto destroy = pinfo.destroy;
  272. auto &pname = pinfo.name;
  273. auto &&cpptype = pinfo.tinfo.cppreftype(pinfo.transfer);
  274. const bool callee = kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD;
  275. logger(Log::LOG, "param_in_callback {} {}", param_no, pname);
  276. // lots of sanity to check
  277. static const std::string SCOPE_ASYNC_DEP("async_dep");
  278. const bool async_method = !async_cb_wrapper.empty();
  279. if (closure < 0)
  280. throw skip("callback misses closure info");
  281. auto it = paraminfo.find(closure);
  282. if (it == paraminfo.end())
  283. throw skip("callback has invalid closure parameter");
  284. const auto &cctype = it->second.ptype;
  285. if (get_pointer_depth(cctype) != 1)
  286. throw skip("invalid callback closure parameter type " + cctype);
  287. // if async method, there is at least 1 async scope callback
  288. // if call also supports another callback, it could in principle
  289. // have any valid scope, but quite likely it has no "sane" scope,
  290. // and its user_data parameter is assumed to live within the async scope
  291. // so allow for this case in the sanity checks below
  292. // though this case is only dealt with in regular callforward code
  293. // (not in callback code)
  294. if (scope.empty()) {
  295. if (!async_method)
  296. throw skip("callback misses scope info");
  297. else if (callee)
  298. throw skip(kind + "; async_dep scope not supported");
  299. scope = SCOPE_ASYNC_DEP;
  300. }
  301. if ((scope == SCOPE_NOTIFIED) != (destroy >= 0)) {
  302. if (!async_method)
  303. throw skip("callback destroy info mismatch");
  304. scope = SCOPE_ASYNC_DEP;
  305. }
  306. if (destroy >= 0) {
  307. it = paraminfo.find(destroy);
  308. if (it == paraminfo.end()) {
  309. throw skip("callback has invalid destroynotify parameter");
  310. } else {
  311. auto girname = it->second.tinfo.girname;
  312. // mind qualification
  313. if (girname != GIR_GDESTROYNOTIFY)
  314. throw skip(
  315. "invalid callback destroy notify parameter type " + girname);
  316. }
  317. }
  318. // there may be multiple callbacks, but they should not overlap
  319. // so check if we already entered something for the call parameter
  320. if (def.c_call.find(closure) != def.c_call.end())
  321. throw skip("callback closure parameter already used");
  322. if (def.c_call.find(destroy) != def.c_call.end())
  323. throw skip("callback destroy parameter already used");
  324. { // this could be callback parameter within a callback or virtual method
  325. // so collect the needed parts for the argument trait
  326. // (which have been validated above)
  327. auto &ti = def.arg_traits[param_no];
  328. ti.args = {param_no, closure};
  329. if (destroy >= 0)
  330. ti.args.push_back(destroy);
  331. // determine custom arg trait type from type name
  332. // (with suitable suffix and in internal namespace)
  333. auto index = cpptype.rfind(GI_SCOPE);
  334. auto insert = index != cpptype.npos ? index + GI_SCOPE.size() : 0;
  335. ti.custom = cpptype;
  336. ti.custom.insert(insert, GI_NS_INTERNAL + GI_SCOPE);
  337. ti.custom += GI_SUFFIX_CB_TRAIT;
  338. }
  339. // declaration always the same
  340. def.cpp_decl[param_no] = fmt::format("{} {}", cpptype, pname);
  341. // could be nullable/optional
  342. if (pinfo.nullable && defaultable) {
  343. def.cpp_decl[param_no] += " = nullptr";
  344. } else {
  345. defaultable = false;
  346. }
  347. // some variation in handling
  348. auto cbw_pname = pname + "_wrap_";
  349. // pass along empty callback as NULL
  350. if (scope == SCOPE_CALL) {
  351. auto s = fmt::format("auto {} = {} ? unwrap (std::move ({}), "
  352. "gi::scope_call) : nullptr",
  353. cbw_pname, pname, pname);
  354. def.pre_call.push_back(s);
  355. s = fmt::format("std::unique_ptr<std::remove_pointer<decltype({})>:"
  356. ":type> {}_sp ({})",
  357. cbw_pname, cbw_pname, cbw_pname);
  358. def.pre_call.push_back(s);
  359. } else if (scope == SCOPE_NOTIFIED || scope == SCOPE_ASYNC ||
  360. scope == SCOPE_ASYNC_DEP) {
  361. // consider async_dep like notified but without a destroy;
  362. // ownership of the wrapper (pointer) is made part of the async callback
  363. auto pscope =
  364. scope != SCOPE_ASYNC ? "gi::scope_notified" : "gi::scope_async";
  365. def.pre_call.push_back(
  366. fmt::format("auto {} = {} ? unwrap (std::move ({}), {}) : nullptr",
  367. cbw_pname, pname, pname, pscope));
  368. // track wrapper for potential use below
  369. // (may have to take ownership of another callback wrapper)
  370. const auto &ctype = pinfo.tinfo.ctype;
  371. if (scope == SCOPE_ASYNC &&
  372. ctype.find("AsyncReadyCallback") != ctype.npos &&
  373. async_cb_wrapper.empty())
  374. async_cb_wrapper = cbw_pname;
  375. if (destroy >= 0) {
  376. def.c_call[destroy] =
  377. fmt::format("{} ? &{}->destroy : nullptr", cbw_pname, cbw_pname);
  378. } else {
  379. assert(scope != SCOPE_NOTIFIED);
  380. if (scope == SCOPE_ASYNC_DEP && !async_cb_wrapper.empty()) {
  381. // make async scope callback take ownership of this wrapper callback
  382. def.pre_call.push_back(
  383. fmt::format("{}->take_data ({})", async_cb_wrapper, cbw_pname));
  384. }
  385. }
  386. } else {
  387. throw skip("invalid callback scope " + scope);
  388. }
  389. // common part
  390. def.c_call[param_no] =
  391. fmt::format("{} ? &{}->wrapper : nullptr", cbw_pname, cbw_pname);
  392. def.c_call[closure] = cbw_pname;
  393. return defaultable;
  394. }
  395. // returns defaultable status
  396. bool process_param_in_data(int param_no, const Parameter &pinfo,
  397. const Options &options, FunctionData &def, bool defaultable)
  398. {
  399. auto flags = pinfo.tinfo.flags;
  400. auto &pname = pinfo.name;
  401. auto &&cpptype = pinfo.tinfo.cppreftype(pinfo.transfer);
  402. auto &ctype = pinfo.ptype;
  403. auto &transfer = pinfo.transfer;
  404. auto &tinfo = pinfo.tinfo;
  405. const bool callee = kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD;
  406. typedef std::vector<std::pair<int, std::string>> callexp_t;
  407. callexp_t callexps;
  408. std::string callexp, cpp_decl;
  409. logger(Log::LOG, "param_in_data {} {}", param_no, pname);
  410. if (flags & TYPE_VALUE) {
  411. // value types always passed simply
  412. // mind g(const)pointer case (const not in normalized girtype)
  413. cpp_decl = ((flags & TYPE_ENUM) ? cpptype : ctype) + " " + pname;
  414. callexp = flags & TYPE_ENUM
  415. ? fmt::format(GI_NS_SCOPED + "unwrap ({})", pname)
  416. : pname;
  417. } else if (flags & TYPE_CLASS) {
  418. // otherwise have to mind ownership issues
  419. if (pinfo.nullable && options.nullable != opt_nullable::PRESENT) {
  420. // discard nullable
  421. // NOTE: default value not possible with only forward
  422. // declaration
  423. callexp = "nullptr";
  424. } else {
  425. // preserve const signature
  426. // at least, if it makes sense; full transfer on const does not
  427. // (as we may have to move from it)
  428. if ((is_const(ctype) && transfer == TRANSFER_NOTHING)) {
  429. if (flags & TYPE_OBJECT) {
  430. // side-step ref/unref, in as much as such matters
  431. cpp_decl = fmt::format("const {} & {}", cpptype, pname);
  432. } else {
  433. cpp_decl = fmt::format("const {} {}", cpptype, pname);
  434. }
  435. } else {
  436. cpp_decl = fmt::format("{} {}", cpptype, pname);
  437. }
  438. auto wpname = pname;
  439. // may need to move from a boxed wrapper or string
  440. bool is_string = (flags & TYPE_BASIC);
  441. if ((is_string || (flags & TYPE_BOXED)) &&
  442. pinfo.transfer == TRANSFER_FULL)
  443. wpname = fmt::format("{}({})", MOVE, pname);
  444. callexp = fmt::format(GI_NS_SCOPED + "unwrap ({}, {})", wpname,
  445. get_transfer_parameter(transfer));
  446. }
  447. } else if (flags & TYPE_CONTAINER) {
  448. auto &&cppreftype = tinfo.first.cppreftype(pinfo.transfer);
  449. auto tmpvar = pname + "_w";
  450. auto unwrapvar = pname + "_i";
  451. std::string coltype;
  452. std::string coleltype = tinfo.first.argtype;
  453. if (flags & TYPE_MAP) {
  454. coltype = get_list_type(tinfo);
  455. coleltype = fmt::format(
  456. "std::pair<{}, {}>", tinfo.first.argtype, tinfo.second.argtype);
  457. } else if ((flags & TYPE_LIST) || tinfo.zeroterminated) {
  458. if (flags & TYPE_LIST)
  459. coltype = get_list_type(tinfo);
  460. if (tinfo.zeroterminated)
  461. coltype = "gi::ZTSpan";
  462. } else if (tinfo.fixedsize) {
  463. coltype = fmt::format("gi::FSpan<{}>", tinfo.fixedsize);
  464. } else {
  465. // need length parameter
  466. auto len = tinfo.length;
  467. auto it = len >= 0 ? paraminfo.find(len) : paraminfo.end();
  468. if (it == paraminfo.end())
  469. throw skip("array has invalid length parameter");
  470. const bool basicvalue = (tinfo.first.flags & TYPE_BASIC) &&
  471. (tinfo.first.flags & TYPE_VALUE);
  472. // annotations are often wrong with low-level buffers
  473. // so stick to simple interface below in that case
  474. // (which also works in case of bogus in/out mixup)
  475. if (!basicvalue) {
  476. if (callee)
  477. def.arg_traits[param_no].args = {param_no, len};
  478. callexps.emplace_back(len, fmt::format("{}._size()", pname));
  479. coltype = "gi::DSpan";
  480. } else {
  481. // this is an input parameter, so add const
  482. // (as what will be passed is likely const)
  483. cpp_decl = fmt::format("const {} * {}", cppreftype, pname);
  484. // plain basic case, so essentially pass-through
  485. auto &linfo = it->second;
  486. callexps.emplace_back(param_no, pname);
  487. def.cpp_decl[len] = linfo.tinfo.cpptype + " " + linfo.name;
  488. callexps.emplace_back(len, linfo.name);
  489. }
  490. }
  491. if (coltype.size() && coleltype.size()) {
  492. // for a regular function, enable auto-list creation/conversion
  493. // which then manages ownership as a temporary during call expression
  494. // but no such otherwise (neither output neither for callee input)
  495. auto suffix = callee ? "" : "Parameter";
  496. auto cpp_list = fmt::format("gi::Collection{}<{}, {}, {}>", suffix,
  497. coltype, coleltype, get_transfer_parameter(pinfo.transfer, true));
  498. cpp_decl = fmt::format("{} {}", cpp_list, pname);
  499. // move needed in case of full transfer with single ownership
  500. // so let's move anyways in all cases
  501. unwrapvar = fmt::format("{}({})", MOVE, pname);
  502. auto s = fmt::format("auto {} = unwrap ({}, {})", tmpvar, unwrapvar,
  503. get_transfer_parameter(pinfo.transfer));
  504. def.pre_call.push_back(s);
  505. callexps.emplace_back(param_no, tmpvar);
  506. } else {
  507. // plain case above should have handled
  508. assert(callexps.size());
  509. }
  510. } else {
  511. throw std::logic_error("invalid flags");
  512. }
  513. // transfer to def
  514. if (callexps.empty()) {
  515. if (callexp.empty())
  516. throw std::logic_error("unhandled flags");
  517. callexps.emplace_back(std::move(param_no), std::move(callexp));
  518. }
  519. if (cpp_decl.size()) {
  520. def.cpp_decl.emplace(std::move(param_no), std::move(cpp_decl));
  521. // a declaration here has no defaults
  522. // so no defaults further down
  523. defaultable = false;
  524. }
  525. for (auto &&s : callexps) {
  526. // use intermediate var for clarity
  527. if (s.first == param_no) {
  528. // sigh, our input name may actually be an expression
  529. // FIXME ?? fall back to global data
  530. auto varname = paraminfo[param_no].name + "_to_c";
  531. def.pre_call.emplace_back(
  532. fmt::format("auto {} = {}", varname, s.second));
  533. def.c_call[s.first] = varname;
  534. } else {
  535. def.c_call[s.first] = s.second;
  536. }
  537. }
  538. return defaultable;
  539. }
  540. bool process_param_in(int param_no, const Parameter &pinfo,
  541. const Options &options, FunctionData &def, bool defaultable)
  542. {
  543. auto flags = pinfo.tinfo.flags;
  544. verify_const_transfer(
  545. pinfo.tinfo, pinfo.transfer, pinfo.direction, kind == EL_CALLBACK);
  546. if (pinfo.instance) {
  547. // check sanity
  548. assert(flags & TYPE_CLASS);
  549. // method is const if it can operate on a const C struct
  550. const_method = const_method || is_const(pinfo.ptype);
  551. def.c_call[param_no] = "gobj_()";
  552. // NOTE transfer != NOTHING might be a silly case (e.g. _unref)
  553. // or a useful one (such as some _merge cases)
  554. defaultable = false;
  555. } else if (flags & TYPE_CALLBACK) {
  556. defaultable =
  557. process_param_in_callback(param_no, pinfo, options, def, defaultable);
  558. } else {
  559. defaultable =
  560. process_param_in_data(param_no, pinfo, options, def, defaultable);
  561. }
  562. return defaultable;
  563. }
  564. std::string get_list_type(const GeneratorBase::ArgInfo &info)
  565. {
  566. assert(info.flags & (TYPE_LIST | TYPE_MAP));
  567. // should be in qualified GLib.listsuffix form
  568. assert(info.girname.find("GLib.") == 0);
  569. auto c = info.girname;
  570. c.erase(c.begin() + 1, c.begin() + 5);
  571. return c;
  572. }
  573. std::string make_out_type(const Parameter &pinfo)
  574. {
  575. const auto &info = pinfo.tinfo;
  576. if (!info.flags)
  577. throw skip(fmt::format("return type {} not supported", info.cpptype));
  578. else if (info.flags & (TYPE_LIST | TYPE_ARRAY)) {
  579. std::string listtype;
  580. if (info.flags & TYPE_LIST) {
  581. listtype = get_list_type(pinfo.tinfo);
  582. } else if (info.zeroterminated) {
  583. listtype = "gi::ZTSpan";
  584. } else if (info.fixedsize) {
  585. listtype = fmt::format("gi::FSpan<{}>", info.fixedsize);
  586. } else {
  587. listtype = "gi::DSpan";
  588. }
  589. return fmt::format("gi::Collection<{}, {}, {}>", listtype,
  590. info.first.argtype, get_transfer_parameter(pinfo.transfer, true));
  591. } else if (info.flags & TYPE_MAP) {
  592. return fmt::format("gi::Collection<{}, std::pair<{}, {}>, {}>",
  593. get_list_type(pinfo.tinfo), info.first.argtype, info.second.argtype,
  594. get_transfer_parameter(pinfo.transfer, true));
  595. } else if ((info.flags & TYPE_BOXED) && pinfo.callerallocates) {
  596. // these always really have transfer full semantics;
  597. // the caller has performed allocation and thus has ownership
  598. return info.cppreftype(TRANSFER_FULL);
  599. } else {
  600. auto ret = info.cppreftype(pinfo.transfer);
  601. return ret;
  602. }
  603. }
  604. void process_param_out_array(int param_no, const Parameter &pinfo,
  605. const Options &options, FunctionData &def)
  606. {
  607. auto pname = pinfo.name;
  608. auto &tinfo = pinfo.tinfo;
  609. auto transfer = pinfo.transfer;
  610. bool inout = pinfo.direction == DIR_INOUT;
  611. bool as_param = (options.output == opt_output::PARAM) || inout;
  612. std::string exp_size;
  613. int length = -1;
  614. Parameter *plinfo = nullptr;
  615. if (tinfo.fixedsize) {
  616. def.cpp_decl[param_no] = fmt::format("{} {}[{}]",
  617. tinfo.first.cppreftype(pinfo.transfer), pname, tinfo.fixedsize);
  618. exp_size = std::to_string(tinfo.fixedsize);
  619. } else {
  620. // must have this (likely checked already though ...)
  621. length = tinfo.length;
  622. if (length < 0)
  623. throw skip("array misses length info");
  624. auto it = paraminfo.find(length);
  625. if (it == paraminfo.end())
  626. throw skip("array has invalid length parameter");
  627. plinfo = &it->second;
  628. auto &linfo = it->second;
  629. inout |= linfo.direction == DIR_INOUT;
  630. // in case of length parameter it is never treated as an output
  631. // since the length is a required input
  632. // so it is always in the declaration
  633. def.cpp_decl[param_no] =
  634. tinfo.first.cppreftype(pinfo.transfer) + " * " + pname;
  635. // also handle length parameter here
  636. def.cpp_decl[length] = linfo.tinfo.cpptype + " " + linfo.name;
  637. exp_size = linfo.name;
  638. }
  639. // FIXME ?? no real examples here and semantics not entirely clear
  640. // (probably a single lvalue container argument could be used here)
  641. if (inout)
  642. throw skip("inout array not supported");
  643. // typically lots of different pointer types around (e.g. gpointer)
  644. // so establish own types all the way
  645. auto tname_cpp = pname + "_cpptype";
  646. auto tname_cpp_def = fmt::format(
  647. "typedef {} {}", tinfo.first.cppreftype(pinfo.transfer), tname_cpp);
  648. auto tname_c = pname + "_ctype";
  649. auto tname_c_def =
  650. fmt::format("typedef traits::ctype<{}>::type {}", tname_cpp, tname_c);
  651. auto outvar = (pname.size() ? pname : "_ret") + "_o";
  652. auto cppouttype = make_out_type(pinfo);
  653. std::string wrap_data;
  654. std::string cppoutvar;
  655. // some remaining restriction in callee case
  656. auto check_callee_support = [this, &pinfo]() {
  657. if (kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD) {
  658. throw skip(kind + " " + pinfo.direction + " array not supported");
  659. }
  660. };
  661. if (pinfo.callerallocates) {
  662. if ((tinfo.first.flags & TYPE_BASIC) &&
  663. (tinfo.first.flags & TYPE_VALUE)) {
  664. // optimization; avoid intermediate copy below
  665. // simply pass along input and done
  666. def.c_call[param_no] = pname;
  667. if (length >= 0)
  668. def.c_call[length] = plinfo->name;
  669. return;
  670. }
  671. check_callee_support();
  672. // pretty much expected
  673. if (plinfo && plinfo->direction != DIR_IN)
  674. throw skip("unexpected length parameter");
  675. // vexing parse parentheses
  676. def.pre_call.push_back(tname_cpp_def);
  677. def.pre_call.push_back(tname_c_def);
  678. def.pre_call.push_back(fmt::format(
  679. "detail::unique_ptr<{}> {} ((g_malloc_n({}, sizeof({}))))", tname_c,
  680. outvar, exp_size, tname_c));
  681. def.c_call[param_no] = fmt::format("{}.get()", outvar);
  682. if (length >= 0)
  683. def.c_call[length] = exp_size;
  684. wrap_data = "outvar.release()";
  685. // normalize transfer as we allocated above
  686. if (transfer != TRANSFER_FULL)
  687. transfer = TRANSFER_CONTAINER;
  688. } else {
  689. if (pinfo.direction != DIR_RETURN) {
  690. // prepare an output parameter var
  691. def.pre_call.push_back(tname_cpp_def);
  692. def.pre_call.push_back(tname_c_def);
  693. def.pre_call.push_back(fmt::format("{} *{}", tname_c, outvar));
  694. def.c_call[param_no] = fmt::format("({}) &{}", pinfo.ptype, outvar);
  695. } else {
  696. check_callee_support();
  697. // assign return to var
  698. def.ret_format = fmt::format("auto {} = {{}}", outvar);
  699. }
  700. wrap_data = outvar;
  701. cppoutvar = pname;
  702. if (length >= 0) {
  703. auto &linfo = *plinfo;
  704. // in either case, lvalue container as parameter/return
  705. def.cpp_decl[param_no] = fmt::format(cppouttype + " & " + cppoutvar);
  706. // arranged above
  707. assert(exp_size == linfo.name);
  708. if (linfo.direction != DIR_IN) {
  709. // no size parameter in Cpp signature, use local variable
  710. def.cpp_decl.erase(length);
  711. def.pre_call.push_back(
  712. fmt::format("{} {}", linfo.tinfo.cpptype, linfo.name));
  713. def.c_call[length] = fmt::format("&{}", linfo.name);
  714. } else {
  715. // use/keep input size parameter in Cpp signature
  716. def.c_call[length] = exp_size;
  717. }
  718. // add length to callee arg trait (regardless of in/out, etc)
  719. def.arg_traits[param_no].args = {param_no, length};
  720. if (linfo.direction != DIR_OUT) {
  721. // an additional argument is needed in Cpp signature
  722. // (as the input size is/can not passed as part of array collection)
  723. def.cpp_decl_extra[length] =
  724. fmt::format("{} {}", linfo.tinfo.cpptype, linfo.name);
  725. // if needed, use any non-void type to mark inout case
  726. // (no longer passthrough, Cpp signature is plain, C signature is ptr)
  727. if (linfo.direction == DIR_INOUT) {
  728. auto &ti = def.arg_traits[length];
  729. ti.args = {length};
  730. ti.inout = true;
  731. ti.custom = "bool";
  732. ti.transfer = linfo.transfer;
  733. }
  734. // TODO however, no known cases and untested at present, so skip
  735. // (if not already skipped above by inout check)
  736. check_callee_support();
  737. }
  738. }
  739. // in case return; always use container wrapper as return
  740. if (pinfo.direction == DIR_RETURN || (!as_param && length >= 0)) {
  741. // so no cpp parameter
  742. def.cpp_decl.erase(param_no);
  743. // output container is temp helper var instead
  744. // make name if return value
  745. if (cppoutvar.empty())
  746. cppoutvar = "_temp_ret";
  747. def.post_call.push_back(fmt::format("{} {}", cppouttype, cppoutvar));
  748. def.cpp_outputs.push_back({cppouttype, cppoutvar});
  749. }
  750. }
  751. if (cppoutvar.empty()) {
  752. cppoutvar = pname + "_temp_wrap_";
  753. def.post_call.push_back(fmt::format("{} {}", cppouttype, cppoutvar));
  754. }
  755. def.post_call.push_back(
  756. fmt::format("{} = gi::wrap_to<{}>({}, {}, {})", cppoutvar, cppouttype,
  757. wrap_data, exp_size, get_transfer_parameter(transfer)));
  758. }
  759. // returns defaultable status
  760. bool process_param_out(int param_no, const Parameter &pinfo,
  761. const Options &options, FunctionData &def, bool defaultable)
  762. {
  763. auto pname = pinfo.name;
  764. auto &tinfo = pinfo.tinfo;
  765. auto &ctype = pinfo.ptype;
  766. int flags = tinfo.flags;
  767. auto &transfer = pinfo.transfer;
  768. bool inout = pinfo.direction == DIR_INOUT;
  769. const bool callee = kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD;
  770. verify_const_transfer(
  771. tinfo, transfer, pinfo.direction, kind != EL_CALLBACK);
  772. if (pinfo.instance)
  773. throw skip("instance out");
  774. // zero-terminated handled below
  775. if ((flags & TYPE_ARRAY) && !tinfo.zeroterminated) {
  776. process_param_out_array(param_no, pinfo, options, def);
  777. return false;
  778. }
  779. if (pinfo.direction == DIR_RETURN) {
  780. if (tinfo.cpptype == CPP_VOID) {
  781. def.ret_format = "{}";
  782. } else {
  783. auto cpp_ret = make_out_type(pinfo);
  784. auto tmpvar = "_temp_ret";
  785. def.ret_format = fmt::format("auto {} = {{}}", tmpvar);
  786. def.cpp_outputs.push_back({cpp_ret,
  787. fmt::format(make_wrap_format(tinfo, transfer, cpp_ret), tmpvar)});
  788. }
  789. return false;
  790. }
  791. // inout never in output tuple
  792. bool as_param = (options.output == opt_output::PARAM) || inout;
  793. // one-to-one non-array cases
  794. // this also handles list/map output with suitable pointer depth
  795. auto paramtype = make_out_type(pinfo);
  796. bool optional = false;
  797. if (as_param) {
  798. optional = pinfo.optional;
  799. auto pass = pinfo.optional ? " * " : " & ";
  800. // no (nullptr) default for pointer output
  801. // as that leads to call ambiguity with the output tuple variant
  802. // if no argument given in call
  803. def.cpp_decl[param_no] = paramtype + pass + pname;
  804. defaultable = false;
  805. } else {
  806. // FIXME ?? could consider defaultable in this case ??
  807. defaultable = false;
  808. }
  809. if ((flags & TYPE_BOXED) && pinfo.callerallocates) {
  810. if (callee) {
  811. // parameter can actually be considered an input (pointer/wrapper)
  812. // (with transfer none, as caller has ownership)
  813. def.cpp_decl.erase(param_no);
  814. auto tpinfo = pinfo;
  815. tpinfo.direction = DIR_IN;
  816. def.arg_traits[param_no].transfer = tpinfo.transfer = TRANSFER_NOTHING;
  817. return process_param_in_data(
  818. param_no, tpinfo, options, def, defaultable);
  819. }
  820. // special case; use provided output plain struct directly
  821. // mimic typical call sequence; declare local struct and pass that
  822. auto cvar = pname + "_c";
  823. // such call is typically used for things that do not need cleanup
  824. // (e.g. GstMapInfo, etc), though GValue is a popular and prominent
  825. // exception
  826. // in any case, this means the struct is not opaque
  827. // so we have no known way to allocate or free
  828. // (well, we could free a boxed GType but not allocate)
  829. // so we will really leave it up to the caller
  830. // and only allocate in case of a GValue or a "plain struct" case
  831. // (if non-optional)
  832. // (which is already tricky if custom setup/free needed after all)
  833. std::string deref;
  834. if (!as_param) {
  835. // make pname point to a local variable
  836. def.pre_call.push_back(fmt::format("{} {}", paramtype, cvar));
  837. def.pre_call.push_back(fmt::format("auto {} = &{}", pname, cvar));
  838. // which is then returned
  839. auto output = cvar;
  840. def.cpp_outputs.push_back({paramtype, output});
  841. deref = "*";
  842. } else if (pinfo.optional) {
  843. deref = "*";
  844. }
  845. if (!pinfo.optional) {
  846. // this should only really do something for GValue or c-boxed
  847. // no deref check needed here, as it is ok in either case
  848. def.pre_call.push_back(
  849. fmt::format("detail::allocate({}{})", deref, pname));
  850. }
  851. def.pre_call.push_back(fmt::format(
  852. "static_assert(sizeof({}) == sizeof(*({}{}).gobj_()), \"\")",
  853. tinfo.dtype, deref, pname));
  854. auto cvalue =
  855. fmt::format("({}*) ({}{}).gobj_()", tinfo.dtype, deref, pname);
  856. def.c_call[param_no] =
  857. deref.size() ? fmt::format("{} ? {} : nullptr", pname, cvalue)
  858. : cvalue;
  859. // no additional post-call
  860. // (already done above in case of return value)
  861. return defaultable;
  862. }
  863. // otherwise use a temp variable and then wrap that one
  864. auto outvar = pname + "_o";
  865. // adjust arginfo for wrapping
  866. auto opinfo = pinfo;
  867. auto &otinfo = opinfo.tinfo;
  868. if (ctype[ctype.size() - 1] != GI_PTR)
  869. throw skip(pname + "; inconsistent pointer type");
  870. // adjust type
  871. opinfo.ptype = ctype.substr(0, ctype.size() - 1);
  872. // optionally init the temp variable using input (if such)
  873. std::string init(" {}");
  874. if (inout && as_param) {
  875. // operate on a temporary definition
  876. // only need to re-use transformation of input to call expression
  877. auto tdef = def;
  878. tdef.pre_call.clear();
  879. // optionally tweak the input expression (type adjusted above)
  880. if (optional)
  881. opinfo.name.insert(0, "*");
  882. process_param_in_data(param_no, opinfo, options, tdef, defaultable);
  883. // be nice, include requested code
  884. for (auto &&p : tdef.pre_call)
  885. def.pre_call.emplace_back(p);
  886. // rest we handle here
  887. init = fmt::format(" = {}", tdef.c_call[param_no]);
  888. }
  889. // always same precall, but slight variation for pointer/ref
  890. def.pre_call.push_back(opinfo.ptype + " " + outvar + init);
  891. auto call = std::string("&") + outvar;
  892. def.c_call[param_no] =
  893. optional ? fmt::format("{} ? {} : nullptr", pname, call) : call;
  894. auto wrapf =
  895. fmt::format(make_wrap_format(otinfo, transfer, paramtype), outvar);
  896. // assign post call or return
  897. if (as_param) {
  898. auto guard = optional ? fmt::format("if ({}) ", pname) : EMPTY;
  899. auto deref = optional ? "*" : "";
  900. def.post_call.push_back(
  901. fmt::format("{}{}{} = {}", guard, deref, pname, wrapf));
  902. } else {
  903. def.cpp_outputs.push_back({paramtype, wrapf});
  904. }
  905. return defaultable;
  906. }
  907. // process info to construct function
  908. // returns defaultable status
  909. bool process_param(int param_no, const Parameter &pinfo,
  910. const Options &options, FunctionData &def, bool defaultable)
  911. {
  912. auto &tinfo = pinfo.tinfo;
  913. auto ctype = tinfo.ctype;
  914. int flags = tinfo.flags;
  915. // check type first, so we do not raise any complaints on unknown type
  916. if (!flags)
  917. throw skip(
  918. fmt::format("{} type {} not supported", pinfo.name, tinfo.cpptype),
  919. skip::OK);
  920. // sanity check on pointer depth to verify annotation
  921. // array annotation or out parameter is frequently missing
  922. auto argdepth = std::count(pinfo.ptype.begin(), pinfo.ptype.end(), GI_PTR);
  923. auto rpdepth = get_pointer_depth(pinfo.tinfo.ctype);
  924. if ((kind != EL_SIGNAL) && (argdepth != rpdepth)) {
  925. // this might happen for an input array of C-boxed structs
  926. // (rather than the expected array of pointers to something-boxed)
  927. if ((pinfo.tinfo.flags & TYPE_CONTAINER) &&
  928. (pinfo.tinfo.first.flags & TYPE_BOXED))
  929. throw skip(fmt::format("{} {} boxed array not supported (depth {})",
  930. pinfo.name, pinfo.direction, rpdepth));
  931. throw skip(fmt::format("inconsistent {} {} pointer depth ({} vs {})",
  932. pinfo.name, pinfo.direction, rpdepth, argdepth));
  933. }
  934. // perhaps this param is part of another's one (e.g. callback)
  935. // processing various checks to bail out early
  936. if (def.c_call.find(param_no) != def.c_call.end()) {
  937. logger(Log::LOG, "call fragment for parameter {} already specified",
  938. param_no);
  939. return false;
  940. } else if (((kind != EL_CALLBACK && kind != EL_SIGNAL) ||
  941. (pinfo.closure < 0)) &&
  942. referenced.count(param_no)) {
  943. /* managing parameter might come later, so skip this one for now
  944. * if a call has to be emitted
  945. * (also; user_data closure in callback can reference itself,
  946. * and that has to be discovered below
  947. * userdata parameter also has to be processed below in callback case
  948. * (to insert proper callexp)
  949. */
  950. logger(Log::LOG, "parameter {} referenced elsewhere", param_no);
  951. return false;
  952. }
  953. // on with it now
  954. // standard transfer, can be overridden
  955. if (!pinfo.instance)
  956. def.arg_traits[param_no] = {
  957. pinfo.transfer, pinfo.direction == DIR_INOUT, {param_no}};
  958. if (pinfo.direction != DIR_IN) {
  959. // (in)out or return
  960. defaultable =
  961. process_param_out(param_no, pinfo, options, def, defaultable);
  962. } else {
  963. defaultable =
  964. process_param_in(param_no, pinfo, options, def, defaultable);
  965. // handle callback user_data
  966. if (kind == EL_CALLBACK) {
  967. if (pinfo.closure >= 0) {
  968. if (pinfo.closure != param_no)
  969. throw skip("invalid closure user_data");
  970. if (ctype != "gpointer")
  971. throw skip("invalid type user_data");
  972. if (found_user_data >= 0)
  973. throw skip("duplicate user_data");
  974. found_user_data = param_no;
  975. // user_data not included in signature (nor transfer)
  976. def.cpp_decl.erase(param_no);
  977. def.arg_traits.erase(param_no);
  978. }
  979. }
  980. }
  981. return defaultable;
  982. }
  983. std::string join_outputs(
  984. const std::vector<FunctionDefinition::Output> &outputs,
  985. std::string FunctionDefinition::Output::*m,
  986. std::string (*transform)(std::string) = nullptr)
  987. {
  988. std::vector<std::string> temp;
  989. for (auto &&o : outputs)
  990. temp.emplace_back(transform ? transform(o.*m) : o.*m);
  991. return boost::algorithm::join(temp, ", ");
  992. }
  993. void make_function(const Options &options, const FunctionDataExtended &def,
  994. const std::string &fname)
  995. {
  996. auto &name = func.name;
  997. // determine return type
  998. std::string cpp_ret(CPP_VOID);
  999. if (def.cpp_outputs.size() == 1) {
  1000. cpp_ret = def.cpp_outputs[0].type;
  1001. } else if (def.cpp_outputs.size() > 1) {
  1002. cpp_ret = fmt::format(
  1003. "std::tuple<{}>", join_outputs(def.cpp_outputs, &Output::type));
  1004. }
  1005. if (options.except == opt_except::EXPECTED) {
  1006. cpp_ret = fmt::format("gi::result<{}>", cpp_ret);
  1007. }
  1008. const auto &cpp_decl = def.cpp_decl_unfolded;
  1009. // generate based on type
  1010. if (kind == EL_SIGNAL) {
  1011. auto decl_name = name;
  1012. // always include instance in signature
  1013. auto cpp_decls = cpp_decl;
  1014. cpp_decls.insert(cpp_decls.begin(), qualify(klasstype, TYPE_OBJECT));
  1015. // the function type specified as gi::signal_proxy template parameter
  1016. // serves 2 purposes;
  1017. // + provide a compile-time type check
  1018. // + select each parameter's corresponding GValue GType
  1019. // (according to the association defined in gi/value.hpp)
  1020. // so we should make sure to pick the proper type, especially for the
  1021. // latter item, as e.g. gint64 may simply be a long
  1022. // (which would not map to a G_TYPE_INT64)
  1023. auto normalize = [](std::string &subject, const std::string &in,
  1024. const std::string &sub) {
  1025. if (subject.find(in) == 0 &&
  1026. (subject.size() == in.size() || subject[in.size()] == ' ')) {
  1027. subject.replace(subject.begin(), subject.begin() + in.size(), sub);
  1028. }
  1029. };
  1030. for (auto &decl : cpp_decls) {
  1031. normalize(decl, "gint64", "long long");
  1032. normalize(decl, "guint64", "unsigned long long");
  1033. }
  1034. // convert signal name to valid identifier
  1035. std::replace(decl_name.begin(), decl_name.end(), '-', '_');
  1036. auto ret = fmt::format("gi::signal_proxy<{}({})>", cpp_ret,
  1037. boost::algorithm::join(cpp_decls, ", "));
  1038. oss_decl << fmt::format(
  1039. "{0} signal_{1}()\n{{ return {0} (*this, \"{2}\"); }}",
  1040. ret, decl_name, name)
  1041. << std::endl;
  1042. } else {
  1043. // internal namespace for callforward helper parts to avoid clutter
  1044. NamespaceGuard nsg_decl(oss_decl);
  1045. NamespaceGuard nsg_impl(oss_impl);
  1046. if (kind == EL_CALLBACK) {
  1047. nsg_decl.push(GI_NS_INTERNAL, false);
  1048. nsg_impl.push(GI_NS_INTERNAL, false);
  1049. }
  1050. const char *CB_SUFFIX = "_CF";
  1051. auto make_sig = [&](bool impl) {
  1052. bool vm = kind == EL_VIRTUAL_METHOD;
  1053. auto funcsuffix = kind == EL_CALLBACK ? CB_SUFFIX : "";
  1054. auto prefix =
  1055. impl
  1056. ? EMPTY
  1057. : (vm ? "virtual "
  1058. : ((kind != EL_METHOD) && klass.size() ? "static " : ""));
  1059. auto klprefix = klass.size() && impl ? klass + "::" : "";
  1060. auto pure = (vm && !impl ? " = 0" : "");
  1061. if (!impl)
  1062. prefix += GI_INLINE + ' ';
  1063. // virtual method might throw in addition to error parameter
  1064. auto sig =
  1065. prefix +
  1066. fmt::format("{} {}{}{} ({}){}{}{}", cpp_ret, klprefix,
  1067. unreserve(fname, vm), funcsuffix,
  1068. boost::algorithm::join(cpp_decl, ", "),
  1069. (const_method ? " const" : ""),
  1070. (((options.except == opt_except::THROW) || (vm && func.throws))
  1071. ? ""
  1072. : " noexcept"),
  1073. pure);
  1074. // remove default values in definition
  1075. static const std::regex re_defaultv(" =[^,)]*", std::regex::optimize);
  1076. return impl ? std::regex_replace(sig, re_defaultv, "") : sig;
  1077. };
  1078. if (!def.cf_ctype.empty())
  1079. oss_decl << def.cf_ctype << ';' << std::endl;
  1080. oss_decl << make_sig(false) << ";" << std::endl;
  1081. oss_impl << make_sig(true) << std::endl;
  1082. // transform to list for joining
  1083. std::vector<std::string> temp;
  1084. for (auto &&e : def.c_call)
  1085. temp.emplace_back(e.second);
  1086. auto call = fmt::format(
  1087. "{} ({})", def.c_callee, boost::algorithm::join(temp, ", "));
  1088. call = fmt::format(def.ret_format, call);
  1089. std::vector<std::string> pre_return;
  1090. std::string returns;
  1091. if (def.cpp_outputs.size() == 1) {
  1092. // avoid -Wpessimizing-move on std::move(x)
  1093. // so pass along as-is
  1094. auto &ret = def.cpp_outputs[0].value;
  1095. returns = fmt::format("return {};", ret);
  1096. } else if (def.cpp_outputs.size() > 1) {
  1097. // wrap in a move()
  1098. // may be needed for move-only types in temp variables
  1099. // however, again avoid -Wpessimizing-move
  1100. // (in case of moving from an expression/temporary)
  1101. // so assign to an intermediate ref and move from that
  1102. // (and should not hurt in other cases)
  1103. // auto moved_outputs = def.cpp_outputs;
  1104. static const std::string tmp_prefix = "tmp_return_";
  1105. int count = 0;
  1106. std::vector<std::string> outputs;
  1107. for (auto &e : def.cpp_outputs) {
  1108. pre_return.push_back(
  1109. fmt::format("auto &&{}{} = {}", tmp_prefix, ++count, e.value));
  1110. outputs.push_back(fmt::format("{}({}{})", MOVE, tmp_prefix, count));
  1111. }
  1112. returns = fmt::format("return std::make_tuple ({});",
  1113. boost::algorithm::join(outputs, ","));
  1114. }
  1115. if (options.except == opt_except::EXPECTED && returns.empty()) {
  1116. // expected<void> is no longer void, so needs explicit return
  1117. returns = "return {};";
  1118. }
  1119. oss_impl << "{" << std::endl;
  1120. // prevent calling NULL in case of vmethod
  1121. // (i.e. Subclass::method != Superclass::method)
  1122. if (kind == EL_VIRTUAL_METHOD) {
  1123. // FIXME in the new approach the class/interface struct entry
  1124. // is only filled if really needed, so it preserves the superclass
  1125. // (unless needed) whether that is NULL or otherwise.
  1126. // In particular, this fallback implementation should not get called
  1127. // (which we could enforce if the new approach becomes the only one).
  1128. // It might still get explicitly called, but then it should first be
  1129. // checked whether the struct entry is non-NULL (as typically done
  1130. // by C code). So, even in that case, we should not hit the situation
  1131. // below that is forced to return some default value
  1132. // (and that could also be enforced in future).
  1133. // So, eventually, the nasty default return should not apply at runtime.
  1134. // Until then, hoping for the best
  1135. // (though *mm does no better here) ...
  1136. // Log a fairly serious warning, as such should such no longer happen
  1137. // (in the auto-detected or manual specification approach).
  1138. auto retexp = fmt::format(
  1139. "{{ g_critical (\"no method in class struct\"); return {}; }}",
  1140. cpp_ret == CPP_VOID ? EMPTY : "{}");
  1141. retexp = fmt::format("if (!{}) {}", func.functionexp, retexp);
  1142. oss_impl << indent << retexp << std::endl;
  1143. }
  1144. for (const auto &p : def.pre_call)
  1145. oss_impl << indent << p << ';' << std::endl;
  1146. oss_impl << indent << call << ';' << std::endl;
  1147. for (const auto &p : def.post_call)
  1148. oss_impl << indent << p << ';' << std::endl;
  1149. for (const auto &p : pre_return)
  1150. oss_impl << indent << p << ';' << std::endl;
  1151. if (returns.size())
  1152. oss_impl << indent << returns << std::endl;
  1153. oss_impl << "}" << std::endl;
  1154. // generate helper trait type when used as argument in another callback
  1155. if (kind == EL_CALLBACK) {
  1156. auto base = unreserve(fname);
  1157. oss_decl << fmt::format("GI_CB_ARG_CALLBACK_CUSTOM({}, {}, {});",
  1158. base + GI_SUFFIX_CB_TRAIT, base + GI_SUFFIX_CF_CTYPE,
  1159. base + CB_SUFFIX)
  1160. << std::endl;
  1161. }
  1162. }
  1163. if (kind == EL_CALLBACK) { // callback
  1164. // NOTE limited container support at present
  1165. // argument trait/transfers; return type to start with
  1166. auto transfers = make_arg_traits(def.arg_traits, def.c_sig);
  1167. // discard expected trailing callforward parameters in regular declaration
  1168. // (return value also specified in transfers)
  1169. assert(def.arg_traits.size() + (2 - 1) == cpp_decl.size());
  1170. auto cpp_decls = boost::make_iterator_range(
  1171. cpp_decl.begin(), cpp_decl.begin() + def.arg_traits.size() - 1);
  1172. oss_decl << fmt::format("typedef {}callback<{}({}), {}> {}",
  1173. GI_NS_DETAIL_SCOPED, cpp_ret,
  1174. boost::algorithm::join(cpp_decls, ", "), transfers,
  1175. unreserve(name))
  1176. << ";" << std::endl;
  1177. }
  1178. }
  1179. FunctionDefinition process()
  1180. {
  1181. auto &name = func.name;
  1182. const bool callee = kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD;
  1183. // pass over parameters to collect info to assemble signature
  1184. struct signature
  1185. {
  1186. std::string c_ret;
  1187. std::vector<std::string> c_decl;
  1188. };
  1189. signature sig_ctype, sig_ptype;
  1190. // as above, but now each entry contains a comment annotation
  1191. signature annotations;
  1192. std::map<int, int> array_sizes;
  1193. // collect flags into a comment to append to parameter name in declaration
  1194. auto annotate_parameter = [](const FunctionParameter &p) -> std::string {
  1195. if ((p.tinfo.flags & TYPE_VALUE) || p.tinfo.cpptype == CPP_VOID)
  1196. return {};
  1197. auto dir = (p.direction.find(DIR_OUT) != p.direction.npos)
  1198. ? fmt::format(",{}", p.direction)
  1199. : "";
  1200. return fmt::format(" /*{}{}{}{}{}*/", p.transfer, dir,
  1201. p.optional ? ",opt" : "", p.nullable ? ",nullable" : "",
  1202. p.callerallocates ? ",ca" : "");
  1203. };
  1204. int callbacks = 0;
  1205. Parameter *callback = nullptr;
  1206. for (auto &p : paraminfo) {
  1207. try {
  1208. auto &pinfo = p.second;
  1209. assert(pinfo.name.size() || pinfo.direction == DIR_RETURN);
  1210. assert((pinfo.direction == DIR_RETURN) == (p.first == INDEX_RETURN));
  1211. assert(pinfo.transfer.size());
  1212. assert(pinfo.direction.size());
  1213. auto annotation = annotate_parameter(pinfo);
  1214. // c signature
  1215. if (p.first == INDEX_RETURN) {
  1216. sig_ctype.c_ret = pinfo.tinfo.ctype;
  1217. annotations.c_ret = annotation;
  1218. } else {
  1219. sig_ctype.c_decl.push_back(pinfo.tinfo.ctype + " " + pinfo.name);
  1220. annotations.c_decl.push_back(annotation);
  1221. }
  1222. auto flags = pinfo.tinfo.flags;
  1223. // also sanity checks
  1224. if (pinfo.direction == DIR_RETURN) {
  1225. // NOTE no more check on none return needed
  1226. // as return type adequately specifies this situation (e.g. cstring_v)
  1227. // and usual caution wrt return "temporary string" then apply
  1228. // (and floating return is handled by callback wrapping code)
  1229. // NOTE constructor return transfer is often marked none = floating
  1230. // so that needs a ref_sink (which wrap() will arrange)
  1231. } else {
  1232. // overall checks
  1233. bool function_type = false;
  1234. if (callee || kind == EL_SIGNAL) {
  1235. function_type = true;
  1236. // no defaults in signatures
  1237. pinfo.nullable = false;
  1238. pinfo.optional = false;
  1239. }
  1240. if (kind == EL_SIGNAL) {
  1241. // a signal is handled much like a callback,
  1242. // so more complex cases need argument trait info (like callback)
  1243. // but that needs more changes in gi support code
  1244. if (pinfo.direction != DIR_IN && !(flags & TYPE_BASIC))
  1245. throw skip(
  1246. kind + ' ' + pinfo.direction + " parameter not supported");
  1247. if ((flags & TYPE_ARRAY) && !pinfo.tinfo.zeroterminated)
  1248. throw skip(kind + ' ' + pinfo.direction +
  1249. " array parameter not supported");
  1250. }
  1251. // trigger additional applicable overload generation
  1252. if (!function_type) {
  1253. if (pinfo.direction == DIR_OUT)
  1254. do_output.insert(opt_output::ALT);
  1255. if ((flags & TYPE_CLASS) && pinfo.nullable &&
  1256. pinfo.direction == DIR_IN)
  1257. do_nullable.insert(opt_nullable::ALT);
  1258. }
  1259. }
  1260. // no known cases, but check anyway
  1261. if ((pinfo.direction != DIR_IN) && (flags & TYPE_CALLBACK))
  1262. throw skip(kind + " " + pinfo.direction +
  1263. " callback parameter not supported");
  1264. track_dependency(deps, pinfo.tinfo);
  1265. // in case of a callback type definition,
  1266. // closure on userdata refers to itself (to identify callback userdata)
  1267. // otherwise, closure attribute should only be on callback argument,
  1268. // but is sometimes also on user_data referring back to callback
  1269. // remove the latter circular reference
  1270. if (!(flags & TYPE_CALLBACK) && pinfo.closure != p.first)
  1271. pinfo.closure = INDEX_DEFAULT;
  1272. // collect parameters that are referenced from elsewhere
  1273. // and as such managed elsewhere
  1274. for (auto p : {&pinfo.closure, &pinfo.destroy, &pinfo.tinfo.length})
  1275. if (*p >= 0)
  1276. referenced.insert(*p);
  1277. array_sizes[pinfo.tinfo.length] = p.first;
  1278. // check if (single) callback parameter
  1279. if (flags & TYPE_CALLBACK) {
  1280. ++callbacks;
  1281. if (pinfo.closure < 0)
  1282. callback = &pinfo;
  1283. }
  1284. } catch (skip &ex) {
  1285. handle_skip(ex);
  1286. }
  1287. }
  1288. // userdata parameter may not be properly annotated
  1289. // (especially for functions considered not introspectable)
  1290. // so, in case of only 1 callback parameter, try to guess userdata
  1291. // (see also issue #85;
  1292. // only limited cases so far, e.g. g_bytes_new_with_free_func)
  1293. // as there is no way to guess the annotated scope,
  1294. // we either have to hope that at least that one is properly annotated,
  1295. // or alternatively let's only guess in specific circumstances
  1296. if (callbacks == 1 && callback &&
  1297. callback->tinfo.girname == GIR_GDESTROYNOTIFY &&
  1298. callback->scope == SCOPE_ASYNC) {
  1299. auto &e = *paraminfo.rbegin();
  1300. // check last parameter
  1301. auto &pinfo = e.second;
  1302. if ((pinfo.name == "data" || ends_with(pinfo.name, "_data")) &&
  1303. (pinfo.tinfo.girname == "gpointer")) {
  1304. // assign as userdata to single callback
  1305. callback->closure = e.first;
  1306. // callback->
  1307. referenced.insert(e.first);
  1308. logger(Log::DEBUG, "{}; guessed {} userdata parameter {}", func.c_id,
  1309. callback->name, pinfo.name);
  1310. }
  1311. }
  1312. // track if func has non-void return
  1313. bool has_return = false;
  1314. // another pass to determine expected normalized parameter type
  1315. // unfortunately some array length size parameters share annotation
  1316. // with the array, so a caller-allocates out array lead to wrong ptr
  1317. // depth (if not compensated for that)
  1318. for (auto &p : paraminfo) {
  1319. try {
  1320. auto &pinfo = p.second;
  1321. // special case; out array length is not so consistent
  1322. // always marked as out (even when passed no-ptr)
  1323. // even when out, then caller-allocates is reversed from a
  1324. // regular out int
  1325. if (pinfo.direction == DIR_OUT) {
  1326. auto it = array_sizes.find(p.first);
  1327. if (it != array_sizes.end()) {
  1328. // normalize based on declaration
  1329. pinfo.direction =
  1330. get_pointer_depth(pinfo.tinfo.ctype) > 0 ? DIR_OUT : DIR_IN;
  1331. // make sure we end up with ptr
  1332. if (pinfo.direction == DIR_OUT)
  1333. pinfo.callerallocates = false;
  1334. }
  1335. }
  1336. pinfo.ptype =
  1337. make_ctype(pinfo.tinfo, pinfo.direction, pinfo.callerallocates);
  1338. // collect deduced signature
  1339. if (p.first == INDEX_RETURN) {
  1340. has_return = pinfo.tinfo.cpptype != CPP_VOID;
  1341. sig_ptype.c_ret = pinfo.ptype;
  1342. } else {
  1343. sig_ptype.c_decl.push_back(pinfo.ptype + " " + pinfo.name);
  1344. }
  1345. } catch (skip &ex) {
  1346. handle_skip(ex);
  1347. }
  1348. }
  1349. // could affect declaration signature
  1350. if (func.throws) {
  1351. // fixed signature
  1352. sig_ctype.c_decl.push_back("GError ** error");
  1353. sig_ptype.c_decl.push_back("GError ** error");
  1354. // stay in sync with parameters, even if empty
  1355. annotations.c_decl.push_back({});
  1356. do_except = {opt_except::GERROR};
  1357. if (!callee)
  1358. do_except.insert(
  1359. ctx.options.expected ? opt_except::EXPECTED : opt_except::THROW);
  1360. } else if (ctx.options.dl && func.lib_symbol) {
  1361. do_except = {
  1362. ctx.options.expected ? opt_except::EXPECTED : opt_except::THROW};
  1363. }
  1364. // we collected enough info so far to reconstruct original declaration
  1365. auto make_declaration = [&](bool def, const std::string name,
  1366. const signature &sig,
  1367. const signature *append = nullptr) {
  1368. auto c_sig_fmt = !def ? "{} {} ({})" : "typedef {} (*{}) ({})";
  1369. const signature *actual = &sig;
  1370. signature combined;
  1371. if (append && sig.c_decl.size() == append->c_decl.size()) {
  1372. combined.c_ret = sig.c_ret + append->c_ret;
  1373. for (std::size_t i = 0; i < sig.c_decl.size(); ++i)
  1374. combined.c_decl.push_back(sig.c_decl[i] + append->c_decl[i]);
  1375. actual = &combined;
  1376. }
  1377. return fmt::format(c_sig_fmt, actual->c_ret, name,
  1378. boost::algorithm::join(actual->c_decl, ", "));
  1379. };
  1380. { // dump original/derived declarations
  1381. bool is_signal = kind == EL_SIGNAL;
  1382. const char *prefix = is_signal ? "(signal) " : "";
  1383. // dump both parsed and derived
  1384. for (auto &sig : {sig_ctype, sig_ptype}) {
  1385. auto c_sig =
  1386. make_declaration(kind == EL_CALLBACK, func.c_id, sig, &annotations);
  1387. oss_decl << "// " << prefix << c_sig << ";" << std::endl;
  1388. if (!is_signal)
  1389. oss_impl << "// " << c_sig << ";" << std::endl;
  1390. }
  1391. }
  1392. // name for error return parameter
  1393. const static std::string ERROR_PARAM = "_error";
  1394. auto make_definition = [&](Options options, bool fallback = false) {
  1395. logger(Log::LOG, "generating {} with except {}, output {}, nullable {}",
  1396. func.c_id, (int)options.except, (int)options.output,
  1397. (int)options.nullable);
  1398. FunctionDefinition def;
  1399. def.c_callee = func.functionexp;
  1400. if (callee) {
  1401. auto c_sig = sig_ptype;
  1402. // instance parameter should not be included
  1403. if (kind == EL_VIRTUAL_METHOD) {
  1404. assert(!c_sig.c_decl.empty());
  1405. c_sig.c_decl.erase(c_sig.c_decl.begin());
  1406. }
  1407. def.c_sig = make_declaration(false, "", c_sig, nullptr);
  1408. }
  1409. if (fallback) {
  1410. sig_ctype = signature{};
  1411. logger(Log::INFO, "method {} creating fallback", name);
  1412. // generate virtual method with original C signature as-is
  1413. // however, do qualify/scope type names to avoid mixup with ns etc
  1414. auto ctype = [](const FunctionParameter &pinfo) {
  1415. if (pinfo.ptype.find(GI_SCOPE) == 0)
  1416. return GI_SCOPE + pinfo.tinfo.ctype;
  1417. return pinfo.tinfo.ctype;
  1418. };
  1419. for (const auto &p : paraminfo) {
  1420. auto &pinfo = p.second;
  1421. track_dependency(deps, pinfo.tinfo);
  1422. if (pinfo.instance) {
  1423. sig_ctype.c_decl.push_back(ctype(pinfo));
  1424. def.c_call[p.first] = "gobj_()";
  1425. } else if (pinfo.direction == DIR_RETURN) {
  1426. sig_ctype.c_ret = ctype(pinfo);
  1427. if (pinfo.tinfo.cpptype == CPP_VOID) {
  1428. def.ret_format = "{}";
  1429. } else {
  1430. // assign return to var
  1431. auto outvar = "result_";
  1432. def.ret_format = fmt::format("auto {} = {{}}", outvar);
  1433. def.cpp_outputs.push_back({ctype(pinfo), outvar});
  1434. }
  1435. } else {
  1436. sig_ctype.c_decl.push_back(ctype(pinfo));
  1437. def.cpp_decl[p.first] = ctype(pinfo) + " " + pinfo.name;
  1438. def.c_call[p.first] = pinfo.name;
  1439. }
  1440. }
  1441. // also consider optional GError
  1442. if (func.throws) {
  1443. const int LAST = INDEX_ERROR;
  1444. const std::string evar = "error_";
  1445. auto &p = def.cpp_decl[LAST] = "::GError **" + evar;
  1446. def.c_call[LAST] = evar;
  1447. sig_ctype.c_decl.push_back(p);
  1448. }
  1449. // commit/specify that a method def was made
  1450. def.name = name;
  1451. }
  1452. // arrange for dynamic load if so requested
  1453. std::string symbol_name;
  1454. if (ctx.options.dl && func.lib_symbol) {
  1455. symbol_name = "_symbol_name";
  1456. def.pre_call.push_back(
  1457. fmt::format("const char *{} = \"{}\"", symbol_name, def.c_callee));
  1458. def.c_callee = fmt::format(
  1459. "detail::load_symbol(internal::_libs(), {})", symbol_name);
  1460. }
  1461. if (kind != EL_CALLBACK) {
  1462. // enforce deduced function signature by cast
  1463. // i.e. type cast to deduced function type
  1464. static const std::string call_wrap_t = "call_wrap_t";
  1465. static const std::string call_wrap_v = "call_wrap_v";
  1466. def.pre_call.push_back(make_declaration(
  1467. true, call_wrap_t, fallback ? sig_ctype : sig_ptype));
  1468. def.pre_call.push_back(fmt::format("{} {} = ({}) {}", call_wrap_t,
  1469. call_wrap_v, call_wrap_t, def.c_callee));
  1470. def.c_callee = call_wrap_v;
  1471. if (symbol_name.size()) {
  1472. std::string check_exp;
  1473. if (options.except == opt_except::EXPECTED) {
  1474. check_exp =
  1475. fmt::format("if (!{}) "
  1476. "return gi::detail::make_unexpected(gi::detail::"
  1477. "missing_symbol_error({}))",
  1478. call_wrap_v, symbol_name);
  1479. } else if (options.except == opt_except::THROW) {
  1480. check_exp = fmt::format(
  1481. "if (!{}) "
  1482. "gi::detail::try_throw(gi::detail::missing_symbol_error({}))",
  1483. call_wrap_v, symbol_name);
  1484. } else if (options.except == opt_except::GERROR) {
  1485. // this could potentially cover up quite some error
  1486. // (in case of null error parameter, but so be it ...)
  1487. check_exp = fmt::format(
  1488. "if (!{0}) {{"
  1489. "if ({2}) *{2} = gi::detail::missing_symbol_error({1}); "
  1490. "return {3}; "
  1491. "}}",
  1492. call_wrap_v, symbol_name, ERROR_PARAM, has_return ? "{}" : "");
  1493. } else {
  1494. // no other options should be possible
  1495. // (due to options arranged for above)
  1496. assert(false);
  1497. }
  1498. def.pre_call.push_back(check_exp);
  1499. }
  1500. }
  1501. if (fallback)
  1502. return def;
  1503. // process parameters from last to first
  1504. // that way we can track whether it is possible to specify a default
  1505. // which is only acceptable if so for all later parameters
  1506. // (or later ones are dropped from signature)
  1507. // init defaultable status to start
  1508. // trailing GError prevents default
  1509. bool defaultable = options.except != opt_except::GERROR;
  1510. // in case of callback;
  1511. // check if some parameter is specified as closure (aka userdata)
  1512. // as it may sadly be missing
  1513. bool has_closure = false;
  1514. if (kind == EL_CALLBACK) {
  1515. for (auto it = paraminfo.rbegin(); it != paraminfo.rend(); ++it) {
  1516. auto &&e = *it;
  1517. if (e.second.closure >= 0) {
  1518. has_closure = true;
  1519. break;
  1520. }
  1521. }
  1522. }
  1523. // if userdata/closure not specified for a closure,
  1524. // accept last parameter as userdata based on name
  1525. if (kind == EL_CALLBACK && !has_closure && paraminfo.size()) {
  1526. auto &e = *paraminfo.rbegin();
  1527. if (e.second.name == "data" || ends_with(e.second.name, "_data")) {
  1528. e.second.closure = e.first;
  1529. logger(Log::DEBUG, "{}; guessed userdata parameter {}", func.c_id,
  1530. e.second.name);
  1531. }
  1532. }
  1533. for (auto it = paraminfo.rbegin(); it != paraminfo.rend(); ++it) {
  1534. auto &&e = *it;
  1535. try {
  1536. defaultable =
  1537. process_param(e.first, e.second, options, def, defaultable);
  1538. } catch (const skip &ex) {
  1539. handle_skip(ex);
  1540. }
  1541. }
  1542. // reverse some results
  1543. std::reverse(def.cpp_outputs.begin(), def.cpp_outputs.end());
  1544. // add potentially missing transfers from length parameters
  1545. // that were not added previously
  1546. // FIXME reorganize data to avoid such
  1547. if (errors.empty() &&
  1548. (kind == EL_CALLBACK || kind == EL_VIRTUAL_METHOD)) {
  1549. for (auto &&p : paraminfo) {
  1550. auto index = p.first;
  1551. if (def.cpp_decl.count(index) && !def.arg_traits.count(index)) {
  1552. if (array_sizes.count(index)) {
  1553. def.arg_traits[p.first].transfer = p.second.transfer;
  1554. def.arg_traits[p.first].args = {p.first};
  1555. } else {
  1556. handle_skip(skip("missing callback transfer info"));
  1557. }
  1558. }
  1559. }
  1560. }
  1561. // enforce deduced function signature by cast
  1562. for (auto &&p : def.c_call) {
  1563. auto it = paraminfo.find(p.first);
  1564. if (it != paraminfo.end()) {
  1565. auto &pinfo = it->second;
  1566. p.second = fmt::format("({}) ({})", pinfo.ptype, p.second);
  1567. }
  1568. }
  1569. // callback/callforward; add additional call/userdata parameters
  1570. if (kind == EL_CALLBACK && found_user_data >= 0 &&
  1571. paraminfo.count(found_user_data)) {
  1572. // need a type for the C function to call
  1573. auto cfc = unreserve(func.name) + GI_SUFFIX_CF_CTYPE;
  1574. def.cf_ctype =
  1575. make_declaration(true, cfc, fallback ? sig_ctype : sig_ptype);
  1576. // which is specified in an extra paramater
  1577. static const std::string param_func = "_call";
  1578. def.cpp_decl[INDEX_CF] = fmt::format("{} {}", cfc, param_func);
  1579. // userdata also given in parameter; re-use original parameter name
  1580. // (which should have been used in regular in parameter processing)
  1581. def.cpp_decl[INDEX_CF + 1] =
  1582. fmt::format("gpointer {}", paraminfo.at(found_user_data).name);
  1583. // call supplied function
  1584. def.c_callee = param_func;
  1585. // def.c_call userdata part should have been arranged as usual
  1586. }
  1587. // if marked throws, GError argument is not mentioned in argument list
  1588. // deal with it here
  1589. switch (options.except) {
  1590. case opt_except::THROW:
  1591. case opt_except::EXPECTED:
  1592. // could be here due to dl only
  1593. if (!func.throws)
  1594. break;
  1595. def.pre_call.push_back("GError *error = NULL");
  1596. def.c_call[def.c_call.size() + 10] = "&error";
  1597. if (options.except == opt_except::THROW) {
  1598. def.post_call.push_back("gi::check_error (error)");
  1599. } else {
  1600. // terminating ; added later
  1601. def.post_call.push_back(
  1602. "if (error) return gi::detail::make_unexpected (error)");
  1603. }
  1604. break;
  1605. case opt_except::GERROR: {
  1606. // simulate optional output error parameter
  1607. options.output = opt_output::PARAM;
  1608. Parameter err;
  1609. err.optional = true;
  1610. err.direction = DIR_OUT;
  1611. err.transfer = TRANSFER_FULL;
  1612. err.name = ERROR_PARAM;
  1613. parse_typeinfo("GLib.Error", err.tinfo);
  1614. err.ptype = err.tinfo.ctype = "GError**";
  1615. // process non-nullable to make sure there is no signature
  1616. // ambiguity
  1617. try {
  1618. process_param_out(INDEX_ERROR, err, options, def, false);
  1619. auto &ti = def.arg_traits[INDEX_ERROR];
  1620. ti.transfer = err.transfer;
  1621. auto lparam =
  1622. paraminfo.empty() ? 0 : paraminfo.crbegin()->first + 1;
  1623. ti.args = {lparam};
  1624. } catch (const skip &ex) {
  1625. handle_skip(ex);
  1626. }
  1627. }
  1628. default:
  1629. break;
  1630. }
  1631. return def;
  1632. };
  1633. // mild check on overload conflict
  1634. // TODO improve check ??
  1635. // what about defaultable arguments and overlap that causes
  1636. std::set<std::vector<std::string>> signatures;
  1637. // pass over to produce cpp declarations and content
  1638. // generate each option
  1639. FunctionDataExtended def;
  1640. if (!check_errors()) {
  1641. for (auto &&output : do_output) {
  1642. for (auto &&except : do_except) {
  1643. for (auto &&nullable : do_nullable) {
  1644. // context for this option run
  1645. Options options(except, output, nullable);
  1646. def = make_definition(options);
  1647. // only care about callbacks with (trailing) user_data
  1648. auto last = paraminfo.end();
  1649. --last;
  1650. if (kind == EL_CALLBACK && found_user_data != last->first)
  1651. errors.push_back("not a callback since no user_data");
  1652. if (check_errors())
  1653. goto exit;
  1654. // duplicate could happen for a special boxed output
  1655. // which is never returned in a tuple
  1656. // normalize without const
  1657. // conflict might otherwise occur e.g. in case of
  1658. // (string output, string input nullable)
  1659. auto cpp_sig = def.cpp_decl_unfolded;
  1660. static const std::regex re_const("const ", std::regex::optimize);
  1661. for (auto &d : cpp_sig)
  1662. d = std::regex_replace(d, re_const, EMPTY);
  1663. if (signatures.count(cpp_sig)) {
  1664. logger(Log::DEBUG,
  1665. "discarding duplicate signature for " + func.c_id);
  1666. } else {
  1667. auto fname =
  1668. !callee && !func.shadows.empty() ? func.shadows : name;
  1669. make_function(options, def, fname);
  1670. // mark ok
  1671. def.name = name;
  1672. signatures.insert(cpp_sig);
  1673. }
  1674. }
  1675. }
  1676. }
  1677. }
  1678. exit:
  1679. // generate a raw fallback virtual method upon failure
  1680. if (ctx.options.classfull && def.name.empty() &&
  1681. kind == EL_VIRTUAL_METHOD) {
  1682. Options options(
  1683. opt_except::NOEXCEPT, opt_output::PARAM, opt_nullable::PRESENT);
  1684. def = make_definition(options, true);
  1685. if (def.name.size())
  1686. make_function(options, def, name);
  1687. }
  1688. return def;
  1689. }
  1690. FunctionDefinition process(const pt::ptree::value_type *entry,
  1691. const std::vector<Parameter> *params, std::ostream &out,
  1692. std::ostream &impl)
  1693. {
  1694. assert(!params || !entry);
  1695. logger(Log::LOG, "processing " + func.c_id);
  1696. try {
  1697. // check if we made it all the way
  1698. // remove callback from known types if failure
  1699. bool success = kind == EL_CALLBACK ? false : true;
  1700. ScopeGuard g([&] {
  1701. if (!success)
  1702. ctx.repo.discard(func.name);
  1703. });
  1704. if (entry) {
  1705. collect_node(*entry);
  1706. } else {
  1707. int pno = 0;
  1708. for (auto &p : *params) {
  1709. int index = pno;
  1710. if (p.direction == DIR_RETURN) {
  1711. index = INDEX_RETURN;
  1712. } else if (p.instance) {
  1713. index = INDEX_INSTANCE;
  1714. } else {
  1715. ++pno;
  1716. }
  1717. paraminfo[index] = p;
  1718. }
  1719. }
  1720. auto def = process();
  1721. // only trigger remove on callback as such has a top-level GIR entry
  1722. // whereas e.g. a method does not
  1723. // (and its name might conflict/match a top-level one)
  1724. success = success || (def.name.size() > 0);
  1725. out << oss_decl.str() << std::endl;
  1726. impl << oss_impl.str() << std::endl;
  1727. return def;
  1728. } catch (std::runtime_error &ex) {
  1729. auto err = fmt::format("// FAILURE on {}; {}", func.c_id, ex.what());
  1730. out << err << std::endl;
  1731. impl << err << std::endl;
  1732. }
  1733. return FunctionDefinition();
  1734. }
  1735. };
  1736. } // namespace
  1737. std::string
  1738. make_arg_traits(const std::map<int, FunctionDefinition::ArgTrait> &traits,
  1739. const std::string &c_sig)
  1740. {
  1741. // check if in 1-to-1 case
  1742. bool complex = false;
  1743. for (auto &&t : traits) {
  1744. if (t.second.args.size() > 1) {
  1745. complex = true;
  1746. break;
  1747. }
  1748. }
  1749. // another pass to set up trait
  1750. std::vector<std::string> transfers;
  1751. std::string ret_transfer;
  1752. for (auto &&t : traits) {
  1753. auto &ti = t.second;
  1754. auto tt = GeneratorBase::get_transfer_parameter(ti.transfer, true);
  1755. // skip return
  1756. if (t.first < 0) {
  1757. ret_transfer = tt;
  1758. continue;
  1759. }
  1760. if (complex) {
  1761. auto transform = [](int index) { return std::to_string(index); };
  1762. auto li = boost::algorithm::join(
  1763. ti.args | boost::adaptors::transformed(transform), ", ");
  1764. auto custom = ti.custom.empty() ? "void" : ti.custom;
  1765. tt = fmt::format("detail::arg_info<{}, {}, {}, detail::args_index<{}>>",
  1766. tt, ti.inout ? "true" : "false", custom, li);
  1767. } else if (ti.inout) {
  1768. tt = fmt::format("detail::arg_info<{}, true>", tt);
  1769. }
  1770. transfers.emplace_back(std::move(tt));
  1771. }
  1772. assert(!ret_transfer.empty());
  1773. auto ret = fmt::format("{}, std::tuple<{}>", ret_transfer,
  1774. boost::algorithm::join(transfers, ", "));
  1775. // also add C signature if needed
  1776. if (complex)
  1777. ret += ", " + c_sig;
  1778. return ret;
  1779. }
  1780. // process a function (or alike) and callback
  1781. //
  1782. // for a call;
  1783. // const on parameter is maintained, always added for string
  1784. // return value and output parameters always non-const
  1785. //
  1786. // callback; likewise (but not output params for now)
  1787. //
  1788. // klass: actual name of class being declared/defined (e.g. xxxBase)
  1789. // klasstype: intended target type of class (e.g. xxx), used in signal instance
  1790. // / constructor returns: last processed function definition (possibly only 1)
  1791. FunctionDefinition
  1792. process_element_function(GeneratorContext &_ctx, const std::string _ns,
  1793. const pt::ptree::value_type &entry, std::ostream &out, std::ostream &impl,
  1794. const std::string &klass, const std::string &klasstype,
  1795. std::set<std::string> &deps, bool allow_deprecated)
  1796. {
  1797. ElementFunction func;
  1798. auto &kind = func.kind = entry.first;
  1799. auto &node = entry.second;
  1800. auto &name = func.name = get_name(node);
  1801. auto c_name = (kind == EL_SIGNAL || kind == EL_VIRTUAL_METHOD)
  1802. ? name
  1803. : get_attribute(node,
  1804. kind == EL_CALLBACK ? AT_CTYPE : AT_CIDENTIFIER);
  1805. func.c_id = (kind == EL_VIRTUAL_METHOD) ? klasstype + "::" + c_name : c_name;
  1806. // global qualifier needed as c_name might otherwise resolve wrongly
  1807. // e.g. if g_mkdir is macro to mkdir (and resolve to namespaced mkdir)
  1808. std::string qualifier =
  1809. (kind == EL_FUNCTION || kind == EL_METHOD) ? "::" : "";
  1810. func.functionexp = kind == EL_VIRTUAL_METHOD
  1811. ? fmt::format("get_struct_()->{}", c_name)
  1812. : qualifier + c_name;
  1813. func.throws = get_attribute<int>(node, AT_THROWS, 0);
  1814. func.shadows = get_attribute(node, AT_SHADOWS, "");
  1815. func.lib_symbol =
  1816. (kind == EL_FUNCTION || kind == EL_METHOD || kind == EL_CONSTRUCTOR);
  1817. FunctionGenerator gen(
  1818. _ctx, _ns, func, klass, klasstype, deps, allow_deprecated);
  1819. gen.const_method = (kind == EL_METHOD) && _ctx.options.const_method;
  1820. return gen.process(&entry, nullptr, out, impl);
  1821. }
  1822. FunctionDefinition
  1823. process_element_function(GeneratorContext &_ctx, const std::string _ns,
  1824. const ElementFunction &func, const std::vector<Parameter> &params,
  1825. std::ostream &out, std::ostream &impl, const std::string &klass,
  1826. const std::string &klasstype, std::set<std::string> &deps)
  1827. {
  1828. FunctionGenerator gen(_ctx, _ns, func, klass, klasstype, deps);
  1829. return gen.process(nullptr, &params, out, impl);
  1830. }