Bug 560250 - Fully parse included modules

For some things, like computing structure offsets to put into the typelib
we need more than just the aliases from included modules. Do a completel
parse of included modules and store in module->included_modules.

Also add g_ir_find_node() to find node information from within the
active set of modules and their includes.

svn path=/trunk/; revision=874
This commit is contained in:
Owen Taylor 2008-11-11 00:48:17 +00:00
parent d041deae59
commit 6d9212674a
5 changed files with 177 additions and 22 deletions

View File

@ -62,6 +62,10 @@ g_ir_module_free (GIrModule *module)
g_list_free (module->entries);
/* Don't free dependencies, we inherit that from the parser */
/* FIXME: we leak the included modules themelves; they may be shared
* between multiple modules, so we would need refcounting */
g_list_free (module->include_modules);
g_free (module);
}

View File

@ -36,6 +36,7 @@ struct _GIrModule
gchar *shared_library;
GList *dependencies;
GList *entries;
GList *include_modules;
};
GIrModule *g_ir_module_new (const gchar *name,

View File

@ -1070,6 +1070,92 @@ find_entry (GIrModule *module,
return idx;
}
static GIrNode *
find_name_in_module (GIrModule *module,
const gchar *name)
{
GList *l;
for (l = module->entries; l; l = l->next)
{
GIrNode *node = (GIrNode *)l->data;
if (strcmp (node->name, name) == 0)
return node;
}
return NULL;
}
gboolean
g_ir_find_node (GIrModule *module,
GList *modules,
const char *name,
GIrNode **node_out,
GIrModule **module_out)
{
char **names = g_strsplit (name, ".", 0);
gint n_names = g_strv_length (names);
GIrNode *node = NULL;
GList *l;
if (n_names == 0)
{
g_warning ("Name can't be empty");
goto out;
}
if (n_names > 2)
{
g_warning ("Too many name parts in '%s'", name);
goto out;
}
if (n_names == 1)
{
*module_out = module;
node = find_name_in_module (module, names[0]);
}
else if (strcmp (names[0], module->name) == 0)
{
*module_out = module;
node = find_name_in_module (module, names[1]);
}
else
{
for (l = module->include_modules; l; l = l->next)
{
GIrModule *m = l->data;
if (strcmp (names[0], m->name) == 0)
{
*module_out = m;
node = find_name_in_module (m, names[1]);
goto out;
}
}
for (l = modules; l; l = l->next)
{
GIrModule *m = l->data;
if (strcmp (names[0], m->name) == 0)
{
*module_out = m;
node = find_name_in_module (m, names[1]);
goto out;
}
}
}
out:
g_strfreev (names);
*node_out = node;
return node != NULL;
}
static void
serialize_type (GIrModule *module,
GList *modules,

View File

@ -23,6 +23,8 @@
#include <glib.h>
#include "girmodule.h"
G_BEGIN_DECLS
typedef struct _GIrNode GIrNode;
@ -340,6 +342,12 @@ guint32 write_string (const gchar *str,
const gchar * g_ir_node_param_direction_string (GIrNodeParam * node);
const gchar * g_ir_node_type_to_string (GIrNodeTypeId type);
gboolean g_ir_find_node (GIrModule *module,
GList *modules,
const char *name,
GIrNode **node_out,
GIrModule **module_out);
G_END_DECLS
#endif /* __G_IR_NODE_H__ */

View File

@ -72,6 +72,7 @@ struct _ParseContext
const char * const*includes;
GList *modules;
GList *include_modules;
gboolean prefix_aliases;
GList *dependencies;
GHashTable *aliases;
@ -87,6 +88,34 @@ struct _ParseContext
int type_depth;
};
static void start_element_handler (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void end_element_handler (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void text_handler (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error);
static void cleanup (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static GMarkupParser parser =
{
start_element_handler,
end_element_handler,
text_handler,
NULL,
cleanup
};
static gboolean
start_alias (GMarkupParseContext *context,
const gchar *element_name,
@ -2116,7 +2145,31 @@ parse_include (GMarkupParseContext *context,
gchar *buffer;
gsize length;
char *girpath;
gboolean success = FALSE;
GList *l;
for (l = ctx->include_modules; l; l = l->next)
{
GIrModule *m = l->data;
if (strcmp (m->name, name) == 0)
{
if (strcmp (m->version, version) == 0)
{
return TRUE;
}
else
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT,
"Module '%s' imported with conflicting versions '%s' and '%s'",
name, m->version, version);
return FALSE;
}
}
}
girpath = locate_gir (name, version, ctx->includes);
if (girpath == NULL)
@ -2147,21 +2200,32 @@ parse_include (GMarkupParseContext *context,
sub_ctx.type_depth = 0;
context = g_markup_parse_context_new (&firstpass_parser, 0, &sub_ctx, NULL);
if (!g_markup_parse_context_parse (context, buffer, length, error))
{
g_free (buffer);
return FALSE;
}
goto out;
if (!g_markup_parse_context_end_parse (context, error))
{
g_free (buffer);
return FALSE;
}
goto out;
g_markup_parse_context_free (context);
return TRUE;
context = g_markup_parse_context_new (&parser, 0, &sub_ctx, NULL);
if (!g_markup_parse_context_parse (context, buffer, length, error))
goto out;
if (!g_markup_parse_context_end_parse (context, error))
goto out;
success = TRUE;
out:
ctx->include_modules = g_list_concat (ctx->include_modules,
sub_ctx.modules);
g_markup_parse_context_free (context);
g_free (buffer);
return success;
}
extern GLogLevelFlags logged_levels;
@ -2358,6 +2422,7 @@ start_element_handler (GMarkupParseContext *context,
ctx->current_module = g_ir_module_new (name, version, shared_library);
ctx->modules = g_list_append (ctx->modules, ctx->current_module);
ctx->current_module->dependencies = ctx->dependencies;
ctx->current_module->include_modules = g_list_copy (ctx->include_modules);
state_switch (ctx, STATE_NAMESPACE);
goto out;
@ -2819,15 +2884,6 @@ cleanup (GMarkupParseContext *context,
ctx->current_module = NULL;
}
static GMarkupParser parser =
{
start_element_handler,
end_element_handler,
text_handler,
NULL,
cleanup
};
static GList *
post_filter_varargs_functions (GList *list)
{