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 * templ.c 6 * 7 * Expands a template into a specialized version. 8 * ----------------------------------------------------------------------------- */ 9 10char cvsroot_templ_c[] = "$Id: templ.c 11097 2009-01-30 10:27:37Z bhy $"; 11 12#include "swig.h" 13#include "cparse.h" 14 15static int template_debug = 0; 16 17 18const char *baselists[3]; 19 20void SwigType_template_init() { 21 baselists[0] = "baselist"; 22 baselists[1] = "protectedbaselist"; 23 baselists[2] = "privatebaselist"; 24} 25 26 27static void add_parms(ParmList *p, List *patchlist, List *typelist) { 28 while (p) { 29 SwigType *ty = Getattr(p, "type"); 30 SwigType *val = Getattr(p, "value"); 31 Append(typelist, ty); 32 Append(typelist, val); 33 Append(patchlist, val); 34 p = nextSibling(p); 35 } 36} 37 38void Swig_cparse_debug_templates(int x) { 39 template_debug = x; 40} 41 42/* ----------------------------------------------------------------------------- 43 * cparse_template_expand() 44 * 45 * Expands a template node into a specialized version. This is done by 46 * patching typenames and other aspects of the node according to a list of 47 * template parameters 48 * ----------------------------------------------------------------------------- */ 49 50static int cparse_template_expand(Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) { 51 static int expanded = 0; 52 int ret; 53 String *nodeType; 54 if (!n) 55 return 0; 56 nodeType = nodeType(n); 57 if (Getattr(n, "error")) 58 return 0; 59 60 if (Equal(nodeType, "template")) { 61 /* Change the node type back to normal */ 62 if (!expanded) { 63 expanded = 1; 64 set_nodeType(n, Getattr(n, "templatetype")); 65 ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); 66 expanded = 0; 67 return ret; 68 } else { 69 /* Called when template appears inside another template */ 70 /* Member templates */ 71 72 set_nodeType(n, Getattr(n, "templatetype")); 73 ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); 74 set_nodeType(n, "template"); 75 return ret; 76 } 77 } else if (Equal(nodeType, "cdecl")) { 78 /* A simple C declaration */ 79 SwigType *t, *v, *d; 80 String *code; 81 t = Getattr(n, "type"); 82 v = Getattr(n, "value"); 83 d = Getattr(n, "decl"); 84 85 code = Getattr(n, "code"); 86 87 Append(typelist, t); 88 Append(typelist, d); 89 Append(patchlist, v); 90 Append(cpatchlist, code); 91 92 if (Getattr(n, "conversion_operator")) { 93 Append(cpatchlist, Getattr(n, "name")); 94 if (Getattr(n, "sym:name")) { 95 Append(cpatchlist, Getattr(n, "sym:name")); 96 } 97 } 98 99 add_parms(Getattr(n, "parms"), cpatchlist, typelist); 100 add_parms(Getattr(n, "throws"), cpatchlist, typelist); 101 102 } else if (Equal(nodeType, "class")) { 103 /* Patch base classes */ 104 { 105 int b = 0; 106 for (b = 0; b < 3; ++b) { 107 List *bases = Getattr(n, baselists[b]); 108 if (bases) { 109 int i; 110 int ilen = Len(bases); 111 for (i = 0; i < ilen; i++) { 112 String *name = Copy(Getitem(bases, i)); 113 Setitem(bases, i, name); 114 Append(typelist, name); 115 } 116 } 117 } 118 } 119 /* Patch children */ 120 { 121 Node *cn = firstChild(n); 122 while (cn) { 123 cparse_template_expand(cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); 124 cn = nextSibling(cn); 125 } 126 } 127 } else if (Equal(nodeType, "constructor")) { 128 String *name = Getattr(n, "name"); 129 if (!(Getattr(n, "templatetype"))) { 130 String *symname; 131 String *stripped_name = SwigType_templateprefix(name); 132 if (Strstr(tname, stripped_name)) { 133 Replaceid(name, stripped_name, tname); 134 } 135 Delete(stripped_name); 136 symname = Getattr(n, "sym:name"); 137 if (symname) { 138 stripped_name = SwigType_templateprefix(symname); 139 if (Strstr(tname, stripped_name)) { 140 Replaceid(symname, stripped_name, tname); 141 } 142 Delete(stripped_name); 143 } 144 if (strchr(Char(name), '<')) { 145 Append(patchlist, Getattr(n, "name")); 146 } else { 147 Append(name, templateargs); 148 } 149 name = Getattr(n, "sym:name"); 150 if (name) { 151 if (strchr(Char(name), '<')) { 152 Clear(name); 153 Append(name, rname); 154 } else { 155 String *tmp = Copy(name); 156 Replace(tmp, tname, rname, DOH_REPLACE_ANY); 157 Clear(name); 158 Append(name, tmp); 159 Delete(tmp); 160 } 161 } 162 /* Setattr(n,"sym:name",name); */ 163 } 164 Append(cpatchlist, Getattr(n, "code")); 165 Append(typelist, Getattr(n, "decl")); 166 add_parms(Getattr(n, "parms"), cpatchlist, typelist); 167 add_parms(Getattr(n, "throws"), cpatchlist, typelist); 168 } else if (Equal(nodeType, "destructor")) { 169 String *name = Getattr(n, "name"); 170 if (name) { 171 if (strchr(Char(name), '<')) 172 Append(patchlist, Getattr(n, "name")); 173 else 174 Append(name, templateargs); 175 } 176 name = Getattr(n, "sym:name"); 177 if (name) { 178 if (strchr(Char(name), '<')) { 179 String *sn = Copy(tname); 180 Setattr(n, "sym:name", sn); 181 Delete(sn); 182 } else { 183 Replace(name, tname, rname, DOH_REPLACE_ANY); 184 } 185 } 186 /* Setattr(n,"sym:name",name); */ 187 Append(cpatchlist, Getattr(n, "code")); 188 } else if (Equal(nodeType, "using")) { 189 String *uname = Getattr(n, "uname"); 190 if (uname && strchr(Char(uname), '<')) { 191 Append(patchlist, uname); 192 } 193 if (Getattr(n, "namespace")) { 194 /* Namespace link. This is nasty. Is other namespace defined? */ 195 196 } 197 } else { 198 /* Look for obvious parameters */ 199 Node *cn; 200 Append(cpatchlist, Getattr(n, "code")); 201 Append(typelist, Getattr(n, "type")); 202 Append(typelist, Getattr(n, "decl")); 203 add_parms(Getattr(n, "parms"), cpatchlist, typelist); 204 add_parms(Getattr(n, "kwargs"), cpatchlist, typelist); 205 add_parms(Getattr(n, "pattern"), cpatchlist, typelist); 206 add_parms(Getattr(n, "throws"), cpatchlist, typelist); 207 cn = firstChild(n); 208 while (cn) { 209 cparse_template_expand(cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); 210 cn = nextSibling(cn); 211 } 212 } 213 return 0; 214} 215 216static 217String *partial_arg(String *s, String *p) { 218 char *c; 219 char *cp = Char(p); 220 String *prefix; 221 String *newarg; 222 223 /* Find the prefix on the partial argument */ 224 225 c = strchr(cp, '$'); 226 if (!c) { 227 return Copy(s); 228 } 229 prefix = NewStringWithSize(cp, c - cp); 230 newarg = Copy(s); 231 Replace(newarg, prefix, "", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); 232 Delete(prefix); 233 return newarg; 234} 235 236/* ----------------------------------------------------------------------------- 237 * Swig_cparse_template_expand() 238 * ----------------------------------------------------------------------------- */ 239 240int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope) { 241 List *patchlist, *cpatchlist, *typelist; 242 String *templateargs; 243 String *tname; 244 String *iname; 245 String *tbase; 246 patchlist = NewList(); 247 cpatchlist = NewList(); 248 typelist = NewList(); 249 250 { 251 String *tmp = NewStringEmpty(); 252 if (tparms) { 253 SwigType_add_template(tmp, tparms); 254 } 255 templateargs = Copy(tmp); 256 Delete(tmp); 257 } 258 259 tname = Copy(Getattr(n, "name")); 260 tbase = Swig_scopename_last(tname); 261 262 /* Look for partial specialization matching */ 263 if (Getattr(n, "partialargs")) { 264 Parm *p, *tp; 265 ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs")); 266 p = ptargs; 267 tp = tparms; 268 while (p && tp) { 269 SwigType *ptype; 270 SwigType *tptype; 271 SwigType *partial_type; 272 ptype = Getattr(p, "type"); 273 tptype = Getattr(tp, "type"); 274 if (ptype && tptype) { 275 partial_type = partial_arg(tptype, ptype); 276 /* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */ 277 Setattr(tp, "type", partial_type); 278 Delete(partial_type); 279 } 280 p = nextSibling(p); 281 tp = nextSibling(tp); 282 } 283 assert(ParmList_len(ptargs) == ParmList_len(tparms)); 284 Delete(ptargs); 285 } 286 287 /* 288 Parm *p = tparms; 289 while (p) { 290 Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value")); 291 p = nextSibling(p); 292 } 293 */ 294 295 /* Printf(stdout,"targs = '%s'\n", templateargs); 296 Printf(stdout,"rname = '%s'\n", rname); 297 Printf(stdout,"tname = '%s'\n", tname); */ 298 cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); 299 300 /* Set the name */ 301 { 302 String *name = Getattr(n, "name"); 303 if (name) { 304 Append(name, templateargs); 305 } 306 iname = name; 307 } 308 309 /* Patch all of the types */ 310 { 311 Parm *tp = Getattr(n, "templateparms"); 312 Parm *p = tparms; 313 /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ 314 315 if (tp) { 316 Symtab *tsdecl = Getattr(n, "sym:symtab"); 317 while (p && tp) { 318 String *name, *value, *valuestr, *tydef, *tmp, *tmpr; 319 int sz, i; 320 String *dvalue = 0; 321 String *qvalue = 0; 322 323 name = Getattr(tp, "name"); 324 value = Getattr(p, "value"); 325 tydef = Getattr(p, "typedef"); 326 327 if (name) { 328 if (!value) 329 value = Getattr(p, "type"); 330 qvalue = Swig_symbol_typedef_reduce(value, tsdecl); 331 dvalue = Swig_symbol_type_qualify(qvalue, tsdecl); 332 if (SwigType_istemplate(dvalue)) { 333 String *ty = Swig_symbol_template_deftype(dvalue, tscope); 334 Delete(dvalue); 335 dvalue = ty; 336 } 337 338 assert(dvalue); 339 valuestr = SwigType_str(dvalue, 0); 340 /* Need to patch default arguments */ 341 { 342 Parm *rp = nextSibling(p); 343 while (rp) { 344 String *rvalue = Getattr(rp, "value"); 345 if (rvalue) { 346 Replace(rvalue, name, dvalue, DOH_REPLACE_ID); 347 } 348 rp = nextSibling(rp); 349 } 350 } 351 sz = Len(patchlist); 352 for (i = 0; i < sz; i++) { 353 String *s = Getitem(patchlist, i); 354 Replace(s, name, dvalue, DOH_REPLACE_ID); 355 } 356 sz = Len(typelist); 357 for (i = 0; i < sz; i++) { 358 String *s = Getitem(typelist, i); 359 /* Replace(s,name,value, DOH_REPLACE_ID); */ 360 /* Printf(stdout,"name = '%s', value = '%s', tbase = '%s', iname='%s' s = '%s' --> ", name, dvalue, tbase, iname, s); */ 361 SwigType_typename_replace(s, name, dvalue); 362 SwigType_typename_replace(s, tbase, iname); 363 /* Printf(stdout,"'%s'\n", s); */ 364 } 365 366 if (!tydef) { 367 tydef = dvalue; 368 } 369 tmp = NewStringf("#%s", name); 370 tmpr = NewStringf("\"%s\"", valuestr); 371 372 sz = Len(cpatchlist); 373 for (i = 0; i < sz; i++) { 374 String *s = Getitem(cpatchlist, i); 375 Replace(s, tmp, tmpr, DOH_REPLACE_ID); 376 /* Replace(s,name,tydef, DOH_REPLACE_ID); */ 377 Replace(s, name, valuestr, DOH_REPLACE_ID); 378 } 379 Delete(tmp); 380 Delete(tmpr); 381 Delete(valuestr); 382 Delete(dvalue); 383 Delete(qvalue); 384 } 385 p = nextSibling(p); 386 tp = nextSibling(tp); 387 if (!p) 388 p = tp; 389 } 390 } else { 391 /* No template parameters at all. This could be a specialization */ 392 int i, sz; 393 sz = Len(typelist); 394 for (i = 0; i < sz; i++) { 395 String *s = Getitem(typelist, i); 396 SwigType_typename_replace(s, tbase, iname); 397 } 398 } 399 } 400 401 /* Patch bases */ 402 { 403 List *bases = Getattr(n, "baselist"); 404 if (bases) { 405 Iterator b; 406 for (b = First(bases); b.item; b = Next(b)) { 407 String *qn = Swig_symbol_type_qualify(b.item, tscope); 408 Clear(b.item); 409 Append(b.item, qn); 410 Delete(qn); 411 } 412 } 413 } 414 Delete(patchlist); 415 Delete(cpatchlist); 416 Delete(typelist); 417 Delete(tbase); 418 Delete(tname); 419 Delete(templateargs); 420 421 /* set_nodeType(n,"template"); */ 422 return 0; 423} 424 425/* ----------------------------------------------------------------------------- 426 * template_locate() 427 * 428 * Search for a template that matches name with given parameters. 429 * ----------------------------------------------------------------------------- */ 430 431static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { 432 Node *n; 433 String *tname, *rname = 0; 434 Node *templ; 435 List *mpartials = 0; 436 Parm *p; 437 Parm *parms; 438 Parm *targs; 439 ParmList *expandedparms; 440 441 tname = Copy(name); 442 parms = CopyParmList(tparms); 443 444 /* Search for generic template */ 445 templ = Swig_symbol_clookup(name, 0); 446 447 /* Add default values from generic template */ 448 if (templ) { 449 Symtab *tsdecl = Getattr(templ, "sym:symtab"); 450 451 targs = Getattr(templ, "templateparms"); 452 expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, tsdecl); 453 } else { 454 expandedparms = parms; 455 } 456 457 458 /* reduce the typedef */ 459 p = expandedparms; 460 while (p) { 461 SwigType *ty = Getattr(p, "type"); 462 if (ty) { 463 SwigType *nt = Swig_symbol_type_qualify(ty, tscope); 464 Setattr(p, "type", nt); 465 Delete(nt); 466 } 467 p = nextSibling(p); 468 } 469 470 SwigType_add_template(tname, expandedparms); 471 472 if (template_debug) { 473 Printf(stdout, "\n%s:%d: template_debug: Searching for %s\n", cparse_file, cparse_line, tname); 474 } 475 476 /* Search for an exact specialization. 477 Example: template<> class name<int> { ... } */ 478 { 479 if (template_debug) { 480 Printf(stdout, " searching: '%s' (exact specialization)\n", tname); 481 } 482 n = Swig_symbol_clookup_local(tname, 0); 483 if (!n) { 484 SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope); 485 if (!Equal(rname, tname)) { 486 if (template_debug) { 487 Printf(stdout, " searching: '%s' (exact specialization)\n", rname); 488 } 489 n = Swig_symbol_clookup_local(rname, 0); 490 } 491 Delete(rname); 492 } 493 if (n) { 494 Node *tn; 495 String *nodeType = nodeType(n); 496 if (Equal(nodeType, "template")) 497 goto success; 498 tn = Getattr(n, "template"); 499 if (tn) { 500 n = tn; 501 goto success; /* Previously wrapped by a template return that */ 502 } 503 Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n)); 504 Delete(tname); 505 Delete(parms); 506 return 0; /* Found a match, but it's not a template of any kind. */ 507 } 508 } 509 510 /* Search for partial specialization. 511 Example: template<typename T> class name<T *> { ... } */ 512 513 /* Generate reduced template name (stripped of extraneous pointers, etc.) */ 514 515 rname = NewStringf("%s<(", name); 516 p = parms; 517 while (p) { 518 String *t; 519 t = Getattr(p, "type"); 520 if (!t) 521 t = Getattr(p, "value"); 522 if (t) { 523 String *ty = Swig_symbol_typedef_reduce(t, tscope); 524 String *tb = SwigType_base(ty); 525 String *td = SwigType_default(ty); 526 Replaceid(td, "enum SWIGTYPE", tb); 527 Replaceid(td, "SWIGTYPE", tb); 528 Append(rname, td); 529 Delete(tb); 530 Delete(ty); 531 Delete(td); 532 } 533 p = nextSibling(p); 534 if (p) { 535 Append(rname, ","); 536 } 537 } 538 Append(rname, ")>"); 539 540 mpartials = NewList(); 541 if (templ) { 542 /* First, we search using an exact type prototype */ 543 Parm *p; 544 char tmp[32]; 545 int i; 546 List *partials; 547 String *ss; 548 Iterator pi; 549 550 partials = Getattr(templ, "partials"); 551 if (partials) { 552 for (pi = First(partials); pi.item; pi = Next(pi)) { 553 ss = Copy(pi.item); 554 p = parms; 555 i = 1; 556 while (p) { 557 String *t, *tn; 558 sprintf(tmp, "$%d", i); 559 t = Getattr(p, "type"); 560 if (!t) 561 t = Getattr(p, "value"); 562 if (t) { 563 String *ty = Swig_symbol_typedef_reduce(t, tscope); 564 tn = SwigType_base(ty); 565 Replaceid(ss, tmp, tn); 566 Delete(tn); 567 Delete(ty); 568 } 569 i++; 570 p = nextSibling(p); 571 } 572 if (template_debug) { 573 Printf(stdout, " searching: '%s' (partial specialization - %s)\n", ss, pi.item); 574 } 575 if ((Equal(ss, tname)) || (Equal(ss, rname))) { 576 Append(mpartials, pi.item); 577 } 578 Delete(ss); 579 } 580 } 581 } 582 583 if (template_debug) { 584 Printf(stdout, " Matched partials: %s\n", mpartials); 585 } 586 587 if (Len(mpartials)) { 588 String *s = Getitem(mpartials, 0); 589 n = Swig_symbol_clookup_local(s, 0); 590 if (Len(mpartials) > 1) { 591 if (n) { 592 Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname)); 593 Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), " instantiation '%s' is used.\n", SwigType_namestr(Getattr(n, "name"))); 594 } 595 } 596 } 597 598 if (!n) { 599 n = templ; 600 } 601 if (!n) { 602 Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); 603 } else if (n) { 604 String *nodeType = nodeType(n); 605 if (!Equal(nodeType, "template")) { 606 Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType); 607 n = 0; 608 } 609 } 610success: 611 Delete(tname); 612 Delete(rname); 613 Delete(mpartials); 614 if ((template_debug) && (n)) { 615 Printf(stdout, "Node: %p\n", n); 616 Swig_print_node(n); 617 } 618 Delete(parms); 619 return n; 620} 621 622 623/* ----------------------------------------------------------------------------- 624 * Swig_cparse_template_locate() 625 * 626 * Search for a template that matches name with given parameters. 627 * For templated classes finds the specialized template should there be one. 628 * For templated functions finds the unspecialized template even if a specialized 629 * template exists. 630 * ----------------------------------------------------------------------------- */ 631 632Node *Swig_cparse_template_locate(String *name, Parm *tparms, Symtab *tscope) { 633 Node *n = template_locate(name, tparms, tscope); /* this function does what we want for templated classes */ 634 635 if (n) { 636 String *nodeType = nodeType(n); 637 int isclass = 0; 638 assert(Equal(nodeType, "template")); 639 isclass = (Equal(Getattr(n, "templatetype"), "class")); 640 if (!isclass) { 641 /* If not a templated class we must have a templated function. 642 The template found is not necessarily the one we want when dealing with templated 643 functions. We don't want any specialized templated functions as they won't have 644 the default parameters. Lets look for the unspecialized template. Also make sure 645 the number of template parameters is correct as it is possible to overload a 646 templated function with different numbers of template parameters. */ 647 648 if (template_debug) { 649 Printf(stdout, " Not a templated class, seeking most appropriate templated function\n"); 650 } 651 652 n = Swig_symbol_clookup_local(name, 0); 653 while (n) { 654 Parm *tparmsfound = Getattr(n, "templateparms"); 655 if (ParmList_len(tparms) == ParmList_len(tparmsfound)) { 656 /* successful match */ 657 break; 658 } 659 /* repeat until we find a match with correct number of templated parameters */ 660 n = Getattr(n, "sym:nextSibling"); 661 } 662 663 if (!n) { 664 Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); 665 } 666 667 if ((template_debug) && (n)) { 668 Printf(stdout, "Templated function found: %p\n", n); 669 Swig_print_node(n); 670 } 671 } 672 } 673 674 return n; 675} 676