static guint json_parse_statement (JsonParser *parser, JsonScanner *scanner) { JsonParserPrivate *priv = parser->priv; guint token; token = json_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Statement is object declaration"); return json_parse_object (parser, scanner, &priv->root); case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Statement is array declaration"); return json_parse_array (parser, scanner, &priv->root); /* some web APIs are not only passing the data structures: they are * also passing an assigment, which makes parsing horribly complicated * only because web developers are lazy, and writing "var foo = " is * evidently too much to request from them. */ case JSON_TOKEN_VAR: { guint next_token; gchar *name; JSON_NOTE (PARSER, "Statement is an assignment"); /* swallow the 'var' token... */ token = json_scanner_get_next_token (scanner); /* ... swallow the variable name... */ next_token = json_scanner_get_next_token (scanner); if (next_token != G_TOKEN_IDENTIFIER) { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_IDENTIFIER; } name = g_strdup (scanner->value.v_identifier); /* ... and finally swallow the '=' */ next_token = json_scanner_get_next_token (scanner); if (next_token != '=') { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; g_free (name); return '='; } priv->has_assignment = TRUE; priv->variable_name = name; token = json_parse_statement (parser, scanner); /* remove the trailing semi-colon */ next_token = json_scanner_peek_next_token (scanner); if (next_token == ';') { token = json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } return token; } break; case JSON_TOKEN_NULL: case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case '-': case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case G_TOKEN_IDENTIFIER: JSON_NOTE (PARSER, "Statement is a value"); token = json_scanner_get_next_token (scanner); return json_parse_value (parser, scanner, token, &priv->root); default: JSON_NOTE (PARSER, "Unknown statement"); json_scanner_get_next_token (scanner); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_SYMBOL; } }
static gboolean json_parser_load (JsonParser *parser, const gchar *data, gsize length, GError **error) { JsonParserPrivate *priv = parser->priv; JsonScanner *scanner; gboolean done; gboolean retval = TRUE; gint i; json_parser_clear (parser); if (!g_utf8_validate (data, -1, NULL)) { g_set_error_literal (error, JSON_PARSER_ERROR, JSON_PARSER_ERROR_INVALID_DATA, _("JSON data must be UTF-8 encoded")); g_signal_emit (parser, parser_signals[ERROR], 0, *error); return FALSE; } scanner = json_scanner_create (parser); json_scanner_input_text (scanner, data, length); priv->scanner = scanner; g_signal_emit (parser, parser_signals[PARSE_START], 0); done = FALSE; while (!done) { if (json_scanner_peek_next_token (scanner) == G_TOKEN_EOF) done = TRUE; else { guint expected_token; gint cur_token; /* we try to show the expected token, if possible */ expected_token = json_parse_statement (parser, scanner); if (expected_token != G_TOKEN_NONE) { const gchar *symbol_name; gchar *msg; cur_token = scanner->token; msg = NULL; symbol_name = NULL; if (scanner->scope_id == 0) { if (expected_token > JSON_TOKEN_INVALID && expected_token < JSON_TOKEN_LAST) { for (i = 0; i < n_symbols; i++) if (symbols[i].token == expected_token) symbol_name = symbol_names + symbols[i].name_offset; if (!msg) msg = g_strconcat ("e.g. '", symbol_name, "'", NULL); } if (cur_token > JSON_TOKEN_INVALID && cur_token < JSON_TOKEN_LAST) { symbol_name = "???"; for (i = 0; i < n_symbols; i++) if (symbols[i].token == cur_token) symbol_name = symbol_names + symbols[i].name_offset; } } /* this will emit the ::error signal via the custom * message handler we install */ json_scanner_unexp_token (scanner, expected_token, NULL, "value", symbol_name, msg); /* and this will propagate the error we create in the * same message handler */ if (priv->last_error) { g_propagate_error (error, priv->last_error); priv->last_error = NULL; } retval = FALSE; g_free (msg); done = TRUE; } } } g_signal_emit (parser, parser_signals[PARSE_END], 0); /* remove the scanner */ json_scanner_destroy (scanner); priv->scanner = NULL; priv->current_node = NULL; return retval; }
static guint json_parse_statement (JsonParser *parser, JsonScanner *scanner) { JsonParserPrivate *priv = parser->priv; guint token; token = json_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: return json_parse_object (parser, scanner, &priv->root); case G_TOKEN_LEFT_BRACE: return json_parse_array (parser, scanner, &priv->root); /* some web APIs are not only passing the data structures: they are * also passing an assigment, which makes parsing horribly complicated * only because web developers are lazy, and writing "var foo = " is * evidently too much to request from them. */ case JSON_TOKEN_VAR: { guint next_token; gchar *name; /* swallow the 'var' token... */ token = json_scanner_get_next_token (scanner); /* ... swallow the variable name... */ next_token = json_scanner_get_next_token (scanner); if (next_token != G_TOKEN_IDENTIFIER) return G_TOKEN_IDENTIFIER; name = g_strdup (scanner->value.v_identifier); /* ... and finally swallow the '=' */ next_token = json_scanner_get_next_token (scanner); if (next_token != '=') return '='; priv->has_assignment = TRUE; priv->variable_name = name; token = json_parse_statement (parser, scanner); /* remove the trailing semi-colon */ next_token = json_scanner_peek_next_token (scanner); if (next_token == ';') { token = json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } return token; } break; case JSON_TOKEN_NULL: priv->root = priv->current_node = json_node_new (JSON_NODE_NULL); json_scanner_get_next_token (scanner); return G_TOKEN_NONE; case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE); json_node_set_boolean (priv->current_node, token == JSON_TOKEN_TRUE ? TRUE : FALSE); json_scanner_get_next_token (scanner); return G_TOKEN_NONE; case '-': { guint next_token; token = json_scanner_get_next_token (scanner); next_token = json_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 = json_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_INT: json_node_set_int (priv->current_node, scanner->value.v_int64 * -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; } json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } else return G_TOKEN_INT; } break; case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: token = json_scanner_get_next_token (scanner); return json_parse_value (parser, scanner, token, &priv->root); default: json_scanner_get_next_token (scanner); return G_TOKEN_SYMBOL; } }