/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}