Fix type parsing for both GLib case and GLib.List

* girepository/girparser.c: Rewrite type parsing
	to handle both GLib parsing case as well as correctly
	handling GLib.List and friends.  Don't try to treat
	e.g. ListStore as a List.

svn path=/trunk/; revision=527
This commit is contained in:
Colin Walters
2008-08-29 19:33:09 +00:00
parent 295fc99a40
commit da9249d559

View File

@@ -216,20 +216,10 @@ state_switch (ParseContext *ctx, ParseState newstate)
ctx->state = newstate; ctx->state = newstate;
} }
static GIrNodeType * parse_type_internal (gchar *str, gchar **rest); static GIrNodeType * parse_type_internal (const gchar *str, gchar **next, gboolean in_glib);
static GIrNodeType * static GIrNodeType *
create_pointer () parse_type_internal (const gchar *str, char **next, gboolean in_glib)
{
char *pointer = g_strdup ("any");
char *pointer_rest;
GIrNodeType *ret = parse_type_internal (pointer, &pointer_rest);
g_free (pointer);
return ret;
}
static GIrNodeType *
parse_type_internal (gchar *str, gchar **rest)
{ {
gint i; gint i;
@@ -304,175 +294,186 @@ parse_type_internal (gchar *str, gchar **rest)
}; };
gint n_basic = G_N_ELEMENTS (basic); gint n_basic = G_N_ELEMENTS (basic);
gchar *start, *end; gchar *temporary_type = NULL;
const gchar *start;
const gchar *end;
GIrNodeType *type; GIrNodeType *type;
type = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE); type = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE);
str = g_strstrip (str);
type->unparsed = g_strdup (str); type->unparsed = g_strdup (str);
*rest = str; if (in_glib)
{
if (g_str_has_prefix (str, "List<") ||
strcmp (str, "List") == 0)
{
temporary_type = g_strdup_printf ("GLib.List%s", str + 4);
str = temporary_type;
}
else if (g_str_has_prefix (str, "SList<") ||
strcmp (str, "SList") == 0)
{
temporary_type = g_strdup_printf ("GLib.SList%s", str + 5);
str = temporary_type;
}
else if (g_str_has_prefix (str, "HashTable<") ||
strcmp (str, "HashTable") == 0)
{
temporary_type = g_strdup_printf ("GLib.HashTable%s", str + 9);
str = temporary_type;
}
else if (g_str_has_prefix (str, "Error<") ||
strcmp (str, "Error") == 0)
{
temporary_type = g_strdup_printf ("GLib.Error%s", str + 5);
str = temporary_type;
}
}
for (i = 0; i < n_basic; i++) for (i = 0; i < n_basic; i++)
{ {
if (g_str_has_prefix (*rest, basic[i].str)) if (g_str_has_prefix (str, basic[i].str))
{ {
type->is_basic = TRUE; type->is_basic = TRUE;
type->tag = basic[i].tag; type->tag = basic[i].tag;
type->is_pointer = basic[i].pointer; type->is_pointer = basic[i].pointer;
*rest += strlen(basic[i].str); str += strlen(basic[i].str);
*rest = g_strchug (*rest); if (*str == '*' && !type->is_pointer)
if (**rest == '*' && !type->is_pointer)
{ {
type->is_pointer = TRUE; type->is_pointer = TRUE;
(*rest)++; str++;
} }
break; break;
} }
} }
if (i < n_basic) if (i < n_basic)
/* found a basic type */; /* found a basic type */;
else if (g_str_has_prefix (*rest, "GLib.List") || else if (g_str_has_prefix (str, "GLib.List") ||
g_str_has_prefix (*rest, "GLib.SList") || g_str_has_prefix (str, "GLib.SList"))
g_str_has_prefix (*rest, "List") ||
g_str_has_prefix (*rest, "SList"))
{ {
if (g_str_has_prefix (*rest, "GLib.")) str += strlen ("GLib.");
*rest += strlen ("GLib."); if (g_str_has_prefix (str, "List"))
if (g_str_has_prefix (*rest, "List"))
{ {
type->tag = GI_TYPE_TAG_GLIST; type->tag = GI_TYPE_TAG_GLIST;
type->is_glist = TRUE; type->is_glist = TRUE;
type->is_pointer = TRUE; type->is_pointer = TRUE;
*rest += strlen ("List"); str += strlen ("List");
} }
else else
{ {
type->tag = GI_TYPE_TAG_GSLIST; type->tag = GI_TYPE_TAG_GSLIST;
type->is_gslist = TRUE; type->is_gslist = TRUE;
type->is_pointer = TRUE; type->is_pointer = TRUE;
*rest += strlen ("SList"); str += strlen ("SList");
} }
*rest = g_strchug (*rest); if (*str == '<')
if (**rest == '<')
{ {
(*rest)++; (str)++;
char *rest;
type->parameter_type1 = parse_type_internal (*rest, rest);
type->parameter_type1 = parse_type_internal (str, &rest, in_glib);
if (type->parameter_type1 == NULL) if (type->parameter_type1 == NULL)
goto error; goto error;
str = rest;
*rest = g_strchug (*rest); if (str[0] != '>')
if ((*rest)[0] != '>')
goto error; goto error;
(*rest)++; (str)++;
} }
else else
{ {
type->parameter_type1 = create_pointer (); type->parameter_type1 = parse_type_internal ("any", NULL, in_glib);
} }
} }
else if (g_str_has_prefix (*rest, "HashTable") || else if (g_str_has_prefix (str, "GLib.HashTable"))
g_str_has_prefix (*rest, "GLib.HashTable"))
{ {
if (g_str_has_prefix (*rest, "GLib.")) str += strlen ("GLib.");
*rest += strlen ("GLib.");
type->tag = GI_TYPE_TAG_GHASH; type->tag = GI_TYPE_TAG_GHASH;
type->is_ghashtable = TRUE; type->is_ghashtable = TRUE;
type->is_pointer = TRUE; type->is_pointer = TRUE;
*rest += strlen ("HashTable"); str += strlen ("HashTable");
*rest = g_strchug (*rest); if (*str == '<')
if (**rest == '<')
{ {
(*rest)++; char *rest;
(str)++;
type->parameter_type1 = parse_type_internal (*rest, rest); type->parameter_type1 = parse_type_internal (str, &rest, in_glib);
if (type->parameter_type1 == NULL) if (type->parameter_type1 == NULL)
goto error; goto error;
str = rest;
*rest = g_strchug (*rest); if (str[0] != ',')
if ((*rest)[0] != ',')
goto error; goto error;
(*rest)++; (str)++;
type->parameter_type2 = parse_type_internal (*rest, rest); type->parameter_type2 = parse_type_internal (str, &rest, in_glib);
if (type->parameter_type2 == NULL) if (type->parameter_type2 == NULL)
goto error; goto error;
str = rest;
if ((*rest)[0] != '>') if ((str)[0] != '>')
goto error; goto error;
(*rest)++; (str)++;
} }
else else
{ {
type->parameter_type1 = create_pointer (); type->parameter_type1 = parse_type_internal ("any", NULL, in_glib);
type->parameter_type2 = create_pointer (); type->parameter_type2 = parse_type_internal ("any", NULL, in_glib);
} }
} }
else if (g_str_has_prefix (*rest, "GLib.Error") else if (g_str_has_prefix (str, "GLib.Error"))
|| g_str_has_prefix (*rest, "Error"))
{ {
if (g_str_has_prefix (*rest, "GLib.")) str += strlen ("GLib.");
*rest += strlen ("GLib.");
type->tag = GI_TYPE_TAG_ERROR; type->tag = GI_TYPE_TAG_ERROR;
type->is_error = TRUE; type->is_error = TRUE;
type->is_pointer = TRUE; type->is_pointer = TRUE;
*rest += strlen ("GError"); str += strlen ("Error");
*rest = g_strchug (*rest); if (*str == '<')
if (**rest == '<')
{ {
(*rest)++; (str)++;
char *tmp;
end = strchr (*rest, '>'); end = strchr (str, '>');
str = g_strndup (*rest, end - *rest); tmp = g_strndup (str, end - str);
type->errors = g_strsplit (str, ",", 0); type->errors = g_strsplit (tmp, ",", 0);
g_free (str); g_free (tmp);
*rest = end + 1; str = end;
} }
} }
else else
{ {
type->tag = GI_TYPE_TAG_INTERFACE; type->tag = GI_TYPE_TAG_INTERFACE;
type->is_interface = TRUE; type->is_interface = TRUE;
start = *rest; start = str;
/* must be an interface type */ /* must be an interface type */
while (g_ascii_isalnum (**rest) || while (g_ascii_isalnum (*str) ||
**rest == '.' || *str == '.' ||
**rest == '-' || *str == '-' ||
**rest == '_' || *str == '_' ||
**rest == ':') *str == ':')
(*rest)++; (str)++;
type->interface = g_strndup (start, *rest - start); type->interface = g_strndup (start, str - start);
*rest = g_strchug (*rest); if (*str == '*')
if (**rest == '*')
{ {
type->is_pointer = TRUE; type->is_pointer = TRUE;
(*rest)++; (str)++;
} }
} }
*rest = g_strchug (*rest); if (g_str_has_prefix (str, "["))
if (g_str_has_prefix (*rest, "["))
{ {
GIrNodeType *array; GIrNodeType *array;
@@ -488,15 +489,13 @@ parse_type_internal (gchar *str, gchar **rest)
array->has_length = FALSE; array->has_length = FALSE;
array->length = 0; array->length = 0;
if (!g_str_has_prefix (*rest, "[]")) if (!g_str_has_prefix (str, "[]"))
{ {
gchar *end, *str, **opts; gchar *end, *tmp, **opts;
end = strchr (*rest, ']'); end = strchr (str, ']');
str = g_strndup (*rest + 1, (end - *rest) - 1); tmp = g_strndup (str + 1, (end - str) - 1);
opts = g_strsplit (str, ",", 0); opts = g_strsplit (tmp, ",", 0);
*rest = end + 1;
for (i = 0; opts[i]; i++) for (i = 0; opts[i]; i++)
{ {
@@ -515,19 +514,24 @@ parse_type_internal (gchar *str, gchar **rest)
g_strfreev (vals); g_strfreev (vals);
} }
g_free (str); g_free (tmp);
g_strfreev (opts); g_strfreev (opts);
str = end;
} }
type = array; type = array;
} }
if (next)
*next = (char*)str;
g_assert (type->tag >= 0 && type->tag <= GI_TYPE_TAG_ERROR); g_assert (type->tag >= 0 && type->tag <= GI_TYPE_TAG_ERROR);
g_free (temporary_type);
return type; return type;
error: error:
g_ir_node_free ((GIrNode *)type); g_ir_node_free ((GIrNode *)type);
g_free (temporary_type);
return NULL; return NULL;
} }
@@ -556,14 +560,18 @@ static GIrNodeType *
parse_type (ParseContext *ctx, const gchar *type) parse_type (ParseContext *ctx, const gchar *type)
{ {
gchar *str; gchar *str;
gchar *rest;
GIrNodeType *node; GIrNodeType *node;
gboolean in_glib;
gboolean matched_special = FALSE;
in_glib = strcmp (ctx->namespace, "GLib") == 0;
type = resolve_aliases (ctx, type); type = resolve_aliases (ctx, type);
str = g_strdup (type); node = parse_type_internal (type, NULL, in_glib);
node = parse_type_internal (str, &rest); if (node)
g_free (str); g_debug ("Parsed type: %s => %d", type, node->tag);
g_debug ("Parsed type: %s => %d", type, node->tag); else
g_critical ("Failed to parse type: '%s'", type);
return node; return node;
} }