summaryrefslogtreecommitdiff
path: root/src/parse/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/parse.c')
-rw-r--r--src/parse/parse.c204
1 files changed, 128 insertions, 76 deletions
diff --git a/src/parse/parse.c b/src/parse/parse.c
index 4cc1c98..cbd8b56 100644
--- a/src/parse/parse.c
+++ b/src/parse/parse.c
@@ -67,7 +67,8 @@ enum {
sMalformedAtRule = 22,
sInlineStyle = 23,
sISBody0 = 24,
- sISBody = 25
+ sISBody = 25,
+ sMediaQuery = 26,
};
/**
@@ -99,8 +100,6 @@ struct css_parser
bool parseError; /**< A parse error has occurred */
parserutils_stack *open_items; /**< Stack of open brackets */
- uint8_t match_char; /**< Close bracket type for parseAny */
-
bool last_was_ws; /**< Last token was whitespace */
css_parser_event_handler event; /**< Client's event handler */
@@ -146,8 +145,9 @@ static css_error parseMalformedAtRule(css_parser *parser);
static css_error parseInlineStyle(css_parser *parser);
static css_error parseISBody0(css_parser *parser);
static css_error parseISBody(css_parser *parser);
+static css_error parseMediaQuery(css_parser *parser);
-static void unref_interned_strings_in_tokens(css_parser *parser);
+static void discard_tokens(css_parser *parser);
/**
* Dispatch table for parsing, indexed by major state number
@@ -178,7 +178,8 @@ static css_error (*parseFuncs[])(css_parser *parser) = {
parseMalformedAtRule,
parseInlineStyle,
parseISBody0,
- parseISBody
+ parseISBody,
+ parseMediaQuery,
};
/**
@@ -220,6 +221,25 @@ css_error css__parser_create_for_inline_style(const char *charset,
}
/**
+ * Create a CSS parser for a media query
+ *
+ * \param charset Charset of data, if known, or NULL
+ * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT
+ * \param parser Pointer to location to receive parser instance
+ * \return CSS_OK on success,
+ * CSS_BADPARM on bad parameters,
+ * CSS_NOMEM on memory exhaustion
+ */
+css_error css__parser_create_for_media_query(const char *charset,
+ css_charset_source cs_source, css_parser **parser)
+{
+ parser_state initial = { sMediaQuery, 0 };
+
+ return css__parser_create_internal(charset, cs_source,
+ initial, parser);
+}
+
+/**
* Destroy a CSS parser
*
* \param parser The parser instance to destroy
@@ -459,7 +479,6 @@ css_error css__parser_create_internal(const char *charset,
p->quirks = false;
p->pushback = NULL;
p->parseError = false;
- p->match_char = 0;
p->event = NULL;
p->last_was_ws = false;
p->event_pw = NULL;
@@ -746,8 +765,7 @@ css_error parseStart(css_parser *parser)
parser->event_pw);
}
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -778,8 +796,7 @@ css_error parseStylesheet(css_parser *parser)
if (error != CSS_OK)
return error;
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
case CSS_TOKEN_CDO:
@@ -849,8 +866,7 @@ css_error parseRuleset(css_parser *parser)
switch (state->substate) {
case Initial:
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
error = getToken(parser, &token);
if (error != CSS_OK)
@@ -890,17 +906,6 @@ css_error parseRuleset(css_parser *parser)
}
break;
case Brace:
-#if !defined(NDEBUG) && defined(DEBUG_EVENTS)
- printf("Begin ruleset\n");
- parserutils_vector_dump(parser->tokens, __func__, tprinter);
-#endif
- if (parser->parseError == false && parser->event != NULL) {
- if (parser->event(CSS_PARSER_START_RULESET,
- parser->tokens, parser->event_pw) ==
- CSS_INVALID)
- parser->parseError = true;
- }
-
if (parser->parseError == true) {
parser_state to = { sMalformedSelector, Initial };
@@ -911,22 +916,40 @@ css_error parseRuleset(css_parser *parser)
if (error != CSS_OK)
return error;
- if (token->type == CSS_TOKEN_EOF) {
+ if (token->type != CSS_TOKEN_CHAR ||
+ lwc_string_length(token->idata) != 1 ||
+ lwc_string_data(token->idata)[0] != '{') {
+ /* FOLLOW(selector) contains only '{', but we may
+ * also have seen EOF, which is a parse error. */
error = pushBack(parser, token);
if (error != CSS_OK)
return error;
+ parser->parseError = true;
return done(parser);
}
- if (token->type != CSS_TOKEN_CHAR ||
- lwc_string_length(token->idata) != 1 ||
- lwc_string_data(token->idata)[0] != '{') {
- /* This should never happen, as FOLLOW(selector)
- * contains only '{' */
- assert(0 && "Expected {");
+ /* We don't want to emit the brace, so push it back */
+ error = pushBack(parser, token);
+ if (error != CSS_OK)
+ return error;
+
+#if !defined(NDEBUG) && defined(DEBUG_EVENTS)
+ printf("Begin ruleset\n");
+ parserutils_vector_dump(parser->tokens, __func__, tprinter);
+#endif
+ if (parser->parseError == false && parser->event != NULL) {
+ if (parser->event(CSS_PARSER_START_RULESET,
+ parser->tokens, parser->event_pw) ==
+ CSS_INVALID)
+ parser->parseError = true;
}
+ /* Re-read the brace */
+ error = getToken(parser, &token);
+ if (error != CSS_OK)
+ return error;
+
state->substate = WS;
/* Fall through */
case WS:
@@ -1041,8 +1064,7 @@ css_error parseAtRule(css_parser *parser)
switch (state->substate) {
case Initial:
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
error = getToken(parser, &token);
if (error != CSS_OK)
@@ -1212,8 +1234,7 @@ css_error parseBlock(css_parser *parser)
assert(0 && "Expected {");
}
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
state->substate = WS;
/* Fall through */
@@ -1269,8 +1290,7 @@ css_error parseBlock(css_parser *parser)
parser->event(CSS_PARSER_END_BLOCK, NULL, parser->event_pw);
}
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -1322,10 +1342,7 @@ css_error parseBlockContent(css_parser *parser)
parser->event_pw);
}
- unref_interned_strings_in_tokens(
- parser);
- parserutils_vector_clear(
- parser->tokens);
+ discard_tokens(parser);
return transition(parser, to,
subsequent);
@@ -1353,10 +1370,7 @@ css_error parseBlockContent(css_parser *parser)
if (error != CSS_OK)
return error;
- unref_interned_strings_in_tokens(
- parser);
- parserutils_vector_clear(
- parser->tokens);
+ discard_tokens(parser);
state->substate = WS;
} else if (lwc_string_length(
@@ -1379,10 +1393,7 @@ css_error parseBlockContent(css_parser *parser)
parser->event_pw);
}
- unref_interned_strings_in_tokens(
- parser);
- parserutils_vector_clear(
- parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -1401,8 +1412,7 @@ css_error parseBlockContent(css_parser *parser)
parser->event_pw);
}
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -1445,8 +1455,7 @@ css_error parseSelector(css_parser *parser)
parser_state to = { sAny1, Initial };
parser_state subsequent = { sSelector, AfterAny1 };
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return transition(parser, to, subsequent);
}
@@ -1472,8 +1481,7 @@ css_error parseDeclaration(css_parser *parser)
parser_state to = { sProperty, Initial };
parser_state subsequent = { sDeclaration, Colon };
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return transition(parser, to, subsequent);
}
@@ -1945,6 +1953,9 @@ css_error parseAny1(css_parser *parser)
if (error != CSS_OK)
return error;
+ if (token->type == CSS_TOKEN_EOF)
+ return done(parser);
+
/* Grammar ambiguity: any0 can be followed by
* '{', ';', ')', ']'. any1 can only be followed by '{'. */
if (token->type == CSS_TOKEN_CHAR &&
@@ -2025,18 +2036,19 @@ css_error parseAny(css_parser *parser)
}
if (token->type == CSS_TOKEN_FUNCTION) {
- parser->match_char = ')';
+ parserutils_stack_push(parser->open_items, &")"[0]);
state->substate = WS;
} else if (token->type == CSS_TOKEN_CHAR &&
lwc_string_length(token->idata) == 1 &&
(lwc_string_data(token->idata)[0] == '(' ||
lwc_string_data(token->idata)[0] == '[')) {
- parser->match_char = lwc_string_data(
- token->idata)[0] == '(' ? ')' : ']';
+ parserutils_stack_push(parser->open_items,
+ &(lwc_string_data(
+ token->idata)[0] == '(' ? ")" : "]")[0]);
state->substate = WS;
+ } else {
+ state->substate = WS2;
}
-
- state->substate = WS2;
/* Fall through */
case WS:
case WS2:
@@ -2063,11 +2075,24 @@ css_error parseAny(css_parser *parser)
if (error != CSS_OK)
return error;
+ if (token->type == CSS_TOKEN_EOF) {
+ error = pushBack(parser, token);
+ if (error != CSS_OK)
+ return error;
+
+ /* parse error */
+ parser->parseError = true;
+
+ return done(parser);
+ }
+
/* Match correct close bracket (grammar ambiguity) */
if (token->type == CSS_TOKEN_CHAR &&
lwc_string_length(token->idata) == 1 &&
lwc_string_data(token->idata)[0] ==
- parser->match_char) {
+ ((uint8_t *) parserutils_stack_get_current(
+ parser->open_items))[0]) {
+ parserutils_stack_pop(parser->open_items, NULL);
state->substate = WS2;
goto ws2;
}
@@ -2174,8 +2199,7 @@ css_error parseMalformedDeclaration(css_parser *parser)
return error;
/* Discard the tokens we've read */
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -2270,8 +2294,7 @@ css_error parseMalformedSelector(css_parser *parser)
return error;
/* Discard the tokens we've read */
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -2379,8 +2402,7 @@ css_error parseMalformedAtRule(css_parser *parser)
return error;
/* Discard the tokens we've read */
- unref_interned_strings_in_tokens(parser);
- parserutils_vector_clear(parser->tokens);
+ discard_tokens(parser);
return done(parser);
}
@@ -2425,7 +2447,7 @@ css_error parseInlineStyle(css_parser *parser)
}
case AfterISBody0:
/* Clean up any remaining tokens */
- unref_interned_strings_in_tokens(parser);
+ discard_tokens(parser);
/* Emit remaining fake events to end the parse */
if (parser->event != NULL) {
@@ -2571,22 +2593,48 @@ css_error parseISBody(css_parser *parser)
return done(parser);
}
+css_error parseMediaQuery(css_parser *parser)
+{
+ enum { Initial = 0, AfterAtRule = 1 };
+ parser_state *state = parserutils_stack_get_current(parser->states);
+
+ /* media-query = at-rule */
+
+ switch (state->substate) {
+ case Initial:
+ {
+ parser_state to = { sAtRule, Initial };
+ parser_state subsequent = { sMediaQuery, AfterAtRule };
+
+ return transition(parser, to, subsequent);
+ }
+ case AfterAtRule:
+ /* Clean up any remaining tokens */
+ discard_tokens(parser);
+ break;
+ }
+
+ return done(parser);
+}
+
/**
- * Iterate the token vector and unref any interned strings in the tokens.
+ * Discard the contents of the token vector
*
* \param parser The parser whose tokens we are cleaning up.
*/
-void unref_interned_strings_in_tokens(css_parser *parser)
+void discard_tokens(css_parser *parser)
{
- int32_t ctx = 0;
- const css_token *tok;
+ int32_t ctx = 0;
+ const css_token *tok;
- while ((tok = parserutils_vector_iterate(
+ while ((tok = parserutils_vector_iterate(
parser->tokens, &ctx)) != NULL) {
- if (tok->idata != NULL) {
- lwc_string_unref(tok->idata);
+ if (tok->idata != NULL) {
+ lwc_string_unref(tok->idata);
}
- }
+ }
+
+ parserutils_vector_clear(parser->tokens);
}
#ifndef NDEBUG
@@ -2604,7 +2652,11 @@ static void tprinter(void *token)
{
css_token *t = token;
- if (t->data.data)
+ if (t->idata) {
+ printf("%d: %.*s", t->type,
+ (int) lwc_string_length(t->idata),
+ lwc_string_data(t->idata));
+ } else if (t->data.data)
printf("%d: %.*s", t->type, (int) t->data.len, t->data.data);
else
printf("%d", t->type);