Add union.test.
authorMatthias Clasen <mclasen@redhat.com>
Sun, 15 May 2005 04:30:43 +0000 (04:30 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sun, 15 May 2005 04:30:43 +0000 (04:30 +0000)
2005-05-15  Matthias Clasen  <mclasen@redhat.com>

        * tests/roundtrips.sh (SIMPLE_TESTS): Add union.test.

        * tests/union.test: Add a union test.

        * src/generate.c: Handle unions.

        * src/girepository.h:
        * src/ginfo.c: Add GIUnionInfo and functions to access it.

        * src/gidlnode.c: Handle GIdlNodeUnion nodes.

        * src/gidlparser.c (start_union): Parse <union> elements.

        * src/gidlnode.h: Add a GIdlNodeUnion.

        * gidl.dtd: Add a <union> element.

        * src/gmetadata.c (g_metadata_check_sanity): Check
        union_blob_size.

        * src/gmetadata.h: Add union_blob_size to Header,
        add a UnionBlob.

        * metadata-format.txt: Add a UnionBlob.

15 files changed:
ChangeLog
TODO
gidl.dtd
metadata-format.txt
src/generate.c
src/gidlmodule.c
src/gidlnode.c
src/gidlnode.h
src/gidlparser.c
src/ginfo.c
src/girepository.h
src/gmetadata.c
src/gmetadata.h
tests/roundtrips.sh
tests/union.test [new file with mode: 0644]

index 48188f4..900468c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2005-05-15  Matthias Clasen  <mclasen@redhat.com>
+
+       * tests/roundtrips.sh (SIMPLE_TESTS): Add union.test.
+
+       * tests/union.test: Add a union test.
+
+       * src/generate.c: Handle unions.
+
+       * src/girepository.h: 
+       * src/ginfo.c: Add GIUnionInfo and functions to access it.
+
+       * src/gidlnode.c: Handle GIdlNodeUnion nodes. 
+
+       * src/gidlparser.c (start_union): Parse <union> elements.
+
+       * src/gidlnode.h: Add a GIdlNodeUnion.
+
+       * gidl.dtd: Add a <union> element.
+
+       * src/gmetadata.c (g_metadata_check_sanity): Check
+       union_blob_size.
+
+       * src/gmetadata.h: Add union_blob_size to Header,
+       add a UnionBlob.
+
+       * metadata-format.txt: Add a UnionBlob.
+
 2005-05-13  Matthias Clasen  <mclasen@redhat.com>
 
        * tests/*: Update testcases. 
diff --git a/TODO b/TODO
index 325db9d..34375af 100644 (file)
--- a/TODO
+++ b/TODO
@@ -9,7 +9,6 @@ XML format
 Binary format
 -------------
 - Add hashes to lookup interfaces and functions in interfaces
-- Do we need (at least limited) handling of unions ? E.g. GdkEvent
 - Write a validator
 - Handle parent being 0
 
@@ -25,6 +24,8 @@ Repository
 - Add thorough error checking
 - Use hashes 
 - Maybe allow populating repositories at runtime
+- Think about a system-wide repository mapping namespace ids to 
+  libraries/metadata files
 
 General
 -------
index f19b037..d134fc1 100644 (file)
--- a/gidl.dtd
+++ b/gidl.dtd
@@ -2,7 +2,7 @@
 
 <!ATTLIST api version CDATA #REQUIRED >
 
-<!ELEMENT namespace (function|callback|object|interface|enum|flags|boxed|struct|constant|errordomain)* >
+<!ELEMENT namespace (function|callback|object|interface|enum|flags|boxed|struct|constant|errordomain|union)* >
 <!ATTLIST namespace name CDATA #REQUIRED >
 
 <!ELEMENT function (return-type,parameters?) >
@@ -15,7 +15,6 @@
                       null-ok (0|1) #IMPLIED
                       transfer (full|shallow|none) #IMPLIED >
 
-
 <!ELEMENT parameter EMPTY >
 <!ATTLIST parameter type CDATA #REQUIRED
                     name CDATA #REQUIRED
                 is-class-closure (0|1) #IMPLIED > 
 
 <!ELEMENT field EMPTY >
-<!ATTLIST field name CDATA #REQUIRED 
-                type CDATA #REQUIRED
-                bits CDATA #IMPLIED >
+<!ATTLIST field name   CDATA #REQUIRED 
+                type   CDATA #REQUIRED
+                bits   CDATA #IMPLIED 
+                branch CDATA #IMPLIED>
 
 <!ELEMENT enum (member+) >
 <!ATTLIST enum name CDATA #REQUIRED 
 <!ATTLIST struct name CDATA #REQUIRED 
                  deprecated (0|1) #IMPLIED >
 
+<!ELEMENT union (discriminator?,(constructor|field|method)*) >
+<!ATTLIST union name CDATA #REQUIRED 
+                type-name CDATA #IMPLIED
+                get-type CDATA #IMPLIED
+                deprecated (0|1) #IMPLIED >
+
+<!ELEMENT discriminator EMPTY >
+<!ATTLIST discriminator offset CDATA #REQUIRED
+                        type   CDATA #REQUIRED >
+
 <!ELEMENT constant EMPTY >
 <!ATTLIST constant name CDATA #REQUIRED 
                    type CDATA #REQUIRED
index c623446..4d4ac3c 100644 (file)
@@ -1,7 +1,10 @@
 GObject binary metadata for introspection
 -----------------------------------------
 
-Version 0.4
+Version 0.5
+
+Changes since 0.4:
+- add a UnionBlob
 
 Changes since 0.3:
 - drop short_name for ValueBlob. 
@@ -63,7 +66,7 @@ directory ::= list of entries
 
 entry ::= blob type, name, namespace, offset
 
-blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain
+blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain|union
 
 annotations ::= list of annotations, sorted by offset 
 
@@ -112,6 +115,7 @@ struct Header
   guint16   struct_blob_size;       /* 20 */
   guint16   object_blob_size;       /* 32 */
   guint16   interface_blob_size;    /* 28 */
+  guint16   union_blob_size;        /* 28 */
 }
 
 magic:    The string "GOBJ\nMETADATA\r\n\032". This was inspired by XPCOM, 
@@ -989,5 +993,50 @@ name:     The name of the annotation, a string.
 value:    The value of the annotation (also a string)
 
 
+UnionBlob (28 + x bytes)
+
+struct UnionBlob 
+{  
+  guint16      blob_type;  /* 11 */
+  guint        deprecated    : 1;
+  guint        unregistered  : 1;
+  guint        discriminated : 1;
+  guint        reserved      :13;
+  guint32      name;
+
+  GTypeBlob    gtype;
+
+  guint16      n_fields;
+  guint16      n_functions;
+
+  gint32       discriminator_offset; 
+  SimpleTypeBlob discriminator_type;
+
+  FieldBlob    fields[];   
+  FunctionBlob functions[];  
+  ConstantBlob discriminator_values[]
+}
+
+unregistered: 
+          If this is set, the type is not registered with GType.
+
+discriminated: 
+          Is set if the union is discriminated
+
+gtype:    For types which are registered with GType, contains the 
+          information about the GType. Otherwise unused.
+
+n_fields: Length of the arrays
+
+discriminator_offset: 
+          Offset from the beginning of the blob where the
+         discriminator of a discriminated union is located
+
+discriminator_type: 
+          Type of the discriminator 
 
+discriminator_values:
+          On discriminator value per field
 
+fields:   Array of FieldBlobs describing the alternative
+          branches of the union
index 0f87a97..c3cb30c 100644 (file)
@@ -147,8 +147,15 @@ write_type_info (const gchar *namespace,
 }
 
 static void
+write_constant_value (const gchar *namespace, 
+                     GITypeInfo *info,
+                     GArgument *argument,
+                     FILE *file);
+
+static void
 write_field_info (const gchar *namespace,
                  GIFieldInfo *info,
+                 GIConstantInfo *branch,
                  FILE        *file)
 {
   const gchar *name;
@@ -156,6 +163,7 @@ write_field_info (const gchar *namespace,
   gint size;
   gint offset;
   GITypeInfo *type;
+  GArgument value; 
 
   name = g_base_info_get_name ((GIBaseInfo *)info);
   flags = g_field_info_get_flags (info);
@@ -177,7 +185,18 @@ write_field_info (const gchar *namespace,
   write_type_info (namespace, type, file);
   g_base_info_unref ((GIBaseInfo *)type);
 
-  g_fprintf (file, "\" />\n");
+  g_fprintf (file, "\"");
+
+  if (branch)
+    {
+      g_fprintf (file, " branch=\"");
+      type = g_constant_info_get_type (branch);
+      g_constant_info_get_value (branch, &value);
+      write_constant_value (namespace, type, &value, file);
+      g_fprintf (file, "\"");
+    }
+
+  g_fprintf (file," />\n");
 }
 
 static void 
@@ -383,7 +402,7 @@ write_struct_info (const gchar  *namespace,
   for (i = 0; i < g_struct_info_get_n_fields (info); i++)
     {
       GIFieldInfo *field = g_struct_info_get_field (info, i);
-      write_field_info (namespace, field, file);
+      write_field_info (namespace, field, NULL, file);
       g_base_info_unref ((GIBaseInfo *)field);
     }
 
@@ -423,77 +442,86 @@ write_value_info (const gchar *namespace,
 }
 
 static void
-write_constant_info (const gchar    *namespace,
-                    GIConstantInfo *info,
-                    FILE           *file,
-                    gint            indent)
+write_constant_value (const gchar *namespace, 
+                     GITypeInfo *type,
+                     GArgument  *value,
+                     FILE       *file)
 {
-  GITypeInfo *type;
-  const gchar *name;
-  gboolean deprecated;
-  GArgument value;
-
-  name = g_base_info_get_name ((GIBaseInfo *)info);
-  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
-
-  g_fprintf (file, "%*s<constant name=\"%s\" type=\"", indent, "", name);
-
-  type = g_constant_info_get_type (info);
-  write_type_info (namespace, type, file);
-  g_fprintf (file, "\" value=\"");
-
-  g_constant_info_get_value (info, &value);
   switch (g_type_info_get_tag (type))
     {
     case GI_TYPE_TAG_BOOLEAN:
-      g_fprintf (file, "%d", value.v_boolean);
+      g_fprintf (file, "%d", value->v_boolean);
       break;
     case GI_TYPE_TAG_INT8:
-      g_fprintf (file, "%d", value.v_int8);
+      g_fprintf (file, "%d", value->v_int8);
       break;
     case GI_TYPE_TAG_UINT8:
-      g_fprintf (file, "%d", value.v_uint8);
+      g_fprintf (file, "%d", value->v_uint8);
       break;
     case GI_TYPE_TAG_INT16:
-      g_fprintf (file, "%" G_GINT16_FORMAT, value.v_int16);
+      g_fprintf (file, "%" G_GINT16_FORMAT, value->v_int16);
       break;
     case GI_TYPE_TAG_UINT16:
-      g_fprintf (file, "%" G_GUINT16_FORMAT, value.v_uint16);
+      g_fprintf (file, "%" G_GUINT16_FORMAT, value->v_uint16);
       break;
     case GI_TYPE_TAG_INT32:
-      g_fprintf (file, "%" G_GINT32_FORMAT, value.v_int32);
+      g_fprintf (file, "%" G_GINT32_FORMAT, value->v_int32);
       break;
     case GI_TYPE_TAG_UINT32:
-      g_fprintf (file, "%" G_GUINT32_FORMAT, value.v_uint32);
+      g_fprintf (file, "%" G_GUINT32_FORMAT, value->v_uint32);
       break;
     case GI_TYPE_TAG_INT64:
-      g_fprintf (file, "%" G_GINT64_FORMAT, value.v_int64);
+      g_fprintf (file, "%" G_GINT64_FORMAT, value->v_int64);
       break;
     case GI_TYPE_TAG_UINT64:
-      g_fprintf (file, "%" G_GUINT64_FORMAT, value.v_uint64);
+      g_fprintf (file, "%" G_GUINT64_FORMAT, value->v_uint64);
       break;
     case GI_TYPE_TAG_FLOAT:
-      g_fprintf (file, "%f", value.v_float);
+      g_fprintf (file, "%f", value->v_float);
       break;
     case GI_TYPE_TAG_DOUBLE:
-      g_fprintf (file, "%Lf", value.v_double);
+      g_fprintf (file, "%Lf", value->v_double);
       break;
     case GI_TYPE_TAG_STRING:
-      g_fprintf (file, "%s", value.v_string);
+      g_fprintf (file, "%s", value->v_string);
       break;
     case GI_TYPE_TAG_INT:
-      g_fprintf (file, "%d", value.v_int);
+      g_fprintf (file, "%d", value->v_int);
       break;
     case GI_TYPE_TAG_UINT:
-      g_fprintf (file, "%d", value.v_uint);
+      g_fprintf (file, "%d", value->v_uint);
       break;
     case GI_TYPE_TAG_LONG:
-      g_fprintf (file, "%ld", value.v_long);
+      g_fprintf (file, "%ld", value->v_long);
       break;
     case GI_TYPE_TAG_ULONG:
-      g_fprintf (file, "%ld", value.v_ulong);
+      g_fprintf (file, "%ld", value->v_ulong);
       break;
     }
+}
+
+static void
+write_constant_info (const gchar    *namespace,
+                    GIConstantInfo *info,
+                    FILE           *file,
+                    gint            indent)
+{
+  GITypeInfo *type;
+  const gchar *name;
+  gboolean deprecated;
+  GArgument value;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_fprintf (file, "%*s<constant name=\"%s\" type=\"", indent, "", name);
+
+  type = g_constant_info_get_type (info);
+  write_type_info (namespace, type, file);
+  g_fprintf (file, "\" value=\"");
+
+  g_constant_info_get_value (info, &value);
+  write_constant_value (namespace, type, &value, file);
   g_fprintf (file, "\" />\n");
   
   g_base_info_unref ((GIBaseInfo *)type);
@@ -714,7 +742,7 @@ write_object_info (const gchar  *namespace,
   for (i = 0; i < g_object_info_get_n_fields (info); i++)
     {
       GIFieldInfo *field = g_object_info_get_field (info, i);
-      write_field_info (namespace, field, file);
+      write_field_info (namespace, field, NULL, file);
       g_base_info_unref ((GIBaseInfo *)field);
     }
 
@@ -856,6 +884,67 @@ write_error_domain_info (const gchar       *namespace,
 }
 
 static void
+write_union_info (const gchar *namespace, 
+                 GIUnionInfo *info, 
+                 FILE        *file)
+{
+  const gchar *name;
+  const gchar *type_name;
+  const gchar *type_init;
+  gboolean deprecated;
+  gint i;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+  type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+  
+  g_fprintf (file, "    <union name=\"%s\"", name);
+  
+  if (type_name)
+    g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
+         
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+
+  if (g_union_info_is_discriminated (info))
+    {
+      gint offset;
+      GITypeInfo *type;
+
+      offset = g_union_info_get_discriminator_offset (info);
+      type = g_union_info_get_discriminator_type (info);
+      
+      g_fprintf (file, "      <discriminator offset=\"%d\" type=\"", offset);
+      write_type_info (namespace, type, file);
+      g_fprintf (file, "\" />\n");
+      g_base_info_unref ((GIBaseInfo *)type);
+    }
+
+  for (i = 0; i < g_union_info_get_n_fields (info); i++)
+    {
+      GIFieldInfo *field = g_union_info_get_field (info, i);
+      GIConstantInfo *constant = g_union_info_get_discriminator (info, i);
+      write_field_info (namespace, field, constant, file);
+      g_base_info_unref ((GIBaseInfo *)field);
+      if (constant)
+       g_base_info_unref ((GIBaseInfo *)constant);
+    }
+
+  for (i = 0; i < g_union_info_get_n_methods (info); i++)
+    {
+      GIFunctionInfo *function = g_union_info_get_method (info, i);
+      write_function_info (namespace, function, file, 6);
+      g_base_info_unref ((GIBaseInfo *)function);
+    }
+
+  g_fprintf (file, "    </union>\n");
+}
+
+static void
 write_repository (GIRepository *repository,
                  gboolean      needs_prefix)
 {
@@ -915,7 +1004,11 @@ write_repository (GIRepository *repository,
            case GI_INFO_TYPE_BOXED:
              write_struct_info (ns, (GIStructInfo *)info, file);
              break;
-             
+
+           case GI_INFO_TYPE_UNION:
+             write_union_info (ns, (GIUnionInfo *)info, file);
+             break;
+
            case GI_INFO_TYPE_ENUM:
            case GI_INFO_TYPE_FLAGS:
              write_enum_info (ns, (GIEnumInfo *)info, file);
@@ -936,6 +1029,9 @@ write_repository (GIRepository *repository,
            case GI_INFO_TYPE_ERROR_DOMAIN:
              write_error_domain_info (ns, (GIErrorDomainInfo *)info, file);
              break;
+
+           default:
+             g_error ("unknown info type %d\n", g_base_info_get_type (info));
            }
 
          g_base_info_unref (info);
index de155f1..6319e83 100644 (file)
@@ -133,6 +133,7 @@ g_idl_module_build_metadata (GIdlModule  *module,
   header->struct_blob_size = 20;
   header->object_blob_size = 32;
   header->interface_blob_size = 28;
+  header->union_blob_size = 28;
 
   /* fill in directory and content */
   entry = (DirEntry *)&data[header->directory];
index 2bf501a..f8223c4 100644 (file)
@@ -125,6 +125,10 @@ g_idl_node_new (GIdlNodeTypeId type)
       node = g_malloc0 (sizeof (GIdlNodeXRef));
       break;
 
+    case G_IDL_NODE_UNION:
+      node = g_malloc0 (sizeof (GIdlNodeUnion));
+      break;
+
     default:
       g_error ("Unhandled node type %d\n", type);
       break;
@@ -323,6 +327,22 @@ g_idl_node_free (GIdlNode *node)
       }
       break;
 
+    case G_IDL_NODE_UNION:
+      {
+       GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+       
+       g_free (node->name);
+       g_free (union_->gtype_name);
+       g_free (union_->gtype_init);
+
+       g_idl_node_free ((GIdlNode *)union_->discriminator_type);
+       for (l = union_->members; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       for (l = union_->discriminators; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+      }
+      break;
+
     default:
       g_error ("Unhandled node type %d\n", node->type);
       break;
@@ -442,6 +462,18 @@ g_idl_node_get_size (GIdlNode *node)
       size = 0;
       break;
 
+    case G_IDL_NODE_UNION:
+      {
+       GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+       size = 28;
+       for (l = union_->members; l; l = l->next)
+         size += g_idl_node_get_size ((GIdlNode *)l->data);
+       for (l = union_->discriminators; l; l = l->next)
+         size += g_idl_node_get_size ((GIdlNode *)l->data);
+      }
+      break;
+
     default: 
       g_error ("Unhandled node type %d\n", node->type);
       size = 0;
@@ -699,6 +731,19 @@ g_idl_node_get_full_size (GIdlNode *node)
       }
       break;
 
+    case G_IDL_NODE_UNION:
+      {
+       GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+       size = 28;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       for (l = union_->members; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+       for (l = union_->discriminators; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+      }
+      break;
+
     default: 
       g_error ("Unknown type tag %d\n", node->type);
       size = 0;
@@ -1419,6 +1464,86 @@ g_idl_node_build_metadata (GIdlNode   *node,
       }
       break;
 
+    case G_IDL_NODE_UNION:
+      {
+       UnionBlob *blob = (UnionBlob *)&data[*offset];
+       GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+       blob->blob_type = BLOB_TYPE_UNION;
+       blob->deprecated = union_->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       if (union_->gtype_name)
+         {
+           blob->unregistered = FALSE;
+           blob->gtype_name = write_string (union_->gtype_name, strings, data, offset2);
+           blob->gtype_init = write_string (union_->gtype_init, strings, data, offset2);
+         }
+       else
+         {
+           blob->unregistered = TRUE;
+           blob->gtype_name = 0;
+           blob->gtype_init = 0;
+         }
+
+       blob->n_fields = 0;
+       blob->n_functions = 0;
+
+       blob->discriminator_offset = union_->discriminator_offset;
+
+       if (union_->discriminator_type)
+         {
+           *offset += 24;
+           blob->discriminated = TRUE;
+           g_idl_node_build_metadata ((GIdlNode *)union_->discriminator_type, 
+                                      module, modules, strings, types,
+                                      data, offset, offset2);
+         }
+       else 
+         {
+           *offset += 28;
+           blob->discriminated = FALSE;
+           blob->discriminator_type.offset = 0;
+         }
+       
+       
+       for (l = union_->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FIELD)
+             {
+               blob->n_fields++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       for (l = union_->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FUNCTION)
+             {
+               blob->n_functions++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       if (union_->discriminator_type)
+         {
+           for (l = union_->discriminators; l; l = l->next)
+             {
+               GIdlNode *member = (GIdlNode *)l->data;
+               
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+      }
+      break;
+
     case G_IDL_NODE_ENUM:
     case G_IDL_NODE_FLAGS:
       {
index 394d2f4..e81d713 100644 (file)
@@ -41,6 +41,7 @@ typedef struct _GIdlNodeStruct GIdlNodeStruct;
 typedef struct _GIdlNodeConstant GIdlNodeConstant;
 typedef struct _GIdlNodeErrorDomain GIdlNodeErrorDomain;
 typedef struct _GIdlNodeXRef GIdlNodeXRef;
+typedef struct _GIdlNodeUnion GIdlNodeUnion;
 
 typedef enum 
 {
@@ -55,6 +56,7 @@ typedef enum
   G_IDL_NODE_INTERFACE,
   G_IDL_NODE_CONSTANT,
   G_IDL_NODE_ERROR_DOMAIN,
+  G_IDL_NODE_UNION,
   G_IDL_NODE_PARAM,
   G_IDL_NODE_TYPE,
   G_IDL_NODE_PROPERTY,
@@ -271,6 +273,23 @@ struct _GIdlNodeStruct
   GList *members;
 };
 
+struct _GIdlNodeUnion
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+  
+  GList *members;
+  GList *discriminators;
+
+  gchar *gtype_name;
+  gchar *gtype_init;
+
+  gint discriminator_offset;
+  GIdlNodeType *discriminator_type;
+};
+
+
 struct _GIdlNodeErrorDomain
 {
   GIdlNode node;
index c175aba..8b38ed7 100644 (file)
@@ -39,7 +39,8 @@ typedef enum
   STATE_BOXED,
   STATE_STRUCT,
   STATE_SIGNAL,
-  STATE_ERRORDOMAIN
+  STATE_ERRORDOMAIN,
+  STATE_UNION
 } ParseState;
 
 typedef struct _ParseContext ParseContext;
@@ -413,7 +414,8 @@ start_function (GMarkupParseContext *context,
       ((ctx->state == STATE_OBJECT ||
        ctx->state == STATE_INTERFACE ||
        ctx->state == STATE_BOXED ||
-       ctx->state == STATE_STRUCT) &&
+       ctx->state == STATE_STRUCT ||
+        ctx->state == STATE_UNION) &&
        strcmp (element_name, "method") == 0) ||
       ((ctx->state == STATE_OBJECT ||
        ctx->state == STATE_BOXED) &&
@@ -504,6 +506,14 @@ start_function (GMarkupParseContext *context,
                  struct_ = (GIdlNodeStruct *)ctx->current_node;
                  struct_->members = g_list_append (struct_->members, function);                }
                break;
+             case G_IDL_NODE_UNION:
+               {
+                 GIdlNodeUnion *union_;
+                 
+                 union_ = (GIdlNodeUnion *)ctx->current_node;
+                 union_->members = g_list_append (union_->members, function);
+               }
+               break;
              }
          
          ctx->current_node = (GIdlNode *)function;
@@ -657,19 +667,22 @@ start_field (GMarkupParseContext *context,
   if (strcmp (element_name, "field") == 0 &&
       (ctx->state == STATE_OBJECT ||
        ctx->state == STATE_BOXED ||
-       ctx->state == STATE_STRUCT))
+       ctx->state == STATE_STRUCT ||
+       ctx->state == STATE_UNION))
     {
       const gchar *name;
       const gchar *type;
       const gchar *readable;
       const gchar *writable;
       const gchar *bits;
+      const gchar *branch;
       
       name = find_attribute ("name", attribute_names, attribute_values);
       type = find_attribute ("type", attribute_names, attribute_values);
       readable = find_attribute ("readable", attribute_names, attribute_values);
       writable = find_attribute ("writable", attribute_names, attribute_values);
       bits = find_attribute ("bits", attribute_names, attribute_values);
+      branch = find_attribute ("branch", attribute_names, attribute_values);
       
       if (name == NULL)
        MISSING_ATTRIBUTE (error, element_name, "name");
@@ -724,6 +737,26 @@ start_field (GMarkupParseContext *context,
                struct_->members = g_list_append (struct_->members, field);
              }
              break;
+           case G_IDL_NODE_UNION:
+             {
+               GIdlNodeUnion *union_;
+
+               union_ = (GIdlNodeUnion *)ctx->current_node;
+               union_->members = g_list_append (union_->members, field);
+               if (branch)
+                 {
+                   GIdlNodeConstant *constant;
+                   
+                   constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+                   ((GIdlNode *)constant)->name = g_strdup (name);
+                   constant->value = g_strdup (branch);          
+                   constant->type = union_->discriminator_type;
+                   constant->deprecated = FALSE;
+
+                   union_->discriminators = g_list_append (union_->discriminators, constant);
+                 }
+             }
+             break;
            }
        }
       return TRUE;
@@ -1424,6 +1457,88 @@ start_struct (GMarkupParseContext *context,
   return FALSE;
 }
   
+
+static gboolean
+start_union (GMarkupParseContext *context,
+            const gchar         *element_name,
+            const gchar        **attribute_names,
+            const gchar        **attribute_values,
+            ParseContext       *ctx,
+            GError             **error)
+{
+  if (strcmp (element_name, "union") == 0 && 
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *deprecated;
+      const gchar *typename;
+      const gchar *typeinit;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      typename = find_attribute ("type-name", attribute_names, attribute_values);
+      typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else
+       {
+         GIdlNodeUnion *union_;
+
+         union_ = (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+         
+         ((GIdlNode *)union_)->name = g_strdup (name);
+         union_->gtype_name = g_strdup (typename);
+         union_->gtype_init = g_strdup (typeinit);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           union_->deprecated = TRUE;
+         else
+           union_->deprecated = FALSE;
+
+         ctx->current_node = (GIdlNode *)union_;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, union_);
+         
+         ctx->state = STATE_UNION;
+       }
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_discriminator (GMarkupParseContext *context,
+                    const gchar         *element_name,
+                    const gchar        **attribute_names,
+                    const gchar        **attribute_values,
+                    ParseContext       *ctx,
+                    GError             **error)
+{
+  if (strcmp (element_name, "discriminator") == 0 &&
+      ctx->state == STATE_UNION)
+    {
+      const gchar *type;
+      const gchar *offset;
+      
+      type = find_attribute ("type", attribute_names, attribute_values);
+      offset = find_attribute ("offset", attribute_names, attribute_values);
+      if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else if (offset == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "offset");
+       {
+         ((GIdlNodeUnion *)ctx->current_node)->discriminator_type 
+           = parse_type (type);
+         ((GIdlNodeUnion *)ctx->current_node)->discriminator_offset 
+           = atoi (offset);
+       }
+      
+      return TRUE;
+    }
+
+  return FALSE;
+}
+  
 static void
 start_element_handler (GMarkupParseContext *context,
                       const gchar         *element_name,
@@ -1477,6 +1592,13 @@ start_element_handler (GMarkupParseContext *context,
        goto out;
       break;
 
+    case 'd':
+      if (start_discriminator (context, element_name, 
+                              attribute_names, attribute_values,
+                              ctx, error))
+       goto out;
+      break;
+
     case 'e':
       if (start_enum (context, element_name, 
                      attribute_names, attribute_values,
@@ -1660,6 +1782,13 @@ start_element_handler (GMarkupParseContext *context,
 
       break;
 
+    case 'u':
+      if (start_union (context, element_name,
+                      attribute_names, attribute_values,
+                      ctx, error))
+       goto out;
+      break;
+
     case 'v':
       if (start_vfunc (context, element_name,
                       attribute_names, attribute_values,
@@ -1725,6 +1854,8 @@ end_element_handler (GMarkupParseContext *context,
            ctx->state = STATE_BOXED;
          else if (ctx->current_node->type == G_IDL_NODE_STRUCT)
            ctx->state = STATE_STRUCT;
+         else if (ctx->current_node->type == G_IDL_NODE_UNION)
+           ctx->state = STATE_UNION;
        }
       break;
 
@@ -1776,6 +1907,14 @@ end_element_handler (GMarkupParseContext *context,
          ctx->state = STATE_NAMESPACE;
        }
       break;
+    case STATE_UNION:
+      if (strcmp (element_name, "union") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
     case STATE_IMPLEMENTS:
       ctx->state = STATE_OBJECT;
       break;
index 4e44043..5423424 100644 (file)
@@ -121,12 +121,16 @@ struct _GIArgInfo
   GIBaseInfo base;
 };
 
-
 struct _GITypeInfo
 {
   GIBaseInfo base;
 };
 
+struct _GIUnionInfo
+{
+  GIRegisteredTypeInfo registered;
+};
+
 
 /* info creation */
 GIBaseInfo *
@@ -232,6 +236,7 @@ g_base_info_get_name (GIBaseInfo *info)
     case GI_INFO_TYPE_INTERFACE:
     case GI_INFO_TYPE_CONSTANT:
     case GI_INFO_TYPE_ERROR_DOMAIN:
+    case GI_INFO_TYPE_UNION:
       {
        CommonBlob *blob = (CommonBlob *)&info->metadata[info->offset];
 
@@ -1638,3 +1643,100 @@ g_constant_info_get_value (GIConstantInfo *info,
 
   return blob->size;
 }
+
+/* GIUnionInfo functions */
+gint
+g_union_info_get_n_fields  (GIUnionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  
+  return blob->n_fields;
+}
+
+GIFieldInfo *
+g_union_info_get_field (GIUnionInfo *info,
+                       gint         n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, 
+                                    base->offset + header->union_blob_size + 
+                                    n * header->field_blob_size);
+}
+
+gint
+g_union_info_get_n_methods (GIUnionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  
+  return blob->n_functions;
+}
+
+GIFunctionInfo *
+g_union_info_get_method (GIUnionInfo *info,
+                        gint         n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  Header *header = (Header *)base->metadata;  
+  gint offset;
+
+  offset = base->offset + header->union_blob_size 
+    + blob->n_fields * header->field_blob_size 
+    + n * header->function_blob_size;
+  return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, 
+                                       base->metadata, offset);
+}
+
+gboolean
+g_union_info_is_discriminated (GIUnionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  
+  return blob->discriminated;
+}
+
+gint
+g_union_info_get_discriminator_offset (GIUnionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  
+  return blob->discriminator_offset;
+}
+
+GITypeInfo *
+g_union_info_get_discriminator_type (GIUnionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  return g_type_info_new (base, base->metadata, base->offset + 24);
+}
+
+GIConstantInfo *
+g_union_info_get_discriminator (GIUnionInfo *info,
+                               gint         n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+  
+  if (blob->discriminated)
+    {
+      Header *header = (Header *)base->metadata;  
+      gint offset;
+
+      offset = base->offset + header->union_blob_size 
+       + blob->n_fields * header->field_blob_size 
+       + blob->n_functions * header->function_blob_size
+       + n * header->constant_blob_size;
+      
+      return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, 
+                                           base->metadata, offset);  
+    }
+
+  return NULL;
+}
index 6a20cd8..8839d5c 100644 (file)
@@ -37,6 +37,7 @@ typedef struct _GIFunctionInfo       GIFunctionInfo;
 typedef struct _GICallbackInfo       GICallbackInfo;
 typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo;
 typedef struct _GIStructInfo         GIStructInfo;
+typedef struct _GIUnionInfo          GIUnionInfo;
 typedef struct _GIEnumInfo           GIEnumInfo;
 typedef struct _GIObjectInfo         GIObjectInfo;
 typedef struct _GIInterfaceInfo      GIInterfaceInfo;
@@ -102,6 +103,7 @@ typedef enum
   GI_INFO_TYPE_INTERFACE,
   GI_INFO_TYPE_CONSTANT,
   GI_INFO_TYPE_ERROR_DOMAIN,
+  GI_INFO_TYPE_UNION,
   GI_INFO_TYPE_VALUE,
   GI_INFO_TYPE_SIGNAL,
   GI_INFO_TYPE_VFUNC,
@@ -284,6 +286,20 @@ gint                   g_field_info_get_offset     (GIFieldInfo *info);
 GITypeInfo *           g_field_info_get_type       (GIFieldInfo *info);
 
 
+/* GIUnionInfo */
+gint                   g_union_info_get_n_fields  (GIUnionInfo *info);
+GIFieldInfo *          g_union_info_get_field     (GIUnionInfo *info,
+                                                  gint         n);
+gint                   g_union_info_get_n_methods (GIUnionInfo *info);
+GIFunctionInfo *       g_union_info_get_method    (GIUnionInfo *info,
+                                                  gint         n);
+gboolean               g_union_info_is_discriminated (GIUnionInfo *info);
+gint                   g_union_info_get_discriminator_offset (GIUnionInfo *info);
+GITypeInfo *           g_union_info_get_discriminator_type (GIUnionInfo *info);
+GIConstantInfo *       g_union_info_get_discriminator      (GIUnionInfo *info,
+                                                           gint         n);
+
+
 /* GIStructInfo */
 gint                   g_struct_info_get_n_fields  (GIStructInfo *info);
 GIFieldInfo *          g_struct_info_get_field     (GIStructInfo *info,
index 40d7d6f..0e613fc 100644 (file)
@@ -36,7 +36,7 @@ void
 g_metadata_check_sanity (void)
 {
   /* Check that struct layout is as we expect */
-  g_assert (sizeof (Header) == 80);
+  g_assert (sizeof (Header) == 84);
   g_assert (sizeof (DirEntry) == 12);
   g_assert (sizeof (SimpleTypeBlob) == 4);
   g_assert (sizeof (ArgBlob) == 12);
@@ -60,6 +60,7 @@ g_metadata_check_sanity (void)
   g_assert (sizeof (InterfaceBlob) == 28);
   g_assert (sizeof (ConstantBlob) == 20);
   g_assert (sizeof (AnnotationBlob) == 12);
+  g_assert (sizeof (UnionBlob) == 28);
 }
 
 
index 39c2cd2..c09a6b1 100644 (file)
@@ -38,7 +38,8 @@ enum
   BLOB_TYPE_OBJECT,
   BLOB_TYPE_INTERFACE,
   BLOB_TYPE_CONSTANT,
-  BLOB_TYPE_ERROR_DOMAIN
+  BLOB_TYPE_ERROR_DOMAIN,
+  BLOB_TYPE_UNION
 };
 
 typedef struct
@@ -74,6 +75,9 @@ typedef struct
   guint16 struct_blob_size;
   guint16 object_blob_size;
   guint16 interface_blob_size;
+  guint16 union_blob_size;
+  
+  guint16 padding;
 } Header;
 
 typedef struct
@@ -292,6 +296,31 @@ typedef struct
 #endif
 } StructBlob;
 
+typedef struct 
+{  
+  guint16      blob_type; 
+  guint        deprecated    : 1;
+  guint        unregistered  : 1;
+  guint        discriminated : 1;
+  guint        reserved      :13;
+  guint32      name;
+
+  guint32      gtype_name;
+  guint32      gtype_init;
+
+  guint16      n_fields;
+  guint16      n_functions;
+
+  gint32       discriminator_offset; 
+  SimpleTypeBlob discriminator_type;
+
+#if 0
+  FieldBlob    fields[];   
+  FunctionBlob functions[];  
+  ConstantBlob discriminator_values[]
+#endif
+} UnionBlob;
+
 typedef struct
 {
   guint16   blob_type;
index 8ed422a..e5cd0fe 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test"
+SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test union.test"
 
 for i in $SIMPLE_TESTS; do
        echo $i
diff --git a/tests/union.test b/tests/union.test
new file mode 100644 (file)
index 0000000..329512e
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <union name="union1" type-name="UnionType1" get-type="union1_get_type">
+      <discriminator offset="-4" type="gint" />
+      <field name="field1" readable="1" writable="1" offset="0" type="guint32" branch="0" />
+      <field name="field1" readable="1" writable="1" offset="0" type="gdouble" branch="1" />
+    </union>
+    <union name="union2" type-name="UnionType1" get-type="union1_get_type">
+      <field name="field1" readable="1" writable="1" offset="0" type="guint32" />
+      <field name="field1" readable="1" writable="1" offset="0" type="gdouble" />
+    </union>
+  </namespace>
+</api>