diff options
author | Colin Walters <walters@src.gnome.org> | 2008-09-29 19:03:44 +0000 |
---|---|---|
committer | Colin Walters <walters@src.gnome.org> | 2008-09-29 19:03:44 +0000 |
commit | e5840f2da6c58e736c61b2b36bc128e1c418c0a8 (patch) | |
tree | b6e6e62e08131f4455a83057c1fcb0da172b27bb | |
parent | d2465ce9ccefc6921eb5b3558b7db18f87a4f867 (diff) | |
download | gobject-introspection-e5840f2da6c58e736c61b2b36bc128e1c418c0a8.tar.gz |
Rework to use recursive XML
svn path=/trunk/; revision=637
-rw-r--r-- | girepository/girparser.c | 260 | ||||
-rw-r--r-- | giscanner/ast.py | 4 | ||||
-rw-r--r-- | giscanner/girparser.py | 20 | ||||
-rw-r--r-- | giscanner/girwriter.py | 39 | ||||
-rw-r--r-- | giscanner/transformer.py | 2 | ||||
-rw-r--r-- | tests/scanner/annotation-expected.gir | 20 |
6 files changed, 186 insertions, 159 deletions
diff --git a/girepository/girparser.c b/girepository/girparser.c index a64de0ed..88f7c78a 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -59,7 +59,7 @@ typedef enum STATE_CLASS_CONSTANT, STATE_INTERFACE_CONSTANT, STATE_ALIAS, - STATE_TYPE, + STATE_TYPE } ParseState; typedef struct _ParseContext ParseContext; @@ -79,6 +79,8 @@ struct _ParseContext GIrModule *current_module; GIrNode *current_node; GIrNode *current_typed; + GList *type_stack; + GList *type_parameters; int type_depth; }; @@ -347,25 +349,6 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib) type->is_pointer = TRUE; str += strlen ("SList"); } - - if (*str == '<') - { - (str)++; - char *rest; - - type->parameter_type1 = parse_type_internal (str, &rest, in_glib); - if (type->parameter_type1 == NULL) - goto error; - str = rest; - - if (str[0] != '>') - goto error; - (str)++; - } - else - { - type->parameter_type1 = parse_type_internal ("any", NULL, in_glib); - } } else if (g_str_has_prefix (str, "GLib.HashTable")) { @@ -375,35 +358,6 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib) type->is_ghashtable = TRUE; type->is_pointer = TRUE; str += strlen ("HashTable"); - - if (*str == '<') - { - char *rest; - (str)++; - - type->parameter_type1 = parse_type_internal (str, &rest, in_glib); - if (type->parameter_type1 == NULL) - goto error; - str = rest; - - if (str[0] != ',') - goto error; - (str)++; - - type->parameter_type2 = parse_type_internal (str, &rest, in_glib); - if (type->parameter_type2 == NULL) - goto error; - str = rest; - - if ((str)[0] != '>') - goto error; - (str)++; - } - else - { - type->parameter_type1 = parse_type_internal ("any", NULL, in_glib); - type->parameter_type2 = parse_type_internal ("any", NULL, in_glib); - } } else if (g_str_has_prefix (str, "GLib.Error")) { @@ -444,57 +398,6 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib) type->interface = g_strndup (start, str - start); } - if (g_str_has_prefix (str, "[")) - { - GIrNodeType *array; - int i; - - array = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE); - - array->tag = GI_TYPE_TAG_ARRAY; - array->is_pointer = TRUE; - array->is_array = TRUE; - - array->parameter_type1 = type; - - array->zero_terminated = FALSE; - array->has_length = FALSE; - array->length = 0; - - if (!g_str_has_prefix (str, "[]")) - { - gchar *end, *tmp, **opts; - - end = strchr (str, ']'); - tmp = g_strndup (str + 1, (end - str) - 1); - opts = g_strsplit (tmp, ",", 0); - - for (i = 0; opts[i]; i++) - { - gchar **vals; - - vals = g_strsplit (opts[i], "=", 0); - - if (strcmp (vals[0], "zero-terminated") == 0) - array->zero_terminated = (strcmp (vals[1], "1") == 0); - else if (strcmp (vals[0], "length") == 0) - { - array->has_length = TRUE; - array->length = atoi (vals[1]); - } - - g_strfreev (vals); - } - - g_free (tmp); - g_strfreev (opts); - - str = end; - } - - type = array; - } - if (next) *next = (char*)str; g_assert (type->tag >= 0 && type->tag <= GI_TYPE_TAG_ERROR); @@ -1506,14 +1409,20 @@ start_type (GMarkupParseContext *context, { const gchar *name; const gchar *ctype; - gboolean is_pointer; + gboolean is_array; GIrNodeType *typenode; - if (strcmp (element_name, "type") != 0) + is_array = strcmp (element_name, "array") == 0; + + if (!(is_array || (strcmp (element_name, "type") == 0))) return FALSE; - if (ctx->state == STATE_TYPE) - ctx->type_depth++; + if (ctx->state == STATE_TYPE) + { + ctx->type_depth++; + ctx->type_stack = g_list_prepend (ctx->type_stack, ctx->type_parameters); + ctx->type_parameters = NULL; + } else if (ctx->state == STATE_FUNCTION_PARAMETER || ctx->state == STATE_FUNCTION_RETURN || ctx->state == STATE_STRUCT_FIELD || @@ -1530,12 +1439,10 @@ start_type (GMarkupParseContext *context, { state_switch (ctx, STATE_TYPE); ctx->type_depth = 1; + ctx->type_stack = NULL; + ctx->type_parameters = NULL; } - /* FIXME handle recursive types */ - if (ctx->type_depth > 1) - return TRUE; - if (!ctx->current_typed) { g_set_error (error, @@ -1544,22 +1451,69 @@ start_type (GMarkupParseContext *context, "The element <type> is invalid here"); return FALSE; } - - name = find_attribute ("name", attribute_names, attribute_values); - if (name == NULL) - MISSING_ATTRIBUTE (context, error, element_name, "name"); + if (is_array) + { + const char *zero; + const char *len; + int i; + + typenode = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE); - ctype = find_attribute ("c:type", attribute_names, attribute_values); - if (ctype != NULL && strchr (ctype, '*')) - is_pointer = TRUE; + typenode->tag = GI_TYPE_TAG_ARRAY; + typenode->is_pointer = TRUE; + typenode->is_array = TRUE; + + zero = find_attribute ("zero-terminated", attribute_names, attribute_values); + len = find_attribute ("length", attribute_names, attribute_values); + + typenode->zero_terminated = !(zero && strcmp (zero, "1") != 0); + typenode->has_length = len != NULL; + typenode->length = typenode->has_length ? atoi (len) : -1; + } else - is_pointer = FALSE; + { + gboolean is_pointer; + name = find_attribute ("name", attribute_names, attribute_values); + + if (name == NULL) + MISSING_ATTRIBUTE (context, error, element_name, "name"); + + ctype = find_attribute ("c:type", attribute_names, attribute_values); + if (ctype != NULL && strchr (ctype, '*')) + is_pointer = TRUE; + else + is_pointer = FALSE; + + typenode = parse_type (ctx, name); + + if (is_pointer) + typenode->is_pointer = is_pointer; + } + + ctx->type_parameters = g_list_append (ctx->type_parameters, typenode); + + return TRUE; +} + +static void +end_type_top (ParseContext *ctx) +{ + GIrNodeType *typenode = (GIrNodeType*)ctx->type_parameters->data; + + /* Default to pointer for unspecified containers */ + if (typenode->tag == GI_TYPE_TAG_ARRAY || + typenode->tag == GI_TYPE_TAG_GLIST || + typenode->tag == GI_TYPE_TAG_GSLIST) + { + typenode->parameter_type1 = parse_type (ctx, "any"); + } + else if (typenode->tag == GI_TYPE_TAG_GHASH) + { + typenode->parameter_type1 = parse_type (ctx, "any"); + typenode->parameter_type2 = parse_type (ctx, "any"); + } - typenode = parse_type (ctx, name); - if (is_pointer) - typenode->is_pointer = is_pointer; - switch (ctx->current_typed->type) { case G_IR_NODE_PARAM: @@ -1590,10 +1544,61 @@ start_type (GMarkupParseContext *context, g_printerr("current node is %d\n", ctx->current_node->type); g_assert_not_reached (); } + g_list_free (ctx->type_parameters); + + ctx->type_depth = 0; + ctx->type_parameters = NULL; + ctx->current_typed = NULL; +} + +static void +end_type_recurse (ParseContext *ctx) +{ + GList *types; + GIrNodeType *parent; + parent = (GIrNodeType *) ((GList*)ctx->type_stack->data)->data; - ctx->current_typed = NULL; - return TRUE; + if (parent->tag == GI_TYPE_TAG_ARRAY || + parent->tag == GI_TYPE_TAG_GLIST || + parent->tag == GI_TYPE_TAG_GSLIST) + { + if (ctx->type_parameters == NULL) + parent->parameter_type1 = parse_type (ctx, "pointer"); + else + parent->parameter_type1 = (GIrNodeType*)ctx->type_parameters->data; + } + else if (parent->tag == GI_TYPE_TAG_GHASH) + { + if (ctx->type_parameters == NULL) + { + parent->parameter_type1 = parse_type (ctx, "pointer"); + parent->parameter_type2 = parse_type (ctx, "pointer"); + } + else + { + parent->parameter_type1 = (GIrNodeType*) ctx->type_parameters->data; + parent->parameter_type2 = (GIrNodeType*) ctx->type_parameters->next->data; + } + } + g_list_free (ctx->type_parameters); + ctx->type_parameters = (GList *)ctx->type_stack->data; + ctx->type_stack = g_list_delete_link (ctx->type_stack, ctx->type_stack); +} + +static void +end_type (ParseContext *ctx) +{ + if (ctx->type_depth == 1) + { + end_type_top (ctx); + state_switch (ctx, ctx->prev_state); + } + else + { + end_type_recurse (ctx); + ctx->type_depth--; + } } static gboolean @@ -2078,6 +2083,10 @@ start_element_handler (GMarkupParseContext *context, state_switch (ctx, STATE_ALIAS); goto out; } + if (start_type (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; break; case 'b': if (start_enum (context, element_name, @@ -2631,12 +2640,9 @@ end_element_handler (GMarkupParseContext *context, } break; case STATE_TYPE: - if (strcmp ("type", element_name) == 0) + if ((strcmp ("type", element_name) == 0) || (strcmp ("array", element_name) == 0)) { - if (ctx->type_depth == 1) - state_switch (ctx, ctx->prev_state); - else - ctx->type_depth -= 1; + end_type (ctx); break; } default: diff --git a/giscanner/ast.py b/giscanner/ast.py index 9aee04f4..93154d2c 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -170,8 +170,8 @@ class Type(Node): class Array(Type): - def __init__(self, name, ctype, element_type): - Type.__init__(self, name, ctype) + def __init__(self, ctype, element_type): + Type.__init__(self, '<carray>', ctype) self.element_type = element_type self.zeroterminated = True self.length_param_index = -1 diff --git a/giscanner/girparser.py b/giscanner/girparser.py index f3eedf14..09b58cf7 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -21,7 +21,7 @@ from xml.etree.cElementTree import parse from .ast import (Alias, Callback, Function, Parameter, Return, Union, - Struct, Type) + Struct, Type, Array) from .glibast import (GLibEnum, GLibEnumMember, GLibFlags, GLibInterface, GLibObject, GLibBoxedStruct, GLibBoxedUnion, GLibBoxedOther) @@ -128,7 +128,10 @@ class GIRParser(object): def _parse_function(self, node, klass): name = node.attrib['name'] - retval = Return(self._parse_type(node.find(_corens('return-value')))) + returnnode = node.find(_corens('return-value')) + if not returnnode: + raise ValueError('node %r has no return-value' % (name, )) + retval = Return(self._parse_type(returnnode)) parameters = [] for paramnode in node.findall('parameter'): parameters.append(Parameter(paramnode.attrib['name'], @@ -164,10 +167,15 @@ class GIRParser(object): def _parse_type(self, node): typenode = node.find(_corens('type')) - if node is None: - raise ValueError("failed to find type") - return Type(typenode.attrib['name'], - typenode.attrib[_cns('type')]) + if typenode is not None: + return Type(typenode.attrib['name'], + typenode.attrib.get(_cns('type'))) + typenode = node.find(_corens('array')) + if typenode is not None: + return Array(typenode.attrib[_cns('type')], + self._parse_type(typenode)) + raise ValueError("Couldn't parse type of node %r; children=%r", + node, list(node)) def _parse_boxed(self, node): obj = GLibBoxedOther(node.attrib[_glibns('name')], diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index 27f9375b..996da873 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -143,21 +143,6 @@ class GIRWriter(XMLWriter): def _type_to_string(self, ntype): if isinstance(ntype, basestring): return ntype - if isinstance(ntype, List) and ntype.element_type: - return '%s<%s>' % (ntype.name, - self._type_to_string(ntype.element_type)) - if isinstance(ntype, Map) and ntype.key_type: - return '%s<%s,%s>' % (ntype.name, - self._type_to_string(ntype.key_type), - self._type_to_string(ntype.value_type)) - if isinstance(ntype, Array): - options = [] - if not ntype.zeroterminated: - options.append('zero-terminated=0') - if ntype.length_param_index >= 0: - options.append('length=%d' % (ntype.length_param_index, )) - return self._type_to_string(ntype.element_type) + \ - '[%s]' % (','.join(options), ) return ntype.name def _write_type(self, ntype, relation=None): @@ -167,15 +152,33 @@ class GIRWriter(XMLWriter): else: typename = ntype.name type_cname = ntype.ctype + if isinstance(ntype, Array): + attrs = [] + if not ntype.zeroterminated: + attrs.append(('zero-terminated', '0')) + if ntype.length_param_index >= 0: + attrs.append(('length', '%d' % (ntype.length_param_index, ))) + attrs.append(('c:type', ntype.ctype)) + with self.tagcontext('array', attrs): + self._write_type(ntype.element_type) + return attrs = [('name', self._type_to_string(ntype))] - if relation: - attrs.append(('relation', relation)) # FIXME: figure out if type references a basic type # or a boxed/class/interface etc. and skip # writing the ctype if the latter. if type_cname is not None: attrs.append(('c:type', type_cname)) - self.write_tag('type', attrs) + if isinstance(ntype, List) and ntype.element_type: + with self.tagcontext('type', attrs): + self._write_type(ntype.element_type) + return + if isinstance(ntype, Map) and ntype.key_type: + with self.tagcontext('type', attrs): + self._write_type(ntype.key_type) + self._write_type(ntype.value_type) + return + # Not a special type, just write it out + self.write_tag('type', attrs) def _write_enum(self, enum): attrs = [('name', enum.name), diff --git a/giscanner/transformer.py b/giscanner/transformer.py index ef17af92..d560474d 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -347,7 +347,7 @@ class Transformer(object): if 'array' in options: options.remove('array') derefed = ctype[:-1] # strip the * - return Array(None, ctype, + return Array(ctype, self._parse_and_resolve_ctype(derefed)) resolved_type_name = self._parse_and_resolve_ctype(ctype) return Type(resolved_type_name, ctype) diff --git a/tests/scanner/annotation-expected.gir b/tests/scanner/annotation-expected.gir index 5b3e2288..4f8c1f60 100644 --- a/tests/scanner/annotation-expected.gir +++ b/tests/scanner/annotation-expected.gir @@ -151,7 +151,9 @@ <function name="object_get_strings" c:identifier="annotation_object_get_strings"> <return-value transfer-ownership="1"> - <type name="GLib.List<utf8>" c:type="GList*"/> + <type name="GLib.List" c:type="GList*"> + <type name="utf8"/> + </type> </return-value> <parameters> <parameter name="object"> @@ -162,7 +164,9 @@ <function name="object_get_objects" c:identifier="annotation_object_get_objects"> <return-value transfer-ownership="1"> - <type name="GLib.SList<Object>" c:type="GSList*"/> + <type name="GLib.SList" c:type="GSList*"> + <type name="Object"/> + </type> </return-value> <parameters> <parameter name="object"> @@ -180,7 +184,9 @@ <type name="Object" c:type="AnnotationObject*"/> </parameter> <parameter name="bytes"> - <type name="uint8[]" c:type="guchar*"/> + <array c:type="guchar*"> + <type name="uint8"/> + </array> </parameter> </parameters> </function> @@ -194,7 +200,9 @@ <type name="Object" c:type="AnnotationObject*"/> </parameter> <parameter name="nums"> - <type name="int[]" c:type="int*"/> + <array c:type="int*"> + <type name="int"/> + </array> </parameter> </parameters> </function> @@ -208,7 +216,9 @@ <type name="Object" c:type="AnnotationObject*"/> </parameter> <parameter name="nums"> - <type name="int[length=2]" c:type="int*"/> + <array length="2" c:type="int*"> + <type name="int"/> + </array> </parameter> <parameter name="n_nums"> <type name="int" c:type="int"/> |