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 10char 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 24void 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 55void 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 102void 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 207int 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 240int 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 304int 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 320void 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 334static 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 * ----------------------------------------------------------------------------- */ 353int 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 * ----------------------------------------------------------------------------- */ 396String *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} 513