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