Paolo Bonzini <[email protected]> writes:

> Now that all calls to parse_error have a token, add the line and column
> to the message.  As far as I can see the two important TODOs (better
> errors and better EOI handling) are done, and the others (token range
> information and "parsed size"?) do not really matter or are handled
> better by json-streamer.c.  So remove the list, which had sat unchanged
> since 2009.
>
> This needs some adjustments to provide a good x and y for error messages.
> First of all, they switch from zero-based to one-based, which is safe
> because they were both sitting unused.  Second, right now the x and y
> are those of the *last* character in the token.  Modify json-lexer.c to
> freeze tok->x and tok->y at the first character added to the GString.
>
> Signed-off-by: Paolo Bonzini <[email protected]>

QMP errors become obviously better, e.g.

    -> {"execute": "qmp_capabilities", "arguments": {"enable": ["oob"]}}
    <- {"return": {}}
    -> {"execute": "query-commands"]
    <- {"error": {"class": "GenericError", "desc": "JSON parse error, expected 
',' or '}'"}}

improves to

    <- {"error": {"class": "GenericError", "desc": "JSON parse error at line 2, 
column 29, expected ',' or '}'"}}

The change to CLI errors is a mixed bag, e.g.

    $ qemu-system-x86_64 -S -blockdev '{"driver": "host_cdrom", "node-name": 
"blk0", "filename": "/dev/sr0"'
    qemu-system-x86_64: -blockdev {"driver": "host_cdrom", "node-name": "blk0", 
"filename": "/dev/sr0": JSON parse error, premature end of input

becomes

    qemu-system-x86_64: -blockdev {"driver": "host_cdrom", "node-name": "blk0", 
"filename": "/dev/sr0": JSON parse error at line 1, column 69, premature end of 
input

I fear this is confusing.  If you understand what's happening here, the
"column 69" part has value.  The "line 1" part is mostly noise.

Might be less of an issue with more compact location information.  See
below.

> ---
>  include/qobject/json-parser.h |  1 +
>  qobject/json-lexer.c          | 11 +++++++----
>  qobject/json-parser.c         | 12 ++----------
>  3 files changed, 10 insertions(+), 14 deletions(-)
>
> diff --git a/include/qobject/json-parser.h b/include/qobject/json-parser.h
> index 3479e637588..e078b36b2d5 100644
> --- a/include/qobject/json-parser.h
> +++ b/include/qobject/json-parser.h
> @@ -17,6 +17,7 @@
>  typedef struct JSONLexer {
>      int start_state, state;
>      GString *token;
> +    int cur_x, cur_y;
>      int x, y;
>  } JSONLexer;
>  
> diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
> index 51341d96e49..7753ba6c092 100644
> --- a/qobject/json-lexer.c
> +++ b/qobject/json-lexer.c
> @@ -277,7 +277,8 @@ void json_lexer_init(JSONLexer *lexer, bool 
> enable_interpolation)
>      lexer->start_state = lexer->state = enable_interpolation
>          ? IN_START_INTERP : IN_START;
>      lexer->token = g_string_sized_new(3);
> -    lexer->x = lexer->y = 0;
> +    lexer->cur_x = lexer->cur_y = 1;
> +    lexer->x = lexer->y = 1;
>  }
>  
>  static void json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
> @@ -285,10 +286,10 @@ static void json_lexer_feed_char(JSONLexer *lexer, char 
> ch, bool flush)
>      int new_state;
>      bool char_consumed = false;
>  
> -    lexer->x++;
> +    lexer->cur_x++;
>      if (ch == '\n') {
> -        lexer->x = 0;
> -        lexer->y++;
> +        lexer->cur_x = 1;
> +        lexer->cur_y++;
>      }
>  
>      while (flush ? lexer->state != lexer->start_state : !char_consumed) {
> @@ -316,6 +317,8 @@ static void json_lexer_feed_char(JSONLexer *lexer, char 
> ch, bool flush)
>          case IN_START:
>              g_string_truncate(lexer->token, 0);
>              new_state = lexer->start_state;
> +            lexer->x = lexer->cur_x;
> +            lexer->y = lexer->cur_y;
>              break;
>          case JSON_ERROR:
>              json_message_process_token(lexer, lexer->token, JSON_ERROR,
> diff --git a/qobject/json-parser.c b/qobject/json-parser.c
> index faf3a9142bd..8c58ae0349a 100644
> --- a/qobject/json-parser.c
> +++ b/qobject/json-parser.c
> @@ -126,15 +126,6 @@ typedef struct JSONParserStackEntry {
>  
>  #define BUG_ON(cond) assert(!(cond))
>  
> -/**
> - * TODO
> - *
> - * 0) make errors meaningful again
> - * 1) add geometry information to tokens
> - * 3) should we return a parsed size?
> - * 4) deal with premature EOI
> - */
> -
>  static inline JSONParserStackEntry *current_entry(JSONParserContext *ctxt)
>  {
>      return g_queue_peek_tail(ctxt->stack);
> @@ -172,7 +163,8 @@ static void G_GNUC_PRINTF(3, 4) 
> parse_error(JSONParserContext *ctxt,
>      va_start(ap, msg);
>      vsnprintf(message, sizeof(message), msg, ap);
>      va_end(ap);
> -    error_setg(&ctxt->err, "JSON parse error, %s", message);
> +    error_setg(&ctxt->err, "JSON parse error at line %d, column %d, %s",

The usual format used by code parsing tools such as compilers is like

   "%d:%d: JSON parse error: %s, token->x, token->y, message

Should we use it?

> +               token->y, token->x, message);
>  }
>  
>  static int cvt4hex(const char *s)


Reply via email to