import source from 1.3.40
[external/swig.git] / Source / CParse / templ.c
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
10 char cvsroot_templ_c[] = "$Id: templ.c 11097 2009-01-30 10:27:37Z bhy $";
11
12 #include "swig.h"
13 #include "cparse.h"
14
15 static int template_debug = 0;
16
17
18 const char *baselists[3];
19
20 void SwigType_template_init() {
21   baselists[0] = "baselist";
22   baselists[1] = "protectedbaselist";
23   baselists[2] = "privatebaselist";
24 }
25
26
27 static 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
38 void 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
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;
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
216 static
217 String *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
240 int 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
431 static 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   }
610 success:
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
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 */
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 }