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.
7 * Expands a template into a specialized version.
8 * ----------------------------------------------------------------------------- */
10 char cvsroot_templ_c[] = "$Id: templ.c 11097 2009-01-30 10:27:37Z bhy $";
15 static int template_debug = 0;
18 const char *baselists[3];
20 void SwigType_template_init() {
21 baselists[0] = "baselist";
22 baselists[1] = "protectedbaselist";
23 baselists[2] = "privatebaselist";
27 static void add_parms(ParmList *p, List *patchlist, List *typelist) {
29 SwigType *ty = Getattr(p, "type");
30 SwigType *val = Getattr(p, "value");
32 Append(typelist, val);
33 Append(patchlist, val);
38 void Swig_cparse_debug_templates(int x) {
42 /* -----------------------------------------------------------------------------
43 * cparse_template_expand()
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
48 * ----------------------------------------------------------------------------- */
50 static int cparse_template_expand(Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) {
51 static int expanded = 0;
56 nodeType = nodeType(n);
57 if (Getattr(n, "error"))
60 if (Equal(nodeType, "template")) {
61 /* Change the node type back to normal */
64 set_nodeType(n, Getattr(n, "templatetype"));
65 ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist);
69 /* Called when template appears inside another template */
70 /* Member templates */
72 set_nodeType(n, Getattr(n, "templatetype"));
73 ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist);
74 set_nodeType(n, "template");
77 } else if (Equal(nodeType, "cdecl")) {
78 /* A simple C declaration */
81 t = Getattr(n, "type");
82 v = Getattr(n, "value");
83 d = Getattr(n, "decl");
85 code = Getattr(n, "code");
90 Append(cpatchlist, code);
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"));
99 add_parms(Getattr(n, "parms"), cpatchlist, typelist);
100 add_parms(Getattr(n, "throws"), cpatchlist, typelist);
102 } else if (Equal(nodeType, "class")) {
103 /* Patch base classes */
106 for (b = 0; b < 3; ++b) {
107 List *bases = Getattr(n, baselists[b]);
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);
121 Node *cn = firstChild(n);
123 cparse_template_expand(cn, tname, rname, templateargs, patchlist, typelist, cpatchlist);
124 cn = nextSibling(cn);
127 } else if (Equal(nodeType, "constructor")) {
128 String *name = Getattr(n, "name");
129 if (!(Getattr(n, "templatetype"))) {
131 String *stripped_name = SwigType_templateprefix(name);
132 if (Strstr(tname, stripped_name)) {
133 Replaceid(name, stripped_name, tname);
135 Delete(stripped_name);
136 symname = Getattr(n, "sym:name");
138 stripped_name = SwigType_templateprefix(symname);
139 if (Strstr(tname, stripped_name)) {
140 Replaceid(symname, stripped_name, tname);
142 Delete(stripped_name);
144 if (strchr(Char(name), '<')) {
145 Append(patchlist, Getattr(n, "name"));
147 Append(name, templateargs);
149 name = Getattr(n, "sym:name");
151 if (strchr(Char(name), '<')) {
155 String *tmp = Copy(name);
156 Replace(tmp, tname, rname, DOH_REPLACE_ANY);
162 /* Setattr(n,"sym:name",name); */
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");
171 if (strchr(Char(name), '<'))
172 Append(patchlist, Getattr(n, "name"));
174 Append(name, templateargs);
176 name = Getattr(n, "sym:name");
178 if (strchr(Char(name), '<')) {
179 String *sn = Copy(tname);
180 Setattr(n, "sym:name", sn);
183 Replace(name, tname, rname, DOH_REPLACE_ANY);
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);
193 if (Getattr(n, "namespace")) {
194 /* Namespace link. This is nasty. Is other namespace defined? */
198 /* Look for obvious parameters */
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);
209 cparse_template_expand(cn, tname, rname, templateargs, patchlist, typelist, cpatchlist);
210 cn = nextSibling(cn);
217 String *partial_arg(String *s, String *p) {
223 /* Find the prefix on the partial argument */
229 prefix = NewStringWithSize(cp, c - cp);
231 Replace(newarg, prefix, "", DOH_REPLACE_ANY | DOH_REPLACE_FIRST);
236 /* -----------------------------------------------------------------------------
237 * Swig_cparse_template_expand()
238 * ----------------------------------------------------------------------------- */
240 int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope) {
241 List *patchlist, *cpatchlist, *typelist;
242 String *templateargs;
246 patchlist = NewList();
247 cpatchlist = NewList();
248 typelist = NewList();
251 String *tmp = NewStringEmpty();
253 SwigType_add_template(tmp, tparms);
255 templateargs = Copy(tmp);
259 tname = Copy(Getattr(n, "name"));
260 tbase = Swig_scopename_last(tname);
262 /* Look for partial specialization matching */
263 if (Getattr(n, "partialargs")) {
265 ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"));
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);
281 tp = nextSibling(tp);
283 assert(ParmList_len(ptargs) == ParmList_len(tparms));
290 Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value"));
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);
302 String *name = Getattr(n, "name");
304 Append(name, templateargs);
309 /* Patch all of the types */
311 Parm *tp = Getattr(n, "templateparms");
313 /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */
316 Symtab *tsdecl = Getattr(n, "sym:symtab");
318 String *name, *value, *valuestr, *tydef, *tmp, *tmpr;
323 name = Getattr(tp, "name");
324 value = Getattr(p, "value");
325 tydef = Getattr(p, "typedef");
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);
339 valuestr = SwigType_str(dvalue, 0);
340 /* Need to patch default arguments */
342 Parm *rp = nextSibling(p);
344 String *rvalue = Getattr(rp, "value");
346 Replace(rvalue, name, dvalue, DOH_REPLACE_ID);
348 rp = nextSibling(rp);
352 for (i = 0; i < sz; i++) {
353 String *s = Getitem(patchlist, i);
354 Replace(s, name, dvalue, DOH_REPLACE_ID);
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); */
369 tmp = NewStringf("#%s", name);
370 tmpr = NewStringf("\"%s\"", valuestr);
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);
386 tp = nextSibling(tp);
391 /* No template parameters at all. This could be a specialization */
394 for (i = 0; i < sz; i++) {
395 String *s = Getitem(typelist, i);
396 SwigType_typename_replace(s, tbase, iname);
403 List *bases = Getattr(n, "baselist");
406 for (b = First(bases); b.item; b = Next(b)) {
407 String *qn = Swig_symbol_type_qualify(b.item, tscope);
419 Delete(templateargs);
421 /* set_nodeType(n,"template"); */
425 /* -----------------------------------------------------------------------------
428 * Search for a template that matches name with given parameters.
429 * ----------------------------------------------------------------------------- */
431 static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) {
433 String *tname, *rname = 0;
439 ParmList *expandedparms;
442 parms = CopyParmList(tparms);
444 /* Search for generic template */
445 templ = Swig_symbol_clookup(name, 0);
447 /* Add default values from generic template */
449 Symtab *tsdecl = Getattr(templ, "sym:symtab");
451 targs = Getattr(templ, "templateparms");
452 expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, tsdecl);
454 expandedparms = parms;
458 /* reduce the typedef */
461 SwigType *ty = Getattr(p, "type");
463 SwigType *nt = Swig_symbol_type_qualify(ty, tscope);
464 Setattr(p, "type", nt);
470 SwigType_add_template(tname, expandedparms);
472 if (template_debug) {
473 Printf(stdout, "\n%s:%d: template_debug: Searching for %s\n", cparse_file, cparse_line, tname);
476 /* Search for an exact specialization.
477 Example: template<> class name<int> { ... } */
479 if (template_debug) {
480 Printf(stdout, " searching: '%s' (exact specialization)\n", tname);
482 n = Swig_symbol_clookup_local(tname, 0);
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);
489 n = Swig_symbol_clookup_local(rname, 0);
495 String *nodeType = nodeType(n);
496 if (Equal(nodeType, "template"))
498 tn = Getattr(n, "template");
501 goto success; /* Previously wrapped by a template return that */
503 Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n));
506 return 0; /* Found a match, but it's not a template of any kind. */
510 /* Search for partial specialization.
511 Example: template<typename T> class name<T *> { ... } */
513 /* Generate reduced template name (stripped of extraneous pointers, etc.) */
515 rname = NewStringf("%s<(", name);
519 t = Getattr(p, "type");
521 t = Getattr(p, "value");
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);
540 mpartials = NewList();
542 /* First, we search using an exact type prototype */
550 partials = Getattr(templ, "partials");
552 for (pi = First(partials); pi.item; pi = Next(pi)) {
558 sprintf(tmp, "$%d", i);
559 t = Getattr(p, "type");
561 t = Getattr(p, "value");
563 String *ty = Swig_symbol_typedef_reduce(t, tscope);
564 tn = SwigType_base(ty);
565 Replaceid(ss, tmp, tn);
572 if (template_debug) {
573 Printf(stdout, " searching: '%s' (partial specialization - %s)\n", ss, pi.item);
575 if ((Equal(ss, tname)) || (Equal(ss, rname))) {
576 Append(mpartials, pi.item);
583 if (template_debug) {
584 Printf(stdout, " Matched partials: %s\n", mpartials);
587 if (Len(mpartials)) {
588 String *s = Getitem(mpartials, 0);
589 n = Swig_symbol_clookup_local(s, 0);
590 if (Len(mpartials) > 1) {
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")));
602 Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
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);
614 if ((template_debug) && (n)) {
615 Printf(stdout, "Node: %p\n", n);
623 /* -----------------------------------------------------------------------------
624 * Swig_cparse_template_locate()
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
630 * ----------------------------------------------------------------------------- */
632 Node *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 */
636 String *nodeType = nodeType(n);
638 assert(Equal(nodeType, "template"));
639 isclass = (Equal(Getattr(n, "templatetype"), "class"));
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. */
648 if (template_debug) {
649 Printf(stdout, " Not a templated class, seeking most appropriate templated function\n");
652 n = Swig_symbol_clookup_local(name, 0);
654 Parm *tparmsfound = Getattr(n, "templateparms");
655 if (ParmList_len(tparms) == ParmList_len(tparmsfound)) {
656 /* successful match */
659 /* repeat until we find a match with correct number of templated parameters */
660 n = Getattr(n, "sym:nextSibling");
664 Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
667 if ((template_debug) && (n)) {
668 Printf(stdout, "Templated function found: %p\n", n);