Пример #1
0
SwigType *SwigType_strip_qualifiers(SwigType *t) {
  static Hash *memoize_stripped = 0;
  SwigType *r;
  List *l;
  Iterator ei;

  if (!memoize_stripped)
    memoize_stripped = NewHash();
  r = Getattr(memoize_stripped, t);
  if (r)
    return Copy(r);

  l = SwigType_split(t);
  r = NewStringEmpty();

  for (ei = First(l); ei.item; ei = Next(ei)) {
    if (SwigType_isqualifier(ei.item))
      continue;
    Append(r, ei.item);
  }
  Delete(l);
  {
    String *key, *value;
    key = Copy(t);
    value = Copy(r);
    Setattr(memoize_stripped, key, value);
    Delete(key);
    Delete(value);
  }
  return r;
}
Пример #2
0
static
void SwigType_add_default(String *def, SwigType *nr) {
  if (Strcmp(nr, "SWIGTYPE") == 0) {
    Append(def, "SWIGTYPE");
  } else {
    String *q = SwigType_isqualifier(nr) ? SwigType_pop(nr) : 0;
    if (q && strstr(Char(nr), "SWIGTYPE")) {
      Append(def, nr);
    } else {
      String *nd = SwigType_default(nr);
      if (nd) {
	String *bdef = nd;
	if (q) {
	  bdef = NewStringf("%s%s", q, nd);
	  if ((Strcmp(nr, bdef) == 0)) {
	    Delete(bdef);
	    bdef = nd;
	  } else {
	    Delete(nd);
	  }
	}
	Append(def, bdef);
	Delete(bdef);
      } else {
	Append(def, nr);
      }
    }
    Delete(q);
  }
}
Пример #3
0
String *SwigType_lcaststr(const SwigType *s, const_String_or_char_ptr name) {
  String *result;

  result = NewStringEmpty();

  if (SwigType_isarray(s)) {
    String *lstr = SwigType_lstr(s, 0);
    Printf(result, "(%s)%s", lstr, name);
    Delete(lstr);
  } else if (SwigType_isreference(s)) {
    String *str = SwigType_str(s, 0);
    Printf(result, "(%s)", str);
    Delete(str);
    if (name)
      Append(result, name);
  } else if (SwigType_isqualifier(s)) {
    String *lstr = SwigType_lstr(s, 0);
    Printf(result, "(%s)%s", lstr, name);
    Delete(lstr);
  } else {
    if (name)
      Append(result, name);
  }
  return result;
}
Пример #4
0
static void mangle_namestr(String *mangled, SwigType *t) {
  int length = Len(t);
  if (SwigType_isqualifier(t)) {
    Append(mangled, "q_");
    mangle_stringcopy(mangled, Char(t)+2, length-4);
    Append(mangled, "__");
  } else if (SwigType_ismemberpointer(t)) {
    Append(mangled, "m_");
    mangle_stringcopy(mangled, Char(t)+2, length-4);
    Append(mangled, "__");
  } else if (SwigType_isarray(t)) {
    Append(mangled, "a_");
    mangle_stringcopy(mangled, Char(t)+2, length-4);
    Append(mangled, "__");
  } else if (SwigType_isfunction(t)) {
    List *p = SwigType_parmlist(t);
    int sz = Len(p);
    int i;
    Append(mangled, "f_");
    for (i = 0; i < sz; i++) {
      mangle_subtype(mangled, Getitem(p, i));
      Putc('_', mangled);
    }
    Append(mangled, (sz > 0) ? "_" : "__");
  } else if (SwigType_isvarargs(t)) {
    Append(mangled, "___");
  } else {
    char *d = Char(t);
    char *c = strstr(d, "<(");
    if (!c || !strstr(c + 2, ")>")) {
      /* not a template type */
      mangle_stringcopy(mangled, Char(t), Len(t));
    } else {
      /* a template type */
      String *suffix;
      List *p;
      int i, sz;
      mangle_stringcopy(mangled, d, c-d);
      Putc('T', mangled);
      Putc('_', mangled);

      p = SwigType_parmlist(c + 1);
      sz = Len(p);
      for (i = 0; i < sz; i++) {
	mangle_subtype(mangled, Getitem(p, i));
	Putc('_', mangled);
      }
      Putc('t', mangled);
      suffix = SwigType_templatesuffix(t);
      if (Len(suffix) > 0) {
	mangle_namestr(mangled, suffix);
      } else {
	Append(mangled, suffix);
      }
      Delete(suffix);
      Delete(p);
    }
  }
}
Пример #5
0
SwigType *SwigType_strip_single_qualifier(const SwigType *t) {
  static Hash *memoize_stripped = 0;
  SwigType *r = 0;
  List *l;
  int numitems;

  if (!memoize_stripped)
    memoize_stripped = NewHash();
  r = Getattr(memoize_stripped, t);
  if (r)
    return Copy(r);

  l = SwigType_split(t);

  numitems = Len(l);
  if (numitems >= 2) {
    int item;
    /* iterate backwards from last but one item */
    for (item = numitems - 2; item >= 0; --item) {
      String *subtype = Getitem(l, item);
      if (SwigType_isqualifier(subtype)) {
	Iterator it;
	Delitem(l, item);
	r = NewStringEmpty();
	for (it = First(l); it.item; it = Next(it)) {
	  Append(r, it.item);
	}
	break;
      }
    }
  }
  if (!r)
    r = Copy(t);

  Delete(l);
  {
    String *key, *value;
    key = Copy(t);
    value = Copy(r);
    Setattr(memoize_stripped, key, value);
    Delete(key);
    Delete(value);
  }
  return r;
}
Пример #6
0
String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
  String *result, *cast;
  String *element = 0;
  String *nextelement;
  String *forwardelement;
  SwigType *td, *tc = 0;
  const SwigType *rs;
  List *elements;
  int nelements, i;
  int clear = 1;
  int firstarray = 1;
  int isreference = 0;
  int isfunction = 0;

  result = NewStringEmpty();

  if (SwigType_isconst(s)) {
    tc = Copy(s);
    Delete(SwigType_pop(tc));
    rs = tc;
  } else {
    rs = s;
  }

  if ((SwigType_isconst(rs) || SwigType_isarray(rs) || SwigType_isreference(rs))) {
    td = 0;
  } else {
    td = SwigType_typedef_resolve(rs);
  }

  if (td) {
    if ((SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) {
      elements = SwigType_split(td);
    } else {
      elements = SwigType_split(rs);
    }
    Delete(td);
  } else {
    elements = SwigType_split(rs);
  }
  nelements = Len(elements);
  if (nelements > 0) {
    element = Getitem(elements, 0);
  }
  /* Now, walk the type list and start emitting */
  for (i = 0; i < nelements; i++) {
    if (i < (nelements - 1)) {
      nextelement = Getitem(elements, i + 1);
      forwardelement = nextelement;
      if (SwigType_isqualifier(nextelement)) {
	if (i < (nelements - 2))
	  forwardelement = Getitem(elements, i + 2);
      }
    } else {
      nextelement = 0;
      forwardelement = 0;
    }
    if (SwigType_isqualifier(element)) {
      DOH *q = 0;
      q = SwigType_parm(element);
      Insert(result, 0, " ");
      Insert(result, 0, q);
      Delete(q);
      clear = 0;
    } else if (SwigType_ispointer(element)) {
      Insert(result, 0, "*");
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
      firstarray = 0;
    } else if (SwigType_ismemberpointer(element)) {
      String *q;
      Insert(result, 0, "::*");
      q = SwigType_parm(element);
      Insert(result, 0, q);
      Delete(q);
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
      firstarray = 0;
    } else if (SwigType_isreference(element)) {
      Insert(result, 0, "&");
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
      if (!isfunction)
	isreference = 1;
    } else if (SwigType_isarray(element)) {
      DOH *size;
      if (firstarray && !isreference) {
	Append(result, "(*)");
	firstarray = 0;
      } else {
	Append(result, "[");
	size = SwigType_parm(element);
	Append(result, size);
	Append(result, "]");
	Delete(size);
	clear = 0;
      }
    } else if (SwigType_isfunction(element)) {
      DOH *parms, *p;
      int j, plen;
      Append(result, "(");
      parms = SwigType_parmlist(element);
      plen = Len(parms);
      for (j = 0; j < plen; j++) {
	p = SwigType_str(Getitem(parms, j), 0);
	Append(result, p);
	Delete(p);
	if (j < (plen - 1))
	  Append(result, ",");
      }
      Append(result, ")");
      Delete(parms);
      isfunction = 1;
    } else {
      String *bs = SwigType_namestr(element);
      Insert(result, 0, " ");
      Insert(result, 0, bs);
      Delete(bs);
    }
    element = nextelement;
  }
  Delete(elements);
  if (clear) {
    cast = NewStringEmpty();
  } else {
    cast = NewStringf("(%s)", result);
  }
  if (name) {
    if (isreference) {
      Append(cast, "*");
    }
    Append(cast, name);
  }
  Delete(result);
  Delete(tc);
  return cast;
}
Пример #7
0
SwigType *SwigType_ltype(const SwigType *s) {
  String *result;
  String *element;
  SwigType *td, *tc = 0;
  List *elements;
  int nelements, i;
  int firstarray = 1;
  int notypeconv = 0;

  result = NewStringEmpty();
  tc = Copy(s);
  /* Nuke all leading qualifiers */
  while (SwigType_isqualifier(tc)) {
    Delete(SwigType_pop(tc));
  }
  if (SwigType_issimple(tc)) {
    /* Resolve any typedef definitions */
    SwigType *tt = Copy(tc);
    td = 0;
    while ((td = SwigType_typedef_resolve(tt))) {
      if (td && (SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) {
	/* We need to use the typedef type */
	Delete(tt);
	tt = td;
	break;
      } else if (td) {
	Delete(tt);
	tt = td;
      }
    }
    if (td) {
      Delete(tc);
      tc = td;
    }
  }
  elements = SwigType_split(tc);
  nelements = Len(elements);

  /* Now, walk the type list and start emitting */
  for (i = 0; i < nelements; i++) {
    element = Getitem(elements, i);
    /* when we see a function, we need to preserve the following types */
    if (SwigType_isfunction(element)) {
      notypeconv = 1;
    }
    if (SwigType_isqualifier(element)) {
      /* Do nothing. Ignore */
    } else if (SwigType_ispointer(element)) {
      Append(result, element);
      firstarray = 0;
    } else if (SwigType_ismemberpointer(element)) {
      Append(result, element);
      firstarray = 0;
    } else if (SwigType_isreference(element)) {
      if (notypeconv) {
	Append(result, element);
      } else {
	Append(result, "p.");
      }
      firstarray = 0;
    } else if (SwigType_isarray(element) && firstarray) {
      if (notypeconv) {
	Append(result, element);
      } else {
	Append(result, "p.");
      }
      firstarray = 0;
    } else if (SwigType_isenum(element)) {
      int anonymous_enum = (Cmp(element, "enum ") == 0);
      if (notypeconv || !anonymous_enum) {
	Append(result, element);
      } else {
	Append(result, "int");
      }
    } else {
      Append(result, element);
    }
  }
  Delete(elements);
  Delete(tc);
  return result;
}
Пример #8
0
String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
  String *result;
  String *element = 0;
  String *nextelement;
  String *forwardelement;
  List *elements;
  int nelements, i;

  if (id) {
    /* stringify the id expanding templates, for example when the id is a fully qualified templated class name */
    String *id_str = NewString(id); /* unfortunate copy due to current const limitations */
    result = SwigType_str(id_str, 0);
    Delete(id_str);
  } else {
    result = NewStringEmpty();
  }

  elements = SwigType_split(s);
  nelements = Len(elements);

  if (nelements > 0) {
    element = Getitem(elements, 0);
  }
  /* Now, walk the type list and start emitting */
  for (i = 0; i < nelements; i++) {
    if (i < (nelements - 1)) {
      nextelement = Getitem(elements, i + 1);
      forwardelement = nextelement;
      if (SwigType_isqualifier(nextelement)) {
	if (i < (nelements - 2))
	  forwardelement = Getitem(elements, i + 2);
      }
    } else {
      nextelement = 0;
      forwardelement = 0;
    }
    if (SwigType_isqualifier(element)) {
      DOH *q = 0;
      q = SwigType_parm(element);
      Insert(result, 0, " ");
      Insert(result, 0, q);
      Delete(q);
    } else if (SwigType_ispointer(element)) {
      Insert(result, 0, "*");
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
    } else if (SwigType_ismemberpointer(element)) {
      String *q;
      q = SwigType_parm(element);
      Insert(result, 0, "::*");
      Insert(result, 0, q);
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
      Delete(q);
    } else if (SwigType_isreference(element)) {
      Insert(result, 0, "&");
      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
    } else if (SwigType_isarray(element)) {
      DOH *size;
      Append(result, "[");
      size = SwigType_parm(element);
      Append(result, size);
      Append(result, "]");
      Delete(size);
    } else if (SwigType_isfunction(element)) {
      DOH *parms, *p;
      int j, plen;
      Append(result, "(");
      parms = SwigType_parmlist(element);
      plen = Len(parms);
      for (j = 0; j < plen; j++) {
	p = SwigType_str(Getitem(parms, j), 0);
	Append(result, p);
	if (j < (plen - 1))
	  Append(result, ",");
      }
      Append(result, ")");
      Delete(parms);
    } else {
      if (strcmp(Char(element), "v(...)") == 0) {
	Insert(result, 0, "...");
      } else {
	String *bs = SwigType_namestr(element);
	Insert(result, 0, " ");
	Insert(result, 0, bs);
	Delete(bs);
      }
    }
    element = nextelement;
  }
  Delete(elements);
  Chop(result);
  return result;
}
Пример #9
0
SwigType *SwigType_default_deduce(const SwigType *t) {
  SwigType *r = NewStringEmpty();
  List *l;
  Iterator it;
  int numitems;

  l = SwigType_split(t);

  numitems = Len(l);
  if (numitems >= 1) {
    String *last_subtype = Getitem(l, numitems-1);
    int is_enum = SwigType_isenum(last_subtype);

    if (numitems >=2 ) {
      String *subtype = Getitem(l, numitems-2); /* last but one */
      if (SwigType_isarray(subtype)) {
	if (is_enum) {
	  /* enum deduction, enum SWIGTYPE => SWIGTYPE */
	  Setitem(l, numitems-1, NewString("SWIGTYPE"));
	} else {
	  /* array deduction, a(ANY). => a(). => p. */
	  String *deduced_subtype = 0;
	  if (Strcmp(subtype, "a().") == 0) {
	    deduced_subtype = NewString("p.");
	  } else if (Strcmp(subtype, "a(ANY).") == 0) {
	    deduced_subtype = NewString("a().");
	  } else {
	    assert(0);
	  }
	  Setitem(l, numitems-2, deduced_subtype);
	}
      } else if (SwigType_ismemberpointer(subtype)) {
	/* member pointer deduction, m(CLASS). => p. */
	Setitem(l, numitems-2, NewString("p."));
      } else if (is_enum && !SwigType_isqualifier(subtype)) {
	/* enum deduction, enum SWIGTYPE => SWIGTYPE */
	Setitem(l, numitems-1, NewString("SWIGTYPE"));
      } else {
	/* simple type deduction, eg, r.p.p. => r.p. */
	/* also function pointers eg, p.f(ANY). => p. */
	Delitem(l, numitems-2);
      }
    } else {
      if (is_enum) {
	/* enum deduction, enum SWIGTYPE => SWIGTYPE */
	Setitem(l, numitems-1, NewString("SWIGTYPE"));
      } else {
	/* delete the only item, we are done with deduction */
	Delitem(l, 0);
      }
    }
  } else {
    assert(0);
  }

  for (it = First(l); it.item; it = Next(it)) {
    Append(r, it.item);
  }

  if (Len(r) == 0) {
    Delete(r);
    r = 0;
  }

  Delete(l);
  return r;
}
Пример #10
0
String *SwigType_str(SwigType *s, const String_or_char *id) {
  String *result;
  String *element = 0, *nextelement;
  List *elements;
  int nelements, i;

  if (id) {
    result = NewString(id);
  } else {
    result = NewStringEmpty();
  }

  elements = SwigType_split(s);
  nelements = Len(elements);

  if (nelements > 0) {
    element = Getitem(elements, 0);
  }
  /* Now, walk the type list and start emitting */
  for (i = 0; i < nelements; i++) {
    if (i < (nelements - 1)) {
      nextelement = Getitem(elements, i + 1);
    } else {
      nextelement = 0;
    }
    if (SwigType_isqualifier(element)) {
      DOH *q = 0;
      q = SwigType_parm(element);
      Insert(result, 0, " ");
      Insert(result, 0, q);
      Delete(q);
    } else if (SwigType_ispointer(element)) {
      Insert(result, 0, "*");
      if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
    } else if (SwigType_ismemberpointer(element)) {
      String *q;
      q = SwigType_parm(element);
      Insert(result, 0, "::*");
      Insert(result, 0, q);
      if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
      Delete(q);
    } else if (SwigType_isreference(element)) {
      Insert(result, 0, "&");
      if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
	Insert(result, 0, "(");
	Append(result, ")");
      }
    } else if (SwigType_isarray(element)) {
      DOH *size;
      Append(result, "[");
      size = SwigType_parm(element);
      Append(result, size);
      Append(result, "]");
      Delete(size);
    } else if (SwigType_isfunction(element)) {
      DOH *parms, *p;
      int j, plen;
      Append(result, "(");
      parms = SwigType_parmlist(element);
      plen = Len(parms);
      for (j = 0; j < plen; j++) {
	p = SwigType_str(Getitem(parms, j), 0);
	Append(result, p);
	if (j < (plen - 1))
	  Append(result, ",");
      }
      Append(result, ")");
      Delete(parms);
    } else {
      if (strcmp(Char(element), "v(...)") == 0) {
	Insert(result, 0, "...");
      } else {
	String *bs = SwigType_namestr(element);
	Insert(result, 0, " ");
	Insert(result, 0, bs);
	Delete(bs);
      }
    }
    element = nextelement;
  }
  Delete(elements);
  Chop(result);
  return result;
}
Пример #11
0
SwigType *SwigType_default(SwigType *t) {
  String *r1, *def;
  String *r = 0;
  char *cr;

#ifdef SWIG_DEFAULT_CACHE
  if (!default_cache)
    default_cache = NewHash();

  r = Getattr(default_cache, t);
  if (r) {
    return Copy(r);
  }
#endif

  if (SwigType_isvarargs(t)) {
    return 0;
  }

  r = t;
  while ((r1 = SwigType_typedef_resolve(r))) {
    if (r != t)
      Delete(r);
    r = r1;
  }
  if (SwigType_isqualifier(r)) {
    String *q;
    if (r == t)
      r = Copy(t);
    q = SwigType_pop(r);
    if (strstr(Char(r), "SWIGTYPE")) {
      Delete(q);
      def = r;
      return def;
    }
    Delete(q);
  }
  cr = Char(r);
  if (strcmp(cr, "p.SWIGTYPE") == 0) {
    def = NewString("SWIGTYPE");
  } else if (SwigType_ispointer(r)) {
#ifdef SWIG_NEW_TYPE_DEFAULT
    SwigType *nr = Copy(r);
    SwigType_del_pointer(nr);
    def = SwigType_isfunction(nr) ? NewStringEmpty() : NewString("p.");
    SwigType_add_default(def, nr);
    Delete(nr);
#else
    def = NewString("p.SWIGTYPE");
#endif
  } else if (strcmp(cr, "r.SWIGTYPE") == 0) {
    def = NewString("SWIGTYPE");
  } else if (SwigType_isreference(r)) {
#ifdef SWIG_NEW_TYPE_DEFAULT
    SwigType *nr = Copy(r);
    SwigType_del_reference(nr);
    def = NewString("r.");
    SwigType_add_default(def, nr);
    Delete(nr);
#else
    def = NewString("r.SWIGTYPE");
#endif
  } else if (SwigType_isarray(r)) {
    if (strcmp(cr, "a().SWIGTYPE") == 0) {
      def = NewString("p.SWIGTYPE");
    } else if (strcmp(cr, "a(ANY).SWIGTYPE") == 0) {
      def = NewString("a().SWIGTYPE");
    } else {
      int i, empty = 0;
      int ndim = SwigType_array_ndim(r);
      SwigType *nr = Copy(r);
      for (i = 0; i < ndim; i++) {
	String *dim = SwigType_array_getdim(r, i);
	if (!Len(dim)) {
	  char *c = Char(nr);
	  empty = strstr(c, "a(ANY).") != c;
	}
	Delete(dim);
      }
      if (empty) {
	def = NewString("a().");
      } else {
	def = NewString("a(ANY).");
      }
#ifdef SWIG_NEW_TYPE_DEFAULT
      SwigType_del_array(nr);
      SwigType_add_default(def, nr);
#else
      Append(def, "SWIGTYPE");
#endif
      Delete(nr);
    }
  } else if (SwigType_ismemberpointer(r)) {
    if (strcmp(cr, "m(CLASS).SWIGTYPE") == 0) {
      def = NewString("p.SWIGTYPE");
    } else {
      def = NewString("m(CLASS).SWIGTYPE");
    }
  } else if (SwigType_isenum(r)) {
    if (strcmp(cr, "enum SWIGTYPE") == 0) {
      def = NewString("SWIGTYPE");
    } else {
      def = NewString("enum SWIGTYPE");
    }
  } else if (SwigType_isfunction(r)) {
    if (strcmp(cr, "f(ANY).SWIGTYPE") == 0) {
      def = NewString("p.SWIGTYPE");
    } else {
      def = NewString("p.f(ANY).SWIGTYPE");
    }
  } else {
    def = NewString("SWIGTYPE");
  }
  if (r != t)
    Delete(r);
  if (Equal(def, t)) {
    Delete(def);
    def = 0;
  }
#ifdef SWIG_DEFAULT_CACHE
  /* The cache produces strange results, see enum_template.i case */
  if (def) {
    String *cdef = Copy(def);
    Setattr(default_cache, t, cdef);
    Delete(cdef);
  }
#endif

  /* Printf(stderr,"type : def %s : %s\n", t, def);  */

  return def;
}
Пример #12
0
void
Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *node) {
  String *tname;
  DOH    *rn = 0;
  Hash   *n;
  char   *ncdecl = 0;
  
  if (!features) return;

  if ((decl) && (SwigType_isqualifier(decl))) {
    ncdecl = strchr(Char(decl),'.');
    ncdecl++;
  }

  if (name) {
    /* Perform a class-based lookup (if class prefix supplied) */
    if (prefix) {
      if (Len(prefix)) {
	tname = NewStringf("%s::%s",prefix,name);
	n = Getattr(features,tname);
	rn = get_object(n,decl);
	merge_features(rn,node);
	if (ncdecl) {
	  rn = get_object(n,ncdecl);
	  merge_features(rn,node);
	}
	rn = get_object(n,0);
	merge_features(rn,node);
	Delete(tname);
      }
      /* A wildcard-based class lookup */
      tname = NewStringf("*::%s",name);
      n = Getattr(features,tname);
      rn = get_object(n,decl);
      merge_features(rn,node);
      if (ncdecl) {
	rn = get_object(n,ncdecl);
	merge_features(rn,node);
      }
      rn = get_object(n,0);
      merge_features(rn,node);
      Delete(tname);
      
      /* A class-generic feature */
      if (Len(prefix)) {
	tname = NewStringf("%s::",prefix);
	n = Getattr(features,tname);
	rn = get_object(n,0);
	merge_features(rn,node);
	Delete(tname);
      }
      
    } else {
      /* Lookup in the global namespace only */
      tname = NewStringf("::%s",name);
      n = Getattr(features,tname);
      rn = get_object(n,decl);
      merge_features(rn,node);
      if (ncdecl) {
	rn = get_object(n,ncdecl);
	merge_features(rn,node);
      }
      rn = get_object(n,0);
      merge_features(rn,node);
      Delete(tname);
    }
    /* Catch-all */
    n = Getattr(features,name);
    rn = get_object(n,decl);
    merge_features(rn,node);
    if (ncdecl) {
      rn = get_object(n,ncdecl);
      merge_features(rn,node);
    }
    rn = get_object(n,0);
    merge_features(rn,node);
  }
  /* Global features */
  n = Getattr(features,"");
  rn = get_object(n,0);
  merge_features(rn,node);

}