emit.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /* -----------------------------------------------------------------------------
  2. * This file is part of SWIG, which is licensed as a whole under version 3
  3. * (or any later version) of the GNU General Public License. Some additional
  4. * terms also apply to certain portions of SWIG. The full details of the SWIG
  5. * license and copyrights can be found in the LICENSE and COPYRIGHT files
  6. * included with the SWIG source code as distributed by the SWIG developers
  7. * and at https://www.swig.org/legal.html.
  8. *
  9. * emit.cxx
  10. *
  11. * Useful functions for emitting various pieces of code.
  12. * ----------------------------------------------------------------------------- */
  13. #include "swigmod.h"
  14. #include "cparse.h"
  15. /* -----------------------------------------------------------------------------
  16. * emit_return_variable()
  17. *
  18. * Emits a variable declaration for a function return value.
  19. * The variable name is always called result.
  20. * n => Node of the method being wrapped
  21. * rt => the return type
  22. * f => the wrapper to generate code into
  23. * ----------------------------------------------------------------------------- */
  24. void emit_return_variable(Node *n, SwigType *rt, Wrapper *f) {
  25. if (!GetFlag(n, "tmap:out:optimal")) {
  26. if (rt && (SwigType_type(rt) != T_VOID)) {
  27. SwigType *vt = cplus_value_type(rt);
  28. SwigType *tt = vt ? vt : rt;
  29. SwigType *lt = SwigType_ltype(tt);
  30. String *lstr = SwigType_str(lt, Swig_cresult_name());
  31. if (SwigType_ispointer(lt)) {
  32. Wrapper_add_localv(f, Swig_cresult_name(), lstr, "= 0", NULL);
  33. } else {
  34. Wrapper_add_local(f, Swig_cresult_name(), lstr);
  35. }
  36. if (vt) {
  37. Delete(vt);
  38. }
  39. Delete(lt);
  40. Delete(lstr);
  41. }
  42. }
  43. }
  44. /* -----------------------------------------------------------------------------
  45. * emit_parameter_variables()
  46. *
  47. * Emits a list of variable declarations for function parameters.
  48. * The variable names are always called arg1, arg2, etc...
  49. * l => the parameter list
  50. * f => the wrapper to generate code into
  51. * ----------------------------------------------------------------------------- */
  52. void emit_parameter_variables(ParmList *l, Wrapper *f) {
  53. Parm *p;
  54. String *tm;
  55. /* Emit function arguments */
  56. Swig_cargs(f, l);
  57. /* Attach typemaps to parameters */
  58. /* Swig_typemap_attach_parms("ignore",l,f); */
  59. Swig_typemap_attach_parms("default", l, f);
  60. Swig_typemap_attach_parms("arginit", l, f);
  61. /* Apply the arginit and default */
  62. p = l;
  63. while (p) {
  64. tm = Getattr(p, "tmap:arginit");
  65. if (tm) {
  66. Printv(f->code, tm, "\n", NIL);
  67. p = Getattr(p, "tmap:arginit:next");
  68. } else {
  69. p = nextSibling(p);
  70. }
  71. }
  72. /* Apply the default typemap */
  73. p = l;
  74. while (p) {
  75. tm = Getattr(p, "tmap:default");
  76. if (tm) {
  77. Printv(f->code, tm, "\n", NIL);
  78. p = Getattr(p, "tmap:default:next");
  79. } else {
  80. p = nextSibling(p);
  81. }
  82. }
  83. }
  84. /* -----------------------------------------------------------------------------
  85. * emit_attach_parmmaps()
  86. *
  87. * Attach the standard parameter related typemaps.
  88. * ----------------------------------------------------------------------------- */
  89. void emit_attach_parmmaps(ParmList *l, Wrapper *f) {
  90. Swig_typemap_attach_parms("in", l, f);
  91. Swig_typemap_attach_parms("typecheck", l, 0);
  92. Swig_typemap_attach_parms("argout", l, f);
  93. Swig_typemap_attach_parms("check", l, f);
  94. Swig_typemap_attach_parms("freearg", l, f);
  95. {
  96. /* This is compatibility code to deal with the deprecated "ignore" typemap */
  97. Parm *p = l;
  98. Parm *np;
  99. while (p) {
  100. String *tm = Getattr(p, "tmap:in");
  101. if (tm && checkAttribute(p, "tmap:in:numinputs", "0")) {
  102. Printv(f->code, tm, "\n", NIL);
  103. np = Getattr(p, "tmap:in:next");
  104. while (p && (p != np)) {
  105. /* Setattr(p,"ignore","1"); Deprecate */
  106. p = nextSibling(p);
  107. }
  108. } else if (tm) {
  109. p = Getattr(p, "tmap:in:next");
  110. } else {
  111. p = nextSibling(p);
  112. }
  113. }
  114. }
  115. /* Perform a sanity check on "in" and "freearg" typemaps. These
  116. must exactly match to avoid chaos. If a mismatch occurs, we
  117. nuke the freearg typemap */
  118. {
  119. Parm *p = l;
  120. Parm *npin, *npfreearg;
  121. while (p) {
  122. npin = Getattr(p, "tmap:in:next");
  123. /*
  124. if (Getattr(p,"tmap:ignore")) {
  125. npin = Getattr(p,"tmap:ignore:next");
  126. } else if (Getattr(p,"tmap:in")) {
  127. npin = Getattr(p,"tmap:in:next");
  128. }
  129. */
  130. if (Getattr(p, "tmap:freearg")) {
  131. npfreearg = Getattr(p, "tmap:freearg:next");
  132. if (npin != npfreearg) {
  133. while (p != npin) {
  134. Delattr(p, "tmap:freearg");
  135. Delattr(p, "tmap:freearg:next");
  136. p = nextSibling(p);
  137. }
  138. }
  139. }
  140. p = npin;
  141. }
  142. }
  143. /* Check for variable length arguments with no input typemap.
  144. If no input is defined, we set this to ignore and print a
  145. message.
  146. */
  147. {
  148. Parm *p = l;
  149. Parm *lp = 0;
  150. while (p) {
  151. if (!checkAttribute(p, "tmap:in:numinputs", "0")) {
  152. lp = p;
  153. p = Getattr(p, "tmap:in:next");
  154. continue;
  155. }
  156. if (SwigType_isvarargs(Getattr(p, "type"))) {
  157. Swig_warning(WARN_LANG_VARARGS, input_file, line_number, "Variable length arguments discarded.\n");
  158. Setattr(p, "tmap:in", "");
  159. }
  160. lp = 0;
  161. p = nextSibling(p);
  162. }
  163. /* Check if last input argument is variable length argument */
  164. if (lp) {
  165. p = lp;
  166. while (p) {
  167. if (SwigType_isvarargs(Getattr(p, "type"))) {
  168. // Mark the head of the ParmList that it has varargs
  169. Setattr(l, "emit:varargs", lp);
  170. //Printf(stdout, "setting emit:varargs %s ... %s +++ %s\n", Getattr(l, "emit:varargs"), Getattr(l, "type"), Getattr(p, "type"));
  171. break;
  172. }
  173. p = nextSibling(p);
  174. }
  175. }
  176. }
  177. /*
  178. * An equivalent type can be used in the typecheck typemap for SWIG to detect the overloading of equivalent
  179. * target language types. This is primarily for the smartptr feature, where a pointer and a smart pointer
  180. * are seen as equivalent types in the target language.
  181. */
  182. {
  183. Parm *p = l;
  184. while (p) {
  185. String *tm = Getattr(p, "tmap:typecheck");
  186. if (tm) {
  187. String *equivalent = Getattr(p, "tmap:typecheck:equivalent");
  188. if (equivalent) {
  189. String *precedence = Getattr(p, "tmap:typecheck:precedence");
  190. if (precedence && Strcmp(precedence, "0") != 0)
  191. Swig_error(Getfile(tm), Getline(tm), "The 'typecheck' typemap for %s contains an 'equivalent' attribute for a 'precedence' that is not set to SWIG_TYPECHECK_POINTER or 0.\n", SwigType_str(Getattr(p, "type"), 0));
  192. SwigType *cpt = Swig_cparse_type(equivalent);
  193. if (cpt) {
  194. Setattr(p, "equivtype", cpt);
  195. Delete(cpt);
  196. } else {
  197. Swig_error(Getfile(tm), Getline(tm), "Invalid type (%s) in 'equivalent' attribute in 'typecheck' typemap for type %s.\n", equivalent, SwigType_str(Getattr(p, "type"), 0));
  198. }
  199. }
  200. p = Getattr(p, "tmap:typecheck:next");
  201. } else {
  202. p = nextSibling(p);
  203. }
  204. }
  205. }
  206. }
  207. /* -----------------------------------------------------------------------------
  208. * emit_num_arguments()
  209. *
  210. * Calculate the total number of arguments. This function is safe for use
  211. * with multi-argument typemaps which may change the number of arguments in
  212. * strange ways.
  213. * ----------------------------------------------------------------------------- */
  214. int emit_num_arguments(ParmList *parms) {
  215. Parm *p = parms;
  216. int nargs = 0;
  217. while (p) {
  218. if (Getattr(p, "tmap:in")) {
  219. nargs += GetInt(p, "tmap:in:numinputs");
  220. p = Getattr(p, "tmap:in:next");
  221. } else {
  222. p = nextSibling(p);
  223. }
  224. }
  225. /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */
  226. /*
  227. if (parms && (p = Getattr(parms,"emit:varargs"))) {
  228. if (!nextSibling(p)) {
  229. nargs--;
  230. }
  231. }
  232. */
  233. return nargs;
  234. }
  235. /* -----------------------------------------------------------------------------
  236. * emit_num_required()
  237. *
  238. * Computes the number of required arguments. This function is safe for
  239. * use with multi-argument typemaps and knows how to skip over everything
  240. * properly. Note that parameters with default values are counted unless
  241. * the compact default args option is on.
  242. * ----------------------------------------------------------------------------- */
  243. int emit_num_required(ParmList *parms) {
  244. Parm *p = parms;
  245. int nargs = 0;
  246. Parm *first_default_arg = 0;
  247. int compactdefargs = ParmList_is_compactdefargs(p);
  248. while (p) {
  249. if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) {
  250. p = Getattr(p, "tmap:in:next");
  251. } else {
  252. if (Getattr(p, "tmap:default"))
  253. break;
  254. if (Getattr(p, "value")) {
  255. if (!first_default_arg)
  256. first_default_arg = p;
  257. if (compactdefargs)
  258. break;
  259. }
  260. nargs += GetInt(p, "tmap:in:numinputs");
  261. if (Getattr(p, "tmap:in")) {
  262. p = Getattr(p, "tmap:in:next");
  263. } else {
  264. p = nextSibling(p);
  265. }
  266. }
  267. }
  268. /* Print error message for non-default arguments following default arguments */
  269. /* The error message is printed more than once with most language modules, this ought to be fixed */
  270. if (first_default_arg) {
  271. p = first_default_arg;
  272. while (p) {
  273. if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) {
  274. p = Getattr(p, "tmap:in:next");
  275. } else {
  276. if (!Getattr(p, "value") && (!Getattr(p, "tmap:default"))) {
  277. Swig_error(Getfile(p), Getline(p), "Non-optional argument '%s' follows an optional argument.\n", Getattr(p, "name"));
  278. }
  279. if (Getattr(p, "tmap:in")) {
  280. p = Getattr(p, "tmap:in:next");
  281. } else {
  282. p = nextSibling(p);
  283. }
  284. }
  285. }
  286. }
  287. /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */
  288. /*
  289. if (parms && (p = Getattr(parms,"emit:varargs"))) {
  290. if (!nextSibling(p)) {
  291. nargs--;
  292. }
  293. }
  294. */
  295. return nargs;
  296. }
  297. /* -----------------------------------------------------------------------------
  298. * emit_isvarargs()
  299. *
  300. * Checks if a ParmList is a parameter list containing varargs.
  301. * This function requires emit_attach_parmmaps to have been called beforehand.
  302. * ----------------------------------------------------------------------------- */
  303. int emit_isvarargs(ParmList *p) {
  304. if (!p)
  305. return 0;
  306. if (Getattr(p, "emit:varargs"))
  307. return 1;
  308. return 0;
  309. }
  310. /* -----------------------------------------------------------------------------
  311. * emit_isvarargs_function()
  312. *
  313. * Checks for varargs in a function/constructor (can be overloaded)
  314. * ----------------------------------------------------------------------------- */
  315. bool emit_isvarargs_function(Node *n) {
  316. bool has_varargs = false;
  317. Node *over = Getattr(n, "sym:overloaded");
  318. if (over) {
  319. for (Node *sibling = over; sibling; sibling = Getattr(sibling, "sym:nextSibling")) {
  320. if (ParmList_has_varargs(Getattr(sibling, "parms"))) {
  321. has_varargs = true;
  322. break;
  323. }
  324. }
  325. } else {
  326. has_varargs = ParmList_has_varargs(Getattr(n, "parms")) ? true : false;
  327. }
  328. return has_varargs;
  329. }
  330. /* -----------------------------------------------------------------------------
  331. * void emit_mark_vararg_parms()
  332. *
  333. * Marks the vararg parameters which are to be ignored.
  334. * Vararg parameters are marked as ignored if there is no 'in' varargs (...)
  335. * typemap.
  336. * ----------------------------------------------------------------------------- */
  337. void emit_mark_varargs(ParmList *l) {
  338. Parm *p = l;
  339. while (p) {
  340. if (SwigType_isvarargs(Getattr(p, "type")))
  341. if (!Getattr(p, "tmap:in"))
  342. Setattr(p, "varargs:ignore", "1");
  343. p = nextSibling(p);
  344. }
  345. }
  346. #if 0
  347. /* replace_contract_args. This function replaces argument names in contract
  348. specifications. Used in conjunction with the %contract directive. */
  349. static void replace_contract_args(Parm *cp, Parm *rp, String *s) {
  350. while (cp && rp) {
  351. String *n = Getattr(cp, "name");
  352. if (n) {
  353. Replace(s, n, Getattr(rp, "lname"), DOH_REPLACE_ID);
  354. }
  355. cp = nextSibling(cp);
  356. rp = nextSibling(rp);
  357. }
  358. }
  359. #endif
  360. /* -----------------------------------------------------------------------------
  361. * int emit_action_code()
  362. *
  363. * Emits action code for a wrapper. Adds in exception handling code (%exception).
  364. * eaction -> the action code to emit
  365. * wrappercode -> the emitted code (output)
  366. * ----------------------------------------------------------------------------- */
  367. int emit_action_code(Node *n, String *wrappercode, String *eaction) {
  368. assert(Getattr(n, "wrap:name"));
  369. /* Look for except feature (%exception) */
  370. String *tm = GetFlagAttr(n, "feature:except");
  371. if (tm)
  372. tm = Copy(tm);
  373. if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
  374. if (Strstr(tm, "$")) {
  375. Swig_replace_special_variables(n, parentNode(n), tm);
  376. Replaceall(tm, "$function", eaction); // deprecated
  377. Replaceall(tm, "$action", eaction);
  378. }
  379. Printv(wrappercode, tm, "\n", NIL);
  380. Delete(tm);
  381. return 1;
  382. } else {
  383. Printv(wrappercode, eaction, "\n", NIL);
  384. return 0;
  385. }
  386. }
  387. /* -----------------------------------------------------------------------------
  388. * int emit_action()
  389. *
  390. * Emits the call to the wrapped function.
  391. * Adds in exception specification exception handling and %exception code.
  392. * ----------------------------------------------------------------------------- */
  393. String *emit_action(Node *n) {
  394. String *actioncode = NewStringEmpty();
  395. String *tm;
  396. String *action;
  397. String *wrap;
  398. ParmList *catchlist = Getattr(n, "catchlist");
  399. /* Look for fragments */
  400. {
  401. String *fragment = Getattr(n, "feature:fragment");
  402. if (fragment) {
  403. char *c, *tok;
  404. String *t = Copy(fragment);
  405. c = Char(t);
  406. tok = strtok(c, ",");
  407. while (tok) {
  408. String *fname = NewString(tok);
  409. Setfile(fname, Getfile(n));
  410. Setline(fname, Getline(n));
  411. Swig_fragment_emit(fname);
  412. Delete(fname);
  413. tok = strtok(NULL, ",");
  414. }
  415. Delete(t);
  416. }
  417. }
  418. /* Emit wrapper code (if any) */
  419. wrap = Getattr(n, "wrap:code");
  420. if (wrap && Swig_filebyname("header") != Getattr(n, "wrap:code:done")) {
  421. File *f_code = Swig_filebyname("header");
  422. if (f_code) {
  423. Printv(f_code, wrap, NIL);
  424. }
  425. Setattr(n, "wrap:code:done", f_code);
  426. }
  427. action = Getattr(n, "feature:action");
  428. if (!action)
  429. action = Getattr(n, "wrap:action");
  430. assert(action != 0);
  431. /* Emit contract code (if any) */
  432. if (Swig_contract_mode_get()) {
  433. /* Preassertion */
  434. tm = Getattr(n, "contract:preassert");
  435. if (Len(tm)) {
  436. Printv(actioncode, tm, "\n", NIL);
  437. }
  438. }
  439. /* Exception handling code */
  440. /* saves action -> eaction for postcatching exception */
  441. String *eaction = NewString("");
  442. /* If we are in C++ mode and there is an exception specification. We're going to
  443. enclose the block in a try block */
  444. if (catchlist) {
  445. Printf(eaction, "try {\n");
  446. }
  447. String *preaction = Getattr(n, "wrap:preaction");
  448. if (preaction)
  449. Printv(eaction, preaction, NIL);
  450. Printv(eaction, action, NIL);
  451. String *postaction = Getattr(n, "wrap:postaction");
  452. if (postaction)
  453. Printv(eaction, postaction, NIL);
  454. if (catchlist) {
  455. int unknown_catch = 0;
  456. int has_varargs = 0;
  457. Printf(eaction, "}");
  458. for (Parm *ep = catchlist; ep; ep = nextSibling(ep)) {
  459. String *em = Swig_typemap_lookup("throws", ep, "_e", 0);
  460. if (em) {
  461. SwigType *et = Getattr(ep, "type");
  462. SwigType *etr = SwigType_typedef_resolve_all(et);
  463. if (SwigType_isreference(etr) || SwigType_ispointer(etr) || SwigType_isarray(etr)) {
  464. Printf(eaction, " catch(%s) {", SwigType_str(et, "_e"));
  465. } else if (SwigType_isvarargs(etr)) {
  466. Printf(eaction, " catch(...) {");
  467. has_varargs = 1;
  468. } else {
  469. Printf(eaction, " catch(%s) {", SwigType_str(et, "&_e"));
  470. }
  471. Printv(eaction, em, "\n", NIL);
  472. Printf(eaction, "}");
  473. } else {
  474. Swig_warning(WARN_TYPEMAP_THROW, Getfile(n), Getline(n), "No 'throws' typemap defined for exception type '%s'\n", SwigType_str(Getattr(ep, "type"), 0));
  475. unknown_catch = 1;
  476. }
  477. }
  478. if (unknown_catch && !has_varargs) {
  479. Printf(eaction, " catch(...) {\nthrow;\n}");
  480. }
  481. }
  482. /* Look for except typemap (Deprecated) */
  483. tm = Swig_typemap_lookup("except", n, Swig_cresult_name(), 0);
  484. if (tm) {
  485. Setattr(n, "feature:except", tm);
  486. tm = 0;
  487. }
  488. /* emit the except feature code */
  489. emit_action_code(n, actioncode, eaction);
  490. Delete(eaction);
  491. /* Emit contract code (if any) */
  492. if (Swig_contract_mode_get()) {
  493. /* Postassertion */
  494. tm = Getattr(n, "contract:postassert");
  495. if (Len(tm)) {
  496. Printv(actioncode, tm, "\n", NIL);
  497. }
  498. }
  499. return actioncode;
  500. }