summaryrefslogtreecommitdiff
path: root/json-glib/json-parser.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@openedhand.com>2007-10-29 18:18:34 +0000
committerEmmanuele Bassi <ebassi@openedhand.com>2007-10-29 18:18:34 +0000
commit812422e4ed4df83374cdda6d94637448ab94dfef (patch)
tree49aaa5f24588572b6d81616fcfd60093cfb81807 /json-glib/json-parser.c
parent72d007d865a822875dfa311698fb2d13f5d3df69 (diff)
downloadjson-glib-812422e4ed4df83374cdda6d94637448ab94dfef.tar.gz
Backport fixes from Clutter trunk
The copy of JSON-GLib in Clutter trunk has two fixes for the JsonParser object: * support for negative numbers (ints and floats); * correct parse error propagation which should make the JsonParser hopefully complete.
Diffstat (limited to 'json-glib/json-parser.c')
-rw-r--r--json-glib/json-parser.c123
1 files changed, 103 insertions, 20 deletions
diff --git a/json-glib/json-parser.c b/json-glib/json-parser.c
index ce83b36..4700ff3 100644
--- a/json-glib/json-parser.c
+++ b/json-glib/json-parser.c
@@ -25,7 +25,9 @@
* inside a file or inside a static buffer.
*/
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include <string.h>
@@ -47,6 +49,8 @@ struct _JsonParserPrivate
JsonNode *current_node;
GScanner *scanner;
+
+ GError *last_error;
};
static const GScannerConfig json_scanner_config =
@@ -142,6 +146,12 @@ json_parser_dispose (GObject *gobject)
priv->root = NULL;
}
+ if (priv->last_error)
+ {
+ g_error_free (priv->last_error);
+ priv->last_error = NULL;
+ }
+
G_OBJECT_CLASS (json_parser_parent_class)->dispose (gobject);
}
@@ -343,6 +353,7 @@ json_parse_array (JsonParser *parser,
while (token != G_TOKEN_RIGHT_BRACE)
{
JsonNode *node = NULL;
+ gboolean negative = FALSE;
if (token == G_TOKEN_COMMA)
{
@@ -417,16 +428,34 @@ json_parse_array (JsonParser *parser,
continue;
}
+ if (token == '-')
+ {
+ guint next_token = g_scanner_peek_next_token (scanner);
+
+ if (next_token == G_TOKEN_INT ||
+ next_token == G_TOKEN_FLOAT)
+ {
+ negative = TRUE;
+ token = g_scanner_get_next_token (scanner);
+ }
+ else
+ {
+ return G_TOKEN_INT;
+ }
+ }
+
switch (token)
{
case G_TOKEN_INT:
node = json_node_new (JSON_NODE_VALUE);
- json_node_set_int (node, scanner->value.v_int);
+ json_node_set_int (node, negative ? scanner->value.v_int * -1
+ : scanner->value.v_int);
break;
case G_TOKEN_FLOAT:
node = json_node_new (JSON_NODE_VALUE);
- json_node_set_double (node, scanner->value.v_float);
+ json_node_set_double (node, negative ? scanner->value.v_float * -1.0
+ : scanner->value.v_float);
break;
case G_TOKEN_STRING:
@@ -495,6 +524,7 @@ json_parse_object (JsonParser *parser,
{
JsonNode *node = NULL;
gchar *name = NULL;
+ gboolean negative = FALSE;
if (token == G_TOKEN_COMMA)
{
@@ -541,7 +571,10 @@ json_parse_object (JsonParser *parser,
if (token != G_TOKEN_NONE)
{
g_free (name);
- json_node_free (node);
+
+ if (node)
+ json_node_free (node);
+
json_object_unref (object);
return token;
}
@@ -597,16 +630,33 @@ json_parse_object (JsonParser *parser,
continue;
}
+ if (token == '-')
+ {
+ guint next_token = g_scanner_peek_next_token (scanner);
+
+ if (next_token == G_TOKEN_INT || next_token == G_TOKEN_FLOAT)
+ {
+ negative = TRUE;
+ token = g_scanner_get_next_token (scanner);
+ }
+ else
+ {
+ return G_TOKEN_INT;
+ }
+ }
+
switch (token)
{
case G_TOKEN_INT:
node = json_node_new (JSON_NODE_VALUE);
- json_node_set_int (node, scanner->value.v_int);
+ json_node_set_int (node, negative ? scanner->value.v_int * -1
+ : scanner->value.v_int);
break;
case G_TOKEN_FLOAT:
node = json_node_new (JSON_NODE_VALUE);
- json_node_set_double (node, scanner->value.v_float);
+ json_node_set_double (node, negative ? scanner->value.v_float * -1.0
+ : scanner->value.v_float);
break;
case G_TOKEN_STRING:
@@ -626,7 +676,7 @@ json_parse_object (JsonParser *parser,
break;
default:
- return G_TOKEN_RIGHT_BRACE;
+ return G_TOKEN_SYMBOL;
}
if (node)
@@ -680,6 +730,39 @@ json_parse_statement (JsonParser *parser,
token == JSON_TOKEN_TRUE ? TRUE : FALSE);
return G_TOKEN_NONE;
+ case '-':
+ {
+ guint next_token;
+
+ token = g_scanner_get_next_token (scanner);
+ next_token = g_scanner_peek_next_token (scanner);
+
+ if (next_token == G_TOKEN_INT || next_token == G_TOKEN_FLOAT)
+ {
+ priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE);
+
+ token = g_scanner_get_next_token (scanner);
+ switch (token)
+ {
+ case G_TOKEN_INT:
+ json_node_set_int (priv->current_node,
+ scanner->value.v_int * -1);
+ break;
+ case G_TOKEN_FLOAT:
+ json_node_set_double (priv->current_node,
+ scanner->value.v_float * -1.0);
+ break;
+ default:
+ return G_TOKEN_INT;
+ }
+
+ return G_TOKEN_NONE;
+ }
+ else
+ return G_TOKEN_INT;
+ }
+ break;
+
case G_TOKEN_INT:
case G_TOKEN_FLOAT:
case G_TOKEN_STRING:
@@ -701,11 +784,11 @@ json_parse_statement (JsonParser *parser,
static void
json_scanner_msg_handler (GScanner *scanner,
gchar *message,
- gboolean is_error)
+ gboolean error)
{
JsonParser *parser = scanner->user_data;
- if (is_error)
+ if (error)
{
GError *error = NULL;
@@ -715,9 +798,8 @@ json_scanner_msg_handler (GScanner *scanner,
scanner->line,
message);
+ parser->priv->last_error = error;
g_signal_emit (parser, parser_signals[ERROR], 0, error);
-
- g_error_free (error);
}
else
g_warning ("Line %d: %s", scanner->line, message);
@@ -854,6 +936,7 @@ json_parser_load_from_data (JsonParser *parser,
{
guint expected_token;
+ /* we try to show the expected token, if possible */
expected_token = json_parse_statement (parser, scanner);
if (expected_token != G_TOKEN_NONE)
{
@@ -869,10 +952,10 @@ json_parser_load_from_data (JsonParser *parser,
{
for (i = 0; i < n_symbols; i++)
if (symbols[i].token == expected_token)
- msg = (gchar *) symbol_names + symbols[i].name_offset;
+ symbol_name = symbol_names + symbols[i].name_offset;
if (msg)
- msg = g_strconcat ("e.g. `", msg, "'", NULL);
+ msg = g_strconcat ("e.g. `", symbol_name, "'", NULL);
}
if (scanner->token > JSON_TOKEN_INVALID &&
@@ -893,15 +976,15 @@ json_parser_load_from_data (JsonParser *parser,
NULL, "keyword",
symbol_name, msg,
TRUE);
-
- /* we set a generic error here; the message from
- * GScanner is relayed in the ::error signal
+
+ /* and this will propagate the error we create in the
+ * same message handler
*/
- g_set_error (error, JSON_PARSER_ERROR,
- JSON_PARSER_ERROR_PARSE,
- "Invalid token `%s' found: expecting %s",
- symbol_name ? symbol_name : "???",
- msg ? msg : "unknown");
+ if (parser->priv->last_error)
+ {
+ g_propagate_error (error, parser->priv->last_error);
+ parser->priv->last_error = NULL;
+ }
retval = FALSE;