summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@src.gnome.org>2008-09-29 19:03:44 +0000
committerColin Walters <walters@src.gnome.org>2008-09-29 19:03:44 +0000
commite5840f2da6c58e736c61b2b36bc128e1c418c0a8 (patch)
treeb6e6e62e08131f4455a83057c1fcb0da172b27bb
parentd2465ce9ccefc6921eb5b3558b7db18f87a4f867 (diff)
downloadgobject-introspection-e5840f2da6c58e736c61b2b36bc128e1c418c0a8.tar.gz
Rework to use recursive XML
svn path=/trunk/; revision=637
-rw-r--r--girepository/girparser.c260
-rw-r--r--giscanner/ast.py4
-rw-r--r--giscanner/girparser.py20
-rw-r--r--giscanner/girwriter.py39
-rw-r--r--giscanner/transformer.py2
-rw-r--r--tests/scanner/annotation-expected.gir20
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&lt;utf8&gt;" 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&lt;Object&gt;" 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"/>