Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@src.gnome.org>2009-02-04 00:48:24 (GMT)
committer Colin Walters <walters@src.gnome.org>2009-02-04 00:48:24 (GMT)
commite3e84400529899854fe06f7d110685f50be26a18 (patch)
tree6d7ab0ca6fb6b44969063070024628cddc2cfb6e
parentab991adecd8659a8b2843f4191ca4aa16aa4e121 (diff)
Bug 555960 - Nested structs and unions (generation portion)
Patch from Andreas Rottmann <a.rottmann@gmx.at>. * tests/scanner/utility.h (UtilityTaggedValue): Make the union member anonymous. (UtilityByte): New union typedef with an unnamed struct in it. * giscanner/transformer.py (Transformer._create_struct): Create unnamed structs for symbols with a None ident. (Transformer._create_union): Likewise. * giscanner/girwriter.py (GIRWriter._write_record): Allow name being None. (GIRWriter._write_union): Likewise. * girepository/girparser.c (start_struct): Allow a NULL name for non-toplevel structs. (start_union): Likewise. * tests/scanner/utility.h (UtilityTaggedValue): New struct typedef, which has a nested union member. * tests/scanner/utility-expected.gir: Adapted. * giscanner/transformer.py (Transformer._create_member): Create struct/union members if appropriate. (Transformer._create_struct, Transformer._create_union): Allow for structs/unions without a C type. * giscanner/glibtransformer.py (GLibTransformer._resolve_field): We don't need to resolve non-typef'd (GLibTransformer._resolve_field): Add cases for non-typedef'd struct/union "fields". * giscanner/girwriter.py (GIRWriter._write_record): Allow for records without a C type. (GIRWriter._write_field): structs and unions may appear in places where fields do. svn path=/trunk/; revision=1082
-rw-r--r--ChangeLog37
-rw-r--r--girepository/girparser.c73
-rw-r--r--giscanner/girwriter.py43
-rw-r--r--giscanner/glibtransformer.py8
-rw-r--r--giscanner/transformer.py22
-rw-r--r--tests/repository/Makefile.am3
-rw-r--r--tests/scanner/utility-1.0-expected.gir29
-rw-r--r--tests/scanner/utility-1.0-expected.tgir12
-rw-r--r--tests/scanner/utility.h21
9 files changed, 206 insertions, 42 deletions
diff --git a/ChangeLog b/ChangeLog
index bf51572..97d6b3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,41 @@
2009-02-03 Andreas Rottmann <a.rottmann@gmx.at>
+
+ * tests/scanner/utility.h (UtilityTaggedValue): Make the union
+ member anonymous.
+ (UtilityByte): New union typedef with an unnamed struct in it.
+
+ * giscanner/transformer.py (Transformer._create_struct): Create
+ unnamed structs for symbols with a None ident.
+ (Transformer._create_union): Likewise.
+
+ * giscanner/girwriter.py (GIRWriter._write_record): Allow name
+ being None.
+ (GIRWriter._write_union): Likewise.
+
+ * girepository/girparser.c (start_struct): Allow a NULL name for
+ non-toplevel structs.
+ (start_union): Likewise.
+
+ * tests/scanner/utility.h (UtilityTaggedValue): New struct
+ typedef, which has a nested union member.
+ * tests/scanner/utility-expected.gir: Adapted.
+
+ * giscanner/transformer.py (Transformer._create_member): Create
+ struct/union members if appropriate.
+ (Transformer._create_struct, Transformer._create_union): Allow for
+ structs/unions without a C type.
+
+ * giscanner/glibtransformer.py (GLibTransformer._resolve_field):
+ We don't need to resolve non-typef'd
+ (GLibTransformer._resolve_field): Add cases for non-typedef'd
+ struct/union "fields".
+
+ * giscanner/girwriter.py (GIRWriter._write_record): Allow for
+ records without a C type.
+ (GIRWriter._write_field): structs and unions may appear in places
+ where fields do.
+
+2009-02-03 Andreas Rottmann <a.rottmann@gmx.at>
* girepository/girparser.c (ParseContext): Removed member
current_node, added node_stack instead.
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 46c16e5..3e1f9df 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -2112,7 +2112,10 @@ start_struct (GMarkupParseContext *context,
GError **error)
{
if (strcmp (element_name, "record") == 0 &&
- ctx->state == STATE_NAMESPACE)
+ (ctx->state == STATE_NAMESPACE ||
+ ctx->state == STATE_UNION ||
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_CLASS))
{
const gchar *name;
const gchar *deprecated;
@@ -2127,7 +2130,7 @@ start_struct (GMarkupParseContext *context,
gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
- if (name == NULL)
+ if (name == NULL && ctx->node_stack == NULL)
{
MISSING_ATTRIBUTE (context, error, element_name, "name");
return FALSE;
@@ -2145,7 +2148,7 @@ start_struct (GMarkupParseContext *context,
struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
- ((GIrNode *)struct_)->name = g_strdup (name);
+ ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
if (deprecated)
struct_->deprecated = TRUE;
else
@@ -2156,9 +2159,10 @@ start_struct (GMarkupParseContext *context,
struct_->gtype_name = g_strdup (gtype_name);
struct_->gtype_init = g_strdup (gtype_init);
-
- ctx->current_module->entries =
- g_list_append (ctx->current_module->entries, struct_);
+
+ if (ctx->node_stack == NULL)
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, struct_);
push_node (ctx, (GIrNode *)struct_);
state_switch (ctx, STATE_STRUCT);
@@ -2176,8 +2180,11 @@ start_union (GMarkupParseContext *context,
ParseContext *ctx,
GError **error)
{
- if (strcmp (element_name, "union") == 0 &&
- ctx->state == STATE_NAMESPACE)
+ if (strcmp (element_name, "union") == 0 &&
+ (ctx->state == STATE_NAMESPACE ||
+ ctx->state == STATE_UNION ||
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_CLASS))
{
const gchar *name;
const gchar *deprecated;
@@ -2189,7 +2196,7 @@ start_union (GMarkupParseContext *context,
typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
- if (name == NULL)
+ if (name == NULL && ctx->node_stack == NULL)
MISSING_ATTRIBUTE (context, error, element_name, "name");
else
{
@@ -2197,7 +2204,7 @@ start_union (GMarkupParseContext *context,
union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
- ((GIrNode *)union_)->name = g_strdup (name);
+ ((GIrNode *)union_)->name = g_strdup (name ? name : "");
union_->gtype_name = g_strdup (typename);
union_->gtype_init = g_strdup (typeinit);
if (deprecated)
@@ -2205,8 +2212,9 @@ start_union (GMarkupParseContext *context,
else
union_->deprecated = FALSE;
- ctx->current_module->entries =
- g_list_append (ctx->current_module->entries, union_);
+ if (ctx->node_stack == NULL)
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, union_);
push_node (ctx, (GIrNode *)union_);
state_switch (ctx, STATE_UNION);
@@ -2685,6 +2693,41 @@ require_one_of_end_elements (GMarkupParseContext *context,
}
static gboolean
+state_switch_end_struct_or_union (GMarkupParseContext *context,
+ ParseContext *ctx,
+ const gchar *element_name,
+ GError **error)
+{
+ pop_node (ctx);
+ if (ctx->node_stack == NULL)
+ {
+ state_switch (ctx, STATE_NAMESPACE);
+ }
+ else
+ {
+ if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
+ state_switch (ctx, STATE_STRUCT);
+ else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION)
+ state_switch (ctx, STATE_UNION);
+ else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT)
+ state_switch (ctx, STATE_CLASS);
+ else
+ {
+ int line_number, char_number;
+ g_markup_parse_context_get_position (context, &line_number, &char_number);
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Unexpected end tag '%s' on line %d char %d",
+ element_name,
+ line_number, char_number);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
require_end_element (GMarkupParseContext *context,
ParseContext *ctx,
const char *expected_name,
@@ -2897,8 +2940,7 @@ end_element_handler (GMarkupParseContext *context,
case STATE_STRUCT:
if (require_end_element (context, ctx, "record", element_name, error))
{
- pop_node (ctx);
- state_switch (ctx, STATE_NAMESPACE);
+ state_switch_end_struct_or_union (context, ctx, element_name, error);
}
break;
@@ -2914,8 +2956,7 @@ end_element_handler (GMarkupParseContext *context,
case STATE_UNION:
if (require_end_element (context, ctx, "union", element_name, error))
{
- pop_node (ctx);
- state_switch (ctx, STATE_NAMESPACE);
+ state_switch_end_struct_or_union (context, ctx, element_name, error);
}
break;
case STATE_IMPLEMENTS:
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 51a208d..cd19e98 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -366,8 +366,11 @@ and/or use gtk-doc annotations. ''')
('glib:get-type', boxed.get_type)]
def _write_record(self, record):
- attrs = [('name', record.name),
- ('c:type', record.symbol)]
+ attrs = []
+ if record.name is not None:
+ attrs.append(('name', record.name))
+ if record.symbol is not None: # the record might be anonymous
+ attrs.append(('c:type', record.symbol))
if record.disguised:
attrs.append(('disguised', '1'))
if record.doc:
@@ -386,8 +389,11 @@ and/or use gtk-doc annotations. ''')
self._write_method(method)
def _write_union(self, union):
- attrs = [('name', union.name),
- ('c:type', union.symbol)]
+ attrs = []
+ if union.name is not None:
+ attrs.append(('name', union.name))
+ if union.symbol is not None: # the union might be anonymous
+ attrs.append(('c:type', union.symbol))
if union.doc:
attrs.append(('doc', union.doc))
self._append_version(union, attrs)
@@ -410,19 +416,22 @@ and/or use gtk-doc annotations. ''')
if isinstance(field, Callback):
self._write_callback(field)
- return
-
- attrs = [('name', field.name)]
- # Fields are assumed to be read-only
- # (see also girparser.c and generate.c)
- if not field.readable:
- attrs.append(('readable', '0'))
- if field.writable:
- attrs.append(('writable', '1'))
- if field.bits:
- attrs.append(('bits', str(field.bits)))
- with self.tagcontext('field', attrs):
- self._write_type(field.type)
+ elif isinstance(field, Struct):
+ self._write_record(field)
+ elif isinstance(field, Union):
+ self._write_union(field)
+ else:
+ attrs = [('name', field.name)]
+ # Fields are assumed to be read-only
+ # (see also girparser.c and generate.c)
+ if not field.readable:
+ attrs.append(('readable', '0'))
+ if field.writable:
+ attrs.append(('writable', '1'))
+ if field.bits:
+ attrs.append(('bits', str(field.bits)))
+ with self.tagcontext('field', attrs):
+ self._write_type(field.type)
def _write_signal(self, signal):
attrs = [('name', signal.name)]
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 51076a2..749b652 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -870,8 +870,12 @@ class GLibTransformer(object):
def _resolve_field(self, field):
if isinstance(field, Callback):
self._resolve_function(field)
- return
- field.type = self._resolve_param_type(field.type)
+ elif isinstance(field, Record): # non-typedef'd struct
+ self._resolve_record(field)
+ elif isinstance(field, Union): # non-typedef'd union
+ self._resolve_union(field)
+ else:
+ field.type = self._resolve_param_type(field.type)
def _resolve_alias(self, alias):
alias.target = self._resolve_type_name(alias.target, alias.target)
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 1d781c6..f6e89ce 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -307,6 +307,10 @@ class Transformer(object):
if (source_type.type == CTYPE_POINTER and
symbol.base_type.base_type.type == CTYPE_FUNCTION):
node = self._create_callback(symbol)
+ elif source_type.type == CTYPE_STRUCT and source_type.name is None:
+ node = self._create_struct(symbol, anonymous=True)
+ elif source_type.type == CTYPE_UNION and source_type.name is None:
+ node = self._create_union(symbol, anonymous=True)
else:
# Special handling for fields; we don't have annotations on them
# to apply later, yet.
@@ -478,8 +482,14 @@ class Transformer(object):
self._typedefs_ns[callback.name] = callback
return callback
- def _create_compound(self, klass, symbol):
- compound = self._typedefs_ns.get(symbol.ident, None)
+ def _create_compound(self, klass, symbol, anonymous):
+ if symbol.ident is None:
+ # the compound is an anonymous member of another union or a struct
+ assert anonymous
+ compound = klass(None, None)
+ else:
+ compound = self._typedefs_ns.get(symbol.ident, None)
+
if compound is None:
# This is a bit of a hack; really we should try
# to resolve through the typedefs to find the real
@@ -500,11 +510,11 @@ class Transformer(object):
return compound
- def _create_struct(self, symbol):
- return self._create_compound(Struct, symbol)
+ def _create_struct(self, symbol, anonymous=False):
+ return self._create_compound(Struct, symbol, anonymous)
- def _create_union(self, symbol):
- return self._create_compound(Union, symbol)
+ def _create_union(self, symbol, anonymous=False):
+ return self._create_compound(Union, symbol, anonymous)
def _create_callback(self, symbol):
parameters = self._create_parameters(symbol.base_type.base_type)
diff --git a/tests/repository/Makefile.am b/tests/repository/Makefile.am
index 1dd5c4c..e21cff4 100644
--- a/tests/repository/Makefile.am
+++ b/tests/repository/Makefile.am
@@ -13,4 +13,5 @@ gitestthrows_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
gitestthrows_LDADD = $(top_builddir)/girepository/libgirepository-1.0.la $(GIREPO_LIBS)
TESTS = gitestrepo gitestthrows
-TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG)
+TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG) \
+ XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)"
diff --git a/tests/scanner/utility-1.0-expected.gir b/tests/scanner/utility-1.0-expected.gir
index 81c1a6b..bb5a5e4 100644
--- a/tests/scanner/utility-1.0-expected.gir
+++ b/tests/scanner/utility-1.0-expected.gir
@@ -46,6 +46,35 @@ and/or use gtk-doc annotations. -->
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
</field>
</record>
+ <record name="TaggedValue" c:type="UtilityTaggedValue">
+ <field name="tag" writable="1">
+ <type name="int" c:type="int"/>
+ </field>
+ <union>
+ <field name="v_pointer" writable="1">
+ <type name="any" c:type="gpointer"/>
+ </field>
+ <field name="v_real" writable="1">
+ <type name="double" c:type="double"/>
+ </field>
+ <field name="v_integer" writable="1">
+ <type name="long" c:type="long"/>
+ </field>
+ </union>
+ </record>
+ <union name="Byte" c:type="UtilityByte">
+ <field name="value" writable="1">
+ <type name="uint8" c:type="guint8"/>
+ </field>
+ <record>
+ <field name="first_nibble" writable="1" bits="4">
+ <type name="uint8" c:type="guint8"/>
+ </field>
+ <field name="second_nibble" writable="1" bits="4">
+ <type name="uint8" c:type="guint8"/>
+ </field>
+ </record>
+ </union>
<callback name="FileFunc" c:type="UtilityFileFunc">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
diff --git a/tests/scanner/utility-1.0-expected.tgir b/tests/scanner/utility-1.0-expected.tgir
index 26e6d19..7a2364e 100644
--- a/tests/scanner/utility-1.0-expected.tgir
+++ b/tests/scanner/utility-1.0-expected.tgir
@@ -35,6 +35,18 @@
<type name="GObject.ObjectClass"/>
</field>
</record>
+ <record name="TaggedValue">
+ <field name="tag" writable="1">
+ <type name="int"/>
+ </field>
+ <!-- FIXME: anonymous union member missing -->
+ </record>
+ <union name="Byte">
+ <field name="value" writable="1">
+ <type name="uint8"/>
+ </field>
+ <!-- FIXME: anonymous struct member missing -->
+ </union>
<callback name="FileFunc">
<return-value transfer-ownership="none">
<type name="none"/>
diff --git a/tests/scanner/utility.h b/tests/scanner/utility.h
index a744f03..b493a67 100644
--- a/tests/scanner/utility.h
+++ b/tests/scanner/utility.h
@@ -23,6 +23,27 @@ struct _UtilityObjectClass
/* This one is similar to Pango.Glyph */
typedef guint32 UtilityGlyph;
+typedef struct
+{
+ int tag;
+ union
+ {
+ gpointer v_pointer;
+ double v_real;
+ long v_integer;
+ };
+} UtilityTaggedValue;
+
+typedef union
+{
+ guint8 value;
+ struct
+ {
+ guint8 first_nibble : 4;
+ guint8 second_nibble : 4;
+ };
+} UtilityByte;
+
typedef void (*UtilityFileFunc)(const char *path, gpointer user_data);
GType utility_object_get_type (void) G_GNUC_CONST;