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