csstokenizer: Collect error, don't just emit it

This again is part of the quest to make it possible to "undo" reading
a token.
This commit is contained in:
Benjamin Otte
2016-04-07 20:04:31 +02:00
parent c6951488f9
commit 62b2f979e5

View File

@@ -51,6 +51,13 @@ gtk_css_location_init (GtkCssLocation *location)
memset (location, 0, sizeof (GtkCssLocation));
}
static void
gtk_css_location_init_copy (GtkCssLocation *location,
const GtkCssLocation *source)
{
*location = *source;
}
static void
gtk_css_location_advance (GtkCssLocation *location,
gsize bytes,
@@ -551,31 +558,39 @@ gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer)
}
static void
gtk_css_tokenizer_parse_error (GtkCssTokenizer *tokenizer,
const GtkCssToken *token,
const char *format,
...) G_GNUC_PRINTF(3, 4);
set_parse_error (GError **error,
const char *format,
...) G_GNUC_PRINTF(2, 3);
static void
gtk_css_tokenizer_parse_error (GtkCssTokenizer *tokenizer,
const GtkCssToken *token,
const char *format,
...)
set_parse_error (GError **error,
const char *format,
...)
{
GError *error;
va_list args;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
format, args);
va_end (args);
if (error == NULL)
return;
g_assert (*error == NULL);
va_start (args, format);
*error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
format,
args);
va_end (args);
}
static void
gtk_css_tokenizer_emit_error (GtkCssTokenizer *tokenizer,
const GtkCssLocation *location,
const GtkCssToken *token,
const GError *error)
{
if (tokenizer->error_func)
tokenizer->error_func (tokenizer, token, error, tokenizer->user_data);
else
g_print ("error: %s\n", error->message);
g_error_free (error);
g_warning ("Unhandled CSS error: %zu:%zu: %s", location->lines + 1, location->line_chars + 1, error->message);
}
static gboolean
@@ -869,9 +884,9 @@ gtk_css_token_reader_read_bad_url (GtkCssTokenReader *reader,
}
static void
gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
GtkCssTokenReader *reader,
GtkCssToken *token)
gtk_css_token_reader_read_url (GtkCssTokenReader *reader,
GtkCssToken *token,
GError **error)
{
GString *url = g_string_new (NULL);
@@ -903,7 +918,7 @@ gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
else
{
gtk_css_token_reader_read_bad_url (reader, token);
gtk_css_tokenizer_parse_error (tokenizer, token, "Whitespace only allowed at start and end of url");
set_parse_error (error, "Whitespace only allowed at start and end of url");
return;
}
}
@@ -911,7 +926,7 @@ gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
{
gtk_css_token_reader_read_bad_url (reader, token);
g_string_free (url, TRUE);
gtk_css_tokenizer_parse_error (tokenizer, token, "Nonprintable character 0x%02X in url", *reader->data);
set_parse_error (error, "Nonprintable character 0x%02X in url", *reader->data);
return;
}
else if (*reader->data == '"' ||
@@ -919,7 +934,7 @@ gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
*reader->data == '(')
{
gtk_css_token_reader_read_bad_url (reader, token);
gtk_css_tokenizer_parse_error (tokenizer, token, "Invalid character %c in url", *reader->data);
set_parse_error (error, "Invalid character %c in url", *reader->data);
g_string_free (url, TRUE);
return;
}
@@ -930,7 +945,7 @@ gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
else if (*reader->data == '\\')
{
gtk_css_token_reader_read_bad_url (reader, token);
gtk_css_tokenizer_parse_error (tokenizer, token, "Newline may not follow '\' escape character");
set_parse_error (error, "Newline may not follow '\' escape character");
g_string_free (url, TRUE);
return;
}
@@ -944,9 +959,9 @@ gtk_css_token_reader_read_url (GtkCssTokenizer *tokenizer,
}
static void
gtk_css_token_reader_read_ident_like (GtkCssTokenizer *tokenizer,
GtkCssTokenReader *reader,
GtkCssToken *token)
gtk_css_token_reader_read_ident_like (GtkCssTokenReader *reader,
GtkCssToken *token,
GError **error)
{
char *name = gtk_css_token_reader_read_name (reader);
@@ -963,7 +978,7 @@ gtk_css_token_reader_read_ident_like (GtkCssTokenizer *tokenizer,
if (*data != '"' && *data != '\'')
{
gtk_css_token_reader_read_url (tokenizer, reader, token);
gtk_css_token_reader_read_url (reader, token, error);
return;
}
}
@@ -1083,9 +1098,9 @@ gtk_css_token_reader_read_delim (GtkCssTokenReader *reader,
}
static void
gtk_css_token_reader_read_dash (GtkCssTokenizer *tokenizer,
GtkCssTokenReader *reader,
GtkCssToken *token)
gtk_css_token_reader_read_dash (GtkCssTokenReader *reader,
GtkCssToken *token,
GError **error)
{
if (gtk_css_token_reader_remaining (reader) == 1)
{
@@ -1104,7 +1119,7 @@ gtk_css_token_reader_read_dash (GtkCssTokenizer *tokenizer,
}
else if (gtk_css_token_reader_has_identifier (reader))
{
gtk_css_token_reader_read_ident_like (tokenizer, reader, token);
gtk_css_token_reader_read_ident_like (reader, token, error);
}
else
{
@@ -1113,9 +1128,9 @@ gtk_css_token_reader_read_dash (GtkCssTokenizer *tokenizer,
}
static void
gtk_css_token_reader_read_string (GtkCssTokenizer *tokenizer,
GtkCssTokenReader *reader,
GtkCssToken *token)
gtk_css_token_reader_read_string (GtkCssTokenReader *reader,
GtkCssToken *token,
GError **error)
{
GString *string = g_string_new (NULL);
char end = *reader->data;
@@ -1150,7 +1165,7 @@ gtk_css_token_reader_read_string (GtkCssTokenizer *tokenizer,
{
g_string_free (string, TRUE);
gtk_css_token_init (token, GTK_CSS_TOKEN_BAD_STRING);
gtk_css_tokenizer_parse_error (tokenizer, token, "Newlines inside strings must be escaped");
set_parse_error (error, "Newlines inside strings must be escaped");
return;
}
else
@@ -1163,9 +1178,9 @@ gtk_css_token_reader_read_string (GtkCssTokenizer *tokenizer,
}
static void
gtk_css_token_reader_read_comment (GtkCssTokenizer *tokenizer,
GtkCssTokenReader *reader,
GtkCssToken *token)
gtk_css_token_reader_read_comment (GtkCssTokenReader *reader,
GtkCssToken *token,
GError **error)
{
gtk_css_token_reader_consume (reader, 2, 2);
@@ -1182,7 +1197,7 @@ gtk_css_token_reader_read_comment (GtkCssTokenizer *tokenizer,
}
gtk_css_token_init (token, GTK_CSS_TOKEN_COMMENT);
gtk_css_tokenizer_parse_error (tokenizer, token, "Comment not terminated at end of document.");
set_parse_error (error, "Comment not terminated at end of document.");
}
static void
@@ -1206,6 +1221,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
GtkCssToken *token)
{
GtkCssTokenReader reader;
GError *error = NULL;
if (tokenizer->reader.data == tokenizer->reader.end)
{
@@ -1218,7 +1234,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
if (reader.data[0] == '/' && gtk_css_token_reader_remaining (&reader) > 1 &&
reader.data[1] == '*')
{
gtk_css_token_reader_read_comment (tokenizer, &reader, token);
gtk_css_token_reader_read_comment (&reader, token, &error);
goto out;
}
@@ -1233,7 +1249,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
break;
case '"':
gtk_css_token_reader_read_string (tokenizer, &reader, token);
gtk_css_token_reader_read_string (&reader, token, &error);
break;
case '#':
@@ -1262,7 +1278,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
break;
case '\'':
gtk_css_token_reader_read_string (tokenizer, &reader, token);
gtk_css_token_reader_read_string (&reader, token, &error);
break;
case '(':
@@ -1292,7 +1308,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
break;
case '-':
gtk_css_token_reader_read_dash (tokenizer, &reader, token);
gtk_css_token_reader_read_dash (&reader, token, &error);
break;
case '.':
@@ -1349,12 +1365,12 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
case '\\':
if (gtk_css_token_reader_has_valid_escape (&reader))
{
gtk_css_token_reader_read_ident_like (tokenizer, &reader, token);
gtk_css_token_reader_read_ident_like (&reader, token, &error);
}
else
{
gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, '\\');
gtk_css_tokenizer_parse_error (tokenizer, token, "Newline may not follow '\' escape character");
set_parse_error (&error, "Newline may not follow '\' escape character");
}
break;
@@ -1400,7 +1416,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
}
else if (is_name_start (*reader.data))
{
gtk_css_token_reader_read_ident_like (tokenizer, &reader, token);
gtk_css_token_reader_read_ident_like (&reader, token, &error);
}
else
gtk_css_token_reader_read_delim (&reader, token);
@@ -1408,6 +1424,18 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
}
out:
gtk_css_token_reader_init_copy (&tokenizer->reader, &reader);
if (error != NULL)
{
GtkCssLocation error_location;
gtk_css_location_init_copy (&error_location, &reader.position);
gtk_css_token_reader_init_copy (&tokenizer->reader, &reader);
gtk_css_tokenizer_emit_error (tokenizer, &error_location, token, error);
g_error_free (error);
}
else
{
gtk_css_token_reader_init_copy (&tokenizer->reader, &reader);
}
}