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