Fix error reporting in configuration parsing
This commit is contained in:
parent
6bf57d3450
commit
9285974bff
79
common.c
79
common.c
@ -673,16 +673,42 @@ enum config_token
|
||||
CONFIG_T_STRING ///< CONFIG_ITEM_STRING{,_LIST}
|
||||
};
|
||||
|
||||
static const char *
|
||||
config_token_name (enum config_token token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case CONFIG_T_ABORT: return "end of input";
|
||||
|
||||
case CONFIG_T_WORD: return "word";
|
||||
case CONFIG_T_EQUALS: return "equal sign";
|
||||
case CONFIG_T_LBRACE: return "left brace";
|
||||
case CONFIG_T_RBRACE: return "right brace";
|
||||
case CONFIG_T_NEWLINE: return "newline";
|
||||
|
||||
case CONFIG_T_NULL: return "null value";
|
||||
case CONFIG_T_BOOLEAN: return "boolean";
|
||||
case CONFIG_T_INTEGER: return "integer";
|
||||
case CONFIG_T_STRING: return "string";
|
||||
|
||||
default:
|
||||
hard_assert (!"invalid token value");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct config_tokenizer
|
||||
{
|
||||
const char *p;
|
||||
size_t len;
|
||||
const char *p; ///< Current position in input
|
||||
size_t len; ///< How many bytes of input are left
|
||||
|
||||
unsigned line;
|
||||
unsigned column;
|
||||
bool report_line; ///< Whether to count lines at all
|
||||
unsigned line; ///< Current line
|
||||
unsigned column; ///< Current column
|
||||
|
||||
int64_t integer;
|
||||
struct str string;
|
||||
int64_t integer; ///< Parsed boolean or integer value
|
||||
struct str string; ///< Parsed string value
|
||||
};
|
||||
|
||||
/// Input has to be null-terminated anyway
|
||||
@ -692,6 +718,7 @@ config_tokenizer_init (struct config_tokenizer *self, const char *p, size_t len)
|
||||
memset (self, 0, sizeof *self);
|
||||
self->p = p;
|
||||
self->len = len;
|
||||
self->report_line = true;
|
||||
str_init (&self->string);
|
||||
}
|
||||
|
||||
@ -711,7 +738,7 @@ static int
|
||||
config_tokenizer_advance (struct config_tokenizer *self)
|
||||
{
|
||||
int c = *self->p++;
|
||||
if (c == '\n')
|
||||
if (c == '\n' && self->report_line)
|
||||
{
|
||||
self->column = 0;
|
||||
self->line++;
|
||||
@ -723,13 +750,29 @@ config_tokenizer_advance (struct config_tokenizer *self)
|
||||
return c;
|
||||
}
|
||||
|
||||
static void config_tokenizer_error (struct config_tokenizer *self,
|
||||
struct error **e, const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
|
||||
|
||||
static void
|
||||
config_tokenizer_error (struct config_tokenizer *self,
|
||||
struct error **e, const char *description)
|
||||
struct error **e, const char *format, ...)
|
||||
{
|
||||
// FIXME: we don't always want to specify the line
|
||||
error_set (e, "near line %u, column %u: %s",
|
||||
self->line + 1, self->column + 1, description);
|
||||
struct str description;
|
||||
str_init (&description);
|
||||
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
str_append_vprintf (&description, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (self->report_line)
|
||||
error_set (e, "near line %u, column %u: %s",
|
||||
self->line + 1, self->column + 1, description.str);
|
||||
else
|
||||
error_set (e, "near character %u: %s",
|
||||
self->column + 1, description.str);
|
||||
|
||||
str_free (&description);
|
||||
}
|
||||
|
||||
static enum config_token
|
||||
@ -856,9 +899,10 @@ config_parser_expect
|
||||
if (config_parser_accept (self, token, out))
|
||||
return;
|
||||
|
||||
// TODO: fill in "X" and "Y"
|
||||
config_tokenizer_error (&self->tokenizer, &self->error,
|
||||
"unexpected X, expected Y");
|
||||
"unexpected `%s', expected `%s'",
|
||||
config_token_name (self->token),
|
||||
config_token_name (token));
|
||||
longjmp (out, 1);
|
||||
}
|
||||
|
||||
@ -903,9 +947,9 @@ config_parser_parse_value (struct config_parser *self, jmp_buf out)
|
||||
if (ACCEPT (CONFIG_T_STRING))
|
||||
return config_item_string (&self->tokenizer.string);
|
||||
|
||||
// TODO: fill in "X" as the token name
|
||||
config_tokenizer_error (&self->tokenizer, &self->error,
|
||||
"unexpected X, expected a value");
|
||||
"unexpected `%s', expected a value",
|
||||
config_token_name (self->token));
|
||||
longjmp (out, 1);
|
||||
}
|
||||
|
||||
@ -1003,7 +1047,12 @@ config_item_parse (const char *script, size_t len,
|
||||
}
|
||||
|
||||
if (single_value_only)
|
||||
{
|
||||
// This is really only intended for in-program configuration
|
||||
// and telling the line number would look awkward
|
||||
parser.tokenizer.report_line = false;
|
||||
object = config_parser_parse_value (&parser, err);
|
||||
}
|
||||
else
|
||||
object = config_parser_parse_object (&parser, err);
|
||||
config_parser_expect (&parser, CONFIG_T_ABORT, err);
|
||||
|
Loading…
Reference in New Issue
Block a user