genbase.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include "genbase.hpp"
  2. #include <map>
  3. static std::string
  4. qualify(const std::string &ns, const std::string &cpptype, int flags)
  5. {
  6. if (cpptype.find(':') == cpptype.npos && !cpptype.empty() &&
  7. !(flags & TYPE_BASIC))
  8. return ns + "::" + cpptype;
  9. return cpptype;
  10. }
  11. GeneratorBase::GeneratorBase(GeneratorContext &_ctx, const std::string _ns)
  12. : ctx(_ctx), ns(_ns)
  13. {}
  14. std::string
  15. GeneratorBase::qualify(const std::string &cpptype, int flags) const
  16. {
  17. return ::qualify(ns, cpptype, flags);
  18. }
  19. void
  20. GeneratorBase::parse_typeinfo(
  21. const std::string &girname, TypeInfo &result) const
  22. {
  23. auto ti = ctx.repo.lookup(girname);
  24. if (ti && ti->info)
  25. result = *ti->info;
  26. }
  27. GeneratorBase::ArgInfo
  28. GeneratorBase::parse_arginfo(const pt::ptree &node, ArgInfo *routput) const
  29. {
  30. ArgInfo lresult;
  31. ArgInfo &result = routput ? *routput : lresult;
  32. const pt::ptree *pntype{};
  33. std::string kind;
  34. // try most likely in turn
  35. for (auto &&v : {EL_TYPE, EL_ARRAY, EL_VARARGS}) {
  36. const auto &ntypeo = node.get_child_optional(v);
  37. if (ntypeo.is_initialized()) {
  38. kind = v;
  39. pntype = &ntypeo.get();
  40. }
  41. }
  42. if (kind.empty() || !pntype)
  43. throw skip("type info not found");
  44. if (kind == EL_VARARGS)
  45. throw skip("varargs not supported", skip::OK);
  46. auto &ntype = *pntype;
  47. bool discard_element = false;
  48. // no name for array
  49. if (kind == EL_ARRAY) {
  50. result.flags = TYPE_ARRAY;
  51. result.length = get_attribute<int>(ntype, AT_LENGTH, -10);
  52. result.zeroterminated = get_attribute<int>(ntype, AT_ZERO_TERMINATED, 1);
  53. result.fixedsize = get_attribute<int>(ntype, AT_FIXED_SIZE, 0);
  54. if (result.length < 0 && !result.zeroterminated && !result.fixedsize)
  55. throw skip("inconsistent array info");
  56. auto name = get_name(ntype, std::nothrow);
  57. // could be GBytes, etc
  58. if (name.size()) {
  59. // transform to plain argument if not ignored
  60. // FIXME maybe custom wrappers might be more convenient ??
  61. if (ctx.match_ignore.matches(ns, EL_RECORD, {name}))
  62. throw skip(name + " array not supported", skip::OK);
  63. // fresh state and discard element info processing
  64. result = ArgInfo{};
  65. discard_element = true;
  66. parse_typeinfo(name, result);
  67. }
  68. } else {
  69. parse_typeinfo(get_name(ntype), result);
  70. }
  71. // should be present (but not so for signal)
  72. // though const info seems to be missing in array case
  73. result.ctype = get_attribute(ntype, AT_CTYPE, "");
  74. // special case where const is preserved for the cpp type
  75. if (result.girname == "gpointer" && is_const(result.ctype))
  76. parse_typeinfo("gconstpointer", result);
  77. // handle element type info
  78. int i = 0;
  79. for (const auto &n : ntype) {
  80. if (n.first == "type" && !discard_element) {
  81. ArgTypeInfo &ti = i == 0 ? result.first : result.second;
  82. auto elname = get_name(n.second);
  83. parse_typeinfo(elname, ti);
  84. if (!ti.flags)
  85. throw skip("container element not supported", skip::OK);
  86. // probably not, but give it a shot
  87. ti.ctype = get_attribute(n.second, AT_CTYPE, "");
  88. // avoid specialized bool vector
  89. if (ti.cpptype == "bool")
  90. ti.cpptype = "gboolean";
  91. // some char arrays (e.g. g_regex* parameters) specify utf8 element type
  92. // along with ctype char rather than char*
  93. // so discard utf8 in that case and go for a plain array
  94. if (kind == EL_ARRAY && elname == "utf8" && ti.ctype == "gchar")
  95. parse_typeinfo(ti.ctype, ti);
  96. ++i;
  97. }
  98. }
  99. // sanity checks
  100. if ((result.flags & (TYPE_ARRAY | TYPE_LIST))) {
  101. if (i != 1)
  102. throw skip("inconsistent list element info");
  103. if (result.flags & TYPE_ARRAY) {
  104. // NOTE apparently both are possible, see e.g. g_shell_parse_arg*
  105. // in that case it is handled zeroterminated
  106. // and the size param becomes a regular one
  107. if (result.zeroterminated) {
  108. result.length = -1;
  109. result.fixedsize = 0;
  110. }
  111. // 1 pointer level more than the basic type
  112. result.pdepth = ((result.first.flags & TYPE_CLASS) ? 1 : 0) + 1;
  113. }
  114. } else if (result.flags & TYPE_MAP) {
  115. if (i != 2)
  116. throw skip("inconsistent map element info");
  117. } else {
  118. if (i != 0)
  119. throw skip("inconsistent type info");
  120. }
  121. return result;
  122. }
  123. std::string
  124. GeneratorBase::make_ctype(
  125. const ArgInfo &info, const std::string &direction, bool callerallocates)
  126. {
  127. std::string result;
  128. bool out = !(direction == DIR_IN || direction == DIR_RETURN);
  129. if (info.flags & TYPE_ARRAY) {
  130. auto ret = info.first.argtype + GI_PTR;
  131. if (out && !callerallocates)
  132. ret += GI_PTR;
  133. result = ret;
  134. } else if (info.flags & TYPE_CALLBACK) {
  135. result = info.cpptype + "::cfunction_type";
  136. } else {
  137. if (!out || callerallocates) {
  138. result = info.argtype;
  139. } else {
  140. result = info.argtype + GI_PTR;
  141. }
  142. }
  143. return (is_const(info.ctype) ? std::string("const ") : EMPTY) + result;
  144. }
  145. void
  146. GeneratorBase::track_dependency(
  147. std::set<std::string> &deps, const ArgInfo &info) const
  148. {
  149. auto track = [&](const std::string &cpptype, int flags) {
  150. // other items (e.g. enums) are included before anyway
  151. if (flags & TYPE_CLASS && !(flags & (TYPE_BASIC | TYPE_TYPEDEF))) {
  152. // always track scoped
  153. assert(is_qualified(cpptype));
  154. deps.insert(cpptype);
  155. if (flags & TYPE_BOXED)
  156. deps.insert(cpptype + GI_SUFFIX_REF);
  157. }
  158. };
  159. if (!(info.flags & TYPE_CONTAINER)) {
  160. track(info.cpptype, info.flags);
  161. } else {
  162. track(info.first.cpptype, info.first.flags);
  163. if (info.flags & TYPE_MAP)
  164. track(info.second.cpptype, info.second.flags);
  165. }
  166. }
  167. bool
  168. GeneratorBase::check_suppression(const std::string &ns, const std::string &kind,
  169. const std::string &name) const
  170. {
  171. // always generate
  172. ctx.suppressions.insert(ctx.match_sup.format(ns, kind, name));
  173. return ctx.match_sup.matches(ns, kind, {name});
  174. }
  175. std::string
  176. GeneratorBase::make_wrap_format(const ArgInfo &info,
  177. const std::string &transfer, const std::string &outtype)
  178. {
  179. std::string fmts;
  180. auto format = "{}";
  181. if (info.flags & TYPE_CLASS) {
  182. fmts = fmt::format(GI_NS_SCOPED + "wrap ({}, {})", format,
  183. get_transfer_parameter(transfer));
  184. } else if (info.flags & TYPE_ENUM) {
  185. fmts = GI_NS_SCOPED + "wrap ({})";
  186. } else if (info.flags & (TYPE_LIST | TYPE_ARRAY | TYPE_MAP)) {
  187. assert(!outtype.empty());
  188. fmts = fmt::format(GI_NS_SCOPED + "wrap_to<{}>({}, {})", outtype, format,
  189. get_transfer_parameter(transfer));
  190. } else {
  191. fmts = format;
  192. }
  193. return fmts;
  194. }
  195. std::string
  196. GeneratorBase::get_transfer_parameter(const std::string &transfer, bool _type)
  197. {
  198. std::map<std::string, std::string> m{
  199. {TRANSFER_NOTHING, "transfer_none"},
  200. {TRANSFER_FULL, "transfer_full"},
  201. {TRANSFER_CONTAINER, "transfer_container"},
  202. };
  203. auto it = m.find(transfer);
  204. if (it == m.end())
  205. throw std::runtime_error("invalid transfer " + transfer);
  206. return GI_NS_SCOPED + it->second + (_type ? "_t" : "");
  207. }