diff options
Diffstat (limited to 'src/parse/parse.c')
-rw-r--r-- | src/parse/parse.c | 204 |
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); |