PageRenderTime 67ms CodeModel.GetById 27ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/trunk/Source/Modules/emit.cxx

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