PageRenderTime 52ms CodeModel.GetById 12ms app.highlight 28ms RepoModel.GetById 3ms app.codeStats 0ms

/tags/rel-1-3-26/SWIG/Source/CParse/templ.c

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