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  * templ.c
10  *
11  * Expands a template into a specialized version.
12  * ----------------------------------------------------------------------------- */
13 
14 #include "swig.h"
15 #include "cparse.h"
16 
17 static int template_debug = 0;
18 
19 
20 const char *baselists[3];
21 
SwigType_template_init()22 void SwigType_template_init() {
23   baselists[0] = "baselist";
24   baselists[1] = "protectedbaselist";
25   baselists[2] = "privatebaselist";
26 }
27 
28 
add_parms(ParmList * p,List * patchlist,List * typelist,int is_pattern)29 static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_pattern) {
30   while (p) {
31     SwigType *ty = Getattr(p, "type");
32     SwigType *val = Getattr(p, "value");
33     Append(typelist, ty);
34     Append(typelist, val);
35     if (is_pattern) {
36       /* Typemap patterns are not simple parameter lists.
37        * Output style ("out", "ret" etc) typemap names can be
38        * qualified names and so may need template expansion */
39       SwigType *name = Getattr(p, "name");
40       Append(typelist, name);
41     }
42     Append(patchlist, val);
43     p = nextSibling(p);
44   }
45 }
46 
Swig_cparse_debug_templates(int x)47 void Swig_cparse_debug_templates(int x) {
48   template_debug = x;
49 }
50 
51 /* -----------------------------------------------------------------------------
52  * cparse_template_expand()
53  *
54  * Expands a template node into a specialized version.  This is done by
55  * patching typenames and other aspects of the node according to a list of
56  * template parameters
57  * ----------------------------------------------------------------------------- */
58 
cparse_template_expand(Node * templnode,Node * n,String * tname,String * rname,String * templateargs,List * patchlist,List * typelist,List * cpatchlist)59 static void cparse_template_expand(Node *templnode, Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) {
60   static int expanded = 0;
61   String *nodeType;
62   if (!n)
63     return;
64   nodeType = nodeType(n);
65   if (Getattr(n, "error"))
66     return;
67 
68   if (Equal(nodeType, "template")) {
69     /* Change the node type back to normal */
70     if (!expanded) {
71       expanded = 1;
72       set_nodeType(n, Getattr(n, "templatetype"));
73       cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist);
74       expanded = 0;
75       return;
76     } else {
77       /* Called when template appears inside another template */
78       /* Member templates */
79 
80       set_nodeType(n, Getattr(n, "templatetype"));
81       cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist);
82       set_nodeType(n, "template");
83       return;
84     }
85   } else if (Equal(nodeType, "cdecl")) {
86     /* A simple C declaration */
87     SwigType *t, *v, *d;
88     String *code;
89     t = Getattr(n, "type");
90     v = Getattr(n, "value");
91     d = Getattr(n, "decl");
92 
93     code = Getattr(n, "code");
94 
95     Append(typelist, t);
96     Append(typelist, d);
97     Append(patchlist, v);
98     Append(cpatchlist, code);
99 
100     if (Getattr(n, "conversion_operator")) {
101       Append(cpatchlist, Getattr(n, "name"));
102       if (Getattr(n, "sym:name")) {
103 	Append(cpatchlist, Getattr(n, "sym:name"));
104       }
105     }
106     if (checkAttribute(n, "storage", "friend")) {
107       String *symname = Getattr(n, "sym:name");
108       if (symname) {
109 	String *stripped_name = SwigType_templateprefix(symname);
110 	Setattr(n, "sym:name", stripped_name);
111 	Delete(stripped_name);
112       }
113       Append(typelist, Getattr(n, "name"));
114     }
115 
116     add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0);
117     add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0);
118 
119   } else if (Equal(nodeType, "class")) {
120     /* Patch base classes */
121     {
122       int b = 0;
123       for (b = 0; b < 3; ++b) {
124 	List *bases = Getattr(n, baselists[b]);
125 	if (bases) {
126 	  int i;
127 	  int ilen = Len(bases);
128 	  for (i = 0; i < ilen; i++) {
129 	    String *name = Copy(Getitem(bases, i));
130 	    Setitem(bases, i, name);
131 	    Append(typelist, name);
132 	  }
133 	}
134       }
135     }
136     /* Patch children */
137     {
138       Node *cn = firstChild(n);
139       while (cn) {
140 	cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist);
141 	cn = nextSibling(cn);
142       }
143     }
144   } else if (Equal(nodeType, "constructor")) {
145     String *name = Getattr(n, "name");
146     if (!(Getattr(n, "templatetype"))) {
147       String *symname;
148       String *stripped_name = SwigType_templateprefix(name);
149       if (Strstr(tname, stripped_name)) {
150 	Replaceid(name, stripped_name, tname);
151       }
152       Delete(stripped_name);
153       symname = Getattr(n, "sym:name");
154       if (symname) {
155 	stripped_name = SwigType_templateprefix(symname);
156 	if (Strstr(tname, stripped_name)) {
157 	  Replaceid(symname, stripped_name, tname);
158 	}
159 	Delete(stripped_name);
160       }
161       if (strchr(Char(name), '<')) {
162 	Append(patchlist, Getattr(n, "name"));
163       } else {
164 	Append(name, templateargs);
165       }
166       name = Getattr(n, "sym:name");
167       if (name) {
168 	if (strchr(Char(name), '<')) {
169 	  Clear(name);
170 	  Append(name, rname);
171 	} else {
172 	  String *tmp = Copy(name);
173 	  Replace(tmp, tname, rname, DOH_REPLACE_ANY);
174 	  Clear(name);
175 	  Append(name, tmp);
176 	  Delete(tmp);
177 	}
178       }
179       /* Setattr(n,"sym:name",name); */
180     }
181     Append(cpatchlist, Getattr(n, "code"));
182     Append(typelist, Getattr(n, "decl"));
183     add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0);
184     add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0);
185   } else if (Equal(nodeType, "destructor")) {
186     /* We only need to patch the dtor of the template itself, not the destructors of any nested classes, so check that the parent of this node is the root
187      * template node, with the special exception for %extend which adds its methods under an intermediate node. */
188     Node* parent = parentNode(n);
189     if (parent == templnode || (parentNode(parent) == templnode && Equal(nodeType(parent), "extend"))) {
190       String *name = Getattr(n, "name");
191       if (name) {
192 	if (strchr(Char(name), '<'))
193 	  Append(patchlist, Getattr(n, "name"));
194 	else
195 	  Append(name, templateargs);
196       }
197       name = Getattr(n, "sym:name");
198       if (name) {
199 	if (strchr(Char(name), '<')) {
200 	  String *sn = Copy(tname);
201 	  Setattr(n, "sym:name", sn);
202 	  Delete(sn);
203 	} else {
204 	  Replace(name, tname, rname, DOH_REPLACE_ANY);
205 	}
206       }
207       /* Setattr(n,"sym:name",name); */
208       Append(cpatchlist, Getattr(n, "code"));
209     }
210   } else if (Equal(nodeType, "using")) {
211     String *uname = Getattr(n, "uname");
212     if (uname && strchr(Char(uname), '<')) {
213       Append(patchlist, uname);
214     }
215     if (Getattr(n, "namespace")) {
216       /* Namespace link.   This is nasty.  Is other namespace defined? */
217 
218     }
219   } else {
220     /* Look for obvious parameters */
221     Node *cn;
222     Append(cpatchlist, Getattr(n, "code"));
223     Append(typelist, Getattr(n, "type"));
224     Append(typelist, Getattr(n, "decl"));
225     add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0);
226     add_parms(Getattr(n, "kwargs"), cpatchlist, typelist, 0);
227     add_parms(Getattr(n, "pattern"), cpatchlist, typelist, 1);
228     add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0);
229     cn = firstChild(n);
230     while (cn) {
231       cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist);
232       cn = nextSibling(cn);
233     }
234   }
235 }
236 
237 static
partial_arg(String * s,String * p)238 String *partial_arg(String *s, String *p) {
239   char *c;
240   char *cp = Char(p);
241   String *prefix;
242   String *newarg;
243 
244   /* Find the prefix on the partial argument */
245 
246   c = strchr(cp, '$');
247   if (!c) {
248     return Copy(s);
249   }
250   prefix = NewStringWithSize(cp, (int)(c - cp));
251   newarg = Copy(s);
252   Replace(newarg, prefix, "", DOH_REPLACE_ANY | DOH_REPLACE_FIRST);
253   Delete(prefix);
254   return newarg;
255 }
256 
257 /* -----------------------------------------------------------------------------
258  * Swig_cparse_template_expand()
259  * ----------------------------------------------------------------------------- */
260 
Swig_cparse_template_expand(Node * n,String * rname,ParmList * tparms,Symtab * tscope)261 int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope) {
262   List *patchlist, *cpatchlist, *typelist;
263   String *templateargs;
264   String *tname;
265   String *iname;
266   String *tbase;
267   patchlist = NewList();
268   cpatchlist = NewList();
269   typelist = NewList();
270 
271   {
272     String *tmp = NewStringEmpty();
273     if (tparms) {
274       SwigType_add_template(tmp, tparms);
275     }
276     templateargs = Copy(tmp);
277     Delete(tmp);
278   }
279 
280   tname = Copy(Getattr(n, "name"));
281   tbase = Swig_scopename_last(tname);
282 
283   /* Look for partial specialization matching */
284   if (Getattr(n, "partialargs")) {
285     Parm *p, *tp;
286     ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"), n);
287     p = ptargs;
288     tp = tparms;
289     while (p && tp) {
290       SwigType *ptype;
291       SwigType *tptype;
292       SwigType *partial_type;
293       ptype = Getattr(p, "type");
294       tptype = Getattr(tp, "type");
295       if (ptype && tptype) {
296 	partial_type = partial_arg(tptype, ptype);
297 	/*      Printf(stdout,"partial '%s' '%s'  ---> '%s'\n", tptype, ptype, partial_type); */
298 	Setattr(tp, "type", partial_type);
299 	Delete(partial_type);
300       }
301       p = nextSibling(p);
302       tp = nextSibling(tp);
303     }
304     assert(ParmList_len(ptargs) == ParmList_len(tparms));
305     Delete(ptargs);
306   }
307 
308   /*
309     Parm *p = tparms;
310     while (p) {
311       Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value"));
312       p = nextSibling(p);
313     }
314   */
315 
316   /*  Printf(stdout,"targs = '%s'\n", templateargs);
317      Printf(stdout,"rname = '%s'\n", rname);
318      Printf(stdout,"tname = '%s'\n", tname);  */
319   cparse_template_expand(n, n, tname, rname, templateargs, patchlist, typelist, cpatchlist);
320 
321   /* Set the name */
322   {
323     String *name = Getattr(n, "name");
324     if (name) {
325       Append(name, templateargs);
326     }
327     iname = name;
328   }
329 
330   /* Patch all of the types */
331   {
332     Parm *tp = Getattr(n, "templateparms");
333     Parm *p = tparms;
334     /*    Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */
335 
336     if (tp) {
337       Symtab *tsdecl = Getattr(n, "sym:symtab");
338       while (p && tp) {
339 	String *name, *value, *valuestr, *tmp, *tmpr;
340 	int sz, i;
341 	String *dvalue = 0;
342 	String *qvalue = 0;
343 
344 	name = Getattr(tp, "name");
345 	value = Getattr(p, "value");
346 
347 	if (name) {
348 	  if (!value)
349 	    value = Getattr(p, "type");
350 	  qvalue = Swig_symbol_typedef_reduce(value, tsdecl);
351 	  dvalue = Swig_symbol_type_qualify(qvalue, tsdecl);
352 	  if (SwigType_istemplate(dvalue)) {
353 	    String *ty = Swig_symbol_template_deftype(dvalue, tscope);
354 	    Delete(dvalue);
355 	    dvalue = ty;
356 	  }
357 
358 	  assert(dvalue);
359 	  valuestr = SwigType_str(dvalue, 0);
360 	  /* Need to patch default arguments */
361 	  {
362 	    Parm *rp = nextSibling(p);
363 	    while (rp) {
364 	      String *rvalue = Getattr(rp, "value");
365 	      if (rvalue) {
366 		Replace(rvalue, name, dvalue, DOH_REPLACE_ID);
367 	      }
368 	      rp = nextSibling(rp);
369 	    }
370 	  }
371 	  sz = Len(patchlist);
372 	  for (i = 0; i < sz; i++) {
373 	    String *s = Getitem(patchlist, i);
374 	    Replace(s, name, dvalue, DOH_REPLACE_ID);
375 	  }
376 	  sz = Len(typelist);
377 	  for (i = 0; i < sz; i++) {
378 	    String *s = Getitem(typelist, i);
379 	    /*      Replace(s,name,value, DOH_REPLACE_ID); */
380 	    /*      Printf(stdout,"name = '%s', value = '%s', tbase = '%s', iname='%s' s = '%s' --> ", name, dvalue, tbase, iname, s); */
381 	    SwigType_typename_replace(s, name, dvalue);
382 	    SwigType_typename_replace(s, tbase, iname);
383 	    /*      Printf(stdout,"'%s'\n", s); */
384 	  }
385 
386 	  tmp = NewStringf("#%s", name);
387 	  tmpr = NewStringf("\"%s\"", valuestr);
388 
389 	  sz = Len(cpatchlist);
390 	  for (i = 0; i < sz; i++) {
391 	    String *s = Getitem(cpatchlist, i);
392 	    Replace(s, tmp, tmpr, DOH_REPLACE_ID);
393 	    Replace(s, name, valuestr, DOH_REPLACE_ID);
394 	  }
395 	  Delete(tmp);
396 	  Delete(tmpr);
397 	  Delete(valuestr);
398 	  Delete(dvalue);
399 	  Delete(qvalue);
400 	}
401 	p = nextSibling(p);
402 	tp = nextSibling(tp);
403 	if (!p)
404 	  p = tp;
405       }
406     } else {
407       /* No template parameters at all.  This could be a specialization */
408       int i, sz;
409       sz = Len(typelist);
410       for (i = 0; i < sz; i++) {
411 	String *s = Getitem(typelist, i);
412 	SwigType_typename_replace(s, tbase, iname);
413       }
414     }
415   }
416 
417   /* Patch bases */
418   {
419     List *bases = Getattr(n, "baselist");
420     if (bases) {
421       Iterator b;
422       for (b = First(bases); b.item; b = Next(b)) {
423 	String *qn = Swig_symbol_type_qualify(b.item, tscope);
424 	Clear(b.item);
425 	Append(b.item, qn);
426 	Delete(qn);
427       }
428     }
429   }
430   Delete(patchlist);
431   Delete(cpatchlist);
432   Delete(typelist);
433   Delete(tbase);
434   Delete(tname);
435   Delete(templateargs);
436 
437   /*  set_nodeType(n,"template"); */
438   return 0;
439 }
440 
441 typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpecializedMatch = 1, ExactMatch = 2 } EMatch;
442 
443 /* -----------------------------------------------------------------------------
444  * does_parm_match()
445  *
446  * Template argument deduction - check if a template type matches a partially specialized
447  * template parameter type. Typedef reduce 'partial_parm_type' to see if it matches 'type'.
448  *
449  * type - template parameter type to match against
450  * partial_parm_type - partially specialized template type - a possible match
451  * partial_parm_type_base - base type of partial_parm_type
452  * tscope - template scope
453  * specialization_priority - (output) contains a value indicating how good the match is
454  *   (higher is better) only set if return is set to PartiallySpecializedMatch or ExactMatch.
455  * ----------------------------------------------------------------------------- */
456 
does_parm_match(SwigType * type,SwigType * partial_parm_type,const char * partial_parm_type_base,Symtab * tscope,int * specialization_priority)457 static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const char *partial_parm_type_base, Symtab *tscope, int *specialization_priority) {
458   static const int EXACT_MATCH_PRIORITY = 99999; /* a number bigger than the length of any conceivable type */
459   int matches;
460   int substitutions;
461   EMatch match;
462   SwigType *ty = Swig_symbol_typedef_reduce(type, tscope);
463   String *base = SwigType_base(ty);
464   SwigType *t = Copy(partial_parm_type);
465   substitutions = Replaceid(t, partial_parm_type_base, base); /* eg: Replaceid("p.$1", "$1", "int") returns t="p.int" */
466   matches = Equal(ty, t);
467   *specialization_priority = -1;
468   if (substitutions == 1) {
469     /* we have a non-explicit specialized parameter (in partial_parm_type) because a substitution for $1, $2... etc has taken place */
470     SwigType *tt = Copy(partial_parm_type);
471     int len;
472     /*
473        check for match to partial specialization type, for example, all of the following could match the type in the %template:
474        template <typename T> struct XX {};
475        template <typename T> struct XX<T &> {};         // r.$1
476        template <typename T> struct XX<T const&> {};    // r.q(const).$1
477        template <typename T> struct XX<T *const&> {};   // r.q(const).p.$1
478        %template(XXX) XX<int *const&>;                  // r.q(const).p.int
479 
480        where type="r.q(const).p.int" will match either of tt="r.", tt="r.q(const)" tt="r.q(const).p"
481     */
482     Replaceid(tt, partial_parm_type_base, ""); /* remove the $1, $2 etc, eg tt="p.$1" => "p." */
483     len = Len(tt);
484     if (Strncmp(tt, ty, len) == 0) {
485       match = PartiallySpecializedMatch;
486       *specialization_priority = len;
487     } else {
488       match = PartiallySpecializedNoMatch;
489     }
490     Delete(tt);
491   } else {
492     match = matches ? ExactMatch : ExactNoMatch;
493     if (matches)
494       *specialization_priority = EXACT_MATCH_PRIORITY; /* exact matches always take precedence */
495   }
496   /*
497   Printf(stdout, "      does_parm_match %2d %5d [%s] [%s]\n", match, *specialization_priority, type, partial_parm_type);
498   */
499   Delete(t);
500   Delete(base);
501   Delete(ty);
502   return match;
503 }
504 
505 /* -----------------------------------------------------------------------------
506  * template_locate()
507  *
508  * Search for a template that matches name with given parameters.
509  * ----------------------------------------------------------------------------- */
510 
template_locate(String * name,Parm * tparms,Symtab * tscope)511 static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) {
512   Node *n = 0;
513   String *tname = 0;
514   Node *templ;
515   Symtab *primary_scope = 0;
516   List *possiblepartials = 0;
517   Parm *p;
518   Parm *parms = 0;
519   Parm *targs;
520   ParmList *expandedparms;
521   int *priorities_matrix = 0;
522   int max_possible_partials = 0;
523   int posslen = 0;
524 
525   /* Search for primary (unspecialized) template */
526   templ = Swig_symbol_clookup(name, 0);
527 
528   if (template_debug) {
529     tname = Copy(name);
530     SwigType_add_template(tname, tparms);
531     Printf(stdout, "\n");
532     Swig_diagnostic(cparse_file, cparse_line, "template_debug: Searching for match to: '%s'\n", tname);
533     Delete(tname);
534     tname = 0;
535   }
536 
537   if (templ) {
538     tname = Copy(name);
539     parms = CopyParmList(tparms);
540 
541     /* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */
542     primary_scope = Getattr(templ, "sym:symtab");
543 
544     /* Add default values from primary template */
545     targs = Getattr(templ, "templateparms");
546     expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, primary_scope);
547 
548     /* reduce the typedef */
549     p = expandedparms;
550     while (p) {
551       SwigType *ty = Getattr(p, "type");
552       if (ty) {
553 	SwigType *nt = Swig_symbol_type_qualify(ty, tscope);
554 	Setattr(p, "type", nt);
555 	Delete(nt);
556       }
557       p = nextSibling(p);
558     }
559     SwigType_add_template(tname, expandedparms);
560 
561     /* Search for an explicit (exact) specialization. Example: template<> class name<int> { ... } */
562     {
563       if (template_debug) {
564 	Printf(stdout, "    searching for : '%s' (explicit specialization)\n", tname);
565       }
566       n = Swig_symbol_clookup_local(tname, primary_scope);
567       if (!n) {
568 	SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope);
569 	if (!Equal(rname, tname)) {
570 	  if (template_debug) {
571 	    Printf(stdout, "    searching for : '%s' (explicit specialization with typedef reduction)\n", rname);
572 	  }
573 	  n = Swig_symbol_clookup_local(rname, primary_scope);
574 	}
575 	Delete(rname);
576       }
577       if (n) {
578 	Node *tn;
579 	String *nodeType = nodeType(n);
580 	if (Equal(nodeType, "template")) {
581 	  if (template_debug) {
582 	    Printf(stdout, "    explicit specialization found: '%s'\n", Getattr(n, "name"));
583 	  }
584 	  goto success;
585 	}
586 	tn = Getattr(n, "template");
587 	if (tn) {
588 	  if (template_debug) {
589 	    Printf(stdout, "    previous instantiation found: '%s'\n", Getattr(n, "name"));
590 	  }
591 	  n = tn;
592 	  goto success;	  /* Previously wrapped by a template instantiation */
593 	}
594 	Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n));
595 	Delete(tname);
596 	Delete(parms);
597 	return 0;	  /* Found a match, but it's not a template of any kind. */
598       }
599     }
600 
601     /* Search for partial specializations.
602      * Example: template<typename T> class name<T *> { ... }
603 
604      * There are 3 types of template arguments:
605      * (1) Template type arguments
606      * (2) Template non type arguments
607      * (3) Template template arguments
608      * only (1) is really supported for partial specializations
609      */
610 
611     /* Rank each template parameter against the desired template parameters then build a matrix of best matches */
612     possiblepartials = NewList();
613     {
614       char tmp[32];
615       List *partials;
616 
617       partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */
618       if (partials) {
619 	Iterator pi;
620 	int parms_len = ParmList_len(parms);
621 	int *priorities_row;
622 	max_possible_partials = Len(partials);
623 	priorities_matrix = (int *)malloc(sizeof(int) * max_possible_partials * parms_len); /* slightly wasteful allocation for max possible matches */
624 	priorities_row = priorities_matrix;
625 	for (pi = First(partials); pi.item; pi = Next(pi)) {
626 	  Parm *p = parms;
627 	  int all_parameters_match = 1;
628 	  int i = 1;
629 	  Parm *partialparms = Getattr(pi.item, "partialparms");
630 	  Parm *pp = partialparms;
631 	  String *templcsymname = Getattr(pi.item, "templcsymname");
632 	  if (template_debug) {
633 	    Printf(stdout, "    checking match: '%s' (partial specialization)\n", templcsymname);
634 	  }
635 	  if (ParmList_len(partialparms) == parms_len) {
636 	    while (p && pp) {
637 	      SwigType *t;
638 	      sprintf(tmp, "$%d", i);
639 	      t = Getattr(p, "type");
640 	      if (!t)
641 		t = Getattr(p, "value");
642 	      if (t) {
643 		EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1);
644 		if (match < (int)PartiallySpecializedMatch) {
645 		  all_parameters_match = 0;
646 		  break;
647 		}
648 	      }
649 	      i++;
650 	      p = nextSibling(p);
651 	      pp = nextSibling(pp);
652 	    }
653 	    if (all_parameters_match) {
654 	      Append(possiblepartials, pi.item);
655 	      priorities_row += parms_len;
656 	    }
657 	  }
658 	}
659       }
660     }
661 
662     posslen = Len(possiblepartials);
663     if (template_debug) {
664       int i;
665       if (posslen == 0)
666 	Printf(stdout, "    matched partials: NONE\n");
667       else if (posslen == 1)
668 	Printf(stdout, "    chosen partial: '%s'\n", Getattr(Getitem(possiblepartials, 0), "templcsymname"));
669       else {
670 	Printf(stdout, "    possibly matched partials:\n");
671 	for (i = 0; i < posslen; i++) {
672 	  Printf(stdout, "      '%s'\n", Getattr(Getitem(possiblepartials, i), "templcsymname"));
673 	}
674       }
675     }
676 
677     if (posslen > 1) {
678       /* Now go through all the possibly matched partial specialization templates and look for a non-ambiguous match.
679        * Exact matches rank the highest and deduced parameters are ranked by how specialized they are, eg looking for
680        * a match to const int *, the following rank (highest to lowest):
681        *   const int * (exact match)
682        *   const T *
683        *   T *
684        *   T
685        *
686        *   An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>;
687        *   template<typename T1, typename T2> X class {};  // primary template
688        *   template<typename T1> X<T1, double *> class {}; // specialization (1)
689        *   template<typename T2> X<int *, T2> class {};    // specialization (2)
690        */
691       if (template_debug) {
692 	int row, col;
693 	int parms_len = ParmList_len(parms);
694 	Printf(stdout, "      parameter priorities matrix (%d parms):\n", parms_len);
695 	for (row = 0; row < posslen; row++) {
696 	  int *priorities_row = priorities_matrix + row*parms_len;
697 	  Printf(stdout, "        ");
698 	  for (col = 0; col < parms_len; col++) {
699 	    Printf(stdout, "%5d ", priorities_row[col]);
700 	  }
701 	  Printf(stdout, "\n");
702 	}
703       }
704       {
705 	int row, col;
706 	int parms_len = ParmList_len(parms);
707 	/* Printf(stdout, "      parameter priorities inverse matrix (%d parms):\n", parms_len); */
708 	for (col = 0; col < parms_len; col++) {
709 	  int *priorities_col = priorities_matrix + col;
710 	  int maxpriority = -1;
711 	  /*
712 	     Printf(stdout, "max_possible_partials: %d col:%d\n", max_possible_partials, col);
713 	     Printf(stdout, "        ");
714 	     */
715 	  /* determine the highest rank for this nth parameter */
716 	  for (row = 0; row < posslen; row++) {
717 	    int *element_ptr = priorities_col + row*parms_len;
718 	    int priority = *element_ptr;
719 	    if (priority > maxpriority)
720 	      maxpriority = priority;
721 	    /* Printf(stdout, "%5d ", priority); */
722 	  }
723 	  /* Printf(stdout, "\n"); */
724 	  /* flag all the parameters which equal the highest rank */
725 	  for (row = 0; row < posslen; row++) {
726 	    int *element_ptr = priorities_col + row*parms_len;
727 	    int priority = *element_ptr;
728 	    *element_ptr = (priority >= maxpriority) ? 1 : 0;
729 	  }
730 	}
731       }
732       {
733 	int row, col;
734 	int parms_len = ParmList_len(parms);
735 	Iterator pi = First(possiblepartials);
736 	Node *chosenpartials = NewList();
737 	if (template_debug)
738 	  Printf(stdout, "      priority flags matrix:\n");
739 	for (row = 0; row < posslen; row++) {
740 	  int *priorities_row = priorities_matrix + row*parms_len;
741 	  int highest_count = 0; /* count of highest priority parameters */
742 	  for (col = 0; col < parms_len; col++) {
743 	    highest_count += priorities_row[col];
744 	  }
745 	  if (template_debug) {
746 	    Printf(stdout, "        ");
747 	    for (col = 0; col < parms_len; col++) {
748 	      Printf(stdout, "%5d ", priorities_row[col]);
749 	    }
750 	    Printf(stdout, "\n");
751 	  }
752 	  if (highest_count == parms_len) {
753 	    Append(chosenpartials, pi.item);
754 	  }
755 	  pi = Next(pi);
756 	}
757 	if (Len(chosenpartials) > 0) {
758 	  /* one or more best match found */
759 	  Delete(possiblepartials);
760 	  possiblepartials = chosenpartials;
761 	  posslen = Len(possiblepartials);
762 	} else {
763 	  /* no best match found */
764 	  Delete(chosenpartials);
765 	}
766       }
767     }
768 
769     if (posslen > 0) {
770       String *s = Getattr(Getitem(possiblepartials, 0), "templcsymname");
771       n = Swig_symbol_clookup_local(s, primary_scope);
772       if (posslen > 1) {
773 	int i;
774 	if (n) {
775 	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname));
776 	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), "  instantiation '%s' used,\n", SwigType_namestr(Getattr(n, "name")));
777 	}
778 	for (i = 1; i < posslen; i++) {
779 	  String *templcsymname = Getattr(Getitem(possiblepartials, i), "templcsymname");
780 	  Node *ignored_node = Swig_symbol_clookup_local(templcsymname, primary_scope);
781 	  assert(ignored_node);
782 	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(ignored_node), Getline(ignored_node), "  instantiation '%s' ignored.\n", SwigType_namestr(Getattr(ignored_node, "name")));
783 	}
784       }
785     }
786 
787     if (!n) {
788       if (template_debug) {
789 	Printf(stdout, "    chosen primary template: '%s'\n", Getattr(templ, "name"));
790       }
791       n = templ;
792     }
793   } else {
794     if (template_debug) {
795       Printf(stdout, "    primary template not found\n");
796     }
797     /* Give up if primary (unspecialized) template not found as specializations will only exist if there is a primary template */
798     n = 0;
799   }
800 
801   if (!n) {
802     Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
803   } else if (n) {
804     String *nodeType = nodeType(n);
805     if (!Equal(nodeType, "template")) {
806       Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType);
807       n = 0;
808     }
809   }
810 success:
811   Delete(tname);
812   Delete(possiblepartials);
813   if ((template_debug) && (n)) {
814     /*
815     Printf(stdout, "Node: %p\n", n);
816     Swig_print_node(n);
817     */
818     Printf(stdout, "    chosen template:'%s'\n", Getattr(n, "name"));
819   }
820   Delete(parms);
821   free(priorities_matrix);
822   return n;
823 }
824 
825 
826 /* -----------------------------------------------------------------------------
827  * Swig_cparse_template_locate()
828  *
829  * Search for a template that matches name with given parameters.
830  * For templated classes finds the specialized template should there be one.
831  * For templated functions finds the unspecialized template even if a specialized
832  * template exists.
833  * ----------------------------------------------------------------------------- */
834 
Swig_cparse_template_locate(String * name,Parm * tparms,Symtab * tscope)835 Node *Swig_cparse_template_locate(String *name, Parm *tparms, Symtab *tscope) {
836   Node *n = template_locate(name, tparms, tscope);	/* this function does what we want for templated classes */
837 
838   if (n) {
839     String *nodeType = nodeType(n);
840     int isclass = 0;
841     assert(Equal(nodeType, "template"));
842     isclass = (Equal(Getattr(n, "templatetype"), "class"));
843     if (!isclass) {
844       /* If not a templated class we must have a templated function.
845          The template found is not necessarily the one we want when dealing with templated
846          functions. We don't want any specialized templated functions as they won't have
847          the default parameters. Let's look for the unspecialized template. Also make sure
848          the number of template parameters is correct as it is possible to overload a
849          templated function with different numbers of template parameters. */
850 
851       if (template_debug) {
852 	Printf(stdout, "    Not a templated class, seeking most appropriate templated function\n");
853       }
854 
855       n = Swig_symbol_clookup_local(name, 0);
856       while (n) {
857 	Parm *tparmsfound = Getattr(n, "templateparms");
858 	if (ParmList_len(tparms) == ParmList_len(tparmsfound)) {
859 	  /* successful match */
860 	  break;
861 	}
862 	/* repeat until we find a match with correct number of templated parameters */
863 	n = Getattr(n, "sym:nextSibling");
864       }
865 
866       if (!n) {
867 	Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
868       }
869 
870       if ((template_debug) && (n)) {
871 	Printf(stdout, "Templated function found: %p\n", n);
872 	Swig_print_node(n);
873       }
874     }
875   }
876 
877   return n;
878 }
879