[glib/gsettings] Parser improvements
- From: Ryan Lortie <ryanl src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glib/gsettings] Parser improvements
- Date: Wed, 26 Aug 2009 16:22:03 +0000 (UTC)
commit 76a2aed2b0fa5fcd83597262ac5f046d9d435ddc
Author: Ryan Lortie <desrt desrt ca>
Date: Wed Aug 26 12:20:18 2009 -0400
Parser improvements
glib/gvariant-parser.c | 744 ++++++++++++++++++++++++++----------------------
glib/gvariant.h | 21 +-
2 files changed, 408 insertions(+), 357 deletions(-)
---
diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
index 297871f..a577e73 100644
--- a/glib/gvariant-parser.c
+++ b/glib/gvariant-parser.c
@@ -25,31 +25,54 @@
typedef struct
{
+ GVariantParseError error;
+
const gchar *stream;
- gchar *this;
+ const gchar *end;
+
+ const gchar *this;
} TokenStream;
static void
+set_error (GVariantParseError *error,
+ const gchar *start,
+ const gchar *end,
+ const gchar *message)
+{
+ g_assert (error->error == NULL);
+
+ error->error = g_strdup (message);
+ error->start = start;
+ error->end = end;
+}
+
+static void
token_stream_prepare (TokenStream *stream)
{
+ gint brackets = 0;
const gchar *end;
if (stream->this != NULL)
return;
- while (g_ascii_isspace (*stream->stream))
+ while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
stream->stream++;
- switch (stream->stream[0])
+ if (stream->stream == stream->end || *stream->stream == '\0')
{
- case '\0':
+ stream->this = stream->stream;
return;
+ }
+ switch (stream->stream[0])
+ {
case '-': case '+': case '.': case '0': case '1': case '2':
case '3': case '4': case '5': case '6': case '7': case '8':
case '9':
- for (end = stream->stream; g_ascii_isalnum (*end) ||
- *end == '-' || *end == '+' || *end == '.'; end++);
+ for (end = stream->stream; end != stream->end; end++)
+ if (!g_ascii_isalnum (*end) &&
+ *end != '-' && *end != '+' && *end != '.')
+ break;
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
@@ -57,27 +80,35 @@ token_stream_prepare (TokenStream *stream)
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
- for (end = stream->stream; g_ascii_isalnum (*end); end++);
+ for (end = stream->stream; end != stream->end; end++)
+ if (!g_ascii_isalnum (*end))
+ break;
break;
- case '@':
+ case '@': case '%':
+ /* stop at the first space or unmatched bracket.
+ * deals nicely with cases like (%i, %i).
+ */
for (end = stream->stream + 1;
- *end && strchr ("abdgimnoqrstuvxy(){}*?", *end); end++);
- break;
+ end != stream->end && !g_ascii_isspace (*end);
+ end++)
+
+ if (*end == '(' || *end == '{')
+ brackets++;
+
+ else if ((*end == ')' || *end == '}') && !brackets--)
+ break;
- case '%':
- end = stream->stream + 1;
- g_variant_format_string_scan (&end);
break;
case '\'': case '"':
- for (end = stream->stream + 1;
- *end && *end != stream->stream[0] && (*end != '\\' || *++end);
- end++);
+ for (end = stream->stream + 1; end != stream->end; end++)
+ if (*end == stream->stream[0] || *end == '\0' ||
+ (*end == '\\' && (++end == stream->end || *end == '\0')))
+ break;
- if (*end)
+ if (end != stream->end && *end)
end++;
-
break;
default:
@@ -85,14 +116,13 @@ token_stream_prepare (TokenStream *stream)
break;
}
- stream->this = g_strndup (stream->stream, end - stream->stream);
+ stream->this = stream->stream;
stream->stream = end;
}
static void
token_stream_next (TokenStream *stream)
{
- g_free (stream->this);
stream->this = NULL;
}
@@ -102,7 +132,7 @@ token_stream_peek (TokenStream *stream,
{
token_stream_prepare (stream);
- return stream->this && stream->this[0] == first_char;
+ return stream->this[0] == first_char;
}
static gboolean
@@ -110,8 +140,7 @@ token_stream_is_keyword (TokenStream *stream)
{
token_stream_prepare (stream);
- return stream->this &&
- g_ascii_isalpha (stream->this[0]);
+ return g_ascii_isalpha (stream->this[0]);
}
static gboolean
@@ -119,8 +148,7 @@ token_stream_is_numeric (TokenStream *stream)
{
token_stream_prepare (stream);
- return stream->this &&
- (g_ascii_isdigit (stream->this[0]) ||
+ return (g_ascii_isdigit (stream->this[0]) ||
stream->this[0] == '-' ||
stream->this[0] == '+' ||
stream->this[0] == '.');
@@ -130,9 +158,12 @@ static gboolean
token_stream_consume (TokenStream *stream,
const gchar *token)
{
+ gint length = strlen (token);
+
token_stream_prepare (stream);
- if (g_strcmp0 (stream->this, token) == 0)
+ if (stream->stream - stream->this == length &&
+ memcmp (stream->this, token, length) == 0)
{
token_stream_next (stream);
return TRUE;
@@ -141,6 +172,26 @@ token_stream_consume (TokenStream *stream,
return FALSE;
}
+static gboolean
+token_stream_require (TokenStream *stream,
+ const gchar *token,
+ const gchar *purpose)
+{
+
+ if (!token_stream_consume (stream, token))
+ {
+ gchar *message;
+
+ message = g_strdup_printf ("expected `%s'%s", token, purpose);
+ set_error (&stream->error, stream->this, stream->this, message);
+ g_free (message);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
token_stream_assert (TokenStream *stream,
const gchar *token)
@@ -158,8 +209,7 @@ token_stream_get (TokenStream *stream)
token_stream_prepare (stream);
- result = stream->this;
- stream->this = NULL;
+ result = g_strndup (stream->this, stream->stream - stream->this);
return result;
}
@@ -319,10 +369,10 @@ pattern_from_constraints (Constraints constraints)
typedef struct _AST AST;
typedef Pattern * (*get_pattern_func) (AST *ast,
- GError **error);
+ GVariantParseError *error);
typedef GVariant * (*get_value_func) (AST *ast,
const GVariantType *type,
- GError **error);
+ GVariantParseError *error);
typedef GSList * (*get_examples_func) (AST *ast,
gint index,
Constraints *constraints);
@@ -339,11 +389,14 @@ typedef struct
struct _AST
{
const ASTClass *class;
+
+ const gchar *start;
+ const gchar *end;
};
static Pattern *
-ast_get_pattern (AST *ast,
- GError **error)
+ast_get_pattern (AST *ast,
+ GVariantParseError *error)
{
return ast->class->get_pattern (ast, error);
}
@@ -364,9 +417,9 @@ ast_get_pattern_size (AST *ast)
}
static GVariant *
-ast_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+ast_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
return ast->class->get_value (ast, type, error);
}
@@ -380,8 +433,8 @@ ast_get_examples (AST *ast,
}
static GVariant *
-ast_resolve (AST *ast,
- GError **error)
+ast_resolve (AST *ast,
+ GVariantParseError *error)
{
Pattern *pattern;
GVariant *value;
@@ -407,12 +460,11 @@ ast_resolve (AST *ast,
examples = ast_get_examples (ast, i, &constraints);
g_assert_cmpint (g_slist_length (examples), ==, 2);
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_TYPE_MISMATCH,
- "Unable to infer a type to contain both "
- "'%s' and '%s'",
- (gchar *) examples->data,
- (gchar *) examples->next->data);
+ set_error (error,
+ "Unable to infer a type to contain both "
+ "'%s' and '%s'",
+ (gchar *) examples->data,
+ (gchar *) examples->next->data);
g_slist_free (examples);
pattern_free (pattern);
@@ -436,9 +488,8 @@ ast_free (AST *ast)
ast->class->free (ast);
}
-static AST *parse (TokenStream *stream,
- va_list *app,
- GError **error);
+static AST *parse (TokenStream *stream,
+ va_list *app);
static void
ast_array_append (AST ***array,
@@ -462,6 +513,22 @@ ast_array_free (AST **array,
g_free (array);
}
+static void
+ast_set_error (AST *ast,
+ GVariantParseError *error,
+ const gchar *format,
+ ...)
+{
+ gchar *message;
+ va_list ap;
+
+ va_start (ap, format);
+ message = g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ set_error (error, ast->start, ast->end, message);
+}
+
typedef struct
{
AST ast;
@@ -471,8 +538,8 @@ typedef struct
} Array;
static Pattern *
-array_get_pattern (AST *ast,
- GError **error)
+array_get_pattern (AST *ast,
+ GVariantParseError *error)
{
Array *array = (Array *) ast;
Pattern *result = NULL;
@@ -481,9 +548,7 @@ array_get_pattern (AST *ast,
if (array->n_children == 0)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_EMPTY_ARRAY,
- "unable to infer the type of an empty array");
+ ast_set_error (ast, error, "unable to infer type of empty array");
return NULL;
}
@@ -503,11 +568,11 @@ array_get_pattern (AST *ast,
if (!pattern_coalesce (child_type, other_child_type))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_TYPE_MISMATCH,
- "unable to coalesce types '%s' and '%s'",
- child_type->type_string,
- other_child_type->type_string);
+ ast_set_error (ast, error,
+ "unable to coalesce types '%s' and '%s'",
+ child_type->type_string,
+ other_child_type->type_string);
+
pattern_free (other_child_type);
break;
@@ -531,9 +596,9 @@ array_get_pattern (AST *ast,
}
static GVariant *
-array_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+array_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Array *array = (Array *) ast;
const GVariantType *childtype;
@@ -594,9 +659,8 @@ array_free (AST *ast)
}
static AST *
-array_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+array_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass array_class = {
array_get_pattern,
@@ -617,15 +681,12 @@ array_parse (TokenStream *stream,
{
AST *child;
- if (need_comma && !token_stream_consume (stream, ","))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting ',' or ')' to follow tuple element");
- goto error;
- }
+ if (need_comma &&
+ !token_stream_require (stream, ",",
+ " or ']' to follow array element"))
+ goto error;
- child = parse (stream, app, error);
+ child = parse (stream, app);
if (!child)
goto error;
@@ -652,8 +713,8 @@ typedef struct
} Tuple;
static Pattern *
-tuple_get_pattern (AST *ast,
- GError **error)
+tuple_get_pattern (AST *ast,
+ GVariantParseError *error)
{
Tuple *tuple = (Tuple *) ast;
Pattern *result = NULL;
@@ -692,9 +753,9 @@ tuple_get_pattern (AST *ast,
}
static GVariant *
-tuple_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+tuple_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Tuple *tuple = (Tuple *) ast;
const GVariantType *childtype;
@@ -759,9 +820,8 @@ tuple_free (AST *ast)
}
static AST *
-tuple_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+tuple_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass tuple_class = {
tuple_get_pattern,
@@ -782,15 +842,12 @@ tuple_parse (TokenStream *stream,
{
AST *child;
- if (need_comma && !token_stream_consume (stream, ","))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting ',' or ')' to follow tuple element");
- goto error;
- }
+ if (need_comma &&
+ !token_stream_require (stream, ",",
+ " or ')' to follow tuple element"))
+ goto error;
- child = parse (stream, app, error);
+ child = parse (stream, app);
if (!child)
goto error;
@@ -816,16 +873,16 @@ typedef struct
} Variant;
static Pattern *
-variant_get_pattern (AST *ast,
- GError **error)
+variant_get_pattern (AST *ast,
+ GVariantParseError *error)
{
return pattern_from_class (G_VARIANT_TYPE_CLASS_VARIANT);
}
static GVariant *
-variant_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+variant_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Variant *variant = (Variant *) ast;
@@ -851,9 +908,8 @@ variant_free (AST *ast)
}
static AST *
-variant_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+variant_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass variant_class = {
variant_get_pattern,
@@ -865,16 +921,13 @@ variant_parse (TokenStream *stream,
AST *value;
token_stream_assert (stream, "<");
- value = parse (stream, app, error);
+ value = parse (stream, app);
if (!value)
return NULL;
- if (!token_stream_consume (stream, ">"))
+ if (!token_stream_require (stream, ">", " to follow variant value"))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting '>' to follow variant value");
ast_free (value);
return NULL;
}
@@ -896,8 +949,8 @@ typedef struct
} Dictionary;
static Pattern *
-dictionary_get_pattern (AST *ast,
- GError **error)
+dictionary_get_pattern (AST *ast,
+ GVariantParseError *error)
{
Dictionary *dict = (Dictionary *) ast;
Pattern *result = NULL;
@@ -907,9 +960,8 @@ dictionary_get_pattern (AST *ast,
if (dict->n_children == 0)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_EMPTY_ARRAY,
- "unable to infer the type of an empty dictionary");
+ ast_set_error (ast, error,
+ "unable to infer the type of an empty dictionary");
return NULL;
}
@@ -938,19 +990,18 @@ dictionary_get_pattern (AST *ast,
if (!strchr ("bynqiuxtdsog?", other_pattern->type_string[0]))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_EMPTY_ARRAY,
- "dictionary keys must have basic types");
+ ast_set_error (ast, error, "dictionary keys must have basic types");
pattern_free (other_pattern);
break;
}
if (!pattern_coalesce (key_pattern, other_pattern))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_TYPE_MISMATCH,
- "unable to coalesce types '%s' and '%s'",
- key_pattern->type_string, other_pattern->type_string);
+ ast_set_error (ast, error,
+ "unable to coalesce types '%s' and '%s'",
+ key_pattern->type_string,
+ other_pattern->type_string);
+
pattern_free (other_pattern);
break;
@@ -966,10 +1017,11 @@ dictionary_get_pattern (AST *ast,
if (!pattern_coalesce (value_pattern, other_pattern))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_TYPE_MISMATCH,
- "unable to coalesce types '%s' and '%s'",
- key_pattern->type_string, other_pattern->type_string);
+ ast_set_error (ast, error,
+ "unable to coalesce types '%s' and '%s'",
+ key_pattern->type_string,
+ other_pattern->type_string);
+
pattern_free (other_pattern);
break;
@@ -999,9 +1051,9 @@ dictionary_get_pattern (AST *ast,
}
static GVariant *
-dictionary_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+dictionary_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Dictionary *dict = (Dictionary *) ast;
@@ -1129,9 +1181,8 @@ dictionary_free (AST *ast)
}
static AST *
-dictionary_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+dictionary_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass dictionary_class = {
dictionary_get_pattern,
@@ -1152,34 +1203,26 @@ dictionary_parse (TokenStream *stream,
token_stream_assert (stream, "{");
- if ((first = parse (stream, app, error)) == NULL)
+ if ((first = parse (stream, app)) == NULL)
goto error;
ast_array_append (&dict->keys, &n_keys, first);
only_one = token_stream_consume (stream, ",");
- if (!only_one && !token_stream_consume (stream, ":"))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting ',' or ':' to follow dictionary entry key");
- goto error;
- }
+ if (!only_one &&
+ !token_stream_require (stream, ":",
+ " or ':' to follow dictionary entry key"))
+ goto error;
- if ((first = parse (stream, app, error)) == NULL)
+ if ((first = parse (stream, app)) == NULL)
goto error;
ast_array_append (&dict->values, &n_values, first);
if (only_one)
{
- if (!token_stream_consume (stream, "}"))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting '}' at end of dictionary entry");
- goto error;
- }
+ if (!token_stream_require (stream, "}", " at end of dictionary entry"))
+ goto error;
g_assert (n_keys == 1 && n_values == 1);
dict->n_children = -1;
@@ -1191,30 +1234,22 @@ dictionary_parse (TokenStream *stream,
{
AST *child;
- if (!token_stream_consume (stream, ","))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting ',' or '}' to follow dictionary entry");
- goto error;
- }
+ if (!token_stream_require (stream, ",",
+ " or '}' to follow dictionary entry"))
+ goto error;
- child = parse (stream, app, error);
+ child = parse (stream, app);
if (!child)
goto error;
ast_array_append (&dict->keys, &n_keys, child);
- if (!token_stream_consume (stream, ":"))
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting ':' to follow dictionary entry key");
- goto error;
- }
+ if (!token_stream_require (stream, ":",
+ " to follow dictionary entry key"))
+ goto error;
- child = parse (stream, app, error);
+ child = parse (stream, app);
if (!child)
goto error;
@@ -1239,8 +1274,8 @@ typedef struct
{
AST ast;
- gchar *token;
gchar *string;
+ gchar *token;
} Terminal;
static Constraints
@@ -1256,8 +1291,8 @@ constraints_from_string (const gchar *token)
}
static Pattern *
-terminal_get_pattern (AST *ast,
- GError **error)
+terminal_get_pattern (AST *ast,
+ GVariantParseError *error)
{
Terminal *terminal = (Terminal *) ast;
Constraints constraints;
@@ -1268,9 +1303,10 @@ terminal_get_pattern (AST *ast,
}
static gboolean
-parse_string (const gchar *token,
- gchar **result,
- GError **error)
+parse_string (const gchar *token,
+ gchar **result,
+ const gchar *start,
+ GVariantParseError *error)
{
gint length;
gchar *tmp;
@@ -1279,9 +1315,8 @@ parse_string (const gchar *token,
if (length < 2 || token[0] != token[length - 1])
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unterminated string constant");
+ set_error (error, start, start + strlen (token),
+ "unterminated string constant");
return FALSE;
}
@@ -1293,11 +1328,12 @@ parse_string (const gchar *token,
}
static gboolean
-parse_signed (const gchar *token,
- gint64 min,
- gint64 max,
- gint64 *result,
- GError **error)
+parse_signed (const gchar *token,
+ gint64 min,
+ gint64 max,
+ gint64 *result,
+ AST *ast,
+ GVariantParseError *error)
{
gint64 value;
gchar *end;
@@ -1307,17 +1343,15 @@ parse_signed (const gchar *token,
if (errno == ERANGE || value < min || value > max)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Signed integer '%s' is too large for type", token);
+ ast_set_error (ast, error,
+ "Signed integer '%s' is too large for type", token);
return FALSE;
}
if (*end)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unable to parse signed integer '%s'\n", token);
+ ast_set_error (ast, error,
+ "Unable to parse signed integer '%s'", token);
return FALSE;
}
@@ -1327,10 +1361,11 @@ parse_signed (const gchar *token,
}
static gboolean
-parse_unsigned (const gchar *token,
- guint64 max,
- guint64 *result,
- GError **error)
+parse_unsigned (const gchar *token,
+ guint64 max,
+ guint64 *result,
+ AST *ast,
+ GVariantParseError *error)
{
guint64 value;
gchar *end;
@@ -1344,18 +1379,16 @@ parse_unsigned (const gchar *token,
if (errno == ERANGE || value > max)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unsigned integer '%s' is too large for type", token);
+ ast_set_error (ast, error,
+ "Unsigned integer '%s' is too large for type", token);
return FALSE;
}
if (*end)
{
error:
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unable to parse unsigned integer '%s'\n", token);
+ ast_set_error (ast, error,
+ "Unable to parse unsigned integer '%s'", token);
return FALSE;
}
@@ -1365,9 +1398,10 @@ parse_unsigned (const gchar *token,
}
static gboolean
-parse_floating (const gchar *token,
- gdouble *result,
- GError **error)
+parse_floating (const gchar *token,
+ gdouble *result,
+ AST *ast,
+ GVariantParseError *error)
{
gdouble value;
gchar *end;
@@ -1377,17 +1411,15 @@ parse_floating (const gchar *token,
if (errno == ERANGE)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Floating point value '%s' is too large", token);
+ ast_set_error (ast, error,
+ "Floating point value '%s' is too large", token);
return FALSE;
}
if (*end)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unable to parse floating point value '%s'\n", token);
+ ast_set_error (ast, error,
+ "Unable to parse floating point value '%s'", token);
return FALSE;
}
@@ -1397,9 +1429,9 @@ parse_floating (const gchar *token,
}
static GVariant *
-terminal_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+terminal_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Terminal *terminal = (Terminal *) ast;
@@ -1407,41 +1439,28 @@ terminal_get_value (AST *ast,
{
case G_VARIANT_TYPE_CLASS_BOOLEAN:
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unable to parse as boolean: %s", terminal->token);
+ ast_set_error (ast, error,
+ "Unable to parse as boolean: %s", terminal->token);
return NULL;
}
case G_VARIANT_TYPE_CLASS_BYTE:
- if (terminal->token[0] == '\'' || terminal->token[0] == '"')
+ if (terminal->string != NULL)
{
- gchar *string;
- gchar value;
-
- if (!parse_string (terminal->token, &string, error))
- return NULL;
-
- if (strlen (string) != 1)
+ if (strlen (terminal->string) != 1)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Character constants must be one character");
- g_free (string);
-
+ ast_set_error (ast, error,
+ "Character constants must be one character");
return NULL;
}
- value = string[0];
- g_free (string);
-
- return g_variant_new_byte (value);
+ return g_variant_new_byte (terminal->string[0]);
}
else
{
guint64 value;
- if (!parse_unsigned (terminal->token, 255, &value, error))
+ if (!parse_unsigned (terminal->token, 255, &value, ast, error))
return NULL;
return g_variant_new_byte (value);
@@ -1453,7 +1472,7 @@ terminal_get_value (AST *ast,
if (!parse_signed (terminal->token,
G_MININT16, G_MAXINT16,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_int16 (value);
@@ -1465,7 +1484,7 @@ terminal_get_value (AST *ast,
if (!parse_unsigned (terminal->token,
G_MAXUINT16,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_uint16 (value);
@@ -1477,7 +1496,7 @@ terminal_get_value (AST *ast,
if (!parse_signed (terminal->token,
G_MININT32, G_MAXINT32,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_int32 (value);
@@ -1489,7 +1508,7 @@ terminal_get_value (AST *ast,
if (!parse_unsigned (terminal->token,
G_MAXUINT32,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_uint32 (value);
@@ -1501,7 +1520,7 @@ terminal_get_value (AST *ast,
if (!parse_signed (terminal->token,
G_MININT64, G_MAXINT64,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_int64 (value);
@@ -1513,7 +1532,7 @@ terminal_get_value (AST *ast,
if (!parse_unsigned (terminal->token,
G_MAXUINT64,
- &value, error))
+ &value, ast, error))
return NULL;
return g_variant_new_uint64 (value);
@@ -1523,7 +1542,7 @@ terminal_get_value (AST *ast,
{
gdouble floating;
- if (!parse_floating (terminal->token, &floating, error))
+ if (!parse_floating (terminal->token, &floating, ast, error))
return NULL;
return g_variant_new_double (floating);
@@ -1531,20 +1550,13 @@ terminal_get_value (AST *ast,
case G_VARIANT_TYPE_CLASS_STRING:
{
- GVariant *value;
-
if (terminal->string == NULL)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unable to parse as a string: %s",
- terminal->token);
+ ast_set_error (ast, error, "unable to parse as string");
return NULL;
}
- value = g_variant_new_string (terminal->string);
-
- return value;
+ return g_variant_new_string (terminal->string);
}
default:
@@ -1578,14 +1590,12 @@ terminal_free (AST *ast)
Terminal *terminal = (Terminal *) ast;
g_free (terminal->token);
- g_free (terminal->string);
g_slice_free (Terminal, terminal);
}
static AST *
-terminal_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+terminal_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass terminal_class = {
terminal_get_pattern,
@@ -1599,17 +1609,9 @@ terminal_parse (TokenStream *stream,
token = token_stream_get (stream);
- if (token == NULL)
- {
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "expecting token");
- return NULL;
- }
-
if (token[0] == '"' || token[0] == '\'')
{
- if (!parse_string (token, &string, error))
+ if (!parse_string (token, &string, stream->this, &stream->error))
{
g_free (token);
return NULL;
@@ -1623,6 +1625,8 @@ terminal_parse (TokenStream *stream,
terminal->token = token;
terminal->string = string;
+ token_stream_next (stream);
+
return (AST *) terminal;
}
@@ -1633,8 +1637,8 @@ typedef struct
} Boolean;
static Pattern *
-boolean_get_pattern (AST *ast,
- GError **error)
+boolean_get_pattern (AST *ast,
+ GVariantParseError *error)
{
/* do this as a constraint so that
* we get more consistent errors
@@ -1643,9 +1647,9 @@ boolean_get_pattern (AST *ast,
}
static GVariant *
-boolean_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+boolean_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Boolean *boolean = (Boolean *) ast;
@@ -1708,8 +1712,8 @@ typedef struct
} Positional;
static Pattern *
-positional_get_pattern (AST *ast,
- GError **error)
+positional_get_pattern (AST *ast,
+ GVariantParseError *error)
{
Positional *positional = (Positional *) ast;
@@ -1717,9 +1721,9 @@ positional_get_pattern (AST *ast,
}
static GVariant *
-positional_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+positional_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
Positional *positional = (Positional *) ast;
GVariant *tmp;
@@ -1755,9 +1759,8 @@ positional_free (AST *ast)
}
static AST *
-positional_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+positional_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass positional_class = {
positional_get_pattern,
@@ -1780,9 +1783,8 @@ positional_parse (TokenStream *stream,
if (*format)
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "invalid GVariant format string: %s", token + 1);
+ set_error (&stream->error, stream->stream, stream->stream,
+ "invalid GVariant format string");
g_variant_unref (g_variant_ref_sink (positional->value));
g_slice_free (Positional, positional);
@@ -1791,6 +1793,7 @@ positional_parse (TokenStream *stream,
return NULL;
}
+ token_stream_next (stream);
g_free (token);
return (AST *) positional;
@@ -1805,8 +1808,8 @@ typedef struct
} TypeDecl;
static Pattern *
-typedecl_get_pattern (AST *ast,
- GError **error)
+typedecl_get_pattern (AST *ast,
+ GVariantParseError *error)
{
TypeDecl *decl = (TypeDecl *) ast;
@@ -1814,9 +1817,9 @@ typedecl_get_pattern (AST *ast,
}
static GVariant *
-typedecl_get_value (AST *ast,
- const GVariantType *type,
- GError **error)
+typedecl_get_value (AST *ast,
+ const GVariantType *type,
+ GVariantParseError *error)
{
TypeDecl *decl = (TypeDecl *) ast;
@@ -1842,9 +1845,8 @@ typedecl_free (AST *ast)
}
static AST *
-typedecl_parse (TokenStream *stream,
- va_list *app,
- GError **error)
+typedecl_parse (TokenStream *stream,
+ va_list *app)
{
static const ASTClass typedecl_class = {
typedecl_get_pattern,
@@ -1864,9 +1866,8 @@ typedecl_parse (TokenStream *stream,
if (!g_variant_type_string_is_valid (token + 1))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Invalid type declaration '%s'", token);
+ set_error (&stream->error, stream->stream, stream->stream,
+ "Invalid type declaration");
g_free (token);
return NULL;
@@ -1876,15 +1877,15 @@ typedecl_parse (TokenStream *stream,
if (!g_variant_type_is_concrete (type))
{
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Type declarations must be concrete: '%s'", token);
+ set_error (&stream->error, stream->stream, stream->stream,
+ "Type declarations must be concrete");
g_variant_type_free (type);
g_free (token);
return NULL;
}
+ token_stream_next (stream);
g_free (token);
}
else
@@ -1927,19 +1928,14 @@ typedecl_parse (TokenStream *stream,
else
{
- gchar *token;
-
- token = token_stream_get (stream);
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "unknown keyword: %s", token);
- g_free (token);
+ set_error (&stream->error, stream->stream, stream->stream,
+ "unknown keyword");
return NULL;
}
}
- if ((child = parse (stream, app, error)) == NULL)
+ if ((child = parse (stream, app)) == NULL)
{
g_variant_type_free (type);
return NULL;
@@ -1954,87 +1950,139 @@ typedecl_parse (TokenStream *stream,
}
static AST *
-parse (TokenStream *stream,
- va_list *app,
- GError **error)
+parse (TokenStream *stream,
+ va_list *app)
{
+ const gchar *start;
+ AST *result;
+
+ token_stream_prepare (stream);
+ start = stream->this;
+
if (token_stream_peek (stream, '['))
- return array_parse (stream, app, error);
+ result = array_parse (stream, app);
- if (token_stream_peek (stream, '('))
- return tuple_parse (stream, app, error);
+ else if (token_stream_peek (stream, '('))
+ result = tuple_parse (stream, app);
- if (token_stream_peek (stream, '<'))
- return variant_parse (stream, app, error);
+ else if (token_stream_peek (stream, '<'))
+ result = variant_parse (stream, app);
- if (token_stream_peek (stream, '{'))
- return dictionary_parse (stream, app, error);
+ else if (token_stream_peek (stream, '{'))
+ result = dictionary_parse (stream, app);
- if (app && token_stream_peek (stream, '%'))
- return positional_parse (stream, app, error);
+ else if (app && token_stream_peek (stream, '%'))
+ result = positional_parse (stream, app);
- if (token_stream_consume (stream, "true"))
- return boolean_new (TRUE);
+ else if (token_stream_consume (stream, "true"))
+ result = boolean_new (TRUE);
- if (token_stream_consume (stream, "false"))
- return boolean_new (FALSE);
+ else if (token_stream_consume (stream, "false"))
+ result = boolean_new (FALSE);
- if (token_stream_peek (stream, '@') || token_stream_is_keyword (stream))
- return typedecl_parse (stream, app, error);
+ else if (token_stream_peek (stream, '@') || token_stream_is_keyword (stream))
+ result = typedecl_parse (stream, app);
- if (token_stream_is_numeric (stream) ||
- token_stream_peek (stream, '\'') ||
- token_stream_peek (stream, '"'))
- return terminal_parse (stream, app, error);
+ else if (token_stream_is_numeric (stream) ||
+ token_stream_peek (stream, '\'') ||
+ token_stream_peek (stream, '"'))
+ result = terminal_parse (stream, app);
- {
- gchar *token;
+ else
+ {
+ gchar *token = token_stream_get (stream);
- token = token_stream_get (stream);
+ if (token[0])
+ {
+ gchar *escaped = g_strescape (token, 0);
+ set_error (&stream->error, stream->this, stream->stream,
+ "stray symbol");
+ g_free (escaped);
+ }
+ else
+ {
+ set_error (&stream->error, stream->stream, stream->stream,
+ "expected value");
+ }
- if (token)
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Don't know what to do with token: %s\n", token);
+ g_free (token);
- else
- g_set_error (error, G_VARIANT_PARSE_ERROR,
- G_VARIANT_PARSE_ERROR_SYNTAX,
- "Unexpected end of text");
+ return NULL;
+ }
- g_free (token);
+ if (result != NULL)
+ {
+ result->start = start;
+ result->end = stream->stream;
+ }
- return NULL;
- }
+ return result;
+}
+
+GVariant *
+g_variant_parse_full (const gchar **text,
+ const gchar *end,
+ const GVariantType *type,
+ GVariantParseError *error)
+{
+ TokenStream stream = { };
+ GVariant *result = NULL;
+ AST *ast;
+
+ g_return_val_if_fail (text != NULL, NULL);
+ g_return_val_if_fail (*text == end || *text != NULL, NULL);
+
+ stream.stream = *text;
+ stream.end = end;
+
+ if ((ast = parse (&stream, NULL)))
+ {
+ result = ast_resolve (ast, &stream.error);
+
+ if (result != NULL)
+ *text = stream.stream;
+
+ ast_free (ast);
+ }
+
+ if (error != NULL)
+ *error = stream.error;
+
+ return result;
}
GVariant *
g_variant_parsef_va (const gchar *format,
va_list *app)
{
- TokenStream stream = { format };
- GError *error = NULL;
- GVariant *result;
+ TokenStream stream = { };
+ GVariant *result = NULL;
AST *ast;
g_return_val_if_fail (format != NULL, NULL);
g_return_val_if_fail (app != NULL, NULL);
- if ((ast = parse (&stream, app, &error)) == NULL)
- {
- g_critical ("g_variant_parsef: %s", error->message);
- g_error_free (error);
+ stream.stream = format;
+ stream.end = NULL;
- return NULL;
+ if ((ast = parse (&stream, app)))
+ {
+ result = ast_resolve (ast, &stream.error);
+ ast_free (ast);
}
- result = ast_resolve (ast, &error);
- ast_free (ast);
+ if (result != NULL)
+ {
+ while (g_ascii_isspace (*stream.stream))
+ stream.stream++;
- if (result == NULL)
+ if (*stream.stream)
+ g_critical ("g_variant_parsef: trailing text after value");
+ }
+ else
{
- g_critical ("g_variant_parsef: %s", error->message);
- g_error_free (error);
+ g_critical ("g_variant_parsef: %s", stream.error.error);
+ g_free (stream.error.error);
}
return result;
@@ -2060,29 +2108,31 @@ g_variant_parse (const gchar *text,
const GVariantType *type,
GError **error)
{
- TokenStream stream = { text };
+ GVariantParseError parse_error;
GVariant *result;
- gchar *tmp;
- AST *ast;
+ const gchar *end;
g_return_val_if_fail (text != NULL || text_length == 0, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- if (text_length != -1)
- {
- tmp = g_strndup (text, text_length);
- stream.stream = tmp;
- }
+ if (text_length >= 0)
+ end = text + text_length;
else
- tmp = NULL;
-
- if ((ast = parse (&stream, NULL, error)) == NULL)
- return NULL;
+ end = NULL;
- result = ast_resolve (ast, error);
- ast_free (ast);
+ if ((result = g_variant_parse_full (&text, end, type, &parse_error)))
+ {
+ while (g_ascii_isspace (*text))
+ text++;
- g_free (tmp);
+ if (*text)
+ g_set_error_literal (error, 0, 0, "trailing text after value");
+ }
+ else
+ {
+ g_set_error_literal (error, 0, 0, parse_error.error);
+ g_free (parse_error.error);
+ }
return result;
}
diff --git a/glib/gvariant.h b/glib/gvariant.h
index 0056a61..d408642 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -146,6 +146,13 @@ GVariant *g_variant_builder_end (GVarian
void g_variant_builder_cancel (GVariantBuilder *builder);
/* text printing/parsing */
+typedef struct
+{
+ const gchar *start;
+ const gchar *end;
+ gchar *error;
+} GVariantParseError;
+
gchar *g_variant_print (GVariant *value,
gboolean type_annotate);
GString *g_variant_print_string (GVariant *value,
@@ -159,6 +166,10 @@ GVariant * g_variant_parsef (const g
...);
GVariant * g_variant_parsef_va (const gchar *format,
va_list *app);
+GVariant * g_variant_parse_full (const gchar **text,
+ const gchar *end,
+ const GVariantType *type,
+ GVariantParseError *error);
/* markup printing/parsing */
gchar *g_variant_markup_print (GVariant *value,
@@ -196,14 +207,4 @@ typedef enum
G_VARIANT_BUILDER_ERROR_TYPE
} GVariantBuilderError;
-#define G_VARIANT_PARSE_ERROR \
- (g_quark_from_string ("GVariantParseError"))
-
-typedef enum
-{
- G_VARIANT_PARSE_ERROR_EMPTY_ARRAY,
- G_VARIANT_PARSE_ERROR_TYPE_MISMATCH,
- G_VARIANT_PARSE_ERROR_SYNTAX,
-} GVariantParseError;
-
#endif /* _gvariant_h_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]