* python/py-type.c (typy_fields_items): Call check_typedef.
[deliverable/binutils-gdb.git] / gdb / python / py-type.c
index ae12b5895ac54ba42f4f789f82481193e9231dfd..44a22232827bc55ae7b0b75f392ef096cc66e32c 100644 (file)
@@ -1,6 +1,6 @@
 /* Python interface to types.
 
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -27,6 +27,9 @@
 #include "demangle.h"
 #include "objfiles.h"
 #include "language.h"
+#include "vec.h"
+#include "bcache.h"
+#include "dwarf2loc.h"
 
 typedef struct pyty_type_object
 {
@@ -53,6 +56,19 @@ typedef struct pyty_field_object
 
 static PyTypeObject field_object_type;
 
+/* A type iterator object.  */
+typedef struct {
+  PyObject_HEAD
+  /* The current field index.  */
+  int field;
+  /* What to return.  */
+  enum gdbpy_iter_kind kind;
+  /* Pointer back to the original source type object.  */
+  struct pyty_type_object *source;
+} typy_iterator_object;
+
+static PyTypeObject type_iterator_object_type;
+
 /* This is used to initialize various gdb.TYPE_ constants.  */
 struct pyty_code
 {
@@ -62,6 +78,9 @@ struct pyty_code
   const char *name;
 };
 
+/* Forward declarations.  */
+static PyObject *typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind);
+
 #define ENTRY(X) { X, #X }
 
 static struct pyty_code pyty_codes[] =
@@ -101,6 +120,7 @@ static void
 field_dealloc (PyObject *obj)
 {
   field_object *f = (field_object *) obj;
+
   Py_XDECREF (f->dict);
   f->ob_type->tp_free (obj);
 }
@@ -109,6 +129,7 @@ static PyObject *
 field_new (void)
 {
   field_object *result = PyObject_New (field_object, &field_object_type);
+
   if (result)
     {
       result->dict = PyDict_New ();
@@ -128,11 +149,13 @@ static PyObject *
 typy_get_code (PyObject *self, void *closure)
 {
   struct type *type = ((type_object *) self)->type;
+
   return PyInt_FromLong (TYPE_CODE (type));
 }
 
 /* Helper function for typy_fields which converts a single field to a
-   dictionary.  Returns NULL on error.  */
+   gdb.Field object.  Returns NULL on error.  */
+
 static PyObject *
 convert_field (struct type *type, int field)
 {
@@ -205,44 +228,133 @@ convert_field (struct type *type, int field)
   return NULL;
 }
 
-/* Return a sequence of all fields.  Each field is a dictionary with
-   some pre-defined keys.  */
+/* Helper function to return the name of a field, as a gdb.Field object.
+   If the field doesn't have a name, None is returned.  */
+
 static PyObject *
-typy_fields (PyObject *self, PyObject *args)
+field_name (struct type *type, int field)
 {
   PyObject *result;
-  int i;
-  struct type *type = ((type_object *) self)->type;
 
-  /* We would like to make a tuple here, make fields immutable, and
-     then memoize the result (and perhaps make Field.type() lazy).
-     However, that can lead to cycles.  */
-  result = PyList_New (0);
+  if (TYPE_FIELD_NAME (type, field))
+    result = PyString_FromString (TYPE_FIELD_NAME (type, field));
+  else
+    {
+      result = Py_None;
+      Py_INCREF (result);
+    }
+  return result;
+}
 
-  for (i = 0; i < TYPE_NFIELDS (type); ++i)
+/* Helper function for Type standard mapping methods.  Returns a
+   Python object for field i of the type.  "kind" specifies what to
+   return: the name of the field, a gdb.Field object corresponding to
+   the field, or a tuple consisting of field name and gdb.Field
+   object.  */
+
+static PyObject *
+make_fielditem (struct type *type, int i, enum gdbpy_iter_kind kind)
+{
+  PyObject *item = NULL, *key = NULL, *value = NULL;
+
+  switch (kind)
     {
-      PyObject *dict = convert_field (type, i);
-      if (!dict)
-       {
-         Py_DECREF (result);
-         return NULL;
-       }
-      if (PyList_Append (result, dict))
-       {
-         Py_DECREF (dict);
-         Py_DECREF (result);
-         return NULL;
-       }
+    case iter_items:
+      key = field_name (type, i);
+      if (key == NULL)
+       goto fail;
+      value = convert_field (type, i);
+      if (value == NULL)
+       goto fail;
+      item = PyTuple_New (2);
+      if (item == NULL)
+       goto fail;
+      PyTuple_SET_ITEM (item, 0, key);
+      PyTuple_SET_ITEM (item, 1, value);
+      break;
+    case iter_keys:
+      item = field_name (type, i);
+      break;
+    case iter_values:
+      item =  convert_field (type, i);
+      break;
+    }
+  return item;
+  
+ fail:
+  Py_XDECREF (key);
+  Py_XDECREF (value);
+  Py_XDECREF (item);
+  return NULL;
+}
+
+/* Return a sequence of all field names, fields, or (name, field) pairs.
+   Each field is a gdb.Field object.  */
+
+static PyObject *
+typy_fields_items (PyObject *self, enum gdbpy_iter_kind kind)
+{
+  PyObject *py_type = self;
+  PyObject *result = NULL, *iter = NULL;
+  volatile struct gdb_exception except;
+  struct type *type = ((type_object *) py_type)->type;
+  struct type *checked_type = type;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      CHECK_TYPEDEF (checked_type);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (checked_type != type)
+    py_type = type_to_type_object (checked_type);
+  iter = typy_make_iter (py_type, kind);
+  if (checked_type != type)
+    {
+      /* Need to wrap this in braces because Py_DECREF isn't wrapped
+        in a do{}while(0).  */
+      Py_DECREF (py_type);
+    }
+  if (iter != NULL)
+    {
+      result = PySequence_List (iter);
+      Py_DECREF (iter);
     }
 
   return result;
 }
 
+/* Return a sequence of all fields.  Each field is a gdb.Field object.  */
+
+static PyObject *
+typy_fields (PyObject *self, PyObject *args)
+{
+  return typy_fields_items (self, iter_values);
+}
+
+/* Return a sequence of all field names.  Each field is a gdb.Field object.  */
+
+static PyObject *
+typy_field_names (PyObject *self, PyObject *args)
+{
+  return typy_fields_items (self, iter_keys);
+}
+
+/* Return a sequence of all (name, fields) pairs.  Each field is a 
+   gdb.Field object.  */
+
+static PyObject *
+typy_items (PyObject *self, PyObject *args)
+{
+  return typy_fields_items (self, iter_items);
+}
+
 /* Return the type's tag, or None.  */
 static PyObject *
 typy_get_tag (PyObject *self, void *closure)
 {
   struct type *type = ((type_object *) self)->type;
+
   if (!TYPE_TAG_NAME (type))
     Py_RETURN_NONE;
   return PyString_FromString (TYPE_TAG_NAME (type));
@@ -257,6 +369,54 @@ typy_strip_typedefs (PyObject *self, PyObject *args)
   return type_to_type_object (check_typedef (type));
 }
 
+/* Return an array type.  */
+
+static PyObject *
+typy_array (PyObject *self, PyObject *args)
+{
+  long n1, n2;
+  PyObject *n2_obj = NULL;
+  struct type *array = NULL;
+  struct type *type = ((type_object *) self)->type;
+  volatile struct gdb_exception except;
+
+  if (! PyArg_ParseTuple (args, "l|O", &n1, &n2_obj))
+    return NULL;
+
+  if (n2_obj)
+    {
+      if (!PyInt_Check (n2_obj))
+       {
+         PyErr_SetString (PyExc_RuntimeError,
+                          _("Array bound must be an integer"));
+         return NULL;
+       }
+
+      if (! gdb_py_int_as_long (n2_obj, &n2))
+       return NULL;
+    }
+  else
+    {
+      n2 = n1;
+      n1 = 0;
+    }
+
+  if (n2 < n1)
+    {
+      PyErr_SetString (PyExc_ValueError,
+                      _("Array length must not be negative"));
+      return NULL;
+    }
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      array = lookup_array_range_type (type, n1, n2);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  return type_to_type_object (array);
+}
+
 /* Return a Type object which represents a pointer to SELF.  */
 static PyObject *
 typy_pointer (PyObject *self, PyObject *args)
@@ -290,7 +450,7 @@ typy_range (PyObject *self, PyObject *args)
       && TYPE_CODE (type) != TYPE_CODE_RANGE)
     {
       PyErr_SetString (PyExc_RuntimeError,
-                      "This type does not have a range.");
+                      _("This type does not have a range."));
       return NULL;
     }
 
@@ -362,7 +522,8 @@ typy_target (PyObject *self, PyObject *args)
 
   if (!TYPE_TARGET_TYPE (type))
     {
-      PyErr_SetString (PyExc_RuntimeError, "type does not have a target");
+      PyErr_SetString (PyExc_RuntimeError, 
+                      _("Type does not have a target."));
       return NULL;
     }
 
@@ -434,10 +595,11 @@ typy_get_sizeof (PyObject *self, void *closure)
 }
 
 static struct type *
-typy_lookup_typename (char *type_name, struct block *block)
+typy_lookup_typename (const char *type_name, const struct block *block)
 {
   struct type *type = NULL;
   volatile struct gdb_exception except;
+
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
       if (!strncmp (type_name, "struct ", 7))
@@ -452,9 +614,7 @@ typy_lookup_typename (char *type_name, struct block *block)
     }
   if (except.reason < 0)
     {
-      PyErr_Format (except.reason == RETURN_QUIT
-                   ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
-                   "%s", except.message);
+      gdbpy_convert_exception (except);
       return NULL;
     }
 
@@ -463,11 +623,12 @@ typy_lookup_typename (char *type_name, struct block *block)
 
 static struct type *
 typy_lookup_type (struct demangle_component *demangled,
-                 struct block *block)
+                 const struct block *block)
 {
-  struct type *type;
-  char *type_name;
+  struct type *type, *rtype = NULL;
+  char *type_name = NULL;
   enum demangle_component_type demangled_type;
+  volatile struct gdb_exception except;
 
   /* Save the type: typy_lookup_type() may (indirectly) overwrite
      memory pointed by demangled.  */
@@ -482,19 +643,41 @@ typy_lookup_type (struct demangle_component *demangled,
       if (! type)
        return NULL;
 
-      switch (demangled_type)
+      TRY_CATCH (except, RETURN_MASK_ALL)
        {
-       case DEMANGLE_COMPONENT_REFERENCE:
-         return lookup_reference_type (type);
-       case DEMANGLE_COMPONENT_POINTER:
-         return lookup_pointer_type (type);
-       case DEMANGLE_COMPONENT_CONST:
-         return make_cv_type (1, 0, type, NULL);
-       case DEMANGLE_COMPONENT_VOLATILE:
-         return make_cv_type (0, 1, type, NULL);
+         /* If the demangled_type matches with one of the types
+            below, run the corresponding function and save the type
+            to return later.  We cannot just return here as we are in
+            an exception handler.  */
+         switch (demangled_type)
+           {
+           case DEMANGLE_COMPONENT_REFERENCE:
+             rtype =  lookup_reference_type (type);
+             break;
+           case DEMANGLE_COMPONENT_POINTER:
+             rtype = lookup_pointer_type (type);
+             break;
+           case DEMANGLE_COMPONENT_CONST:
+             rtype = make_cv_type (1, 0, type, NULL);
+             break;
+           case DEMANGLE_COMPONENT_VOLATILE:
+             rtype = make_cv_type (0, 1, type, NULL);
+             break;
+           }
+       }
+      if (except.reason < 0)
+       {
+         gdbpy_convert_exception (except);
+         return NULL;
        }
     }
-
+  
+  /* If we have a type from the switch statement above, just return
+     that.  */
+  if (rtype)
+    return rtype;
+  
+  /* We don't have a type, so lookup the type.  */
   type_name = cp_comp_to_string (demangled, 10);
   type = typy_lookup_typename (type_name, block);
   xfree (type_name);
@@ -502,34 +685,21 @@ typy_lookup_type (struct demangle_component *demangled,
   return type;
 }
 
+/* This is a helper function for typy_template_argument that is used
+   when the type does not have template symbols attached.  It works by
+   parsing the type name.  This happens with compilers, like older
+   versions of GCC, that do not emit DW_TAG_template_*.  */
+
 static PyObject *
-typy_template_argument (PyObject *self, PyObject *args)
+typy_legacy_template_argument (struct type *type, const struct block *block,
+                              int argno)
 {
-  int i, argno, n_pointers;
-  struct type *type = ((type_object *) self)->type;
+  int i;
   struct demangle_component *demangled;
+  struct demangle_parse_info *info;
   const char *err;
   struct type *argtype;
-  struct block *block = NULL;
-  PyObject *block_obj = NULL;
-
-  if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj))
-    return NULL;
-
-  if (block_obj)
-    {
-      block = block_object_to_block (block_obj);
-      if (! block)
-       {
-         PyErr_SetString (PyExc_RuntimeError,
-                          _("Second argument must be block."));
-         return NULL;
-       }
-    }
-
-  type = check_typedef (type);
-  if (TYPE_CODE (type) == TYPE_CODE_REF)
-    type = check_typedef (TYPE_TARGET_TYPE (type));
+  struct cleanup *cleanup;
 
   if (TYPE_NAME (type) == NULL)
     {
@@ -538,12 +708,14 @@ typy_template_argument (PyObject *self, PyObject *args)
     }
 
   /* Note -- this is not thread-safe.  */
-  demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
-  if (! demangled)
+  info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
+  if (! info)
     {
       PyErr_SetString (PyExc_RuntimeError, err);
       return NULL;
     }
+  demangled = info->tree;
+  cleanup = make_cleanup_cp_demangled_name_parse_free (info);
 
   /* Strip off component names.  */
   while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME
@@ -552,6 +724,7 @@ typy_template_argument (PyObject *self, PyObject *args)
 
   if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE)
     {
+      do_cleanups (cleanup);
       PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
       return NULL;
     }
@@ -564,18 +737,85 @@ typy_template_argument (PyObject *self, PyObject *args)
 
   if (! demangled)
     {
+      do_cleanups (cleanup);
       PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
                    argno);
       return NULL;
     }
 
   argtype = typy_lookup_type (demangled->u.s_binary.left, block);
+  do_cleanups (cleanup);
   if (! argtype)
     return NULL;
 
   return type_to_type_object (argtype);
 }
 
+static PyObject *
+typy_template_argument (PyObject *self, PyObject *args)
+{
+  int argno;
+  struct type *type = ((type_object *) self)->type;
+  const struct block *block = NULL;
+  PyObject *block_obj = NULL;
+  struct symbol *sym;
+  struct value *val = NULL;
+  volatile struct gdb_exception except;
+
+  if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj))
+    return NULL;
+
+  if (block_obj)
+    {
+      block = block_object_to_block (block_obj);
+      if (! block)
+       {
+         PyErr_SetString (PyExc_RuntimeError,
+                          _("Second argument must be block."));
+         return NULL;
+       }
+    }
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      type = check_typedef (type);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+       type = check_typedef (TYPE_TARGET_TYPE (type));
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  /* We might not have DW_TAG_template_*, so try to parse the type's
+     name.  This is inefficient if we do not have a template type --
+     but that is going to wind up as an error anyhow.  */
+  if (! TYPE_N_TEMPLATE_ARGUMENTS (type))
+    return typy_legacy_template_argument (type, block, argno);
+
+  if (argno >= TYPE_N_TEMPLATE_ARGUMENTS (type))
+    {
+      PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
+                   argno);
+      return NULL;
+    }
+
+  sym = TYPE_TEMPLATE_ARGUMENT (type, argno);
+  if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+    return type_to_type_object (SYMBOL_TYPE (sym));
+  else if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT)
+    {
+      PyErr_Format (PyExc_RuntimeError,
+                   _("Template argument is optimized out"));
+      return NULL;
+    }
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      val = value_of_variable (sym, block);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  return value_to_value_object (val);
+}
+
 static PyObject *
 typy_str (PyObject *self)
 {
@@ -609,6 +849,218 @@ typy_str (PyObject *self)
   return result;
 }
 
+/* An entry in the type-equality bcache.  */
+
+typedef struct type_equality_entry
+{
+  struct type *type1, *type2;
+} type_equality_entry_d;
+
+DEF_VEC_O (type_equality_entry_d);
+
+/* A helper function to compare two strings.  Returns 1 if they are
+   the same, 0 otherwise.  Handles NULLs properly.  */
+
+static int
+compare_strings (const char *s, const char *t)
+{
+  if (s == NULL && t != NULL)
+    return 0;
+  else if (s != NULL && t == NULL)
+    return 0;
+  else if (s == NULL && t== NULL)
+    return 1;
+  return strcmp (s, t) == 0;
+}
+
+/* A helper function for typy_richcompare that checks two types for
+   "deep" equality.  Returns Py_EQ if the types are considered the
+   same, Py_NE otherwise.  */
+
+static int
+check_types_equal (struct type *type1, struct type *type2,
+                  VEC (type_equality_entry_d) **worklist)
+{
+  CHECK_TYPEDEF (type1);
+  CHECK_TYPEDEF (type2);
+
+  if (type1 == type2)
+    return Py_EQ;
+
+  if (TYPE_CODE (type1) != TYPE_CODE (type2)
+      || TYPE_LENGTH (type1) != TYPE_LENGTH (type2)
+      || TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)
+      || TYPE_NOSIGN (type1) != TYPE_NOSIGN (type2)
+      || TYPE_VARARGS (type1) != TYPE_VARARGS (type2)
+      || TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
+      || TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
+      || TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
+      || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
+    return Py_NE;
+
+  if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+    return Py_NE;
+  if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+    return Py_NE;
+
+  if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
+    {
+      if (memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2),
+                 sizeof (*TYPE_RANGE_DATA (type1))) != 0)
+       return Py_NE;
+    }
+  else
+    {
+      int i;
+
+      for (i = 0; i < TYPE_NFIELDS (type1); ++i)
+       {
+         const struct field *field1 = &TYPE_FIELD (type1, i);
+         const struct field *field2 = &TYPE_FIELD (type2, i);
+         struct type_equality_entry entry;
+
+         if (FIELD_ARTIFICIAL (*field1) != FIELD_ARTIFICIAL (*field2)
+             || FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
+             || FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
+           return Py_NE;
+         if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+           return Py_NE;
+         switch (FIELD_LOC_KIND (*field1))
+           {
+           case FIELD_LOC_KIND_BITPOS:
+             if (FIELD_BITPOS (*field1) != FIELD_BITPOS (*field2))
+               return Py_NE;
+             break;
+           case FIELD_LOC_KIND_PHYSADDR:
+             if (FIELD_STATIC_PHYSADDR (*field1)
+                 != FIELD_STATIC_PHYSADDR (*field2))
+               return Py_NE;
+             break;
+           case FIELD_LOC_KIND_PHYSNAME:
+             if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
+                                   FIELD_STATIC_PHYSNAME (*field2)))
+               return Py_NE;
+             break;
+           case FIELD_LOC_KIND_DWARF_BLOCK:
+             {
+               struct dwarf2_locexpr_baton *block1, *block2;
+
+               block1 = FIELD_DWARF_BLOCK (*field1);
+               block2 = FIELD_DWARF_BLOCK (*field2);
+               if (block1->per_cu != block2->per_cu
+                   || block1->size != block2->size
+                   || memcmp (block1->data, block2->data, block1->size) != 0)
+               return Py_NE;
+             }
+             break;
+           default:
+             internal_error (__FILE__, __LINE__, _("Unsupported field kind "
+                                                   "%d by check_types_equal"),
+                             FIELD_LOC_KIND (*field1));
+           }
+
+         entry.type1 = FIELD_TYPE (*field1);
+         entry.type2 = FIELD_TYPE (*field2);
+         VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+       }
+    }
+
+  if (TYPE_TARGET_TYPE (type1) != NULL)
+    {
+      struct type_equality_entry entry;
+      int added;
+
+      if (TYPE_TARGET_TYPE (type2) == NULL)
+       return Py_NE;
+
+      entry.type1 = TYPE_TARGET_TYPE (type1);
+      entry.type2 = TYPE_TARGET_TYPE (type2);
+      VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+    }
+  else if (TYPE_TARGET_TYPE (type2) != NULL)
+    return Py_NE;
+
+  return Py_EQ;
+}
+
+/* Check types on a worklist for equality.  Returns Py_NE if any pair
+   is not equal, Py_EQ if they are all considered equal.  */
+
+static int
+check_types_worklist (VEC (type_equality_entry_d) **worklist,
+                     struct bcache *cache)
+{
+  while (!VEC_empty (type_equality_entry_d, *worklist))
+    {
+      struct type_equality_entry entry;
+      int added;
+
+      entry = *VEC_last (type_equality_entry_d, *worklist);
+      VEC_pop (type_equality_entry_d, *worklist);
+
+      /* If the type pair has already been visited, we know it is
+        ok.  */
+      bcache_full (&entry, sizeof (entry), cache, &added);
+      if (!added)
+       continue;
+
+      if (check_types_equal (entry.type1, entry.type2, worklist) == Py_NE)
+       return Py_NE;
+    }
+
+  return Py_EQ;
+}
+
+/* Implement the richcompare method.  */
+
+static PyObject *
+typy_richcompare (PyObject *self, PyObject *other, int op)
+{
+  int result = Py_NE;
+  struct type *type1 = type_object_to_type (self);
+  struct type *type2 = type_object_to_type (other);
+  volatile struct gdb_exception except;
+
+  /* We can only compare ourselves to another Type object, and only
+     for equality or inequality.  */
+  if (type2 == NULL || (op != Py_EQ && op != Py_NE))
+    {
+      Py_INCREF (Py_NotImplemented);
+      return Py_NotImplemented;
+    }
+
+  if (type1 == type2)
+    result = Py_EQ;
+  else
+    {
+      struct bcache *cache;
+      VEC (type_equality_entry_d) *worklist = NULL;
+      struct type_equality_entry entry;
+
+      cache = bcache_xmalloc (NULL, NULL);
+
+      entry.type1 = type1;
+      entry.type2 = type2;
+      VEC_safe_push (type_equality_entry_d, worklist, &entry);
+
+      TRY_CATCH (except, RETURN_MASK_ALL)
+       {
+         result = check_types_worklist (&worklist, cache);
+       }
+      /* check_types_worklist calls several nested Python helper
+        functions, some of which can raise a GDB Exception, so we
+        just check and convert here.  If there is a GDB exception, a
+        comparison is not capable (or trusted), so exit.  */
+      bcache_xfree (cache);
+      VEC_free (type_equality_entry_d, worklist);
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  if (op == result)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
 \f
 
 static const struct objfile_data *typy_objfile_data_key;
@@ -674,6 +1126,7 @@ typy_dealloc (PyObject *obj)
     {
       /* Must reset head of list.  */
       struct objfile *objfile = TYPE_OBJFILE (type->type);
+
       if (objfile)
        set_objfile_data (objfile, typy_objfile_data_key, type->next);
     }
@@ -683,6 +1136,220 @@ typy_dealloc (PyObject *obj)
   type->ob_type->tp_free (type);
 }
 
+/* Return number of fields ("length" of the field dictionary).  */
+
+static Py_ssize_t
+typy_length (PyObject *self)
+{
+  struct type *type = ((type_object *) self)->type;
+
+  return TYPE_NFIELDS (type);
+}
+
+/* Return a gdb.Field object for the field named by the argument.  */
+
+static PyObject *
+typy_getitem (PyObject *self, PyObject *key)
+{
+  struct type *type = ((type_object *) self)->type;
+  char *field;
+  int i;
+  volatile struct gdb_exception except;
+
+  field = python_string_to_host_string (key);
+  if (field == NULL)
+    return NULL;
+
+  /* We want just fields of this type, not of base types, so instead of 
+     using lookup_struct_elt_type, portions of that function are
+     copied here.  */
+
+  for (;;)
+    {
+      TRY_CATCH (except, RETURN_MASK_ALL)
+       {
+         CHECK_TYPEDEF (type);
+       }
+      GDB_PY_HANDLE_EXCEPTION (except);
+
+      if (TYPE_CODE (type) != TYPE_CODE_PTR
+         && TYPE_CODE (type) != TYPE_CODE_REF)
+       break;
+      type = TYPE_TARGET_TYPE (type);
+    }
+
+  for (i = 0; i < TYPE_NFIELDS (type); i++)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+      if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
+       {
+         return convert_field (type, i);
+       }
+    }
+  PyErr_SetObject (PyExc_KeyError, key);
+  return NULL;
+}
+
+/* Implement the "get" method on the type object.  This is the 
+   same as getitem if the key is present, but returns the supplied
+   default value or None if the key is not found.  */
+
+static PyObject *
+typy_get (PyObject *self, PyObject *args)
+{
+  PyObject *key, *defval = Py_None, *result;
+  
+  if (!PyArg_UnpackTuple (args, "get", 1, 2, &key, &defval))
+    return NULL;
+  
+  result = typy_getitem (self, key);
+  if (result != NULL)
+    return result;
+  
+  /* typy_getitem returned error status.  If the exception is
+     KeyError, clear the exception status and return the defval
+     instead.  Otherwise return the exception unchanged.  */
+  if (!PyErr_ExceptionMatches (PyExc_KeyError))
+    return NULL;
+  
+  PyErr_Clear ();
+  Py_INCREF (defval);
+  return defval;
+}
+
+/* Implement the "has_key" method on the type object.  */
+
+static PyObject *
+typy_has_key (PyObject *self, PyObject *args)
+{
+  struct type *type = ((type_object *) self)->type;
+  const char *field;
+  int i;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "s", &field))
+    return NULL;
+
+  /* We want just fields of this type, not of base types, so instead of 
+     using lookup_struct_elt_type, portions of that function are
+     copied here.  */
+
+  for (;;)
+    {
+      TRY_CATCH (except, RETURN_MASK_ALL)
+       {
+         CHECK_TYPEDEF (type);
+       }
+      GDB_PY_HANDLE_EXCEPTION (except);
+      if (TYPE_CODE (type) != TYPE_CODE_PTR
+         && TYPE_CODE (type) != TYPE_CODE_REF)
+       break;
+      type = TYPE_TARGET_TYPE (type);
+    }
+
+  for (i = 0; i < TYPE_NFIELDS (type); i++)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+      if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
+       Py_RETURN_TRUE;
+    }
+  Py_RETURN_FALSE;
+}
+
+/* Make an iterator object to iterate over keys, values, or items.  */
+
+static PyObject *
+typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind)
+{
+  typy_iterator_object *typy_iter_obj;
+
+  typy_iter_obj = PyObject_New (typy_iterator_object,
+                               &type_iterator_object_type);
+  if (typy_iter_obj == NULL)
+      return NULL;
+
+  typy_iter_obj->field = 0;
+  typy_iter_obj->kind = kind;
+  Py_INCREF (self);
+  typy_iter_obj->source = (type_object *) self;
+
+  return (PyObject *) typy_iter_obj;
+}
+
+/* iteritems() method.  */
+
+static PyObject *
+typy_iteritems (PyObject *self, PyObject *args)
+{
+  return typy_make_iter (self, iter_items);
+}
+
+/* iterkeys() method.  */
+
+static PyObject *
+typy_iterkeys (PyObject *self, PyObject *args)
+{
+  return typy_make_iter (self, iter_keys);
+}
+
+/* Iterating over the class, same as iterkeys except for the function
+   signature.  */
+
+static PyObject *
+typy_iter (PyObject *self)
+{
+  return typy_make_iter (self, iter_keys);
+}
+
+/* itervalues() method.  */
+
+static PyObject *
+typy_itervalues (PyObject *self, PyObject *args)
+{
+  return typy_make_iter (self, iter_values);
+}
+
+/* Return a reference to the type iterator.  */
+
+static PyObject *
+typy_iterator_iter (PyObject *self)
+{
+  Py_INCREF (self);
+  return self;
+}
+
+/* Return the next field in the iteration through the list of fields
+   of the type.  */
+
+static PyObject *
+typy_iterator_iternext (PyObject *self)
+{
+  typy_iterator_object *iter_obj = (typy_iterator_object *) self;
+  struct type *type = iter_obj->source->type;
+  int i;
+  PyObject *result;
+  
+  if (iter_obj->field < TYPE_NFIELDS (type))
+    {
+      result = make_fielditem (type, iter_obj->field, iter_obj->kind);
+      if (result != NULL)
+       iter_obj->field++;
+      return result;
+    }
+
+  return NULL;
+}
+
+static void
+typy_iterator_dealloc (PyObject *obj)
+{
+  typy_iterator_object *iter_obj = (typy_iterator_object *) obj;
+
+  Py_DECREF (iter_obj->source);
+}
+
 /* Create a new Type referring to TYPE.  */
 PyObject *
 type_to_type_object (struct type *type)
@@ -711,10 +1378,10 @@ PyObject *
 gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
 {
   static char *keywords[] = { "name", "block", NULL };
-  char *type_name = NULL;
+  const char *type_name = NULL;
   struct type *type = NULL;
   PyObject *block_obj = NULL;
-  struct block *block = NULL;
+  const struct block *block = NULL;
 
   if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O", keywords,
                                     &type_name, &block_obj))
@@ -750,6 +1417,8 @@ gdbpy_initialize_types (void)
     return;
   if (PyType_Ready (&field_object_type) < 0)
     return;
+  if (PyType_Ready (&type_iterator_object_type) < 0)
+    return;
 
   for (i = 0; pyty_codes[i].name; ++i)
     {
@@ -763,6 +1432,10 @@ gdbpy_initialize_types (void)
   Py_INCREF (&type_object_type);
   PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type);
 
+  Py_INCREF (&type_iterator_object_type);
+  PyModule_AddObject (gdb_module, "TypeIterator",
+                     (PyObject *) &type_iterator_object_type);
+
   Py_INCREF (&field_object_type);
   PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type);
 }
@@ -782,13 +1455,38 @@ static PyGetSetDef type_object_getset[] =
 
 static PyMethodDef type_object_methods[] =
 {
+  { "array", typy_array, METH_VARARGS,
+    "array (N) -> Type\n\
+Return a type which represents an array of N objects of this type." },
+   { "__contains__", typy_has_key, METH_VARARGS,
+     "T.__contains__(k) -> True if T has a field named k, else False" },
   { "const", typy_const, METH_NOARGS,
     "const () -> Type\n\
 Return a const variant of this type." },
   { "fields", typy_fields, METH_NOARGS,
-    "field () -> list\n\
-Return a sequence holding all the fields of this type.\n\
-Each field is a dictionary." },
+    "fields () -> list\n\
+Return a list holding all the fields of this type.\n\
+Each field is a gdb.Field object." },
+  { "get", typy_get, METH_VARARGS,
+    "T.get(k[,default]) -> returns field named k in T, if it exists;\n\
+otherwise returns default, if supplied, or None if not." },
+  { "has_key", typy_has_key, METH_VARARGS,
+    "T.has_key(k) -> True if T has a field named k, else False" },
+  { "items", typy_items, METH_NOARGS,
+    "items () -> list\n\
+Return a list of (name, field) pairs of this type.\n\
+Each field is a gdb.Field object." },
+  { "iteritems", typy_iteritems, METH_NOARGS,
+    "iteritems () -> an iterator over the (name, field)\n\
+pairs of this type.  Each field is a gdb.Field object." },
+  { "iterkeys", typy_iterkeys, METH_NOARGS,
+    "iterkeys () -> an iterator over the field names of this type." },
+  { "itervalues", typy_itervalues, METH_NOARGS,
+    "itervalues () -> an iterator over the fields of this type.\n\
+Each field is a gdb.Field object." },
+  { "keys", typy_field_names, METH_NOARGS,
+    "keys () -> list\n\
+Return a list holding all the fields names of this type." },
   { "pointer", typy_pointer, METH_NOARGS,
     "pointer () -> Type\n\
 Return a type of pointer to this type." },
@@ -810,12 +1508,22 @@ Return the type of a template argument." },
   { "unqualified", typy_unqualified, METH_NOARGS,
     "unqualified () -> Type\n\
 Return a variant of this type without const or volatile attributes." },
+  { "values", typy_fields, METH_NOARGS,
+    "values () -> list\n\
+Return a list holding all the fields of this type.\n\
+Each field is a gdb.Field object." },
   { "volatile", typy_volatile, METH_NOARGS,
     "volatile () -> Type\n\
 Return a volatile variant of this type" },
   { NULL }
 };
 
+static PyMappingMethods typy_mapping = {
+  typy_length,
+  typy_getitem,
+  NULL                           /* no "set" method */
+};
+
 static PyTypeObject type_object_type =
 {
   PyObject_HEAD_INIT (NULL)
@@ -831,7 +1539,7 @@ static PyTypeObject type_object_type =
   0,                             /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
-  0,                             /*tp_as_mapping*/
+  &typy_mapping,                 /*tp_as_mapping*/
   0,                             /*tp_hash */
   0,                             /*tp_call*/
   typy_str,                      /*tp_str*/
@@ -842,9 +1550,9 @@ static PyTypeObject type_object_type =
   "GDB type object",             /* tp_doc */
   0,                             /* tp_traverse */
   0,                             /* tp_clear */
-  0,                             /* tp_richcompare */
+  typy_richcompare,              /* tp_richcompare */
   0,                             /* tp_weaklistoffset */
-  0,                             /* tp_iter */
+  typy_iter,                     /* tp_iter */
   0,                             /* tp_iternext */
   type_object_methods,           /* tp_methods */
   0,                             /* tp_members */
@@ -901,3 +1609,35 @@ static PyTypeObject field_object_type =
   0,                             /* tp_alloc */
   0,                             /* tp_new */
 };
+
+static PyTypeObject type_iterator_object_type = {
+  PyObject_HEAD_INIT (NULL)
+  0,                             /*ob_size*/
+  "gdb.TypeIterator",            /*tp_name*/
+  sizeof (typy_iterator_object),  /*tp_basicsize*/
+  0,                             /*tp_itemsize*/
+  typy_iterator_dealloc,         /*tp_dealloc*/
+  0,                             /*tp_print*/
+  0,                             /*tp_getattr*/
+  0,                             /*tp_setattr*/
+  0,                             /*tp_compare*/
+  0,                             /*tp_repr*/
+  0,                             /*tp_as_number*/
+  0,                             /*tp_as_sequence*/
+  0,                             /*tp_as_mapping*/
+  0,                             /*tp_hash */
+  0,                             /*tp_call*/
+  0,                             /*tp_str*/
+  0,                             /*tp_getattro*/
+  0,                             /*tp_setattro*/
+  0,                             /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,  /*tp_flags*/
+  "GDB type iterator object",    /*tp_doc */
+  0,                             /*tp_traverse */
+  0,                             /*tp_clear */
+  0,                             /*tp_richcompare */
+  0,                             /*tp_weaklistoffset */
+  typy_iterator_iter,             /*tp_iter */
+  typy_iterator_iternext,        /*tp_iternext */
+  0                              /*tp_methods */
+};
This page took 0.037905 seconds and 4 git commands to generate.