PageRenderTime 61ms CodeModel.GetById 11ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Source/CParse/templ.c

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