int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope) { List *patchlist, *cpatchlist, *typelist; String *templateargs; String *tname; String *iname; String *tbase; patchlist = NewList(); cpatchlist = NewList(); typelist = NewList(); { String *tmp = NewStringEmpty(); if (tparms) { SwigType_add_template(tmp, tparms); } templateargs = Copy(tmp); Delete(tmp); } tname = Copy(Getattr(n, "name")); tbase = Swig_scopename_last(tname); /* Look for partial specialization matching */ if (Getattr(n, "partialargs")) { Parm *p, *tp; ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs")); p = ptargs; tp = tparms; while (p && tp) { SwigType *ptype; SwigType *tptype; SwigType *partial_type; ptype = Getattr(p, "type"); tptype = Getattr(tp, "type"); if (ptype && tptype) { partial_type = partial_arg(tptype, ptype); /* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */ Setattr(tp, "type", partial_type); Delete(partial_type); } p = nextSibling(p); tp = nextSibling(tp); } assert(ParmList_len(ptargs) == ParmList_len(tparms)); Delete(ptargs); } /* Parm *p = tparms; while (p) { Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value")); p = nextSibling(p); } */ /* Printf(stdout,"targs = '%s'\n", templateargs); Printf(stdout,"rname = '%s'\n", rname); Printf(stdout,"tname = '%s'\n", tname); */ cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); /* Set the name */ { String *name = Getattr(n, "name"); if (name) { Append(name, templateargs); } iname = name; } /* Patch all of the types */ { Parm *tp = Getattr(n, "templateparms"); Parm *p = tparms; /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ if (tp) { Symtab *tsdecl = Getattr(n, "sym:symtab"); while (p && tp) { String *name, *value, *valuestr, *tydef, *tmp, *tmpr; int sz, i; String *dvalue = 0; String *qvalue = 0; name = Getattr(tp, "name"); value = Getattr(p, "value"); tydef = Getattr(p, "typedef"); if (name) { if (!value) value = Getattr(p, "type"); qvalue = Swig_symbol_typedef_reduce(value, tsdecl); dvalue = Swig_symbol_type_qualify(qvalue, tsdecl); if (SwigType_istemplate(dvalue)) { String *ty = Swig_symbol_template_deftype(dvalue, tscope); Delete(dvalue); dvalue = ty; } assert(dvalue); valuestr = SwigType_str(dvalue, 0); /* Need to patch default arguments */ { Parm *rp = nextSibling(p); while (rp) { String *rvalue = Getattr(rp, "value"); if (rvalue) { Replace(rvalue, name, dvalue, DOH_REPLACE_ID); } rp = nextSibling(rp); } } sz = Len(patchlist); for (i = 0; i < sz; i++) { String *s = Getitem(patchlist, i); Replace(s, name, dvalue, DOH_REPLACE_ID); } sz = Len(typelist); for (i = 0; i < sz; i++) { String *s = Getitem(typelist, i); /* Replace(s,name,value, DOH_REPLACE_ID); */ /* Printf(stdout,"name = '%s', value = '%s', tbase = '%s', iname='%s' s = '%s' --> ", name, dvalue, tbase, iname, s); */ SwigType_typename_replace(s, name, dvalue); SwigType_typename_replace(s, tbase, iname); /* Printf(stdout,"'%s'\n", s); */ } if (!tydef) { tydef = dvalue; } tmp = NewStringf("#%s", name); tmpr = NewStringf("\"%s\"", valuestr); sz = Len(cpatchlist); for (i = 0; i < sz; i++) { String *s = Getitem(cpatchlist, i); Replace(s, tmp, tmpr, DOH_REPLACE_ID); /* Replace(s,name,tydef, DOH_REPLACE_ID); */ Replace(s, name, valuestr, DOH_REPLACE_ID); } Delete(tmp); Delete(tmpr); Delete(valuestr); Delete(dvalue); Delete(qvalue); } p = nextSibling(p); tp = nextSibling(tp); if (!p) p = tp; } } else { /* No template parameters at all. This could be a specialization */ int i, sz; sz = Len(typelist); for (i = 0; i < sz; i++) { String *s = Getitem(typelist, i); SwigType_typename_replace(s, tbase, iname); } } } /* Patch bases */ { List *bases = Getattr(n, "baselist"); if (bases) { Iterator b; for (b = First(bases); b.item; b = Next(b)) { String *qn = Swig_symbol_type_qualify(b.item, tscope); Clear(b.item); Append(b.item, qn); Delete(qn); } } } Delete(patchlist); Delete(cpatchlist); Delete(typelist); Delete(tbase); Delete(tname); Delete(templateargs); /* set_nodeType(n,"template"); */ return 0; }
static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { Node *n; String *tname, *rname = 0; Node *templ; List *mpartials = 0; Parm *p; Parm *parms; Parm *targs; ParmList *expandedparms; tname = Copy(name); parms = CopyParmList(tparms); /* Search for generic template */ templ = Swig_symbol_clookup(name, 0); /* Add default values from generic template */ if (templ) { Symtab *tsdecl = Getattr(templ, "sym:symtab"); targs = Getattr(templ, "templateparms"); expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, tsdecl); } else { expandedparms = parms; } /* reduce the typedef */ p = expandedparms; while (p) { SwigType *ty = Getattr(p, "type"); if (ty) { SwigType *nt = Swig_symbol_type_qualify(ty, tscope); Setattr(p, "type", nt); Delete(nt); } p = nextSibling(p); } SwigType_add_template(tname, expandedparms); if (template_debug) { Printf(stdout, "\n%s:%d: template_debug: Searching for %s\n", cparse_file, cparse_line, tname); } /* Search for an exact specialization. Example: template<> class name<int> { ... } */ { if (template_debug) { Printf(stdout, " searching: '%s' (exact specialization)\n", tname); } n = Swig_symbol_clookup_local(tname, 0); if (!n) { SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope); if (!Equal(rname, tname)) { if (template_debug) { Printf(stdout, " searching: '%s' (exact specialization)\n", rname); } n = Swig_symbol_clookup_local(rname, 0); } Delete(rname); } if (n) { Node *tn; String *nodeType = nodeType(n); if (Equal(nodeType, "template")) goto success; tn = Getattr(n, "template"); if (tn) { n = tn; goto success; /* Previously wrapped by a template return that */ } Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n)); Delete(tname); Delete(parms); return 0; /* Found a match, but it's not a template of any kind. */ } } /* Search for partial specialization. Example: template<typename T> class name<T *> { ... } */ /* Generate reduced template name (stripped of extraneous pointers, etc.) */ rname = NewStringf("%s<(", name); p = parms; while (p) { String *t; t = Getattr(p, "type"); if (!t) t = Getattr(p, "value"); if (t) { String *ty = Swig_symbol_typedef_reduce(t, tscope); String *tb = SwigType_base(ty); String *td = SwigType_default(ty); Replaceid(td, "enum SWIGTYPE", tb); Replaceid(td, "SWIGTYPE", tb); Append(rname, td); Delete(tb); Delete(ty); Delete(td); } p = nextSibling(p); if (p) { Append(rname, ","); } } Append(rname, ")>"); mpartials = NewList(); if (templ) { /* First, we search using an exact type prototype */ Parm *p; char tmp[32]; int i; List *partials; String *ss; Iterator pi; partials = Getattr(templ, "partials"); if (partials) { for (pi = First(partials); pi.item; pi = Next(pi)) { ss = Copy(pi.item); p = parms; i = 1; while (p) { String *t, *tn; sprintf(tmp, "$%d", i); t = Getattr(p, "type"); if (!t) t = Getattr(p, "value"); if (t) { String *ty = Swig_symbol_typedef_reduce(t, tscope); tn = SwigType_base(ty); Replaceid(ss, tmp, tn); Delete(tn); Delete(ty); } i++; p = nextSibling(p); } if (template_debug) { Printf(stdout, " searching: '%s' (partial specialization - %s)\n", ss, pi.item); } if ((Equal(ss, tname)) || (Equal(ss, rname))) { Append(mpartials, pi.item); } Delete(ss); } } } if (template_debug) { Printf(stdout, " Matched partials: %s\n", mpartials); } if (Len(mpartials)) { String *s = Getitem(mpartials, 0); n = Swig_symbol_clookup_local(s, 0); if (Len(mpartials) > 1) { if (n) { Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname)); Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), " instantiation '%s' is used.\n", SwigType_namestr(Getattr(n, "name"))); } } } if (!n) { n = templ; } if (!n) { Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); } else if (n) { String *nodeType = nodeType(n); if (!Equal(nodeType, "template")) { Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType); n = 0; } } success: Delete(tname); Delete(rname); Delete(mpartials); if ((template_debug) && (n)) { Printf(stdout, "Node: %p\n", n); Swig_print_node(n); } Delete(parms); return n; }
static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { Node *n = 0; String *tname = 0; Node *templ; Symtab *primary_scope = 0; List *possiblepartials = 0; Parm *p; Parm *parms = 0; Parm *targs; ParmList *expandedparms; int *priorities_matrix = 0; int max_possible_partials = 0; int posslen = 0; /* Search for primary (unspecialized) template */ templ = Swig_symbol_clookup(name, 0); if (template_debug) { tname = Copy(name); SwigType_add_template(tname, tparms); Printf(stdout, "\n"); Swig_diagnostic(cparse_file, cparse_line, "template_debug: Searching for match to: '%s'\n", tname); Delete(tname); tname = 0; } if (templ) { tname = Copy(name); parms = CopyParmList(tparms); /* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */ primary_scope = Getattr(templ, "sym:symtab"); /* Add default values from primary template */ targs = Getattr(templ, "templateparms"); expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, primary_scope); /* reduce the typedef */ p = expandedparms; while (p) { SwigType *ty = Getattr(p, "type"); if (ty) { SwigType *nt = Swig_symbol_type_qualify(ty, tscope); Setattr(p, "type", nt); Delete(nt); } p = nextSibling(p); } SwigType_add_template(tname, expandedparms); /* Search for an explicit (exact) specialization. Example: template<> class name<int> { ... } */ { if (template_debug) { Printf(stdout, " searching for : '%s' (explicit specialization)\n", tname); } n = Swig_symbol_clookup_local(tname, primary_scope); if (!n) { SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope); if (!Equal(rname, tname)) { if (template_debug) { Printf(stdout, " searching for : '%s' (explicit specialization with typedef reduction)\n", rname); } n = Swig_symbol_clookup_local(rname, primary_scope); } Delete(rname); } if (n) { Node *tn; String *nodeType = nodeType(n); if (Equal(nodeType, "template")) { if (template_debug) { Printf(stdout, " explicit specialization found: '%s'\n", Getattr(n, "name")); } goto success; } tn = Getattr(n, "template"); if (tn) { if (template_debug) { Printf(stdout, " previous instantiation found: '%s'\n", Getattr(n, "name")); } n = tn; goto success; /* Previously wrapped by a template instantiation */ } Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n)); Delete(tname); Delete(parms); return 0; /* Found a match, but it's not a template of any kind. */ } } /* Search for partial specializations. * Example: template<typename T> class name<T *> { ... } * There are 3 types of template arguments: * (1) Template type arguments * (2) Template non type arguments * (3) Template template arguments * only (1) is really supported for partial specializations */ /* Rank each template parameter against the desired template parameters then build a matrix of best matches */ possiblepartials = NewList(); { char tmp[32]; List *partials; partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */ if (partials) { Iterator pi; int parms_len = ParmList_len(parms); int *priorities_row; max_possible_partials = Len(partials); priorities_matrix = (int *)malloc(sizeof(int) * max_possible_partials * parms_len); /* slightly wasteful allocation for max possible matches */ priorities_row = priorities_matrix; for (pi = First(partials); pi.item; pi = Next(pi)) { Parm *p = parms; int all_parameters_match = 1; int i = 1; Parm *partialparms = Getattr(pi.item, "partialparms"); Parm *pp = partialparms; String *templcsymname = Getattr(pi.item, "templcsymname"); if (template_debug) { Printf(stdout, " checking match: '%s' (partial specialization)\n", templcsymname); } if (ParmList_len(partialparms) == parms_len) { while (p && pp) { SwigType *t; sprintf(tmp, "$%d", i); t = Getattr(p, "type"); if (!t) t = Getattr(p, "value"); if (t) { EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1); if (match < (int)PartiallySpecializedMatch) { all_parameters_match = 0; break; } } i++; p = nextSibling(p); pp = nextSibling(pp); } if (all_parameters_match) { Append(possiblepartials, pi.item); priorities_row += parms_len; } } } } } posslen = Len(possiblepartials); if (template_debug) { int i; if (posslen == 0) Printf(stdout, " matched partials: NONE\n"); else if (posslen == 1) Printf(stdout, " chosen partial: '%s'\n", Getattr(Getitem(possiblepartials, 0), "templcsymname")); else { Printf(stdout, " possibly matched partials:\n"); for (i = 0; i < posslen; i++) { Printf(stdout, " '%s'\n", Getattr(Getitem(possiblepartials, i), "templcsymname")); } } } if (posslen > 1) { /* Now go through all the possibly matched partial specialization templates and look for a non-ambiguous match. * Exact matches rank the highest and deduced parameters are ranked by how specialized they are, eg looking for * a match to const int *, the following rank (highest to lowest): * const int * (exact match) * const T * * T * * T * * An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>; * template<typename T1, typename T2> X class {}; // primary template * template<typename T1> X<T1, double *> class {}; // specialization (1) * template<typename T2> X<int *, T2> class {}; // specialization (2) */ if (template_debug) { int row, col; int parms_len = ParmList_len(parms); Printf(stdout, " parameter priorities matrix (%d parms):\n", parms_len); for (row = 0; row < posslen; row++) { int *priorities_row = priorities_matrix + row*parms_len; Printf(stdout, " "); for (col = 0; col < parms_len; col++) { Printf(stdout, "%5d ", priorities_row[col]); } Printf(stdout, "\n"); } } { int row, col; int parms_len = ParmList_len(parms); /* Printf(stdout, " parameter priorities inverse matrix (%d parms):\n", parms_len); */ for (col = 0; col < parms_len; col++) { int *priorities_col = priorities_matrix + col; int maxpriority = -1; /* Printf(stdout, "max_possible_partials: %d col:%d\n", max_possible_partials, col); Printf(stdout, " "); */ /* determine the highest rank for this nth parameter */ for (row = 0; row < posslen; row++) { int *element_ptr = priorities_col + row*parms_len; int priority = *element_ptr; if (priority > maxpriority) maxpriority = priority; /* Printf(stdout, "%5d ", priority); */ } /* Printf(stdout, "\n"); */ /* flag all the parameters which equal the highest rank */ for (row = 0; row < posslen; row++) { int *element_ptr = priorities_col + row*parms_len; int priority = *element_ptr; *element_ptr = (priority >= maxpriority) ? 1 : 0; } } } { int row, col; int parms_len = ParmList_len(parms); Iterator pi = First(possiblepartials); Node *chosenpartials = NewList(); if (template_debug) Printf(stdout, " priority flags matrix:\n"); for (row = 0; row < posslen; row++) { int *priorities_row = priorities_matrix + row*parms_len; int highest_count = 0; /* count of highest priority parameters */ for (col = 0; col < parms_len; col++) { highest_count += priorities_row[col]; } if (template_debug) { Printf(stdout, " "); for (col = 0; col < parms_len; col++) { Printf(stdout, "%5d ", priorities_row[col]); } Printf(stdout, "\n"); } if (highest_count == parms_len) { Append(chosenpartials, pi.item); } pi = Next(pi); } if (Len(chosenpartials) > 0) { /* one or more best match found */ Delete(possiblepartials); possiblepartials = chosenpartials; posslen = Len(possiblepartials); } else { /* no best match found */ Delete(chosenpartials); } } } if (posslen > 0) { String *s = Getattr(Getitem(possiblepartials, 0), "templcsymname"); n = Swig_symbol_clookup_local(s, primary_scope); if (posslen > 1) { int i; if (n) { Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname)); Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), " instantiation '%s' used,\n", SwigType_namestr(Getattr(n, "name"))); } for (i = 1; i < posslen; i++) { String *templcsymname = Getattr(Getitem(possiblepartials, i), "templcsymname"); Node *ignored_node = Swig_symbol_clookup_local(templcsymname, primary_scope); assert(ignored_node); Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(ignored_node), Getline(ignored_node), " instantiation '%s' ignored.\n", SwigType_namestr(Getattr(ignored_node, "name"))); } } } if (!n) { if (template_debug) { Printf(stdout, " chosen primary template: '%s'\n", Getattr(templ, "name")); } n = templ; } } else { if (template_debug) { Printf(stdout, " primary template not found\n"); } /* Give up if primary (unspecialized) template not found as specializations will only exist if there is a primary template */ n = 0; } if (!n) { Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); } else if (n) { String *nodeType = nodeType(n); if (!Equal(nodeType, "template")) { Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType); n = 0; } } success: Delete(tname); Delete(possiblepartials); if ((template_debug) && (n)) { /* Printf(stdout, "Node: %p\n", n); Swig_print_node(n); */ Printf(stdout, " chosen template:'%s'\n", Getattr(n, "name")); } Delete(parms); free(priorities_matrix); return n; }