Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of LibCSS.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
  6.  */
  7.  
  8. #include <assert.h>
  9. #include <ctype.h>
  10. #include <stdbool.h>
  11.  
  12. #include <libwapcaplet/libwapcaplet.h>
  13.  
  14. #include <parserutils/input/inputstream.h>
  15. #include <parserutils/utils/stack.h>
  16. #include <parserutils/utils/vector.h>
  17.  
  18. #include "charset/detect.h"
  19. #include "lex/lex.h"
  20. #include "parse/parse.h"
  21. #include "utils/parserutilserror.h"
  22. #include "utils/utils.h"
  23.  
  24. #undef DEBUG_STACK
  25. #undef DEBUG_EVENTS
  26.  
  27. #ifndef NDEBUG
  28. #include <stdio.h>
  29. extern void parserutils_stack_dump(parserutils_stack *stack, const char *prefix,
  30.                 void (*printer)(void *item));
  31. extern void parserutils_vector_dump(parserutils_vector *vector,
  32.                 const char *prefix, void (*printer)(void *item));
  33. #ifdef DEBUG_STACK
  34. static void printer(void *item);
  35. #endif
  36. #ifdef DEBUG_EVENTS
  37. static void tprinter(void *token);
  38. #endif
  39. #endif
  40.  
  41. /**
  42.  * Major state numbers
  43.  */
  44. enum {
  45.         sStart = 0,
  46.         sStylesheet = 1,
  47.         sStatement = 2,
  48.         sRuleset = 3,
  49.         sRulesetEnd = 4,
  50.         sAtRule = 5,
  51.         sAtRuleEnd = 6,
  52.         sBlock = 7,
  53.         sBlockContent = 8,
  54.         sSelector = 9,
  55.         sDeclaration = 10,
  56.         sDeclList = 11,
  57.         sDeclListEnd = 12,
  58.         sProperty = 13,
  59.         sValue0 = 14,
  60.         sValue1 = 15,
  61.         sValue = 16,
  62.         sAny0 = 17,
  63.         sAny1 = 18,
  64.         sAny = 19,
  65.         sMalformedDecl = 20,
  66.         sMalformedSelector = 21,
  67.         sMalformedAtRule = 22,
  68.         sInlineStyle = 23,
  69.         sISBody0 = 24,
  70.         sISBody = 25
  71. };
  72.  
  73. /**
  74.  * Representation of a parser state
  75.  */
  76. typedef struct parser_state
  77. {
  78.         unsigned int state : 16,
  79.                      substate : 16;
  80. } parser_state;
  81.  
  82. /**
  83.  * CSS parser object
  84.  */
  85. struct css_parser
  86. {
  87.         parserutils_inputstream *stream;        /**< The inputstream */
  88.         css_lexer *lexer;               /**< The lexer to use */
  89.  
  90.         bool quirks;                    /**< Whether to enable parsing quirks */
  91.  
  92. #define STACK_CHUNK 32
  93.         parserutils_stack *states;      /**< Stack of states */
  94.  
  95.         parserutils_vector *tokens;     /**< Vector of pending tokens */
  96.  
  97.         const css_token *pushback;      /**< Push back buffer */
  98.  
  99.         bool parseError;                /**< A parse error has occurred */
  100.         parserutils_stack *open_items;  /**< Stack of open brackets */
  101.  
  102.         uint8_t match_char;             /**< Close bracket type for parseAny */
  103.  
  104.         bool last_was_ws;               /**< Last token was whitespace */
  105.  
  106.         css_parser_event_handler event; /**< Client's event handler */
  107.         void *event_pw;                 /**< Client data for event handler */
  108.  
  109.         css_allocator_fn alloc;         /**< Memory (de)allocation function */
  110.         void *pw;                       /**< Client-specific private data */
  111. };
  112.  
  113. static css_error css__parser_create_internal(const char *charset,
  114.                 css_charset_source cs_source,
  115.                 css_allocator_fn alloc, void *pw, parser_state initial,
  116.                 css_parser **parser);
  117.  
  118. static css_error transition(css_parser *parser, parser_state to,
  119.                 parser_state subsequent);
  120. static css_error transitionNoRet(css_parser *parser, parser_state to);
  121. static css_error done(css_parser *parser);
  122. static css_error expect(css_parser *parser, css_token_type type);
  123. static css_error getToken(css_parser *parser, const css_token **token);
  124. static css_error pushBack(css_parser *parser, const css_token *token);
  125. static css_error eatWS(css_parser *parser);
  126.  
  127. static css_error parseStart(css_parser *parser);
  128. static css_error parseStylesheet(css_parser *parser);
  129. static css_error parseStatement(css_parser *parser);
  130. static css_error parseRuleset(css_parser *parser);
  131. static css_error parseRulesetEnd(css_parser *parser);
  132. static css_error parseAtRule(css_parser *parser);
  133. static css_error parseAtRuleEnd(css_parser *parser);
  134. static css_error parseBlock(css_parser *parser);
  135. static css_error parseBlockContent(css_parser *parser);
  136. static css_error parseSelector(css_parser *parser);
  137. static css_error parseDeclaration(css_parser *parser);
  138. static css_error parseDeclList(css_parser *parser);
  139. static css_error parseDeclListEnd(css_parser *parser);
  140. static css_error parseProperty(css_parser *parser);
  141. static css_error parseValue0(css_parser *parser);
  142. static css_error parseValue1(css_parser *parser);
  143. static css_error parseValue(css_parser *parser);
  144. static css_error parseAny0(css_parser *parser);
  145. static css_error parseAny1(css_parser *parser);
  146. static css_error parseAny(css_parser *parser);
  147. static css_error parseMalformedDeclaration(css_parser *parser);
  148. static css_error parseMalformedSelector(css_parser *parser);
  149. static css_error parseMalformedAtRule(css_parser *parser);
  150. static css_error parseInlineStyle(css_parser *parser);
  151. static css_error parseISBody0(css_parser *parser);
  152. static css_error parseISBody(css_parser *parser);
  153.  
  154. static void unref_interned_strings_in_tokens(css_parser *parser);
  155.  
  156. /**
  157.  * Dispatch table for parsing, indexed by major state number
  158.  */
  159. static css_error (*parseFuncs[])(css_parser *parser) = {
  160.         parseStart,
  161.         parseStylesheet,
  162.         parseStatement,
  163.         parseRuleset,
  164.         parseRulesetEnd,
  165.         parseAtRule,
  166.         parseAtRuleEnd,
  167.         parseBlock,
  168.         parseBlockContent,
  169.         parseSelector,
  170.         parseDeclaration,
  171.         parseDeclList,
  172.         parseDeclListEnd,
  173.         parseProperty,
  174.         parseValue0,
  175.         parseValue1,
  176.         parseValue,
  177.         parseAny0,
  178.         parseAny1,
  179.         parseAny,
  180.         parseMalformedDeclaration,
  181.         parseMalformedSelector,
  182.         parseMalformedAtRule,
  183.         parseInlineStyle,
  184.         parseISBody0,
  185.         parseISBody
  186. };
  187.  
  188. /**
  189.  * Create a CSS parser
  190.  *
  191.  * \param charset     Charset of data, if known, or NULL
  192.  * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT
  193.  * \param alloc       Memory (de)allocation function
  194.  * \param pw          Pointer to client-specific private data
  195.  * \param parser      Pointer to location to receive parser instance
  196.  * \return CSS_OK on success,
  197.  *         CSS_BADPARM on bad parameters,
  198.  *         CSS_NOMEM on memory exhaustion
  199.  */
  200. css_error css__parser_create(const char *charset, css_charset_source cs_source,
  201.                 css_allocator_fn alloc, void *pw,
  202.                 css_parser **parser)
  203. {
  204.         parser_state initial = { sStart, 0 };
  205.  
  206.         return css__parser_create_internal(charset, cs_source,
  207.                         alloc, pw, initial, parser);
  208. }
  209.  
  210. /**
  211.  * Create a CSS parser for an inline style
  212.  *
  213.  * \param charset     Charset of data, if known, or NULL
  214.  * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT
  215.  * \param alloc       Memory (de)allocation function
  216.  * \param pw          Pointer to client-specific private data
  217.  * \param parser      Pointer to location to receive parser instance
  218.  * \return CSS_OK on success,
  219.  *         CSS_BADPARM on bad parameters,
  220.  *         CSS_NOMEM on memory exhaustion
  221.  */
  222. css_error css__parser_create_for_inline_style(const char *charset,
  223.                 css_charset_source cs_source,
  224.                 css_allocator_fn alloc, void *pw, css_parser **parser)
  225. {
  226.         parser_state initial = { sInlineStyle, 0 };
  227.  
  228.         return css__parser_create_internal(charset, cs_source,
  229.                         alloc, pw, initial, parser);
  230. }
  231.  
  232. /**
  233.  * Destroy a CSS parser
  234.  *
  235.  * \param parser  The parser instance to destroy
  236.  * \return CSS_OK on success, appropriate error otherwise
  237.  */
  238. css_error css__parser_destroy(css_parser *parser)
  239. {
  240.         if (parser == NULL)
  241.                 return CSS_BADPARM;
  242.  
  243.         parserutils_stack_destroy(parser->open_items);
  244.  
  245.         parserutils_vector_destroy(parser->tokens);
  246.  
  247.         parserutils_stack_destroy(parser->states);
  248.  
  249.         css__lexer_destroy(parser->lexer);
  250.  
  251.         parserutils_inputstream_destroy(parser->stream);
  252.  
  253.         parser->alloc(parser, 0, parser->pw);
  254.  
  255.         return CSS_OK;
  256. }
  257.  
  258. /**
  259.  * Configure a CSS parser
  260.  *
  261.  * \param parser  The parser instance to configure
  262.  * \param type    The option to configure
  263.  * \param params  Option-specific data
  264.  * \return CSS_OK on success, appropriate error otherwise
  265.  */
  266. css_error css__parser_setopt(css_parser *parser, css_parser_opttype type,
  267.                 css_parser_optparams *params)
  268. {
  269.         if (parser == NULL || params == NULL)
  270.                 return CSS_BADPARM;
  271.  
  272.         switch (type) {
  273.         case CSS_PARSER_QUIRKS:
  274.                 parser->quirks = params->quirks;
  275.                 break;
  276.         case CSS_PARSER_EVENT_HANDLER:
  277.                 parser->event = params->event_handler.handler;
  278.                 parser->event_pw = params->event_handler.pw;
  279.                 break;
  280.         }
  281.  
  282.         return CSS_OK;
  283. }
  284.  
  285. /**
  286.  * Parse a chunk of data using a CSS parser
  287.  *
  288.  * \param parser  The parser to use
  289.  * \param data    Pointer to the chunk to parse
  290.  * \param len     Length of chunk
  291.  * \return CSS_OK on success, appropriate error otherwise
  292.  */
  293. css_error css__parser_parse_chunk(css_parser *parser, const uint8_t *data,
  294.                 size_t len)
  295. {
  296.         parserutils_error perror;
  297.         parser_state *state;
  298.         css_error error = CSS_OK;
  299.  
  300.         if (parser == NULL || data == NULL)
  301.                 return CSS_BADPARM;
  302.  
  303.         perror = parserutils_inputstream_append(parser->stream, data, len);
  304.         if (perror != PARSERUTILS_OK)
  305.                 return css_error_from_parserutils_error(perror);
  306.  
  307.         do {
  308.                 state = parserutils_stack_get_current(parser->states);
  309.                 if (state == NULL)
  310.                         break;
  311.  
  312.                 error = parseFuncs[state->state](parser);
  313.         } while (error == CSS_OK);
  314.  
  315.         return error;
  316. }
  317.  
  318. /**
  319.  * Inform a CSS parser that all data has been received.
  320.  *
  321.  * \param parser  The parser to inform
  322.  * \return CSS_OK on success, appropriate error otherwise
  323.  */
  324. css_error css__parser_completed(css_parser *parser)
  325. {
  326.         parserutils_error perror;
  327.         parser_state *state;
  328.         css_error error = CSS_OK;
  329.  
  330.         if (parser == NULL)
  331.                 return CSS_BADPARM;
  332.  
  333.         /* Send EOF to input stream */
  334.         perror = parserutils_inputstream_append(parser->stream, NULL, 0);
  335.         if (perror != PARSERUTILS_OK)
  336.                 return css_error_from_parserutils_error(perror);
  337.  
  338.         /* Flush through any remaining data */
  339.         do {
  340.                 state = parserutils_stack_get_current(parser->states);
  341.                 if (state == NULL)
  342.                         break;
  343.  
  344.                 error = parseFuncs[state->state](parser);
  345.         } while (error == CSS_OK);
  346.  
  347.         return error;
  348. }
  349.  
  350. /**
  351.  * Retrieve document charset information from a CSS parser
  352.  *
  353.  * \param parser  The parser instance
  354.  * \param source  Pointer to location to receive charset source
  355.  * \return Pointer to charset name (constant; do not free)
  356.  */
  357. const char *css__parser_read_charset(css_parser *parser,
  358.                 css_charset_source *source)
  359. {
  360.         const char *charset;
  361.         uint32_t src;
  362.  
  363.         if (parser == NULL || source == NULL)
  364.                 return NULL;
  365.  
  366.         charset = parserutils_inputstream_read_charset(parser->stream, &src);
  367.  
  368.         *source = (css_charset_source) src;
  369.  
  370.         return charset;
  371. }
  372.  
  373. /**
  374.  * Quirks permitted when parsing
  375.  *
  376.  * \param parser  Parser to query
  377.  * \return True if quirks permitted, false otherwise
  378.  */
  379. bool css__parser_quirks_permitted(css_parser *parser)
  380. {
  381.         return parser->quirks;
  382. }
  383.  
  384. /******************************************************************************
  385.  * Parser creation helper                                                     *
  386.  ******************************************************************************/
  387.  
  388. /**
  389.  * Create a CSS parser (internal)
  390.  *
  391.  * \param charset     Charset of data, if known, or NULL
  392.  * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT
  393.  * \param alloc       Memory (de)allocation function
  394.  * \param pw          Pointer to client-specific private data
  395.  * \param initial     The required initial state of the parser
  396.  * \param parser      Pointer to location to receive parser instance
  397.  * \return CSS_OK on success,
  398.  *         CSS_BADPARM on bad parameters,
  399.  *         CSS_NOMEM on memory exhaustion
  400.  */
  401. css_error css__parser_create_internal(const char *charset,
  402.                 css_charset_source cs_source,
  403.                 css_allocator_fn alloc, void *pw, parser_state initial,
  404.                 css_parser **parser)
  405. {
  406.         css_parser *p;
  407.         parserutils_error perror;
  408.         css_error error;
  409.  
  410.         if (alloc == NULL || parser == NULL)
  411.                 return CSS_BADPARM;
  412.  
  413.         p = alloc(NULL, sizeof(css_parser), pw);
  414.         if (p == NULL)
  415.                 return CSS_NOMEM;
  416.  
  417.         perror = parserutils_inputstream_create(charset, cs_source,
  418.                         css__charset_extract, (parserutils_alloc) alloc, pw,
  419.                         &p->stream);
  420.         if (perror != PARSERUTILS_OK) {
  421.                 alloc(p, 0, pw);
  422.                 return css_error_from_parserutils_error(perror);
  423.         }
  424.  
  425.         error = css__lexer_create(p->stream, alloc, pw, &p->lexer);
  426.         if (error != CSS_OK) {
  427.                 parserutils_inputstream_destroy(p->stream);
  428.                 alloc(p, 0, pw);
  429.                 return error;
  430.         }
  431.  
  432.         perror = parserutils_stack_create(sizeof(parser_state),
  433.                         STACK_CHUNK, (parserutils_alloc) alloc, pw,
  434.                         &p->states);
  435.         if (perror != PARSERUTILS_OK) {
  436.                 css__lexer_destroy(p->lexer);
  437.                 parserutils_inputstream_destroy(p->stream);
  438.                 alloc(p, 0, pw);
  439.                 return css_error_from_parserutils_error(perror);
  440.         }
  441.  
  442.         perror = parserutils_vector_create(sizeof(css_token),
  443.                         STACK_CHUNK, (parserutils_alloc) alloc, pw,
  444.                         &p->tokens);
  445.         if (perror != PARSERUTILS_OK) {
  446.                 parserutils_stack_destroy(p->states);
  447.                 css__lexer_destroy(p->lexer);
  448.                 parserutils_inputstream_destroy(p->stream);
  449.                 alloc(p, 0, pw);
  450.                 return css_error_from_parserutils_error(perror);
  451.         }
  452.  
  453.         perror = parserutils_stack_create(sizeof(char),
  454.                         STACK_CHUNK, (parserutils_alloc) alloc, pw,
  455.                         &p->open_items);
  456.         if (perror != PARSERUTILS_OK) {
  457.                 parserutils_vector_destroy(p->tokens);
  458.                 parserutils_stack_destroy(p->states);
  459.                 css__lexer_destroy(p->lexer);
  460.                 parserutils_inputstream_destroy(p->stream);
  461.                 alloc(p, 0, pw);
  462.                 return css_error_from_parserutils_error(perror);
  463.         }
  464.  
  465.         perror = parserutils_stack_push(p->states, (void *) &initial);
  466.         if (perror != PARSERUTILS_OK) {
  467.                 parserutils_stack_destroy(p->open_items);
  468.                 parserutils_vector_destroy(p->tokens);
  469.                 parserutils_stack_destroy(p->states);
  470.                 css__lexer_destroy(p->lexer);
  471.                 parserutils_inputstream_destroy(p->stream);
  472.                 alloc(p, 0, pw);
  473.                 return css_error_from_parserutils_error(perror);
  474.         }
  475.  
  476.         p->quirks = false;
  477.         p->pushback = NULL;
  478.         p->parseError = false;
  479.         p->match_char = 0;
  480.         p->event = NULL;
  481.         p->last_was_ws = false;
  482.         p->event_pw = NULL;
  483.         p->alloc = alloc;
  484.         p->pw = pw;
  485.  
  486.         *parser = p;
  487.  
  488.         return CSS_OK;
  489. }
  490.  
  491. /******************************************************************************
  492.  * Helper functions                                                           *
  493.  ******************************************************************************/
  494.  
  495. /**
  496.  * Transition to a new state, ensuring return to the one specified
  497.  *
  498.  * \param parser      The parser instance
  499.  * \param to          Destination state
  500.  * \param subsequent  The state to return to
  501.  * \return CSS_OK on success, appropriate error otherwise
  502.  */
  503. css_error transition(css_parser *parser, parser_state to,
  504.                 parser_state subsequent)
  505. {
  506.         parser_state *state = parserutils_stack_get_current(parser->states);
  507.         parser_state current = *state;
  508.         parserutils_error perror;
  509.  
  510.         /* Replace current state on the stack with the subsequent one */
  511.         *state = subsequent;
  512.  
  513.         /* Push next state on the stack */
  514.         perror = parserutils_stack_push(parser->states, (void *) &to);
  515.         if (perror != PARSERUTILS_OK) {
  516.                 *state = current;
  517.                 return css_error_from_parserutils_error(perror);
  518.         }
  519.  
  520. #if !defined(NDEBUG) && defined(DEBUG_STACK)
  521.         parserutils_stack_dump(parser->states, __func__, printer);
  522. #endif
  523.  
  524.         /* Clear the error flag */
  525.         parser->parseError = false;
  526.  
  527.         return CSS_OK;
  528. }
  529.  
  530. /**
  531.  * Transition to a new state, returning to previous state on stack
  532.  *
  533.  * \param parser  The parser instance
  534.  * \param to      Destination state
  535.  * \return CSS_OK on success, appropriate error otherwise
  536.  */
  537. css_error transitionNoRet(css_parser *parser, parser_state to)
  538. {
  539.         parser_state *state = parserutils_stack_get_current(parser->states);
  540.  
  541.         /* Replace current state on the stack with destination */
  542.         *state = to;
  543.  
  544. #if !defined(NDEBUG) && defined(DEBUG_STACK)
  545.         parserutils_stack_dump(parser->states, __func__, printer);
  546. #endif
  547.  
  548.         /* Clear the error flag */
  549.         parser->parseError = false;
  550.  
  551.         return CSS_OK;
  552. }
  553.  
  554. /**
  555.  * Return to previous state on the stack
  556.  *
  557.  * \param parser  The parser instance
  558.  * \return CSS_OK on success, appropriate error otherwise
  559.  */
  560. css_error done(css_parser *parser)
  561. {
  562.         parserutils_error perror;
  563.  
  564.         /* Pop current state from stack */
  565.         perror = parserutils_stack_pop(parser->states, NULL);
  566.         if (perror != PARSERUTILS_OK)
  567.                 return css_error_from_parserutils_error(perror);
  568.  
  569. #if !defined(NDEBUG) && defined(DEBUG_STACK)
  570.         parserutils_stack_dump(parser->states, __func__, printer);
  571. #endif
  572.  
  573.         return CSS_OK;
  574. }
  575.  
  576. /**
  577.  * Assert that the expected token is next in the input
  578.  *
  579.  * \param parser  The parser instance
  580.  * \param type    The expected token type
  581.  * \return CSS_OK on success, appropriate error otherwise
  582.  */
  583. css_error expect(css_parser *parser, css_token_type type)
  584. {
  585.         const css_token *token;
  586.         css_error error;
  587.  
  588.         error = getToken(parser, &token);
  589.         if (error != CSS_OK)
  590.                 return error;
  591.  
  592.         if (token->type != type) {
  593.                 error = pushBack(parser, token);
  594.                 if (error != CSS_OK)
  595.                         return error;
  596.                 return CSS_INVALID;
  597.         }
  598.  
  599.         return CSS_OK;
  600. }
  601.  
  602. /**
  603.  * Retrieve the next token in the input
  604.  *
  605.  * \param parser  The parser instance
  606.  * \param token   Pointer to location to receive token
  607.  * \return CSS_OK on success, appropriate error otherwise
  608.  */
  609. css_error getToken(css_parser *parser, const css_token **token)
  610. {
  611.         parserutils_error perror;
  612.         lwc_error lerror;
  613.         css_error error;
  614.  
  615.         /* Use pushback, if it exists */
  616.         if (parser->pushback != NULL) {
  617.                 *token = parser->pushback;
  618.                 parser->pushback = NULL;
  619.         } else {
  620.                 /* Otherwise, ask the lexer */
  621.                 css_token *t;
  622.  
  623.                 error = css__lexer_get_token(parser->lexer, &t);
  624.                 if (error != CSS_OK)
  625.                         return error;
  626.  
  627.                 /* If the last token read was whitespace, keep reading
  628.                  * tokens until we encounter one that isn't whitespace */
  629.                 while (parser->last_was_ws && t->type == CSS_TOKEN_S) {
  630.                         error = css__lexer_get_token(parser->lexer, &t);
  631.                         if (error != CSS_OK)
  632.                                 return error;
  633.                 }
  634.  
  635.                 /* We need only intern for the following token types:
  636.                  *
  637.                  * CSS_TOKEN_IDENT, CSS_TOKEN_ATKEYWORD, CSS_TOKEN_STRING,
  638.                  * CSS_TOKEN_INVALID_STRING, CSS_TOKEN_HASH, CSS_TOKEN_URI,
  639.                  * CSS_TOKEN_UNICODE_RANGE?, CSS_TOKEN_FUNCTION, CSS_TOKEN_CHAR,
  640.                  * CSS_TOKEN_NUMBER, CSS_TOKEN_PERCENTAGE, CSS_TOKEN_DIMENSION
  641.                  *
  642.                  * These token types all appear before CSS_TOKEN_LAST_INTERN.
  643.                  * All other token types appear after this magic value.
  644.                  */
  645.  
  646.                 if (t->type < CSS_TOKEN_LAST_INTERN && t->data.data != NULL) {
  647.                         /* Insert token text into the dictionary */
  648.                         lerror = lwc_intern_string((char *)t->data.data,
  649.                                                     t->data.len, &t->idata);
  650.                         if (lerror != lwc_error_ok)
  651.                                 return css_error_from_lwc_error(lerror);
  652.                 } else {
  653.                         t->idata = NULL;
  654.                 }
  655.  
  656.                 *token = t;
  657.         }
  658.  
  659.         /* Append token to vector */
  660.         perror = parserutils_vector_append(parser->tokens,
  661.                         (css_token *) (*token));
  662.         if (perror != PARSERUTILS_OK)
  663.                 return css_error_from_parserutils_error(perror);
  664.  
  665.         parser->last_was_ws = ((*token)->type == CSS_TOKEN_S);
  666.  
  667.         return CSS_OK;
  668. }
  669.  
  670. /**
  671.  * Push a token back on the input
  672.  *
  673.  * \param parser  The parser instance
  674.  * \param token   The token to push back
  675.  * \return CSS_OK on success.
  676.  */
  677. css_error pushBack(css_parser *parser, const css_token *token)
  678. {
  679.         parserutils_error perror;
  680.  
  681.         /* The pushback buffer depth is 1 token. Assert this. */
  682.         assert(parser->pushback == NULL);
  683.        
  684.         perror = parserutils_vector_remove_last(parser->tokens);
  685.         if (perror != PARSERUTILS_OK)
  686.                 return css_error_from_parserutils_error(perror);
  687.  
  688.         parser->pushback = token;
  689.  
  690.         return CSS_OK;
  691. }
  692.  
  693. /**
  694.  * Eat whitespace tokens
  695.  *
  696.  * \param parser  The parser instance
  697.  * \return CSS_OK on success, appropriate error otherwise
  698.  */
  699. css_error eatWS(css_parser *parser)
  700. {
  701.         const css_token *token;
  702.         css_error error;
  703.  
  704.         error = getToken(parser, &token);
  705.         if (error != CSS_OK)
  706.                 return error;
  707.  
  708.         if (token->type != CSS_TOKEN_S) {
  709.                 error = pushBack(parser, token);
  710.                 if (error != CSS_OK)
  711.                         return error;
  712.         }
  713.  
  714.         return CSS_OK;
  715. }
  716.  
  717. /******************************************************************************
  718.  * Parser stages                                                              *
  719.  ******************************************************************************/
  720.  
  721. css_error parseStart(css_parser *parser)
  722. {
  723.         enum { Initial = 0, AfterWS = 1, AfterStylesheet = 2 };
  724.         parser_state *state = parserutils_stack_get_current(parser->states);
  725.         css_error error = CSS_OK;
  726.  
  727.         /* start -> ws stylesheet EOF */
  728.  
  729.         switch (state->substate) {
  730.         case Initial:
  731. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  732.                 printf("Begin stylesheet\n");
  733. #endif
  734.                 if (parser->event != NULL) {
  735.                         parser->event(CSS_PARSER_START_STYLESHEET, NULL,
  736.                                         parser->event_pw);
  737.                 }
  738.  
  739.                 error = eatWS(parser);
  740.                 if (error != CSS_OK)
  741.                         return error;
  742.                 state->substate = AfterWS;
  743.                 /* Fall through */
  744.         case AfterWS:
  745.         {
  746.                 parser_state to = { sStylesheet, Initial };
  747.                 parser_state subsequent = { sStart, AfterStylesheet };
  748.  
  749.                 return transition(parser, to, subsequent);
  750.         }
  751.         case AfterStylesheet:
  752.                 error = expect(parser, CSS_TOKEN_EOF);
  753.                 if (error != CSS_OK)
  754.                         return error;
  755.  
  756.                 /* Flag completion, just in case */
  757.         }
  758.  
  759. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  760.         parserutils_vector_dump(parser->tokens, __func__, tprinter);
  761.         printf("End stylesheet\n");
  762. #endif
  763.         if (parser->event != NULL) {
  764.                 parser->event(CSS_PARSER_END_STYLESHEET, NULL,
  765.                                 parser->event_pw);
  766.         }
  767.        
  768.         unref_interned_strings_in_tokens(parser);
  769.         parserutils_vector_clear(parser->tokens);
  770.  
  771.         return done(parser);
  772. }
  773.  
  774. css_error parseStylesheet(css_parser *parser)
  775. {
  776.         enum { Initial = 0, WS = 1 };
  777.         parser_state *state = parserutils_stack_get_current(parser->states);
  778.         const css_token *token;
  779.         css_error error;
  780.  
  781.         /* stylesheet -> CDO ws stylesheet
  782.          *            -> CDC ws stylesheet
  783.          *            -> statement ws stylesheet
  784.          *            ->
  785.          */
  786.  
  787.         while (1) {
  788.                 switch (state->substate) {
  789.                 case Initial:
  790.                         error = getToken(parser, &token);
  791.                         if (error != CSS_OK)
  792.                                 return error;
  793.  
  794.                         switch (token->type) {
  795.                         case CSS_TOKEN_EOF:
  796.                                 error = pushBack(parser, token);
  797.                                 if (error != CSS_OK)
  798.                                         return error;
  799.  
  800.                                 unref_interned_strings_in_tokens(parser);
  801.                                 parserutils_vector_clear(parser->tokens);
  802.  
  803.                                 return done(parser);
  804.                         case CSS_TOKEN_CDO:
  805.                         case CSS_TOKEN_CDC:
  806.                                 break;
  807.                         default:
  808.                         {
  809.                                 parser_state to = { sStatement, Initial };
  810.                                 parser_state subsequent = { sStylesheet, WS };
  811.  
  812.                                 error = pushBack(parser, token);
  813.                                 if (error != CSS_OK)
  814.                                         return error;
  815.  
  816.                                 return transition(parser, to, subsequent);
  817.                         }
  818.                         }
  819.  
  820.                         state->substate = WS;
  821.                         /* Fall through */
  822.                 case WS:
  823.                         error = eatWS(parser);
  824.                         if (error != CSS_OK)
  825.                                 return error;
  826.  
  827.                         state->substate = Initial;
  828.                 }
  829.         }
  830. }
  831.  
  832. css_error parseStatement(css_parser *parser)
  833. {
  834.         enum { Initial = 0 };
  835.         const css_token *token;
  836.         parser_state to = { sRuleset, Initial };
  837.         css_error error;
  838.  
  839.         /* statement -> ruleset
  840.          *              at-rule
  841.          */
  842.  
  843.         error = getToken(parser, &token);
  844.         if (error != CSS_OK)
  845.                 return error;
  846.  
  847.         if (token->type == CSS_TOKEN_ATKEYWORD)
  848.                 to.state = sAtRule;
  849.  
  850.         error = pushBack(parser, token);
  851.         if (error != CSS_OK)
  852.                 return error;
  853.  
  854.         return transitionNoRet(parser, to);
  855. }
  856.  
  857. css_error parseRuleset(css_parser *parser)
  858. {
  859.         enum { Initial = 0, Brace = 1, WS = 2 };
  860.         parser_state *state = parserutils_stack_get_current(parser->states);
  861.         parser_state to = { sRulesetEnd, Initial };
  862.         const css_token *token;
  863.         css_error error;
  864.  
  865.         /* ruleset -> selector '{' ws ruleset-end
  866.          *         -> '{' ws ruleset-end
  867.          */
  868.  
  869.         switch (state->substate) {
  870.         case Initial:
  871.                 unref_interned_strings_in_tokens(parser);
  872.                 parserutils_vector_clear(parser->tokens);
  873.  
  874.                 error = getToken(parser, &token);
  875.                 if (error != CSS_OK)
  876.                         return error;
  877.  
  878.                 /* The grammar's ambiguous here -- selectors may start with a
  879.                  * brace. We're going to assume that that won't happen,
  880.                  * however. */
  881.                 if (token->type == CSS_TOKEN_CHAR &&
  882.                                 lwc_string_length(token->idata) == 1 &&
  883.                                 lwc_string_data(token->idata)[0] == '{') {
  884. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  885.                         printf("Begin ruleset\n");
  886. #endif
  887.                         if (parser->event != NULL) {
  888.                                 if (parser->event(CSS_PARSER_START_RULESET,
  889.                                                 NULL, parser->event_pw) ==
  890.                                                 CSS_INVALID) {
  891.                                         parser_state to =
  892.                                                 { sMalformedSelector, Initial };
  893.  
  894.                                         return transitionNoRet(parser, to);
  895.                                 }
  896.                         }
  897.  
  898.                         state->substate = WS;
  899.                         goto ws;
  900.                 } else {
  901.                         parser_state to = { sSelector, Initial };
  902.                         parser_state subsequent = { sRuleset, Brace };
  903.  
  904.                         error = pushBack(parser, token);
  905.                         if (error != CSS_OK)
  906.                                 return error;
  907.  
  908.                         return transition(parser, to, subsequent);
  909.                 }
  910.                 break;
  911.         case Brace:
  912. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  913.                 printf("Begin ruleset\n");
  914.                 parserutils_vector_dump(parser->tokens, __func__, tprinter);
  915. #endif
  916.                 if (parser->parseError == false && parser->event != NULL) {
  917.                         if (parser->event(CSS_PARSER_START_RULESET,
  918.                                         parser->tokens, parser->event_pw) ==
  919.                                         CSS_INVALID)
  920.                                 parser->parseError = true;
  921.                 }
  922.  
  923.                 if (parser->parseError == true) {
  924.                         parser_state to = { sMalformedSelector, Initial };
  925.  
  926.                         return transitionNoRet(parser, to);
  927.                 }
  928.  
  929.                 error = getToken(parser, &token);
  930.                 if (error != CSS_OK)
  931.                         return error;
  932.  
  933.                 if (token->type == CSS_TOKEN_EOF) {
  934.                         error = pushBack(parser, token);
  935.                         if (error != CSS_OK)
  936.                                 return error;
  937.  
  938.                         return done(parser);
  939.                 }
  940.  
  941.                 if (token->type != CSS_TOKEN_CHAR ||
  942.                                 lwc_string_length(token->idata) != 1 ||
  943.                                 lwc_string_data(token->idata)[0] != '{') {
  944.                         /* This should never happen, as FOLLOW(selector)
  945.                          * contains only '{' */
  946.                         assert(0 && "Expected {");
  947.                 }
  948.                
  949.                 state->substate = WS;
  950.                 /* Fall through */
  951.         case WS:
  952.         ws:
  953.                 error = eatWS(parser);
  954.                 if (error != CSS_OK)
  955.                         return error;
  956.  
  957.                 break;
  958.         }
  959.  
  960.         return transitionNoRet(parser, to);
  961. }
  962.  
  963. css_error parseRulesetEnd(css_parser *parser)
  964. {
  965.         enum { Initial = 0, DeclList = 1, Brace = 2, WS = 3 };
  966.         parser_state *state = parserutils_stack_get_current(parser->states);
  967.         const css_token *token;
  968.         css_error error;
  969.  
  970.         /* ruleset-end -> declaration decl-list '}' ws
  971.          *             -> decl-list '}' ws
  972.          */
  973.  
  974.         switch (state->substate) {
  975.         case Initial:
  976.                 error = getToken(parser, &token);
  977.                 if (error != CSS_OK)
  978.                         return error;
  979.  
  980.                 error = pushBack(parser, token);
  981.                 if (error != CSS_OK)
  982.                         return error;
  983.  
  984.                 if (token->type == CSS_TOKEN_EOF)
  985.                         return done(parser);
  986.  
  987.                 /* If this can't possibly be the start of a decl-list, then
  988.                  * attempt to parse a declaration. This will catch any invalid
  989.                  * input at this point and read to the start of the next
  990.                  * declaration. FIRST(decl-list) = (';', '}') */
  991.                 if (token->type != CSS_TOKEN_CHAR ||
  992.                                 lwc_string_length(token->idata) != 1 ||
  993.                                 (lwc_string_data(token->idata)[0] != '}' &&
  994.                                 lwc_string_data(token->idata)[0] != ';')) {
  995.                         parser_state to = { sDeclaration, Initial };
  996.                         parser_state subsequent = { sRulesetEnd, DeclList };
  997.  
  998.                         return transition(parser, to, subsequent);
  999.                 }
  1000.  
  1001.                 state->substate = DeclList;
  1002.                 /* Fall through */
  1003.         case DeclList:
  1004.         {
  1005.                 parser_state to = { sDeclList, Initial };
  1006.                 parser_state subsequent = { sRulesetEnd, Brace };
  1007.  
  1008.                 return transition(parser, to, subsequent);
  1009.         }
  1010.         case Brace:
  1011.                 error = getToken(parser, &token);
  1012.                 if (error != CSS_OK)
  1013.                         return error;
  1014.  
  1015.                 if (token->type == CSS_TOKEN_EOF) {
  1016.                         error = pushBack(parser, token);
  1017.                         if (error != CSS_OK)
  1018.                                 return error;
  1019.  
  1020.                         return done(parser);
  1021.                 }
  1022.  
  1023.                 if (token->type != CSS_TOKEN_CHAR ||
  1024.                                 lwc_string_length(token->idata) != 1 ||
  1025.                                 lwc_string_data(token->idata)[0] != '}') {
  1026.                         /* This should never happen, as FOLLOW(decl-list)
  1027.                          * contains only '}' */
  1028.                         assert(0 && "Expected }");
  1029.                 }
  1030.  
  1031.                 state->substate = WS;
  1032.                 /* Fall through */
  1033.         case WS:
  1034.                 error = eatWS(parser);
  1035.                 if (error != CSS_OK)
  1036.                         return error;
  1037.  
  1038.                 break;
  1039.         }
  1040.  
  1041. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1042.         printf("End ruleset\n");
  1043. #endif
  1044.         if (parser->event != NULL) {
  1045.                 parser->event(CSS_PARSER_END_RULESET, NULL, parser->event_pw);
  1046.         }
  1047.  
  1048.         return done(parser);
  1049. }
  1050.  
  1051. css_error parseAtRule(css_parser *parser)
  1052. {
  1053.         enum { Initial = 0, WS = 1, Any = 2, AfterAny = 3 };
  1054.         parser_state *state = parserutils_stack_get_current(parser->states);
  1055.         parser_state to = { sAtRuleEnd, Initial };
  1056.         const css_token *token;
  1057.         css_error error;
  1058.  
  1059.         /* at-rule -> ATKEYWORD ws any0 at-rule-end */
  1060.  
  1061.         switch (state->substate) {
  1062.         case Initial:
  1063.                 unref_interned_strings_in_tokens(parser);
  1064.                 parserutils_vector_clear(parser->tokens);
  1065.  
  1066.                 error = getToken(parser, &token);
  1067.                 if (error != CSS_OK)
  1068.                         return error;
  1069.  
  1070.                 assert(token->type == CSS_TOKEN_ATKEYWORD);
  1071.  
  1072.                 state->substate = WS;
  1073.                 /* Fall through */
  1074.         case WS:
  1075.                 error = eatWS(parser);
  1076.                 if (error != CSS_OK)
  1077.                         return error;
  1078.  
  1079.                 state->substate = Any;
  1080.                 /* Fall through */
  1081.         case Any:
  1082.         {
  1083.                 parser_state to = { sAny0, Initial };
  1084.                 parser_state subsequent = { sAtRule, AfterAny };
  1085.  
  1086.                 return transition(parser, to, subsequent);
  1087.         }
  1088.         case AfterAny:
  1089.                 if (parser->parseError) {
  1090.                         parser_state to = { sMalformedAtRule, Initial };
  1091.  
  1092.                         return transitionNoRet(parser, to);
  1093.                 }
  1094.  
  1095.                 error = getToken(parser, &token);
  1096.                 if (error != CSS_OK)
  1097.                         return error;
  1098.  
  1099.                 /* Grammar ambiguity: any0 can be followed by '{',';',')',']'.
  1100.                  * at-rule can only be followed by '{' and ';'. */
  1101.                 if (token->type == CSS_TOKEN_CHAR &&
  1102.                                 lwc_string_length(token->idata) == 1) {
  1103.                         if (lwc_string_data(token->idata)[0] == ')' ||
  1104.                                         lwc_string_data(
  1105.                                                 token->idata)[0] == ']') {
  1106.                                 parser_state to = { sAny0, Initial };
  1107.                                 parser_state subsequent = { sAtRule, AfterAny };
  1108.  
  1109.                                 return transition(parser, to, subsequent);
  1110.                         }
  1111.                 }
  1112.  
  1113.                 error = pushBack(parser, token);
  1114.                 if (error != CSS_OK)
  1115.                         return error;
  1116.  
  1117.                 break;
  1118.         }
  1119.  
  1120.         return transitionNoRet(parser, to);
  1121. }
  1122.  
  1123. css_error parseAtRuleEnd(css_parser *parser)
  1124. {
  1125.         enum { Initial = 0, WS = 1, AfterBlock = 2 };
  1126.         parser_state *state = parserutils_stack_get_current(parser->states);
  1127.         const css_token *token;
  1128.         css_error error;
  1129.  
  1130.         /* at-rule-end -> block
  1131.          *             -> ';' ws
  1132.          */
  1133.  
  1134.         switch (state->substate) {
  1135.         case Initial:
  1136. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1137.                 printf("Begin at-rule\n");
  1138.                 parserutils_vector_dump(parser->tokens, __func__, tprinter);
  1139. #endif
  1140.                 if (parser->event != NULL) {
  1141.                         if (parser->event(CSS_PARSER_START_ATRULE,
  1142.                                         parser->tokens, parser->event_pw) ==
  1143.                                         CSS_INVALID) {
  1144.                                 parser_state to = { sMalformedAtRule, Initial };
  1145.  
  1146.                                 return transitionNoRet(parser, to);
  1147.                         }
  1148.                 }
  1149.  
  1150.                 error = getToken(parser, &token);
  1151.                 if (error != CSS_OK)
  1152.                         return error;
  1153.  
  1154.                 if (token->type == CSS_TOKEN_EOF) {
  1155.                         error = pushBack(parser, token);
  1156.                         if (error != CSS_OK)
  1157.                                 return error;
  1158.  
  1159.                         return done(parser);
  1160.                 }
  1161.  
  1162.                 if (token->type != CSS_TOKEN_CHAR ||
  1163.                                 lwc_string_length(token->idata) != 1) {
  1164.                         /* Should never happen FOLLOW(at-rule) == '{', ';'*/
  1165.                         assert(0 && "Expected { or ;");
  1166.                 }
  1167.                
  1168.                 if (lwc_string_data(token->idata)[0] == '{') {
  1169.                         parser_state to = { sBlock, Initial };
  1170.                         parser_state subsequent = { sAtRuleEnd, AfterBlock };
  1171.  
  1172.                         error = pushBack(parser, token);
  1173.                         if (error != CSS_OK)
  1174.                                 return error;
  1175.  
  1176.                         return transition(parser, to, subsequent);
  1177.                 } else if (lwc_string_data(token->idata)[0] != ';') {
  1178.                         /* Again, should never happen */
  1179.                         assert(0 && "Expected ;");
  1180.                 }
  1181.  
  1182.                 state->substate = WS;
  1183.                 /* Fall through */
  1184.         case WS:
  1185.                 error = eatWS(parser);
  1186.                 if (error != CSS_OK)
  1187.                         return error;
  1188.  
  1189.                 break;
  1190.         case AfterBlock:
  1191.                 break;
  1192.         }
  1193.  
  1194. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1195.         printf("End at-rule\n");
  1196. #endif
  1197.         if (parser->event != NULL) {
  1198.                 parser->event(CSS_PARSER_END_ATRULE, NULL, parser->event_pw);
  1199.         }
  1200.  
  1201.         return done(parser);
  1202. }
  1203.  
  1204. css_error parseBlock(css_parser *parser)
  1205. {
  1206.         enum { Initial = 0, WS = 1, Content = 2, Brace = 3, WS2 = 4 };
  1207.         parser_state *state = parserutils_stack_get_current(parser->states);
  1208.         const css_token *token;
  1209.         css_error error;
  1210.  
  1211.         /* block -> '{' ws block-content '}' ws */
  1212.  
  1213.         switch (state->substate) {
  1214.         case Initial:
  1215.                 error = getToken(parser, &token);
  1216.                 if (error != CSS_OK)
  1217.                         return error;
  1218.  
  1219. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1220.                 printf("Begin block\n");
  1221. #endif
  1222.                 if (parser->event != NULL) {
  1223.                         parser->event(CSS_PARSER_START_BLOCK, NULL,
  1224.                                         parser->event_pw);
  1225.                 }
  1226.  
  1227.                 if (token->type != CSS_TOKEN_CHAR ||
  1228.                                 lwc_string_length(token->idata) != 1 ||
  1229.                                 lwc_string_data(token->idata)[0] != '{') {
  1230.                         /* This should never happen, as FIRST(block) == '{' */
  1231.                         assert(0 && "Expected {");
  1232.                 }
  1233.  
  1234.                 unref_interned_strings_in_tokens(parser);
  1235.                 parserutils_vector_clear(parser->tokens);
  1236.  
  1237.                 state->substate = WS;
  1238.                 /* Fall through */
  1239.         case WS:
  1240.                 error = eatWS(parser);
  1241.                 if (error != CSS_OK)
  1242.                         return error;
  1243.  
  1244.                 state->substate = Content;
  1245.                 /* Fall through */
  1246.         case Content:
  1247.         {
  1248.                 parser_state to = { sBlockContent, Initial };
  1249.                 parser_state subsequent = { sBlock, Brace };
  1250.  
  1251.                 return transition(parser, to, subsequent);
  1252.         }
  1253.         case Brace:
  1254.                 error = getToken(parser, &token);
  1255.                 if (error != CSS_OK)
  1256.                         return error;
  1257.  
  1258.                 if (token->type == CSS_TOKEN_EOF) {
  1259.                         error = pushBack(parser, token);
  1260.                         if (error != CSS_OK)
  1261.                                 return error;
  1262.  
  1263.                         return done(parser);
  1264.                 }
  1265.  
  1266.                 if (token->type != CSS_TOKEN_CHAR ||
  1267.                                 lwc_string_length(token->idata) != 1 ||
  1268.                                 lwc_string_data(token->idata)[0] != '}') {
  1269.                         /* This should never happen, as
  1270.                          * FOLLOW(block-content) == '}' */
  1271.                         assert(0 && "Expected }");
  1272.                 }
  1273.  
  1274.                 state->substate = WS2;
  1275.                 /* Fall through */
  1276.         case WS2:
  1277.                 error = eatWS(parser);
  1278.                 if (error != CSS_OK)
  1279.                         return error;
  1280.  
  1281.                 break;
  1282.         }
  1283.  
  1284. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1285.         printf("End block\n");
  1286. #endif
  1287.         if (parser->event != NULL) {
  1288.                 parser->event(CSS_PARSER_END_BLOCK, NULL, parser->event_pw);
  1289.         }
  1290.  
  1291.         unref_interned_strings_in_tokens(parser);
  1292.         parserutils_vector_clear(parser->tokens);
  1293.  
  1294.         return done(parser);
  1295. }
  1296.  
  1297. css_error parseBlockContent(css_parser *parser)
  1298. {
  1299.         enum { Initial = 0, WS = 1 };
  1300.         parser_state *state = parserutils_stack_get_current(parser->states);
  1301.         const css_token *token;
  1302.         css_error error;
  1303.  
  1304.         /* block-content -> any block-content
  1305.          *               -> block block-content
  1306.          *               -> ATKEYWORD ws block-content
  1307.          *               -> ';' ws block-content
  1308.          *               ->
  1309.          */
  1310.  
  1311.         while (1) {
  1312.                 switch (state->substate) {
  1313.                 case Initial:
  1314.                         error = getToken(parser, &token);
  1315.                         if (error != CSS_OK)
  1316.                                 return error;
  1317.  
  1318.                         if (token->type == CSS_TOKEN_ATKEYWORD) {
  1319.                                 state->substate = WS;
  1320.                         } else if (token->type == CSS_TOKEN_CHAR) {
  1321.                                 if (lwc_string_length(token->idata) == 1 &&
  1322.                                                 lwc_string_data(
  1323.                                                 token->idata)[0] == '{') {
  1324.                                         /* Grammar ambiguity. Assume block */
  1325.                                         parser_state to = { sBlock, Initial };
  1326.                                         parser_state subsequent =
  1327.                                                 { sBlockContent, Initial };
  1328.  
  1329.                                         error = pushBack(parser, token);
  1330.                                         if (error != CSS_OK)
  1331.                                                 return error;
  1332.  
  1333. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1334.                                         parserutils_vector_dump(parser->tokens,
  1335.                                                         __func__, tprinter);
  1336. #endif
  1337.                                         if (parser->event != NULL) {
  1338.                                                 parser->event(
  1339.                                                         CSS_PARSER_BLOCK_CONTENT,
  1340.                                                         parser->tokens,
  1341.                                                         parser->event_pw);
  1342.                                         }
  1343.  
  1344.                                         unref_interned_strings_in_tokens(
  1345.                                                         parser);
  1346.                                         parserutils_vector_clear(
  1347.                                                         parser->tokens);
  1348.  
  1349.                                         return transition(parser, to,
  1350.                                                         subsequent);
  1351.                                 } else if (lwc_string_length(
  1352.                                                 token->idata) == 1 &&
  1353.                                                 lwc_string_data(
  1354.                                                 token->idata)[0] == ';') {
  1355.                                         /* Grammar ambiguity. Assume semi */
  1356.                                         error = pushBack(parser, token);
  1357.                                         if (error != CSS_OK)
  1358.                                                 return error;
  1359.  
  1360. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1361.                                         parserutils_vector_dump(parser->tokens,
  1362.                                                         __func__, tprinter);
  1363. #endif
  1364.                                         if (parser->event != NULL) {
  1365.                                                 parser->event(
  1366.                                                         CSS_PARSER_BLOCK_CONTENT,
  1367.                                                         parser->tokens,
  1368.                                                         parser->event_pw);
  1369.                                         }
  1370.  
  1371.                                         error = getToken(parser, &token);
  1372.                                         if (error != CSS_OK)
  1373.                                                 return error;
  1374.  
  1375.                                         unref_interned_strings_in_tokens(
  1376.                                                         parser);
  1377.                                         parserutils_vector_clear(
  1378.                                                         parser->tokens);
  1379.  
  1380.                                         state->substate = WS;
  1381.                                 } else if (lwc_string_length(
  1382.                                                 token->idata) == 1 &&
  1383.                                                 lwc_string_data(
  1384.                                                 token->idata)[0] == '}') {
  1385.                                         /* Grammar ambiguity. Assume end */
  1386.                                         error = pushBack(parser, token);
  1387.                                         if (error != CSS_OK)
  1388.                                                 return error;
  1389.  
  1390. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1391.                                         parserutils_vector_dump(parser->tokens,
  1392.                                                         __func__, tprinter);
  1393. #endif
  1394.                                         if (parser->event != NULL) {
  1395.                                                 parser->event(
  1396.                                                         CSS_PARSER_BLOCK_CONTENT,
  1397.                                                         parser->tokens,
  1398.                                                         parser->event_pw);
  1399.                                         }
  1400.  
  1401.                                         unref_interned_strings_in_tokens(
  1402.                                                         parser);
  1403.                                         parserutils_vector_clear(
  1404.                                                         parser->tokens);
  1405.  
  1406.                                         return done(parser);
  1407.                                 }
  1408.                         } else if (token->type == CSS_TOKEN_EOF) {
  1409.                                 error = pushBack(parser, token);
  1410.                                 if (error != CSS_OK)
  1411.                                         return error;
  1412.  
  1413. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1414.                                 parserutils_vector_dump(parser->tokens,
  1415.                                                 __func__, tprinter);
  1416. #endif
  1417.                                 if (parser->event != NULL) {
  1418.                                         parser->event(CSS_PARSER_BLOCK_CONTENT,
  1419.                                                         parser->tokens,
  1420.                                                         parser->event_pw);
  1421.                                 }
  1422.  
  1423.                                 unref_interned_strings_in_tokens(parser);
  1424.                                 parserutils_vector_clear(parser->tokens);
  1425.  
  1426.                                 return done(parser);
  1427.                         }
  1428.  
  1429.                         if (state->substate == Initial) {
  1430.                                 parser_state to = { sAny, Initial };
  1431.                                 parser_state subsequent =
  1432.                                                 { sBlockContent, Initial };
  1433.  
  1434.                                 error = pushBack(parser, token);
  1435.                                 if (error != CSS_OK)
  1436.                                         return error;
  1437.  
  1438.                                 return transition(parser, to, subsequent);
  1439.                         }
  1440.  
  1441.                         break;
  1442.                 case WS:
  1443.                         error = eatWS(parser);
  1444.                         if (error != CSS_OK)
  1445.                                 return error;
  1446.  
  1447.                         state->substate = Initial;
  1448.                 }
  1449.         }
  1450.  
  1451.          return done(parser);
  1452. }
  1453.  
  1454. css_error parseSelector(css_parser *parser)
  1455. {
  1456.         enum { Initial = 0, AfterAny1 = 1 };
  1457.         parser_state *state = parserutils_stack_get_current(parser->states);
  1458.  
  1459.         /* selector -> any1 */
  1460.  
  1461.         switch (state->substate) {
  1462.         case Initial:
  1463.         {
  1464.                 parser_state to = { sAny1, Initial };
  1465.                 parser_state subsequent = { sSelector, AfterAny1 };
  1466.  
  1467.                 unref_interned_strings_in_tokens(parser);
  1468.                 parserutils_vector_clear(parser->tokens);
  1469.  
  1470.                 return transition(parser, to, subsequent);
  1471.         }
  1472.         case AfterAny1:
  1473.                 break;
  1474.         }
  1475.  
  1476.         return done(parser);
  1477. }
  1478.  
  1479. css_error parseDeclaration(css_parser *parser)
  1480. {
  1481.         enum { Initial = 0, Colon = 1, WS = 2, AfterValue1 = 3 };
  1482.         parser_state *state = parserutils_stack_get_current(parser->states);
  1483.         const css_token *token;
  1484.         css_error error;
  1485.  
  1486.         /* declaration -> property ':' ws value1 */
  1487.  
  1488.         switch (state->substate) {
  1489.         case Initial:
  1490.         {
  1491.                 parser_state to = { sProperty, Initial };
  1492.                 parser_state subsequent = { sDeclaration, Colon };
  1493.  
  1494.                 unref_interned_strings_in_tokens(parser);
  1495.                 parserutils_vector_clear(parser->tokens);
  1496.  
  1497.                 return transition(parser, to, subsequent);
  1498.         }
  1499.         case Colon:
  1500.                 if (parser->parseError) {
  1501.                         parser_state to = { sMalformedDecl, Initial };
  1502.  
  1503.                         parser->parseError = false;
  1504.  
  1505.                         return transitionNoRet(parser, to);
  1506.                 }
  1507.  
  1508.                 error = getToken(parser, &token);
  1509.                 if (error != CSS_OK)
  1510.                         return error;
  1511.  
  1512.                 if (token->type == CSS_TOKEN_EOF) {
  1513.                         error = pushBack(parser, token);
  1514.                         if (error != CSS_OK)
  1515.                                 return error;
  1516.  
  1517.                         return done(parser);
  1518.                 }
  1519.  
  1520.                 if (token->type != CSS_TOKEN_CHAR ||
  1521.                                 lwc_string_length(token->idata) != 1 ||
  1522.                                 lwc_string_data(token->idata)[0] != ':') {
  1523.                         /* parse error -- expected : */
  1524.                         parser_state to = { sMalformedDecl, Initial };
  1525.  
  1526.                         error = pushBack(parser, token);
  1527.                         if (error != CSS_OK)
  1528.                                 return error;
  1529.  
  1530.                         return transitionNoRet(parser, to);
  1531.                 }
  1532.  
  1533.                 state->substate = WS;
  1534.                 /* Fall through */
  1535.         case WS:
  1536.         {
  1537.                 parser_state to = { sValue1, Initial };
  1538.                 parser_state subsequent = { sDeclaration, AfterValue1 };
  1539.  
  1540.                 error = eatWS(parser);
  1541.                 if (error != CSS_OK)
  1542.                         return error;
  1543.  
  1544.                 return transition(parser, to, subsequent);
  1545.         }
  1546.         case AfterValue1:
  1547.                 if (parser->parseError) {
  1548.                         parser_state to = { sMalformedDecl, Initial };
  1549.  
  1550.                         parser->parseError = false;
  1551.  
  1552.                         return transitionNoRet(parser, to);
  1553.                 }
  1554.  
  1555. #if !defined(NDEBUG) && defined(DEBUG_EVENTS)
  1556.                 parserutils_vector_dump(parser->tokens, __func__, tprinter);
  1557. #endif
  1558.                 if (parser->event != NULL) {
  1559.                         parser->event(CSS_PARSER_DECLARATION, parser->tokens,
  1560.                                         parser->event_pw);
  1561.                 }
  1562.                 break;
  1563.         }
  1564.  
  1565.         return done(parser);
  1566. }
  1567.  
  1568. css_error parseDeclList(css_parser *parser)
  1569. {
  1570.         enum { Initial = 0, WS = 1 };
  1571.         parser_state *state = parserutils_stack_get_current(parser->states);
  1572.         parser_state to = { sDeclListEnd, Initial };
  1573.         const css_token *token;
  1574.         css_error error;
  1575.  
  1576.         /* decl-list -> ';' ws decl-list-end
  1577.          *           ->
  1578.          */
  1579.  
  1580.         switch (state->substate) {
  1581.         case Initial:
  1582.                 error = getToken(parser, &token);
  1583.                 if (error != CSS_OK)
  1584.                         return error;
  1585.  
  1586.                 if (token->type == CSS_TOKEN_EOF) {
  1587.                         error = pushBack(parser, token);
  1588.                         if (error != CSS_OK)
  1589.                                 return error;
  1590.  
  1591.                         return done(parser);
  1592.                 }
  1593.  
  1594.                 if (token->type != CSS_TOKEN_CHAR ||
  1595.                                 lwc_string_length(token->idata) != 1 ||
  1596.                                 (lwc_string_data(token->idata)[0] != '}' &&
  1597.                                 lwc_string_data(token->idata)[0] != ';')) {
  1598.                         /* Should never happen */
  1599.                         assert(0 && "Expected ; or  }");
  1600.                 }
  1601.  
  1602.                 if (lwc_string_data(token->idata)[0] == '}') {
  1603.                         error = pushBack(parser, token);
  1604.                         if (error != CSS_OK)
  1605.                                 return error;
  1606.  
  1607.                         return done(parser);
  1608.                 } else {
  1609.                         /* ; */
  1610.                         state->substate = WS;
  1611.                 }
  1612.  
  1613.                 /* Fall through */
  1614.         case WS:
  1615.                 error = eatWS(parser);
  1616.                 if (error != CSS_OK)
  1617.                         return error;
  1618.  
  1619.                 break;
  1620.         }
  1621.  
  1622.         return transitionNoRet(parser, to);
  1623. }
  1624.  
  1625. css_error parseDeclListEnd(css_parser *parser)
  1626. {
  1627.         enum { Initial = 0, AfterDeclaration = 1 };
  1628.         parser_state *state = parserutils_stack_get_current(parser->states);
  1629.         parser_state to = { sDeclList, Initial };
  1630.         const css_token *token;
  1631.         css_error error;
  1632.  
  1633.         /* decl-list-end -> declaration decl-list
  1634.          *               -> decl-list
  1635.          */
  1636.  
  1637.         switch (state->substate) {
  1638.         case Initial:
  1639.                 error = getToken(parser, &token);
  1640.                 if (error != CSS_OK)
  1641.                         return error;
  1642.  
  1643.                 if (token->type != CSS_TOKEN_CHAR ||
  1644.                                 lwc_string_length(token->idata) != 1 ||
  1645.                                 (lwc_string_data(token->idata)[0] != ';' &&
  1646.                                 lwc_string_data(token->idata)[0] != '}')) {
  1647.                         parser_state to = { sDeclaration, Initial };
  1648.                         parser_state subsequent =
  1649.                                         { sDeclListEnd, AfterDeclaration };
  1650.  
  1651.                         error = pushBack(parser, token);
  1652.                         if (error != CSS_OK)
  1653.                                 return error;
  1654.  
  1655.                         return transition(parser, to, subsequent);
  1656.                 } else {
  1657.                         error = pushBack(parser, token);
  1658.                         if (error != CSS_OK)
  1659.                                 return error;
  1660.                 }
  1661.  
  1662.                 state->substate = AfterDeclaration;
  1663.                 /* Fall through */
  1664.         case AfterDeclaration:
  1665.                 break;
  1666.         }
  1667.  
  1668.         return transitionNoRet(parser, to);
  1669. }
  1670.  
  1671. css_error parseProperty(css_parser *parser)
  1672. {
  1673.         enum { Initial = 0, WS = 1 };
  1674.         parser_state *state = parserutils_stack_get_current(parser->states);
  1675.         const css_token *token;
  1676.         css_error error;
  1677.  
  1678.         /* property -> IDENT ws */
  1679.  
  1680.         switch (state->substate) {
  1681.         case Initial:
  1682.                 error = getToken(parser, &token);
  1683.                 if (error != CSS_OK)
  1684.                         return error;
  1685.  
  1686.                 if (token->type == CSS_TOKEN_EOF) {
  1687.                         error = pushBack(parser, token);
  1688.                         if (error != CSS_OK)
  1689.                                 return error;
  1690.  
  1691.                         return done(parser);
  1692.                 }
  1693.  
  1694.                 if (token->type != CSS_TOKEN_IDENT) {
  1695.                         /* parse error */
  1696.                         parser->parseError = true;
  1697.  
  1698.                         return done(parser);
  1699.                 }
  1700.  
  1701.                 state->substate = WS;
  1702.                 /* Fall through */
  1703.         case WS:
  1704.                 error = eatWS(parser);
  1705.                 if (error != CSS_OK)
  1706.                         return error;
  1707.  
  1708.                 break;
  1709.         }
  1710.  
  1711.         return done(parser);
  1712. }
  1713.  
  1714. css_error parseValue1(css_parser *parser)
  1715. {
  1716.         enum { Initial = 0, AfterValue = 1 };
  1717.         parser_state *state = parserutils_stack_get_current(parser->states);
  1718.         parser_state to = { sValue0, Initial };
  1719.         const css_token *token;
  1720.         css_error error;
  1721.  
  1722.         /* value1 -> value value0 */
  1723.  
  1724.         switch (state->substate) {
  1725.         case Initial:
  1726.         {
  1727.                 parser_state to = { sValue, Initial };
  1728.                 parser_state subsequent = { sValue1, AfterValue };
  1729.  
  1730.                 error = getToken(parser, &token);
  1731.                 if (error != CSS_OK)
  1732.                         return error;
  1733.  
  1734.                 error = pushBack(parser, token);
  1735.                 if (error != CSS_OK)
  1736.                         return error;
  1737.  
  1738.                 /* Grammar ambiguity -- assume ';' or '}' mark end */
  1739.                 if (token->type == CSS_TOKEN_CHAR &&
  1740.                                 lwc_string_length(token->idata) == 1 &&
  1741.                                 (lwc_string_data(token->idata)[0] == ';' ||
  1742.                                 lwc_string_data(token->idata)[0] == '}')) {
  1743.                         /* Parse error */
  1744.                         parser->parseError = true;
  1745.  
  1746.                         return done(parser);
  1747.                 }
  1748.  
  1749.                 return transition(parser, to, subsequent);
  1750.         }
  1751.         case AfterValue:
  1752.                 if (parser->parseError)
  1753.                         return done(parser);
  1754.                 break;
  1755.         }
  1756.  
  1757.         return transitionNoRet(parser, to);
  1758. }
  1759.  
  1760. css_error parseValue0(css_parser *parser)
  1761. {
  1762.         enum { Initial = 0, AfterValue = 1 };
  1763.         parser_state *state = parserutils_stack_get_current(parser->states);
  1764.         const css_token *token;
  1765.         css_error error;
  1766.  
  1767.         /* value0 -> value value0
  1768.          *        ->
  1769.          */
  1770.  
  1771.         while (1) {
  1772.                 switch (state->substate) {
  1773.                 case Initial:
  1774.                 {
  1775.                         parser_state to = { sValue, Initial };
  1776.                         parser_state subsequent = { sValue0, AfterValue };
  1777.  
  1778.                         error = getToken(parser, &token);
  1779.                         if (error != CSS_OK)
  1780.                                 return error;
  1781.  
  1782.                         error = pushBack(parser, token);
  1783.                         if (error != CSS_OK)
  1784.                                 return error;
  1785.  
  1786.                         if (token->type == CSS_TOKEN_EOF)
  1787.                                 return done(parser);
  1788.  
  1789.                         /* Grammar ambiguity -- assume ';' or '}' mark end */
  1790.                         if (token->type == CSS_TOKEN_CHAR &&
  1791.                                         lwc_string_length(
  1792.                                                 token->idata) == 1 &&
  1793.                                         (lwc_string_data(
  1794.                                                 token->idata)[0] == ';' ||
  1795.                                         lwc_string_data(
  1796.                                                 token->idata)[0] == '}')) {
  1797.                                 return done(parser);
  1798.                         }
  1799.  
  1800.                         return transition(parser, to, subsequent);
  1801.                 }
  1802.                 case AfterValue:
  1803.                         if (parser->parseError)
  1804.                                 return done(parser);
  1805.  
  1806.                         state->substate = Initial;
  1807.  
  1808.                         break;
  1809.                 }
  1810.         }
  1811.  
  1812.         return done(parser);
  1813. }
  1814.  
  1815. css_error parseValue(css_parser *parser)
  1816. {
  1817.         enum { Initial = 0, WS = 1 };
  1818.         parser_state *state = parserutils_stack_get_current(parser->states);
  1819.         const css_token *token;
  1820.         css_error error;
  1821.  
  1822.         /* value  -> any
  1823.          *        -> block
  1824.          *        -> ATKEYWORD ws
  1825.          */
  1826.  
  1827.         switch (state->substate) {
  1828.         case Initial:
  1829.                 error = getToken(parser, &token);
  1830.                 if (error != CSS_OK)
  1831.                         return error;
  1832.  
  1833.                 if (token->type == CSS_TOKEN_ATKEYWORD) {
  1834.                         state->substate = WS;
  1835.                 } else if (token->type == CSS_TOKEN_CHAR &&
  1836.                                 lwc_string_length(token->idata) == 1 &&
  1837.                                 lwc_string_data(token->idata)[0] == '{') {
  1838.                         /* Grammar ambiguity. Assume block. */
  1839.                         parser_state to = { sBlock, Initial };
  1840.  
  1841.                         error = pushBack(parser, token);
  1842.                         if (error != CSS_OK)
  1843.                                 return error;
  1844.  
  1845.                         return transitionNoRet(parser, to);
  1846.                 } else {
  1847.                         parser_state to = { sAny, Initial };
  1848.  
  1849.                         error = pushBack(parser, token);
  1850.                         if (error != CSS_OK)
  1851.                                 return error;
  1852.  
  1853.                         return transitionNoRet(parser, to);
  1854.                 }
  1855.  
  1856.                 /* Fall through */
  1857.         case WS:
  1858.                 error = eatWS(parser);
  1859.                 if (error != CSS_OK)
  1860.                         return error;
  1861.  
  1862.                 break;
  1863.         }
  1864.  
  1865.         return done(parser);
  1866. }
  1867.  
  1868. css_error parseAny0(css_parser *parser)
  1869. {
  1870.         enum { Initial = 0, AfterAny = 1 };
  1871.         parser_state *state = parserutils_stack_get_current(parser->states);
  1872.         const css_token *token;
  1873.         css_error error;
  1874.  
  1875.         /* any0 -> any any0
  1876.          *      ->
  1877.          */
  1878.  
  1879.         while (1) {
  1880.                 switch (state->substate) {
  1881.                 case Initial:
  1882.                 {
  1883.                         parser_state to = { sAny, Initial };
  1884.                         parser_state subsequent = { sAny0, AfterAny };
  1885.  
  1886.                         error = getToken(parser, &token);
  1887.                         if (error != CSS_OK)
  1888.                                 return error;
  1889.  
  1890.                         error = pushBack(parser, token);
  1891.                         if (error != CSS_OK)
  1892.                                 return error;
  1893.  
  1894.                         if (token->type == CSS_TOKEN_EOF)
  1895.                                 return done(parser);
  1896.  
  1897.                         /* Grammar ambiguity:
  1898.                          * assume '{', ';', ')', ']' mark end */
  1899.                         if (token->type == CSS_TOKEN_CHAR &&
  1900.                                         lwc_string_length(
  1901.                                                 token->idata) == 1 &&
  1902.                                         (lwc_string_data(
  1903.                                                 token->idata)[0] == '{' ||
  1904.                                         lwc_string_data(
  1905.                                                 token->idata)[0] == ';' ||
  1906.                                         lwc_string_data(
  1907.                                                 token->idata)[0] == ')' ||
  1908.                                         lwc_string_data(
  1909.                                                 token->idata)[0] == ']')) {
  1910.                                 return done(parser);
  1911.                         }
  1912.  
  1913.                         return transition(parser, to, subsequent);
  1914.                 }
  1915.                 case AfterAny:
  1916.                         if (parser->parseError)
  1917.                                 return done(parser);
  1918.  
  1919.                         state->substate = Initial;
  1920.  
  1921.                         break;
  1922.                 }
  1923.         }
  1924.  
  1925.         return done(parser);
  1926. }
  1927.  
  1928. css_error parseAny1(css_parser *parser)
  1929. {
  1930.         enum { Initial = 0, AfterAny = 1, AfterAny0 = 2 };
  1931.         parser_state *state = parserutils_stack_get_current(parser->states);
  1932.         const css_token *token;
  1933.         css_error error;
  1934.  
  1935.         /* any1 -> any any0 */
  1936.  
  1937.         switch (state->substate) {
  1938.         case Initial:
  1939.         {
  1940.                 parser_state to = { sAny, Initial };
  1941.                 parser_state subsequent = { sAny1, AfterAny };
  1942.  
  1943.                 return transition(parser, to, subsequent);
  1944.         }
  1945.         case AfterAny:
  1946.         {
  1947.                 parser_state to = { sAny0, Initial };
  1948.                 parser_state subsequent = { sAny1, AfterAny0 };
  1949.  
  1950.                 if (parser->parseError)
  1951.                         return done(parser);
  1952.  
  1953.                 return transition(parser, to, subsequent);
  1954.         }
  1955.         case AfterAny0:
  1956.                 if (parser->parseError)
  1957.                         return done(parser);
  1958.  
  1959.                 error = getToken(parser, &token);
  1960.                 if (error != CSS_OK)
  1961.                         return error;
  1962.  
  1963.                 error = pushBack(parser, token);
  1964.                 if (error != CSS_OK)
  1965.                         return error;
  1966.  
  1967.                 /* Grammar ambiguity: any0 can be followed by
  1968.                  * '{', ';', ')', ']'. any1 can only be followed by '{'. */
  1969.                 if (token->type == CSS_TOKEN_CHAR &&
  1970.                                 lwc_string_length(token->idata) == 1) {
  1971.                         if (lwc_string_data(token->idata)[0] == ';' ||
  1972.                                         lwc_string_data(
  1973.                                                 token->idata)[0] == ')' ||
  1974.                                         lwc_string_data(
  1975.                                                 token->idata)[0] == ']') {
  1976.                                 parser_state to = { sAny, Initial };
  1977.                                 parser_state subsequent = { sAny1, AfterAny };
  1978.  
  1979.                                 return transition(parser, to, subsequent);
  1980.                         } else if (lwc_string_data(token->idata)[0] != '{') {
  1981.                                 /* parse error */
  1982.                                 parser->parseError = true;
  1983.                         }
  1984.                 } else {
  1985.                         /* parse error */
  1986.                         parser->parseError = true;
  1987.                 }
  1988.         }
  1989.  
  1990.         return done(parser);
  1991. }
  1992.  
  1993. css_error parseAny(css_parser *parser)
  1994. {
  1995.         enum { Initial = 0, WS = 1, AfterAny0 = 2, WS2 = 3 };
  1996.         parser_state *state = parserutils_stack_get_current(parser->states);
  1997.         const css_token *token;
  1998.         css_error error;
  1999.  
  2000.         /* any -> IDENT ws
  2001.          *     -> NUMBER ws
  2002.          *     -> PERCENTAGE ws
  2003.          *     -> DIMENSION ws
  2004.          *     -> STRING ws
  2005.          *     -> CHAR ws
  2006.          *     -> URI ws
  2007.          *     -> HASH ws
  2008.          *     -> UNICODE-RANGE ws
  2009.          *     -> INCLUDES ws
  2010.          *     -> DASHMATCH ws
  2011.          *     -> PREFIXMATCH ws
  2012.          *     -> SUFFIXMATCH ws
  2013.          *     -> SUBSTRINGMATCH ws
  2014.          *     -> FUNCTION ws any0 ')' ws
  2015.          *     -> '(' ws any0 ')' ws
  2016.          *     -> '[' ws any0 ']' ws
  2017.          */
  2018.  
  2019.         switch (state->substate) {
  2020.         case Initial:
  2021.                 error = getToken(parser, &token);
  2022.                 if (error != CSS_OK)
  2023.                         return error;
  2024.  
  2025.                 if (token->type != CSS_TOKEN_IDENT &&
  2026.                                 token->type != CSS_TOKEN_NUMBER &&
  2027.                                 token->type != CSS_TOKEN_PERCENTAGE &&
  2028.                                 token->type != CSS_TOKEN_DIMENSION &&
  2029.                                 token->type != CSS_TOKEN_STRING &&
  2030.                                 token->type != CSS_TOKEN_CHAR &&
  2031.                                 token->type != CSS_TOKEN_URI &&
  2032.                                 token->type != CSS_TOKEN_HASH &&
  2033.                                 token->type != CSS_TOKEN_UNICODE_RANGE &&
  2034.                                 token->type != CSS_TOKEN_INCLUDES &&
  2035.                                 token->type != CSS_TOKEN_DASHMATCH &&
  2036.                                 token->type != CSS_TOKEN_PREFIXMATCH &&
  2037.                                 token->type != CSS_TOKEN_SUFFIXMATCH &&
  2038.                                 token->type != CSS_TOKEN_SUBSTRINGMATCH &&
  2039.                                 token->type != CSS_TOKEN_FUNCTION) {
  2040.                         /* parse error */
  2041.                         parser->parseError = true;
  2042.  
  2043.                         return done(parser);
  2044.                 }
  2045.  
  2046.                 if (token->type == CSS_TOKEN_FUNCTION) {
  2047.                         parser->match_char = ')';
  2048.                         state->substate = WS;
  2049.                 } else if (token->type == CSS_TOKEN_CHAR &&
  2050.                                 lwc_string_length(token->idata) == 1 &&
  2051.                                 (lwc_string_data(token->idata)[0] == '(' ||
  2052.                                 lwc_string_data(token->idata)[0] == '[')) {
  2053.                         parser->match_char = lwc_string_data(
  2054.                                         token->idata)[0] == '(' ? ')' : ']';
  2055.                         state->substate = WS;
  2056.                 }
  2057.  
  2058.                 state->substate = WS2;
  2059.                 /* Fall through */
  2060.         case WS:
  2061.         case WS2:
  2062.         ws2:
  2063.         {
  2064.                 parser_state to = { sAny0, Initial };
  2065.                 parser_state subsequent = { sAny, AfterAny0 };
  2066.  
  2067.                 error = eatWS(parser);
  2068.                 if (error != CSS_OK)
  2069.                         return error;
  2070.  
  2071.                 if (state->substate == WS2)
  2072.                         break;
  2073.  
  2074.                 return transition(parser, to, subsequent);
  2075.         }
  2076.         case AfterAny0:
  2077.         {
  2078.                 parser_state to = { sAny0, Initial };
  2079.                 parser_state subsequent = { sAny, AfterAny0 };
  2080.  
  2081.                 error = getToken(parser, &token);
  2082.                 if (error != CSS_OK)
  2083.                         return error;
  2084.  
  2085.                 /* Match correct close bracket (grammar ambiguity) */
  2086.                 if (token->type == CSS_TOKEN_CHAR &&
  2087.                                 lwc_string_length(token->idata) == 1 &&
  2088.                                 lwc_string_data(token->idata)[0] ==
  2089.                                 parser->match_char) {
  2090.                         state->substate = WS2;
  2091.                         goto ws2;
  2092.                 }
  2093.  
  2094.                 return transition(parser, to, subsequent);
  2095.         }
  2096.         }
  2097.  
  2098.         return done(parser);
  2099. }
  2100.  
  2101. css_error parseMalformedDeclaration(css_parser *parser)
  2102. {
  2103.         enum { Initial = 0, Go = 1 };
  2104.         parser_state *state = parserutils_stack_get_current(parser->states);
  2105.         const css_token *token = NULL;
  2106.         css_error error;
  2107.  
  2108.         /* Malformed declaration: read everything up to the next ; or }
  2109.          * We must ensure that pairs of {}, (), [], are balanced */
  2110.  
  2111.         switch (state->substate) {
  2112.         case Initial:
  2113.         {
  2114.                 /* Clear stack of open items */
  2115.                 while (parserutils_stack_pop(parser->open_items, NULL) ==
  2116.                                 PARSERUTILS_OK)
  2117.                         ;
  2118.  
  2119.                 state->substate = Go;
  2120.                 /* Fall through */
  2121.         }
  2122.         case Go:
  2123.                 while (1) {
  2124.                         char want;
  2125.                         char *match;
  2126.                         const char *data;
  2127.                         size_t len;
  2128.  
  2129.                         error = getToken(parser, &token);
  2130.                         if (error != CSS_OK)
  2131.                                 return error;
  2132.  
  2133.                         if (token->type == CSS_TOKEN_EOF)
  2134.                                 break;
  2135.  
  2136.                         if (token->type != CSS_TOKEN_CHAR)
  2137.                                 continue;
  2138.  
  2139.                         len = lwc_string_length(token->idata);
  2140.                         data = lwc_string_data(token->idata);
  2141.  
  2142.                         if (len != 1 || (data[0] != '{' && data[0] != '}' &&
  2143.                                         data[0] != '[' && data[0] != ']' &&
  2144.                                         data[0] != '(' && data[0] != ')' &&
  2145.                                         data[0] != ';'))
  2146.                                 continue;
  2147.  
  2148.                         match = parserutils_stack_get_current(
  2149.                                         parser->open_items);
  2150.  
  2151.                         /* If the stack is empty, then we're done if we've got
  2152.                          * either a ';' or '}' */
  2153.                         if (match == NULL) {
  2154.                                 if (data[0] == ';' || data[0] == '}')
  2155.                                         break;
  2156.                         }
  2157.  
  2158.                         /* Regardless, if we've got a semicolon, ignore it */
  2159.                         if (data[0] == ';')
  2160.                                 continue;
  2161.  
  2162.                         /* Get corresponding start tokens for end tokens */
  2163.                         switch (data[0]) {
  2164.                         case '}':
  2165.                                 want = '{';
  2166.                                 break;
  2167.                         case ']':
  2168.                                 want = '[';
  2169.                                 break;
  2170.                         case ')':
  2171.                                 want = '(';
  2172.                                 break;
  2173.                         default:
  2174.                                 want = 0;
  2175.                                 break;
  2176.                         }
  2177.  
  2178.                         /* Either pop off the stack, if we've matched the
  2179.                          * current item, or push the start token on */
  2180.                         if (match != NULL && *match == want) {
  2181.                                 parserutils_stack_pop(
  2182.                                         parser->open_items, NULL);
  2183.                         } else if (want == 0) {
  2184.                                 parserutils_stack_push(parser->open_items,
  2185.                                                 &data[0]);
  2186.                         }
  2187.                 }
  2188.         }
  2189.  
  2190.         /* Push the last token (';', '}' or EOF) back */
  2191.         error = pushBack(parser, token);
  2192.         if (error != CSS_OK)
  2193.                 return error;
  2194.  
  2195.         /* Discard the tokens we've read */
  2196.         unref_interned_strings_in_tokens(parser);
  2197.         parserutils_vector_clear(parser->tokens);
  2198.  
  2199.         return done(parser);
  2200. }
  2201.  
  2202. css_error parseMalformedSelector(css_parser *parser)
  2203. {
  2204.         enum { Initial = 0, Go = 1 };
  2205.         parser_state *state = parserutils_stack_get_current(parser->states);
  2206.         const css_token *token;
  2207.         css_error error;
  2208.  
  2209.         /* Malformed selector: discard the entirety of the next block,
  2210.          * ensuring we correctly match pairs of {}, [], and (). */
  2211.  
  2212.         switch (state->substate) {
  2213.         case Initial:
  2214.                 /* Clear the stack of open items */
  2215.                 while (parserutils_stack_pop(parser->open_items, NULL) ==
  2216.                                 PARSERUTILS_OK)
  2217.                         ;
  2218.  
  2219.                 state->substate = Go;
  2220.                 /* Fall through */
  2221.         case Go:
  2222.                 while (1) {
  2223.                         char want;
  2224.                         char *match;
  2225.                         const char *data;
  2226.                         size_t len;
  2227.  
  2228.                         error = getToken(parser, &token);
  2229.                         if (error != CSS_OK)
  2230.                                 return error;
  2231.  
  2232.                         if (token->type == CSS_TOKEN_EOF)
  2233.                                 break;
  2234.  
  2235.                         if (token->type != CSS_TOKEN_CHAR)
  2236.                                 continue;
  2237.  
  2238.                         len = lwc_string_length(token->idata);
  2239.                         data = lwc_string_data(token->idata);
  2240.  
  2241.                         if (len != 1 || (data[0] != '{' && data[0] != '}' &&
  2242.                                         data[0] != '[' && data[0] != ']' &&
  2243.                                         data[0] != '(' && data[0] != ')'))
  2244.                                 continue;
  2245.  
  2246.                         match = parserutils_stack_get_current(
  2247.                                         parser->open_items);
  2248.  
  2249.                         /* Get corresponding start tokens for end tokens */
  2250.                         switch (data[0]) {
  2251.                         case '}':
  2252.                                 want = '{';
  2253.                                 break;
  2254.                         case ']':
  2255.                                 want = '[';
  2256.                                 break;
  2257.                         case ')':
  2258.                                 want = '(';
  2259.                                 break;
  2260.                         default:
  2261.                                 want = 0;
  2262.                                 break;
  2263.                         }
  2264.  
  2265.                         /* Either pop off the stack, if we've matched the
  2266.                          * current item, or push the start token on */
  2267.                         if (match != NULL && *match == want) {
  2268.                                 parserutils_stack_pop(
  2269.                                         parser->open_items, NULL);
  2270.                         } else if (want == 0) {
  2271.                                 parserutils_stack_push(parser->open_items,
  2272.                                                 &data[0]);
  2273.                         }
  2274.  
  2275.                         /* If we encountered a '}', there was data on the stack
  2276.                          * before, and the stack's now empty, then we've popped
  2277.                          * a '{' off the stack. That means we've found the end
  2278.                          * of the block, so we're done here. */
  2279.                         if (want == '{' && match != NULL &&
  2280.                                         parserutils_stack_get_current(
  2281.                                         parser->open_items) == NULL)
  2282.                                 break;
  2283.                 }
  2284.         }
  2285.  
  2286.         /* Consume any trailing whitespace after the ruleset */
  2287.         error = eatWS(parser);
  2288.         if (error != CSS_OK)
  2289.                 return error;
  2290.  
  2291.         /* Discard the tokens we've read */
  2292.         unref_interned_strings_in_tokens(parser);
  2293.         parserutils_vector_clear(parser->tokens);
  2294.  
  2295.         return done(parser);
  2296. }
  2297.  
  2298. css_error parseMalformedAtRule(css_parser *parser)
  2299. {
  2300.         enum { Initial = 0, Go = 1 };
  2301.         parser_state *state = parserutils_stack_get_current(parser->states);
  2302.         const css_token *token = NULL;
  2303.         css_error error;
  2304.  
  2305.         /* Malformed at-rule: read everything up to the next ; or the next
  2306.          * block, whichever is first.
  2307.          * We must ensure that pairs of {}, (), [], are balanced */
  2308.  
  2309.         switch (state->substate) {
  2310.         case Initial:
  2311.         {
  2312.                 /* Clear stack of open items */
  2313.                 while (parserutils_stack_pop(parser->open_items, NULL) ==
  2314.                                 PARSERUTILS_OK)
  2315.                         ;
  2316.  
  2317.                 state->substate = Go;
  2318.                 /* Fall through */
  2319.         }
  2320.         case Go:
  2321.                 while (1) {
  2322.                         char want;
  2323.                         char *match;
  2324.                         const char *data;
  2325.                         size_t len;
  2326.  
  2327.                         error = getToken(parser, &token);
  2328.                         if (error != CSS_OK)
  2329.                                 return error;
  2330.  
  2331.                         if (token->type == CSS_TOKEN_EOF)
  2332.                                 break;
  2333.  
  2334.                         if (token->type != CSS_TOKEN_CHAR)
  2335.                                 continue;
  2336.  
  2337.                         len = lwc_string_length(token->idata);
  2338.                         data = lwc_string_data(token->idata);
  2339.  
  2340.                         if (len != 1 || (data[0] != '{' && data[0] != '}' &&
  2341.                                         data[0] != '[' && data[0] != ']' &&
  2342.                                         data[0] != '(' && data[0] != ')' &&
  2343.                                         data[0] != ';'))
  2344.                                 continue;
  2345.  
  2346.                         match = parserutils_stack_get_current(
  2347.                                         parser->open_items);
  2348.  
  2349.                         /* If we have a semicolon, then we're either done or
  2350.                          * need to ignore it */
  2351.                         if (data[0] == ';') {
  2352.                                 if (match == NULL)
  2353.                                         break;
  2354.                                 else
  2355.                                         continue;
  2356.                         }
  2357.  
  2358.                         /* Get corresponding start tokens for end tokens */
  2359.                         switch (data[0]) {
  2360.                         case '}':
  2361.                                 want = '{';
  2362.                                 break;
  2363.                         case ']':
  2364.                                 want = '[';
  2365.                                 break;
  2366.                         case ')':
  2367.                                 want = '(';
  2368.                                 break;
  2369.                         default:
  2370.                                 want = 0;
  2371.                                 break;
  2372.                         }
  2373.  
  2374.                         /* Either pop off the stack, if we've matched the
  2375.                          * current item, or push the start token on */
  2376.                         if (match != NULL && *match == want) {
  2377.                                 parserutils_stack_pop(
  2378.                                         parser->open_items, NULL);
  2379.                         } else if (want == 0) {
  2380.                                 parserutils_stack_push(parser->open_items,
  2381.                                                 &data[0]);
  2382.                         }
  2383.  
  2384.                         /* If we encountered a '}', there was data on the stack
  2385.                          * before, and the stack's now empty, then we've popped
  2386.                          * a '{' off the stack. That means we've found the end
  2387.                          * of the block, so we're done here. */
  2388.                         if (want == '{' && match != NULL &&
  2389.                                         parserutils_stack_get_current(
  2390.                                         parser->open_items) == NULL)
  2391.                                 break;
  2392.                 }
  2393.         }
  2394.  
  2395.         /* Consume any trailing whitespace after the at-rule */
  2396.         error = eatWS(parser);
  2397.         if (error != CSS_OK)
  2398.                 return error;
  2399.  
  2400.         /* Discard the tokens we've read */
  2401.         unref_interned_strings_in_tokens(parser);
  2402.         parserutils_vector_clear(parser->tokens);
  2403.  
  2404.         return done(parser);
  2405. }
  2406.  
  2407. css_error parseInlineStyle(css_parser *parser)
  2408. {
  2409.         enum { Initial = 0, WS = 1, AfterISBody0 = 2 };
  2410.         parser_state *state = parserutils_stack_get_current(parser->states);
  2411.         css_error error;
  2412.  
  2413.         /* inline-style = ws is-body0 */
  2414.  
  2415.         switch (state->substate) {
  2416.         case Initial:
  2417.                 /* Emit fake events such that the language parser knows
  2418.                  * no different from a normal parse. */
  2419.  
  2420.                 if (parser->event != NULL) {
  2421.                         /* 1) begin stylesheet */
  2422.                         parser->event(CSS_PARSER_START_STYLESHEET, NULL,
  2423.                                         parser->event_pw);
  2424.  
  2425.                         /* 2) begin ruleset */
  2426.                         parser->event(CSS_PARSER_START_RULESET, NULL,
  2427.                                         parser->event_pw);
  2428.                 }
  2429.  
  2430.                 /* Fall through */
  2431.         case WS:
  2432.         {
  2433.                 parser_state to = { sISBody0, Initial };
  2434.                 parser_state subsequent = { sInlineStyle, AfterISBody0 };
  2435.  
  2436.                 state->substate = WS;
  2437.  
  2438.                 /* Consume leading whitespace */
  2439.                 error = eatWS(parser);
  2440.                 if (error != CSS_OK)
  2441.                         return error;
  2442.  
  2443.                 return transition(parser, to, subsequent);
  2444.         }
  2445.         case AfterISBody0:
  2446.                 /* Clean up any remaining tokens */
  2447.                 unref_interned_strings_in_tokens(parser);
  2448.  
  2449.                 /* Emit remaining fake events to end the parse */
  2450.                 if (parser->event != NULL) {
  2451.                         /* 1) end ruleset */
  2452.                         parser->event(CSS_PARSER_END_RULESET, NULL,
  2453.                                         parser->event_pw);
  2454.  
  2455.                         /* 2) end stylesheet */
  2456.                         parser->event(CSS_PARSER_END_STYLESHEET, NULL,
  2457.                                         parser->event_pw);
  2458.                 }
  2459.  
  2460.                 break;
  2461.         }
  2462.  
  2463.         return done(parser);
  2464. }
  2465.  
  2466. css_error parseISBody0(css_parser *parser)
  2467. {
  2468.         enum { Initial = 0, AfterISBody = 1 };
  2469.         parser_state *state = parserutils_stack_get_current(parser->states);
  2470.         const css_token *token;
  2471.         css_error error;
  2472.  
  2473.         /* is-body0     -> is-body is-body0
  2474.          *              ->
  2475.          */
  2476.  
  2477.         while (1) {
  2478.                 switch (state->substate) {
  2479.                 case Initial:
  2480.                 {
  2481.                         parser_state to = { sISBody, Initial };
  2482.                         parser_state subsequent = { sISBody0, AfterISBody };
  2483.  
  2484.                         error = getToken(parser, &token);
  2485.                         if (error != CSS_OK)
  2486.                                 return error;
  2487.  
  2488.                         error = pushBack(parser, token);
  2489.                         if (error != CSS_OK)
  2490.                                 return error;
  2491.  
  2492.                         /* EOF is the only way out */
  2493.                         if (token->type == CSS_TOKEN_EOF)
  2494.                                 return done(parser);
  2495.  
  2496.                         return transition(parser, to, subsequent);
  2497.                 }
  2498.                 case AfterISBody:
  2499.                         /* Unless there's a parse error */
  2500.                         if (parser->parseError)
  2501.                                 return done(parser);
  2502.  
  2503.                         state->substate = Initial;
  2504.  
  2505.                         break;
  2506.                 }
  2507.         }
  2508.  
  2509.         return done(parser);
  2510. }
  2511.  
  2512. css_error parseISBody(css_parser *parser)
  2513. {
  2514.         enum { Initial = 0, DeclList = 1, Brace = 2, WS = 3 };
  2515.         parser_state *state = parserutils_stack_get_current(parser->states);
  2516.         const css_token *token;
  2517.         css_error error;
  2518.  
  2519.         /* is-body      -> declaration decl-list '}' ws
  2520.          *              -> decl-list '}' ws
  2521.          *
  2522.          * Note that this looks suspiciously similar to ruleset-end.
  2523.          * The difference here, however, is that we never end the ruleset.
  2524.          */
  2525.  
  2526.         switch (state->substate) {
  2527.         case Initial:
  2528.                 error = getToken(parser, &token);
  2529.                 if (error != CSS_OK)
  2530.                         return error;
  2531.  
  2532.                 error = pushBack(parser, token);
  2533.                 if (error != CSS_OK)
  2534.                         return error;
  2535.  
  2536.                 /* If this can't possibly be the start of a decl-list, then
  2537.                  * attempt to parse a declaration. This will catch any invalid
  2538.                  * input at this point and read to the start of the next
  2539.                  * declaration. FIRST(decl-list) = (';', '}') */
  2540.                 if (token->type != CSS_TOKEN_CHAR ||
  2541.                                 lwc_string_length(token->idata) != 1 ||
  2542.                                 (lwc_string_data(token->idata)[0] != '}' &&
  2543.                                 lwc_string_data(token->idata)[0] != ';')) {
  2544.                         parser_state to = { sDeclaration, Initial };
  2545.                         parser_state subsequent = { sISBody, DeclList };
  2546.  
  2547.                         return transition(parser, to, subsequent);
  2548.                 }
  2549.  
  2550.                 state->substate = DeclList;
  2551.                 /* Fall through */
  2552.         case DeclList:
  2553.         {
  2554.                 parser_state to = { sDeclList, Initial };
  2555.                 parser_state subsequent = { sISBody, Brace };
  2556.  
  2557.                 return transition(parser, to, subsequent);
  2558.         }
  2559.         case Brace:
  2560.                 error = getToken(parser, &token);
  2561.                 if (error != CSS_OK)
  2562.                         return error;
  2563.  
  2564.                 if (token->type == CSS_TOKEN_EOF) {
  2565.                         error = pushBack(parser, token);
  2566.                         if (error != CSS_OK)
  2567.                                 return error;
  2568.  
  2569.                         return done(parser);
  2570.                 }
  2571.  
  2572.                 if (token->type != CSS_TOKEN_CHAR ||
  2573.                                 lwc_string_length(token->idata) != 1 ||
  2574.                                 lwc_string_data(token->idata)[0] != '}') {
  2575.                         /* This should never happen, as FOLLOW(decl-list)
  2576.                          * contains only '}' */
  2577.                         assert(0 && "Expected }");
  2578.                 }
  2579.  
  2580.                 state->substate = WS;
  2581.                 /* Fall through */
  2582.         case WS:
  2583.                 error = eatWS(parser);
  2584.                 if (error != CSS_OK)
  2585.                         return error;
  2586.  
  2587.                 break;
  2588.         }
  2589.  
  2590.         return done(parser);
  2591. }
  2592.  
  2593. /**
  2594.  * Iterate the token vector and unref any interned strings in the tokens.
  2595.  *
  2596.  * \param parser The parser whose tokens we are cleaning up.
  2597.  */
  2598. void unref_interned_strings_in_tokens(css_parser *parser)
  2599. {
  2600.         int32_t ctx = 0;
  2601.         const css_token *tok;
  2602.        
  2603.         while ((tok = parserutils_vector_iterate(
  2604.                         parser->tokens, &ctx)) != NULL) {
  2605.                 if (tok->idata != NULL) {
  2606.                         lwc_string_unref(tok->idata);
  2607.                 }
  2608.         }
  2609. }
  2610.  
  2611. #ifndef NDEBUG
  2612. #ifdef DEBUG_STACK
  2613. static void printer(void *item)
  2614. {
  2615.         parser_state *s = item;
  2616.  
  2617.         printf("[%d %d]", s->state, s->substate);
  2618. }
  2619. #endif
  2620.  
  2621. #ifdef DEBUG_EVENTS
  2622. static void tprinter(void *token)
  2623. {
  2624.         css_token *t = token;
  2625.  
  2626.         if (t->data.data)
  2627.                 printf("%d: %.*s", t->type, (int) t->data.len, t->data.data);
  2628.         else
  2629.                 printf("%d", t->type);
  2630. }
  2631. #endif
  2632. #endif
  2633.  
  2634.