1/*
2 *  Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
3 *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
4 *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
5 *  Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 *  Copyright (C) 2012 Intel Corporation. All rights reserved.
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU Lesser General Public
10 *  License as published by the Free Software Foundation; either
11 *  version 2 of the License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  Lesser General Public License for more details.
17 *
18 *  You should have received a copy of the GNU Lesser General Public
19 *  License along with this library; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24%pure-parser
25
26%parse-param { CSSParser* parser }
27%lex-param { CSSParser* parser }
28
29%union {
30    double number;
31    CSSParserString string;
32    CSSSelector::MarginBoxType marginBox;
33    CSSParserValue value;
34}
35
36%{
37
38static inline int cssyyerror(void*, const char*)
39{
40    return 1;
41}
42
43#if YYDEBUG > 0
44
45static inline bool isCSSTokenAString(int yytype)
46{
47    switch (yytype) {
48    case IDENT:
49    case STRING:
50    case NTH:
51    case HEX:
52    case IDSEL:
53    case DIMEN:
54    case INVALIDDIMEN:
55    case URI:
56    case FUNCTION:
57    case ANYFUNCTION:
58    case NOTFUNCTION:
59    case CALCFUNCTION:
60    case MINFUNCTION:
61    case MAXFUNCTION:
62    case UNICODERANGE:
63        return true;
64    default:
65        return false;
66    }
67}
68
69#endif
70
71static inline CSSParserValue makeIdentValue(CSSParserString string)
72{
73    CSSParserValue v;
74    v.id = cssValueKeywordID(string);
75    v.unit = CSSPrimitiveValue::CSS_IDENT;
76    v.string = string;
77    return v;
78}
79
80%}
81
82#if ENABLE_CSS_GRID_LAYOUT
83#if ENABLE_PICTURE_SIZES
84%expect 34
85#else
86%expect 30
87#endif
88#else
89#if ENABLE_PICTURE_SIZES
90%expect 33
91#else
92%expect 29
93#endif
94#endif
95
96%nonassoc LOWEST_PREC
97
98%left UNIMPORTANT_TOK
99
100%token WHITESPACE SGML_CD
101%token TOKEN_EOF 0
102
103%token INCLUDES
104%token DASHMATCH
105%token BEGINSWITH
106%token ENDSWITH
107%token CONTAINS
108
109%token <string> STRING
110%right <string> IDENT
111%token <string> NTH
112
113%nonassoc <string> HEX
114%nonassoc <string> IDSEL
115%nonassoc ':'
116%nonassoc '.'
117%nonassoc '['
118%nonassoc <string> '*'
119%nonassoc error
120%left '|'
121
122%token IMPORT_SYM
123%token PAGE_SYM
124%token MEDIA_SYM
125%token FONT_FACE_SYM
126%token CHARSET_SYM
127%token NAMESPACE_SYM
128%token WEBKIT_RULE_SYM
129%token WEBKIT_DECLS_SYM
130%token WEBKIT_KEYFRAME_RULE_SYM
131%token WEBKIT_KEYFRAMES_SYM
132%token WEBKIT_VALUE_SYM
133%token WEBKIT_MEDIAQUERY_SYM
134#if ENABLE_PICTURE_SIZES
135%token WEBKIT_SIZESATTR_SYM
136#endif
137%token WEBKIT_SELECTOR_SYM
138%token WEBKIT_REGION_RULE_SYM
139%token WEBKIT_VIEWPORT_RULE_SYM
140%token <marginBox> TOPLEFTCORNER_SYM
141%token <marginBox> TOPLEFT_SYM
142%token <marginBox> TOPCENTER_SYM
143%token <marginBox> TOPRIGHT_SYM
144%token <marginBox> TOPRIGHTCORNER_SYM
145%token <marginBox> BOTTOMLEFTCORNER_SYM
146%token <marginBox> BOTTOMLEFT_SYM
147%token <marginBox> BOTTOMCENTER_SYM
148%token <marginBox> BOTTOMRIGHT_SYM
149%token <marginBox> BOTTOMRIGHTCORNER_SYM
150%token <marginBox> LEFTTOP_SYM
151%token <marginBox> LEFTMIDDLE_SYM
152%token <marginBox> LEFTBOTTOM_SYM
153%token <marginBox> RIGHTTOP_SYM
154%token <marginBox> RIGHTMIDDLE_SYM
155%token <marginBox> RIGHTBOTTOM_SYM
156
157%token ATKEYWORD
158
159%token IMPORTANT_SYM
160%token MEDIA_ONLY
161%token MEDIA_NOT
162%token MEDIA_AND
163
164%token <number> REMS
165%token <number> CHS
166%token <number> QEMS
167%token <number> EMS
168%token <number> EXS
169%token <number> PXS
170%token <number> CMS
171%token <number> MMS
172%token <number> INS
173%token <number> PTS
174%token <number> PCS
175%token <number> DEGS
176%token <number> RADS
177%token <number> GRADS
178%token <number> TURNS
179%token <number> MSECS
180%token <number> SECS
181%token <number> HERTZ
182%token <number> KHERTZ
183%token <string> DIMEN
184%token <string> INVALIDDIMEN
185%token <number> PERCENTAGE
186%token <number> FLOATTOKEN
187%token <number> INTEGER
188%token <number> VW
189%token <number> VH
190%token <number> VMIN
191%token <number> VMAX
192%token <number> DPPX
193%token <number> DPI
194%token <number> DPCM
195%token <number> FR
196
197%token <string> URI
198%token <string> FUNCTION
199%token <string> ANYFUNCTION
200%token <string> NOTFUNCTION
201%token <string> CALCFUNCTION
202%token <string> MINFUNCTION
203%token <string> MAXFUNCTION
204
205%token <string> UNICODERANGE
206
207%union { CSSSelector::Relation relation; }
208%type <relation> combinator
209
210%union { StyleRuleBase* rule; }
211%type <rule> block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule
212%destructor { if ($$) $$->deref(); } block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule
213
214%union { Vector<RefPtr<StyleRuleBase>>* ruleList; }
215%type <ruleList> block_rule_list block_valid_rule_list
216%destructor { delete $$; } block_rule_list block_valid_rule_list
217
218%type <string> ident_or_string maybe_ns_prefix namespace_selector string_or_uri
219
220%type <marginBox> margin_sym
221
222%union { MediaQuerySet* mediaList; }
223%type <mediaList> media_list maybe_media_list
224%destructor { if ($$) $$->deref(); } media_list maybe_media_list
225
226%union { MediaQuery* mediaQuery; }
227%type <mediaQuery> media_query
228%destructor { delete $$; } media_query
229
230%union { MediaQuery::Restrictor mediaQueryRestrictor; }
231%type <mediaQueryRestrictor> maybe_media_restrictor
232
233%union { MediaQueryExp* mediaQueryExp; }
234%type <mediaQueryExp> media_query_exp
235%destructor { delete $$; } media_query_exp
236
237#if ENABLE_PICTURE_SIZES
238%union { MediaQueryExp* mediaCondition; }
239%type <mediaQueryExp> media_condition
240%destructor { delete $$; } media_condition
241
242%union { SourceSize* sourceSize; }
243%type <sourceSize> source_size
244%destructor { delete $$; } source_size
245
246%union { SourceSizeList* sourceSizeList; }
247%type <sourceSizeList> source_size_list
248%destructor { delete $$; } source_size_list
249
250%type <value> source_size_length
251#endif
252
253%union { Vector<std::unique_ptr<MediaQueryExp>>* mediaQueryExpList; }
254%type <mediaQueryExpList> media_query_exp_list maybe_and_media_query_exp_list
255%destructor { delete $$; } media_query_exp_list maybe_and_media_query_exp_list
256
257%type <string> keyframe_name
258
259%union { StyleKeyframe* keyframe; }
260%type <keyframe> keyframe_rule
261%destructor { if ($$) $$->deref(); } keyframe_rule
262
263%union { Vector<RefPtr<StyleKeyframe>>* keyframeRuleList; }
264%type <keyframeRuleList> keyframes_rule
265%destructor { delete $$; } keyframes_rule
266
267// These two parser values never need to be destroyed because they are never functions or value lists.
268%type <value> key unary_term
269
270// These parser values need to be destroyed because they might be functions.
271%type <value> calc_func_term calc_function function min_or_max_function term
272%destructor { destroy($$); } calc_func_term calc_function function min_or_max_function term
273
274%union { CSSPropertyID id; }
275%type <id> property
276
277%union { CSSParserSelector* selector; }
278%type <selector> attrib class page_selector pseudo pseudo_page selector selector_with_trailing_whitespace simple_selector specifier specifier_list
279%destructor { delete $$; } attrib class page_selector pseudo pseudo_page selector selector_with_trailing_whitespace simple_selector specifier specifier_list
280
281%union { Vector<std::unique_ptr<CSSParserSelector>>* selectorList; }
282%type <selectorList> selector_list simple_selector_list
283%destructor { delete $$; } selector_list simple_selector_list
284
285%union { bool boolean; }
286%type <boolean> declaration declaration_list decl_list priority
287
288%union { CSSSelector::Match match; }
289%type <match> match
290
291%union { int integer; }
292%type <integer> unary_operator maybe_unary_operator
293
294%union { char character; }
295%type <character> operator calc_func_operator
296
297%union { CSSParserValueList* valueList; }
298%type <valueList> calc_func_expr calc_func_expr_list calc_func_paren_expr expr key_list maybe_media_value valid_calc_func_expr valid_expr
299%destructor { delete $$; } calc_func_expr calc_func_expr_list calc_func_paren_expr expr key_list maybe_media_value valid_calc_func_expr valid_expr
300
301%type <string> min_or_max
302
303%type <string> element_name
304
305%union { CSSParser::Location location; }
306%type <location> error_location
307
308#if ENABLE_CSS_GRID_LAYOUT
309%type <valueList> ident_list
310%destructor { delete $$; } ident_list
311
312%type <value> track_names_list
313%destructor { destroy($$); } track_names_list
314#endif
315
316#if ENABLE_CSS3_CONDITIONAL_RULES
317
318%token SUPPORTS_AND
319%token SUPPORTS_NOT
320%token SUPPORTS_OR
321%token SUPPORTS_SYM
322%token WEBKIT_SUPPORTS_CONDITION_SYM
323
324%type <rule> supports
325%destructor { if ($$) $$->deref(); } supports
326
327%type <boolean> supports_condition supports_condition_in_parens supports_conjunction supports_declaration_condition supports_disjunction supports_error supports_negation
328
329#endif
330
331#if ENABLE_CSS_DEVICE_ADAPTATION
332
333%type <rule> viewport
334%destructor { if ($$) $$->deref(); } viewport
335
336#endif
337
338#if ENABLE_VIDEO_TRACK
339
340%token <string> CUEFUNCTION
341
342#endif
343
344%%
345
346stylesheet:
347    maybe_space maybe_charset maybe_sgml rule_list
348  | webkit_rule maybe_space
349  | webkit_decls maybe_space
350  | webkit_value maybe_space
351  | webkit_mediaquery maybe_space
352#if ENABLE_PICTURE_SIZES
353  | webkit_source_size_list maybe_space
354#endif
355  | webkit_selector maybe_space
356  | webkit_keyframe_rule maybe_space
357#if ENABLE_CSS3_CONDITIONAL_RULES
358  | webkit_supports_condition maybe_space
359#endif
360  ;
361
362webkit_rule: WEBKIT_RULE_SYM '{' maybe_space valid_rule maybe_space '}' { parser->m_rule = adoptRef($4); } ;
363
364webkit_keyframe_rule: WEBKIT_KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' { parser->m_keyframe = adoptRef($4); } ;
365
366webkit_decls: WEBKIT_DECLS_SYM '{' maybe_space_before_declaration declaration_list '}' ;
367
368webkit_value:
369    WEBKIT_VALUE_SYM '{' maybe_space expr '}' {
370        if ($4) {
371            parser->m_valueList = std::unique_ptr<CSSParserValueList>($4);
372            int oldParsedProperties = parser->m_parsedProperties.size();
373            if (!parser->parseValue(parser->m_id, parser->m_important))
374                parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
375            parser->m_valueList = nullptr;
376        }
377    }
378;
379
380webkit_mediaquery: WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' { parser->m_mediaQuery = std::unique_ptr<MediaQuery>($4); } ;
381
382webkit_selector:
383    WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' {
384        if ($4) {
385            if (parser->m_selectorListForParseSelector)
386                parser->m_selectorListForParseSelector->adoptSelectorVector(*$4);
387            parser->recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4));
388        }
389    }
390;
391
392#if ENABLE_CSS3_CONDITIONAL_RULES
393
394webkit_supports_condition: WEBKIT_SUPPORTS_CONDITION_SYM '{' maybe_space supports_condition '}' { parser->m_supportsCondition = $4; } ;
395
396#endif
397
398/* for expressions that require at least one whitespace to be present, like the + and - operators in calc expressions */
399space: WHITESPACE | space WHITESPACE ;
400
401maybe_space: /* empty */ %prec UNIMPORTANT_TOK | maybe_space WHITESPACE ;
402
403maybe_sgml: /* empty */ | maybe_sgml SGML_CD | maybe_sgml WHITESPACE ;
404
405maybe_charset: /* empty */ | charset ;
406
407closing_brace: '}' | %prec LOWEST_PREC TOKEN_EOF ;
408
409closing_parenthesis: ')' | %prec LOWEST_PREC TOKEN_EOF ;
410
411charset:
412  CHARSET_SYM maybe_space STRING maybe_space ';' {
413     if (parser->m_styleSheet)
414         parser->m_styleSheet->parserSetEncodingFromCharsetRule($3);
415     if (parser->isExtractingSourceData() && parser->m_currentRuleDataStack->isEmpty() && parser->m_ruleSourceDataResult)
416         parser->addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
417  }
418  | CHARSET_SYM error invalid_block
419  | CHARSET_SYM error ';'
420;
421
422// Ignore any @charset rule not at the beginning of the style sheet.
423ignored_charset: CHARSET_SYM maybe_space STRING maybe_space ';' | CHARSET_SYM maybe_space ';' ;
424
425rule_list:
426    /* empty */
427    | rule_list rule maybe_sgml {
428        if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
429            if (parser->m_styleSheet)
430                parser->m_styleSheet->parserAppendRule(rule.releaseNonNull());
431        }
432    }
433    ;
434
435valid_rule:
436    ruleset
437  | media
438  | page
439  | font_face
440  | keyframes
441  | namespace { $$ = nullptr; }
442  | import
443  | region
444#if ENABLE_CSS3_CONDITIONAL_RULES
445  | supports
446#endif
447#if ENABLE_CSS_DEVICE_ADAPTATION
448  | viewport
449#endif
450  ;
451
452rule:
453    valid_rule {
454        $$ = $1;
455        parser->m_hadSyntacticallyValidCSSRule = true;
456    }
457    | ignored_charset { $$ = nullptr; }
458    | invalid_rule { $$ = nullptr; }
459    | invalid_at { $$ = nullptr; }
460    ;
461
462block_rule_list:
463    /* empty */ { $$ = nullptr; }
464  | block_rule_list block_rule maybe_sgml {
465      $$ = $1;
466      if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
467          if (!$$)
468              $$ = new Vector<RefPtr<StyleRuleBase>>;
469          $$->append(rule.release());
470      }
471  }
472  ;
473
474block_valid_rule_list:
475    /* empty */ { $$ = nullptr; }
476  | block_valid_rule_list block_valid_rule maybe_sgml {
477      $$ = $1;
478      if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
479          if (!$$)
480              $$ = new Vector<RefPtr<StyleRuleBase>>;
481          $$->append(rule.release());
482      }
483  }
484  ;
485
486block_valid_rule:
487    ruleset
488  | page
489  | font_face
490  | media
491  | keyframes
492#if ENABLE_CSS3_CONDITIONAL_RULES
493  | supports
494#endif
495#if ENABLE_CSS_DEVICE_ADAPTATION
496  | viewport
497#endif
498  ;
499
500block_rule: block_valid_rule | invalid_rule { $$ = nullptr; } | invalid_at { $$ = nullptr; } | namespace { $$ = nullptr; } | import | region ;
501
502at_import_header_end_maybe_space:
503    maybe_space {
504        parser->markRuleHeaderEnd();
505        parser->markRuleBodyStart();
506    }
507    ;
508
509before_import_rule:
510    /* empty */ {
511        parser->markRuleHeaderStart(CSSRuleSourceData::IMPORT_RULE);
512    }
513    ;
514
515import:
516    before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list ';' {
517        $$ = parser->createImportRule($4, adoptRef($6)).leakRef();
518    }
519  | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list TOKEN_EOF {
520        $$ = parser->createImportRule($4, adoptRef($6)).leakRef();
521    }
522  | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list invalid_block {
523        $$ = nullptr;
524        parser->popRuleData();
525        if ($6)
526            $6->deref();
527    }
528  | before_import_rule IMPORT_SYM error ';' {
529        $$ = nullptr;
530        parser->popRuleData();
531    }
532  | before_import_rule IMPORT_SYM error invalid_block {
533        $$ = nullptr;
534        parser->popRuleData();
535    }
536  ;
537
538namespace:
539    NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' { parser->addNamespace($3, $4); }
540    | NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space invalid_block
541    | NAMESPACE_SYM error invalid_block
542    | NAMESPACE_SYM error ';'
543    ;
544
545maybe_ns_prefix: /* empty */ { $$.clear(); } | IDENT maybe_space;
546
547string_or_uri: STRING | URI ;
548
549maybe_media_value: /*empty*/ { $$ = nullptr; } | ':' maybe_space expr maybe_space { $$ = $3; } ;
550
551#if ENABLE_PICTURE_SIZES
552media_condition:
553    maybe_space '(' maybe_space IDENT maybe_space maybe_media_value ')' maybe_space {
554        std::unique_ptr<CSSParserValueList> mediaValue($6);
555        $4.lower();
556        $$ = new MediaQueryExp($4, mediaValue.get());
557    }
558    ;
559
560webkit_source_size_list:
561    WEBKIT_SIZESATTR_SYM WHITESPACE source_size_list '}' { parser->m_sourceSizeList = std::unique_ptr<SourceSizeList>($3); };
562
563source_size_list:
564    maybe_space source_size maybe_space {
565        $$ = new SourceSizeList();
566        $$->append(std::unique_ptr<SourceSize>($2));
567    }
568    | maybe_space source_size maybe_space ',' maybe_space source_size_list maybe_space {
569        $$ = $6;
570        $$->append(std::unique_ptr<SourceSize>($2));
571    };
572
573source_size_length:
574    unary_term {
575        $$ = $1;
576    }
577    | calc_function {
578        $$ = $1;
579    };
580
581source_size:
582    media_condition source_size_length {
583        $$ = new SourceSize(std::unique_ptr<MediaQueryExp>($1), $2);
584    }
585    | source_size_length {
586        $$ = new SourceSize(std::make_unique<MediaQueryExp>(emptyString(), nullptr), $1);
587    };
588#endif
589
590media_query_exp:
591    maybe_media_restrictor maybe_space '(' maybe_space IDENT maybe_space maybe_media_value ')' maybe_space {
592        // If restrictor is specified, media query expression is invalid.
593        // Create empty media query expression and continue parsing media query.
594        std::unique_ptr<CSSParserValueList> mediaValue($7);
595        if ($1 != MediaQuery::None)
596            $$ = new MediaQueryExp(emptyString(), nullptr);
597        else {
598            $5.lower();
599            $$ = new MediaQueryExp($5, mediaValue.get());
600        }
601    }
602    ;
603
604media_query_exp_list:
605    media_query_exp {
606        $$ = new Vector<std::unique_ptr<MediaQueryExp>>;
607        $$->append(std::unique_ptr<MediaQueryExp>($1));
608    }
609    | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp {
610        $$ = $1;
611        $$->append(std::unique_ptr<MediaQueryExp>($5));
612    }
613    ;
614
615maybe_and_media_query_exp_list:
616    /*empty*/ {
617        $$ = new Vector<std::unique_ptr<MediaQueryExp>>;
618    }
619    | MEDIA_AND maybe_space media_query_exp_list {
620        $$ = $3;
621    }
622    ;
623
624maybe_media_restrictor:
625    /*empty*/ {
626        $$ = MediaQuery::None;
627    }
628    | MEDIA_ONLY {
629        $$ = MediaQuery::Only;
630    }
631    | MEDIA_NOT {
632        $$ = MediaQuery::Not;
633    }
634    ;
635
636media_query:
637    media_query_exp_list {
638        $$ = new MediaQuery(MediaQuery::None, "all", std::unique_ptr<Vector<std::unique_ptr<MediaQueryExp>>>($1));
639    }
640    |
641    maybe_media_restrictor maybe_space IDENT maybe_space maybe_and_media_query_exp_list {
642        $3.lower();
643        $$ = new MediaQuery($1, $3, std::unique_ptr<Vector<std::unique_ptr<MediaQueryExp>>>($5));
644    }
645    ;
646
647maybe_media_list: /* empty */ { $$ = MediaQuerySet::create().leakRef(); } | media_list ;
648
649media_list:
650    media_query {
651        $$ = MediaQuerySet::create().leakRef();
652        $$->addMediaQuery(std::unique_ptr<MediaQuery>($1));
653        parser->updateLastMediaLine($$);
654    }
655    | media_list ',' maybe_space media_query {
656        $$ = $1;
657        std::unique_ptr<MediaQuery> mediaQuery($4);
658        if ($$) {
659            $$->addMediaQuery(WTF::move(mediaQuery));
660            parser->updateLastMediaLine($$);
661        }
662    }
663    | media_list error {
664        $$ = nullptr;
665        if ($1)
666            $1->deref();
667    }
668    ;
669
670at_rule_body_start:
671    /* empty */ {
672        parser->markRuleBodyStart();
673    }
674    ;
675
676before_media_rule:
677    /* empty */ {
678        parser->markRuleHeaderStart(CSSRuleSourceData::MEDIA_RULE);
679    }
680    ;
681
682at_rule_header_end_maybe_space:
683    maybe_space {
684        parser->markRuleHeaderEnd();
685    }
686    ;
687
688media:
689    before_media_rule MEDIA_SYM maybe_space media_list at_rule_header_end '{' at_rule_body_start maybe_space block_rule_list save_block {
690        $$ = parser->createMediaRule(adoptRef($4), std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($9).get()).leakRef();
691    }
692    | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space block_rule_list save_block {
693        $$ = parser->createEmptyMediaRule(std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($7).get()).leakRef();
694    }
695    | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space ';' {
696        $$ = nullptr;
697        parser->popRuleData();
698    }
699    ;
700
701#if ENABLE_CSS3_CONDITIONAL_RULES
702
703supports:
704    before_supports_rule SUPPORTS_SYM maybe_space supports_condition at_supports_rule_header_end '{' at_rule_body_start maybe_space block_rule_list save_block {
705        $$ = parser->createSupportsRule($4, std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($9).get()).leakRef();
706    }
707    | before_supports_rule SUPPORTS_SYM supports_error {
708        $$ = nullptr;
709        parser->popRuleData();
710        parser->popSupportsRuleData();
711    }
712    ;
713
714supports_error: error ';' | error invalid_block ;
715
716before_supports_rule:
717    /* empty */ {
718        parser->markRuleHeaderStart(CSSRuleSourceData::SUPPORTS_RULE);
719        parser->markSupportsRuleHeaderStart();
720    }
721    ;
722
723at_supports_rule_header_end:
724    /* empty */ {
725        parser->markRuleHeaderEnd();
726        parser->markSupportsRuleHeaderEnd();
727    }
728    ;
729
730supports_condition: supports_condition_in_parens | supports_negation | supports_conjunction | supports_disjunction ;
731
732supports_negation: SUPPORTS_NOT maybe_space supports_condition_in_parens { $$ = !$3; } ;
733
734supports_conjunction:
735    supports_condition_in_parens SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; }
736    | supports_conjunction SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; }
737    ;
738
739supports_disjunction:
740    supports_condition_in_parens SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; }
741    | supports_disjunction SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; }
742    ;
743
744supports_condition_in_parens:
745    '(' maybe_space supports_condition ')' maybe_space { $$ = $3; }
746    | supports_declaration_condition { $$ = $1; }
747    | '(' error ')' { $$ = false; }
748    ;
749
750supports_declaration_condition:
751    '(' maybe_space property ':' maybe_space expr priority ')' maybe_space {
752        $$ = false;
753        CSSParser* p = static_cast<CSSParser*>(parser);
754        std::unique_ptr<CSSParserValueList> propertyValue($6);
755        if ($3 && propertyValue) {
756            p->m_valueList = WTF::move(propertyValue);
757            int oldParsedProperties = p->m_parsedProperties.size();
758            $$ = p->parseValue($3, $7);
759            // We just need to know if the declaration is supported as it is written. Rollback any additions.
760            if ($$)
761                p->rollbackLastProperties(p->m_parsedProperties.size() - oldParsedProperties);
762            p->m_valueList = nullptr;
763        }
764        p->markPropertyEnd($7, false);
765    }
766    ;
767
768#endif
769
770before_keyframes_rule:
771    /* empty */ {
772        parser->markRuleHeaderStart(CSSRuleSourceData::KEYFRAMES_RULE);
773    }
774    ;
775
776keyframes:
777    before_keyframes_rule WEBKIT_KEYFRAMES_SYM maybe_space keyframe_name at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space keyframes_rule closing_brace {
778        $$ = parser->createKeyframesRule($4, std::unique_ptr<Vector<RefPtr<StyleKeyframe>>>($9)).leakRef();
779    }
780    ;
781
782keyframe_name: IDENT | STRING ;
783
784keyframes_rule:
785    /* empty */ { $$ = new Vector<RefPtr<StyleKeyframe>>; }
786    | keyframes_rule keyframe_rule maybe_space {
787        $$ = $1;
788        if (RefPtr<StyleKeyframe> keyframe = adoptRef($2))
789            $$->append(keyframe.release());
790    }
791    ;
792
793keyframe_rule: key_list maybe_space '{' maybe_space declaration_list closing_brace { $$ = parser->createKeyframe(*std::unique_ptr<CSSParserValueList>($1)).leakRef(); } ;
794
795key_list:
796    key {
797        $$ = new CSSParserValueList;
798        $$->addValue($1);
799    }
800    | key_list maybe_space ',' maybe_space key {
801        $$ = $1;
802        ASSERT($5.unit != CSSParserValue::Function); // No need to call destroy.
803        if ($$)
804            $$->addValue($5);
805    }
806    ;
807
808key:
809    maybe_unary_operator PERCENTAGE { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1 * $2; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
810    | IDENT {
811        $$.id = CSSValueInvalid; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER;
812        CSSParserString& str = $1;
813        if (str.equalIgnoringCase("from"))
814            $$.fValue = 0;
815        else if (str.equalIgnoringCase("to"))
816            $$.fValue = 100;
817        else {
818            $$.unit = 0;
819            YYERROR;
820        }
821    }
822    | error {
823        $$.unit = 0;
824    }
825    ;
826
827before_page_rule:
828    /* empty */ {
829        parser->markRuleHeaderStart(CSSRuleSourceData::PAGE_RULE);
830    }
831    ;
832
833page:
834    before_page_rule PAGE_SYM maybe_space page_selector at_rule_header_end_maybe_space
835    '{' at_rule_body_start maybe_space_before_declaration declarations_and_margins closing_brace {
836        if ($4)
837            $$ = parser->createPageRule(std::unique_ptr<CSSParserSelector>($4)).leakRef();
838        else {
839            // Clear properties in the invalid @page rule.
840            parser->clearProperties();
841            // Also clear margin at-rules here once we fully implement margin at-rules parsing.
842            $$ = nullptr;
843            parser->popRuleData();
844        }
845    }
846    | before_page_rule PAGE_SYM error invalid_block {
847        parser->popRuleData();
848        $$ = nullptr;
849    }
850    | before_page_rule PAGE_SYM error ';' {
851        parser->popRuleData();
852        $$ = nullptr;
853    }
854    ;
855
856page_selector:
857    IDENT {
858        $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
859        $$->setForPage();
860    }
861    | IDENT pseudo_page {
862        $$ = $2;
863        if ($$) {
864            $$->prependTagSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
865            $$->setForPage();
866        }
867    }
868    | pseudo_page {
869        $$ = $1;
870        if ($$)
871            $$->setForPage();
872    }
873    | /* empty */ {
874        $$ = new CSSParserSelector;
875        $$->setForPage();
876    }
877    ;
878
879declarations_and_margins: declaration_list | declarations_and_margins margin_box maybe_space declaration_list ;
880
881margin_box:
882    margin_sym {
883        parser->startDeclarationsForMarginBox();
884    } maybe_space '{' maybe_space declaration_list closing_brace {
885        parser->createMarginAtRule($1);
886    }
887    ;
888
889margin_sym:
890    TOPLEFTCORNER_SYM {
891        $$ = CSSSelector::TopLeftCornerMarginBox;
892    }
893    | TOPLEFT_SYM {
894        $$ = CSSSelector::TopLeftMarginBox;
895    }
896    | TOPCENTER_SYM {
897        $$ = CSSSelector::TopCenterMarginBox;
898    }
899    | TOPRIGHT_SYM {
900        $$ = CSSSelector::TopRightMarginBox;
901    }
902    | TOPRIGHTCORNER_SYM {
903        $$ = CSSSelector::TopRightCornerMarginBox;
904    }
905    | BOTTOMLEFTCORNER_SYM {
906        $$ = CSSSelector::BottomLeftCornerMarginBox;
907    }
908    | BOTTOMLEFT_SYM {
909        $$ = CSSSelector::BottomLeftMarginBox;
910    }
911    | BOTTOMCENTER_SYM {
912        $$ = CSSSelector::BottomCenterMarginBox;
913    }
914    | BOTTOMRIGHT_SYM {
915        $$ = CSSSelector::BottomRightMarginBox;
916    }
917    | BOTTOMRIGHTCORNER_SYM {
918        $$ = CSSSelector::BottomRightCornerMarginBox;
919    }
920    | LEFTTOP_SYM {
921        $$ = CSSSelector::LeftTopMarginBox;
922    }
923    | LEFTMIDDLE_SYM {
924        $$ = CSSSelector::LeftMiddleMarginBox;
925    }
926    | LEFTBOTTOM_SYM {
927        $$ = CSSSelector::LeftBottomMarginBox;
928    }
929    | RIGHTTOP_SYM {
930        $$ = CSSSelector::RightTopMarginBox;
931    }
932    | RIGHTMIDDLE_SYM {
933        $$ = CSSSelector::RightMiddleMarginBox;
934    }
935    | RIGHTBOTTOM_SYM {
936        $$ = CSSSelector::RightBottomMarginBox;
937    }
938    ;
939
940before_font_face_rule:
941    /* empty */ {
942        parser->markRuleHeaderStart(CSSRuleSourceData::FONT_FACE_RULE);
943    }
944    ;
945
946font_face:
947    before_font_face_rule FONT_FACE_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace {
948        $$ = parser->createFontFaceRule().leakRef();
949    }
950    | before_font_face_rule FONT_FACE_SYM error invalid_block {
951        $$ = nullptr;
952        parser->popRuleData();
953    }
954    | before_font_face_rule FONT_FACE_SYM error ';' {
955        $$ = nullptr;
956        parser->popRuleData();
957    }
958;
959
960#if ENABLE_CSS_DEVICE_ADAPTATION
961
962before_viewport_rule:
963    /* empty */ {
964        parser->markViewportRuleBodyStart();
965        parser->markRuleHeaderStart(CSSRuleSourceData::VIEWPORT_RULE);
966    }
967    ;
968
969viewport:
970    before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM at_rule_header_end_maybe_space
971    '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace {
972        $$ = parser->createViewportRule().leakRef();
973        parser->markViewportRuleBodyEnd();
974    }
975    | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error invalid_block {
976        $$ = nullptr;
977        parser->popRuleData();
978        parser->markViewportRuleBodyEnd();
979    }
980    | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error ';' {
981        $$ = nullptr;
982        parser->popRuleData();
983        parser->markViewportRuleBodyEnd();
984    }
985;
986
987#endif
988
989before_region_rule:
990    /* empty */ {
991        parser->markRuleHeaderStart(CSSRuleSourceData::REGION_RULE);
992    }
993    ;
994
995region:
996    before_region_rule WEBKIT_REGION_RULE_SYM maybe_space selector_list at_rule_header_end '{' at_rule_body_start maybe_space block_valid_rule_list save_block {
997        std::unique_ptr<Vector<RefPtr<StyleRuleBase>>> ruleList($9);
998        if ($4)
999            $$ = parser->createRegionRule(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4).get(), ruleList.get()).leakRef();
1000        else {
1001            $$ = nullptr;
1002            parser->popRuleData();
1003        }
1004    }
1005;
1006
1007combinator:
1008    '+' maybe_space { $$ = CSSSelector::DirectAdjacent; }
1009  | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; }
1010  | '>' maybe_space { $$ = CSSSelector::Child; }
1011  ;
1012
1013maybe_unary_operator: unary_operator | { $$ = 1; } ;
1014
1015unary_operator: '-' { $$ = -1; } | '+' { $$ = 1; } ;
1016
1017maybe_space_before_declaration: maybe_space { parser->markPropertyStart(); } ;
1018
1019before_selector_list:
1020    {
1021        parser->markRuleHeaderStart(CSSRuleSourceData::STYLE_RULE);
1022        parser->markSelectorStart();
1023    }
1024  ;
1025
1026at_rule_header_end: { parser->markRuleHeaderEnd(); } ;
1027
1028at_selector_end: { parser->markSelectorEnd(); } ;
1029
1030ruleset:
1031    before_selector_list selector_list at_selector_end at_rule_header_end '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace {
1032        $$ = parser->createStyleRule($2).leakRef();
1033        parser->recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($2));
1034    }
1035  ;
1036
1037before_selector_group_item: { parser->markSelectorStart(); } ;
1038
1039selector_list:
1040    selector %prec UNIMPORTANT_TOK {
1041        $$ = nullptr;
1042        if ($1) {
1043            $$ = parser->createSelectorVector().release();
1044            $$->append(std::unique_ptr<CSSParserSelector>($1));
1045            parser->updateLastSelectorLineAndPosition();
1046        }
1047    }
1048    | selector_list at_selector_end ',' maybe_space before_selector_group_item selector %prec UNIMPORTANT_TOK {
1049        std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> selectorList($1);
1050        std::unique_ptr<CSSParserSelector> selector($6);
1051        $$ = nullptr;
1052        if (selectorList && selector) {
1053            $$ = selectorList.release();
1054            $$->append(WTF::move(selector));
1055            parser->updateLastSelectorLineAndPosition();
1056        }
1057    }
1058    | selector_list error {
1059        $$ = nullptr;
1060        delete $1;
1061    }
1062   ;
1063
1064selector_with_trailing_whitespace:
1065    selector WHITESPACE;
1066
1067selector:
1068    simple_selector
1069    | selector_with_trailing_whitespace
1070    | selector_with_trailing_whitespace simple_selector {
1071        std::unique_ptr<CSSParserSelector> left($1);
1072        std::unique_ptr<CSSParserSelector> right($2);
1073        $$ = nullptr;
1074        if (left && right) {
1075            right->appendTagHistory(CSSSelector::Descendant, WTF::move(left));
1076            $$ = right.release();
1077        }
1078    }
1079    | selector combinator simple_selector {
1080        std::unique_ptr<CSSParserSelector> left($1);
1081        std::unique_ptr<CSSParserSelector> right($3);
1082        $$ = nullptr;
1083        if (left && right) {
1084            right->appendTagHistory($2, WTF::move(left));
1085            $$ = right.release();
1086        }
1087    }
1088    | selector error {
1089        $$ = nullptr;
1090        delete $1;
1091    }
1092    ;
1093
1094namespace_selector:
1095    '|' { $$.clear(); }
1096    | '*' '|' { static LChar star = '*'; $$.init(&star, 1); }
1097    | IDENT '|'
1098;
1099
1100simple_selector:
1101    element_name {
1102        $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
1103    }
1104    | element_name specifier_list {
1105        $$ = $2;
1106        if ($$)
1107            parser->rewriteSpecifiersWithElementName(nullAtom, $1, *$$);
1108    }
1109    | specifier_list {
1110        $$ = $1;
1111        if ($$)
1112            parser->rewriteSpecifiersWithNamespaceIfNeeded(*$$);
1113    }
1114    | namespace_selector element_name {
1115        $$ = new CSSParserSelector(parser->determineNameInNamespace($1, $2));
1116    }
1117    | namespace_selector element_name specifier_list {
1118        $$ = $3;
1119        if ($$)
1120            parser->rewriteSpecifiersWithElementName($1, $2, *$$);
1121    }
1122    | namespace_selector specifier_list {
1123        $$ = $2;
1124        if ($$)
1125            parser->rewriteSpecifiersWithElementName($1, starAtom, *$$);
1126    }
1127  ;
1128
1129simple_selector_list:
1130    simple_selector %prec UNIMPORTANT_TOK {
1131        $$ = nullptr;
1132        if ($1) {
1133            $$ = parser->createSelectorVector().release();
1134            $$->append(std::unique_ptr<CSSParserSelector>($1));
1135        }
1136    }
1137    | simple_selector_list maybe_space ',' maybe_space simple_selector %prec UNIMPORTANT_TOK {
1138        std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> list($1);
1139        std::unique_ptr<CSSParserSelector> selector($5);
1140        $$ = nullptr;
1141        if (list && selector) {
1142            $$ = list.release();
1143            $$->append(WTF::move(selector));
1144        }
1145    }
1146    | simple_selector_list error {
1147        $$ = nullptr;
1148        delete $1;
1149    }
1150    ;
1151
1152element_name:
1153    IDENT {
1154        if (parser->m_context.isHTMLDocument)
1155            $1.lower();
1156        $$ = $1;
1157    }
1158    | '*' {
1159        static LChar star = '*';
1160        $$.init(&star, 1);
1161    }
1162    ;
1163
1164specifier_list:
1165    specifier
1166    | specifier_list specifier {
1167        std::unique_ptr<CSSParserSelector> list($1);
1168        std::unique_ptr<CSSParserSelector> specifier($2);
1169        $$ = nullptr;
1170        if (list && specifier)
1171            $$ = parser->rewriteSpecifiers(WTF::move(list), WTF::move(specifier)).release();
1172    }
1173    | specifier_list error {
1174        $$ = nullptr;
1175        delete $1;
1176    }
1177;
1178
1179specifier:
1180    IDSEL {
1181        $$ = new CSSParserSelector;
1182        $$->setMatch(CSSSelector::Id);
1183        if (parser->m_context.mode == CSSQuirksMode)
1184            $1.lower();
1185        $$->setValue($1);
1186    }
1187  | HEX {
1188        if ($1[0] >= '0' && $1[0] <= '9')
1189            $$ = nullptr;
1190        else {
1191            $$ = new CSSParserSelector;
1192            $$->setMatch(CSSSelector::Id);
1193            if (parser->m_context.mode == CSSQuirksMode)
1194                $1.lower();
1195            $$->setValue($1);
1196        }
1197    }
1198  | class
1199  | attrib
1200  | pseudo
1201    ;
1202
1203class:
1204    '.' IDENT {
1205        $$ = new CSSParserSelector;
1206        $$->setMatch(CSSSelector::Class);
1207        if (parser->m_context.mode == CSSQuirksMode)
1208            $2.lower();
1209        $$->setValue($2);
1210    }
1211  ;
1212
1213attrib:
1214    '[' maybe_space IDENT maybe_space ']' {
1215        $$ = new CSSParserSelector;
1216        $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument);
1217        $$->setMatch(CSSSelector::Set);
1218    }
1219    | '[' maybe_space IDENT maybe_space match maybe_space ident_or_string maybe_space ']' {
1220        $$ = new CSSParserSelector;
1221        $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument);
1222        $$->setMatch($5);
1223        $$->setValue($7);
1224    }
1225    | '[' maybe_space namespace_selector IDENT maybe_space ']' {
1226        $$ = new CSSParserSelector;
1227        $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument);
1228        $$->setMatch(CSSSelector::Set);
1229    }
1230    | '[' maybe_space namespace_selector IDENT maybe_space match maybe_space ident_or_string maybe_space ']' {
1231        $$ = new CSSParserSelector;
1232        $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument);
1233        $$->setMatch($6);
1234        $$->setValue($8);
1235    }
1236  ;
1237
1238match:
1239    '=' {
1240        $$ = CSSSelector::Exact;
1241    }
1242    | INCLUDES {
1243        $$ = CSSSelector::List;
1244    }
1245    | DASHMATCH {
1246        $$ = CSSSelector::Hyphen;
1247    }
1248    | BEGINSWITH {
1249        $$ = CSSSelector::Begin;
1250    }
1251    | ENDSWITH {
1252        $$ = CSSSelector::End;
1253    }
1254    | CONTAINS {
1255        $$ = CSSSelector::Contain;
1256    }
1257    ;
1258
1259ident_or_string: IDENT | STRING ;
1260
1261pseudo_page:
1262    ':' IDENT {
1263        $$ = CSSParserSelector::parsePagePseudoSelector($2);
1264    }
1265
1266pseudo:
1267    ':' IDENT {
1268        $$ = CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector($2);
1269    }
1270    | ':' ':' IDENT {
1271        $$ = CSSParserSelector::parsePseudoElementSelector($3);
1272    }
1273#if ENABLE_VIDEO_TRACK
1274    // used by ::cue(:past/:future)
1275    | ':' ':' CUEFUNCTION maybe_space simple_selector_list maybe_space ')' {
1276        $$ = CSSParserSelector::parsePseudoElementCueFunctionSelector($3, $5);
1277    }
1278#endif
1279    // use by :-webkit-any.
1280    // FIXME: should we support generic selectors here or just simple_selectors?
1281    // Use simple_selector_list for now to match -moz-any.
1282    // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0566.html for some
1283    // related discussion with respect to :not.
1284    | ':' ANYFUNCTION maybe_space simple_selector_list maybe_space ')' {
1285        $$ = nullptr;
1286        if ($4) {
1287            auto selector = std::make_unique<CSSParserSelector>();
1288            selector->setMatch(CSSSelector::PseudoClass);
1289            selector->adoptSelectorVector(*std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4));
1290            selector->setPseudoClassValue($2);
1291            if (selector->pseudoClassType() == CSSSelector::PseudoClassAny)
1292                $$ = selector.release();
1293        }
1294    }
1295    // used by :nth-*(ax+b)
1296    | ':' FUNCTION maybe_space NTH maybe_space ')' {
1297        $$ = nullptr;
1298        auto selector = std::make_unique<CSSParserSelector>();
1299        selector->setMatch(CSSSelector::PseudoClass);
1300        selector->setArgument($4);
1301        selector->setPseudoClassValue($2);
1302        if (selector->pseudoClassType() != CSSSelector::PseudoClassUnknown)
1303            $$ = selector.release();
1304    }
1305    // used by :nth-*
1306    | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' {
1307        $$ = nullptr;
1308        auto selector = std::make_unique<CSSParserSelector>();
1309        selector->setMatch(CSSSelector::PseudoClass);
1310        selector->setArgument(AtomicString::number($4 * $5));
1311        selector->setPseudoClassValue($2);
1312        if (selector->pseudoClassType() != CSSSelector::PseudoClassUnknown)
1313            $$ = selector.release();
1314    }
1315    // used by :nth-*(odd/even) and :lang
1316    | ':' FUNCTION maybe_space IDENT maybe_space ')' {
1317        auto selector = std::make_unique<CSSParserSelector>();
1318        selector->setMatch(CSSSelector::PseudoClass);
1319        selector->setArgument($4);
1320        selector->setPseudoClassValue($2);
1321        CSSSelector::PseudoClassType type = selector->pseudoClassType();
1322        if (type == CSSSelector::PseudoClassUnknown)
1323            selector = nullptr;
1324        else if (type == CSSSelector::PseudoClassNthChild ||
1325                 type == CSSSelector::PseudoClassNthOfType ||
1326                 type == CSSSelector::PseudoClassNthLastChild ||
1327                 type == CSSSelector::PseudoClassNthLastOfType) {
1328            if (!isValidNthToken($4))
1329                selector = nullptr;
1330        }
1331        $$ = selector.release();
1332    }
1333    // used by :not
1334    | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' {
1335        std::unique_ptr<CSSParserSelector> selector($4);
1336        $$ = nullptr;
1337        if (selector && selector->isSimple()) {
1338            $$ = new CSSParserSelector;
1339            $$->setMatch(CSSSelector::PseudoClass);
1340
1341            Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
1342            selectorVector.append(WTF::move(selector));
1343            $$->adoptSelectorVector(selectorVector);
1344            $$->setPseudoClassValue($2);
1345        }
1346    }
1347  ;
1348
1349declaration_list:
1350    /* empty */ { $$ = false; }
1351    | declaration
1352    | decl_list declaration { $$ = $1 || $2; }
1353    | decl_list
1354    | decl_list_recovery { $$ = false; }
1355    | decl_list decl_list_recovery
1356    ;
1357
1358decl_list:
1359    declaration ';' maybe_space {
1360        parser->markPropertyStart();
1361        $$ = $1;
1362    }
1363    | decl_list_recovery ';' maybe_space {
1364        parser->markPropertyStart();
1365        $$ = false;
1366    }
1367    | decl_list declaration ';' maybe_space {
1368        parser->markPropertyStart();
1369        $$ = $1;
1370        if ($2)
1371            $$ = $2;
1372    }
1373    | decl_list decl_list_recovery ';' maybe_space {
1374        parser->markPropertyStart();
1375        $$ = $1;
1376    }
1377    ;
1378
1379decl_list_recovery:
1380    error error_location error_recovery {
1381        parser->syntaxError($2, CSSParser::PropertyDeclarationError);
1382    }
1383    ;
1384
1385declaration:
1386    property ':' maybe_space expr priority {
1387        $$ = false;
1388        bool isPropertyParsed = false;
1389        std::unique_ptr<CSSParserValueList> propertyValue($4);
1390        if ($1 && propertyValue) {
1391            parser->m_valueList = WTF::move(propertyValue);
1392            int oldParsedProperties = parser->m_parsedProperties.size();
1393            $$ = parser->parseValue($1, $5);
1394            if (!$$)
1395                parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
1396            else
1397                isPropertyParsed = true;
1398            parser->m_valueList = nullptr;
1399        }
1400        parser->markPropertyEnd($5, isPropertyParsed);
1401    }
1402    | property declaration_recovery { $$ = false; }
1403    | property ':' maybe_space expr priority declaration_recovery {
1404        // When we encounter something like p {color: red !important fail;} we should drop the declaration.
1405        parser->markPropertyEnd(false, false);
1406        delete $4;
1407        $$ = false;
1408    }
1409    | IMPORTANT_SYM maybe_space declaration_recovery {
1410        // Handle this case -- div { text-align: center; !important } -- by just reducing away the stray !important.
1411        $$ = false;
1412    }
1413    | property ':' maybe_space declaration_recovery {
1414        // If we come across rules with invalid values like this case: p { weight: *; }, just discard the rule.
1415        parser->markPropertyEnd(false, false);
1416        $$ = false;
1417    }
1418  ;
1419
1420declaration_recovery: error error_location error_recovery { parser->syntaxError($2); } ;
1421
1422property: IDENT maybe_space { $$ = cssPropertyID($1); } ;
1423
1424priority: IMPORTANT_SYM maybe_space { $$ = true; } | /* empty */ { $$ = false; } ;
1425
1426#if ENABLE_CSS_GRID_LAYOUT
1427
1428ident_list:
1429    IDENT maybe_space {
1430        $$ = new CSSParserValueList;
1431        $$->addValue(makeIdentValue($1));
1432    }
1433    | ident_list IDENT maybe_space {
1434        $$ = $1;
1435        $$->addValue(makeIdentValue($2));
1436    }
1437    ;
1438
1439track_names_list:
1440    '(' maybe_space closing_parenthesis {
1441        $$.setFromValueList(std::make_unique<CSSParserValueList>());
1442    }
1443    | '(' maybe_space ident_list closing_parenthesis {
1444        $$.setFromValueList(std::unique_ptr<CSSParserValueList>($3));
1445    }
1446    | '(' maybe_space expr_recovery closing_parenthesis {
1447        $$.id = CSSValueInvalid;
1448        $$.unit = 0;
1449        YYERROR;
1450    }
1451  ;
1452
1453#endif
1454
1455expr: valid_expr | valid_expr expr_recovery { $$ = nullptr; delete $1; } ;
1456
1457valid_expr:
1458    term {
1459        $$ = new CSSParserValueList;
1460        $$->addValue($1);
1461    }
1462    | valid_expr operator term {
1463        $$ = $1;
1464        if (!$$)
1465            destroy($3);
1466        else {
1467            if ($2) {
1468                CSSParserValue v;
1469                v.id = CSSValueInvalid;
1470                v.unit = CSSParserValue::Operator;
1471                v.iValue = $2;
1472                $$->addValue(v);
1473            }
1474            $$->addValue($3);
1475        }
1476    }
1477  ;
1478
1479expr_recovery: error error_location error_recovery ;
1480
1481operator: '/' maybe_space { $$ = '/'; } | ',' maybe_space { $$ = ','; } | /* empty */ { $$ = 0; } ;
1482
1483term:
1484  unary_term maybe_space
1485  | unary_operator unary_term maybe_space { $$ = $2; $$.fValue *= $1; }
1486  | STRING maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
1487  | IDENT maybe_space { $$ = makeIdentValue($1); }
1488  /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
1489  | DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1490  | unary_operator DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1491  | URI maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
1492  | UNICODERANGE maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; }
1493  | HEX maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; }
1494  | '#' maybe_space { $$.id = CSSValueInvalid; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */
1495  /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1496  | function maybe_space
1497  | calc_function maybe_space
1498  | min_or_max_function maybe_space
1499  | '%' maybe_space { /* Handle width: %; */
1500      $$.id = CSSValueInvalid; $$.unit = 0;
1501  }
1502#if ENABLE_CSS_GRID_LAYOUT
1503  | track_names_list maybe_space
1504#endif
1505  ;
1506
1507unary_term:
1508  INTEGER { $$.id = CSSValueInvalid; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1509  | FLOATTOKEN { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1510  | PERCENTAGE { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
1511  | PXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
1512  | CMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
1513  | MMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
1514  | INS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
1515  | PTS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
1516  | PCS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
1517  | DEGS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
1518  | RADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
1519  | GRADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
1520  | TURNS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; }
1521  | MSECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
1522  | SECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
1523  | HERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
1524  | KHERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
1525  | EMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
1526  | QEMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; }
1527  | EXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
1528  | REMS {
1529      $$.id = CSSValueInvalid;
1530      $$.fValue = $1;
1531      $$.unit = CSSPrimitiveValue::CSS_REMS;
1532      if (parser->m_styleSheet)
1533          parser->m_styleSheet->parserSetUsesRemUnits(true);
1534  }
1535  | CHS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CHS; }
1536  | VW { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VW; }
1537  | VH { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VH; }
1538  | VMIN { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMIN; }
1539  | VMAX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMAX; }
1540  | DPPX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPPX; }
1541  | DPI { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPI; }
1542  | DPCM { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPCM; }
1543  | FR { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_FR; }
1544  ;
1545
1546function:
1547    FUNCTION maybe_space expr closing_parenthesis {
1548        CSSParserFunction* f = new CSSParserFunction;
1549        f->name = $1;
1550        f->args = std::unique_ptr<CSSParserValueList>($3);
1551        $$.id = CSSValueInvalid;
1552        $$.unit = CSSParserValue::Function;
1553        $$.function = f;
1554    } |
1555    FUNCTION maybe_space closing_parenthesis {
1556        CSSParserFunction* f = new CSSParserFunction;
1557        f->name = $1;
1558        f->args = std::unique_ptr<CSSParserValueList>(new CSSParserValueList);
1559        $$.id = CSSValueInvalid;
1560        $$.unit = CSSParserValue::Function;
1561        $$.function = f;
1562    } |
1563    FUNCTION maybe_space expr_recovery closing_parenthesis {
1564        CSSParserFunction* f = new CSSParserFunction;
1565        f->name = $1;
1566        f->args = nullptr;
1567        $$.id = CSSValueInvalid;
1568        $$.unit = CSSParserValue::Function;
1569        $$.function = f;
1570  }
1571  ;
1572
1573calc_func_term:
1574  unary_term
1575  | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
1576  ;
1577
1578/*
1579 * The grammar requires spaces around binary ‘+’ and ‘-’ operators.
1580 * The '*' and '/' operators do not require spaces.
1581 * http://www.w3.org/TR/css3-values/#calc-syntax
1582 */
1583calc_func_operator:
1584    space '+' space {
1585        $$ = '+';
1586    }
1587    | space '-' space {
1588        $$ = '-';
1589    }
1590    | calc_maybe_space '*' maybe_space {
1591        $$ = '*';
1592    }
1593    | calc_maybe_space '/' maybe_space {
1594        $$ = '/';
1595    }
1596  ;
1597
1598calc_maybe_space: /* empty */ | WHITESPACE ;
1599
1600calc_func_paren_expr:
1601    '(' maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1602        $$ = nullptr;
1603        if ($3) {
1604            $$ = $3;
1605            CSSParserValue v;
1606            v.id = CSSValueInvalid;
1607            v.unit = CSSParserValue::Operator;
1608            v.iValue = '(';
1609            $$->insertValueAt(0, v);
1610            v.iValue = ')';
1611            $$->addValue(v);
1612        }
1613    }
1614  ;
1615
1616calc_func_expr: valid_calc_func_expr | valid_calc_func_expr expr_recovery { $$ = nullptr; delete $1; } ;
1617
1618valid_calc_func_expr:
1619    calc_func_term {
1620        $$ = new CSSParserValueList;
1621        $$->addValue($1);
1622    }
1623    | calc_func_expr calc_func_operator calc_func_term {
1624        std::unique_ptr<CSSParserValueList> expression($1);
1625        $$ = nullptr;
1626        if (expression && $2) {
1627            $$ = expression.release();
1628            CSSParserValue v;
1629            v.id = CSSValueInvalid;
1630            v.unit = CSSParserValue::Operator;
1631            v.iValue = $2;
1632            $$->addValue(v);
1633            $$->addValue($3);
1634        } else {
1635            destroy($3);
1636        }
1637
1638    }
1639    | calc_func_expr calc_func_operator calc_func_paren_expr {
1640        std::unique_ptr<CSSParserValueList> left($1);
1641        std::unique_ptr<CSSParserValueList> right($3);
1642        $$ = nullptr;
1643        if (left && $2 && right) {
1644            CSSParserValue v;
1645            v.id = CSSValueInvalid;
1646            v.unit = CSSParserValue::Operator;
1647            v.iValue = $2;
1648            left->addValue(v);
1649            left->extend(*right);
1650            $$ = left.release();
1651        }
1652    }
1653    | calc_func_paren_expr
1654  ;
1655
1656calc_func_expr_list:
1657    calc_func_expr calc_maybe_space
1658    | calc_func_expr_list ',' maybe_space calc_func_expr calc_maybe_space {
1659        std::unique_ptr<CSSParserValueList> list($1);
1660        std::unique_ptr<CSSParserValueList> expression($4);
1661        $$ = nullptr;
1662        if (list && expression) {
1663            $$ = list.release();
1664            CSSParserValue v;
1665            v.id = CSSValueInvalid;
1666            v.unit = CSSParserValue::Operator;
1667            v.iValue = ',';
1668            $$->addValue(v);
1669            $$->extend(*expression);
1670        }
1671    }
1672  ;
1673
1674calc_function:
1675    CALCFUNCTION maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1676        CSSParserFunction* f = new CSSParserFunction;
1677        f->name = $1;
1678        f->args = std::unique_ptr<CSSParserValueList>($3);
1679        $$.id = CSSValueInvalid;
1680        $$.unit = CSSParserValue::Function;
1681        $$.function = f;
1682    }
1683    | CALCFUNCTION maybe_space expr_recovery closing_parenthesis {
1684        $$.id = CSSValueInvalid;
1685        $$.unit = 0;
1686        YYERROR;
1687    }
1688    ;
1689
1690
1691min_or_max: MINFUNCTION | MAXFUNCTION ;
1692
1693min_or_max_function:
1694    min_or_max maybe_space calc_func_expr_list closing_parenthesis {
1695        CSSParserFunction* f = new CSSParserFunction;
1696        f->name = $1;
1697        f->args = std::unique_ptr<CSSParserValueList>($3);
1698        $$.id = CSSValueInvalid;
1699        $$.unit = CSSParserValue::Function;
1700        $$.function = f;
1701    }
1702    | min_or_max maybe_space expr_recovery closing_parenthesis {
1703        $$.id = CSSValueInvalid;
1704        $$.unit = 0;
1705        YYERROR;
1706    }
1707    ;
1708
1709/* error handling rules */
1710
1711save_block: closing_brace | error closing_brace ;
1712
1713invalid_at: ATKEYWORD error invalid_block | ATKEYWORD error ';' ;
1714
1715invalid_rule: error invalid_block ;
1716
1717invalid_block: '{' error_recovery closing_brace { parser->invalidBlockHit(); } ;
1718
1719invalid_square_brackets_block: '[' error_recovery ']' | '[' error_recovery TOKEN_EOF ;
1720
1721invalid_parentheses_block: opening_parenthesis error_recovery closing_parenthesis;
1722
1723opening_parenthesis:
1724    '(' | FUNCTION | CALCFUNCTION | MINFUNCTION | MAXFUNCTION | ANYFUNCTION | NOTFUNCTION
1725#if ENABLE_VIDEO_TRACK
1726    | CUEFUNCTION
1727#endif
1728    ;
1729
1730error_location: { $$ = parser->currentLocation(); } ;
1731
1732error_recovery:
1733    /* empty */
1734  | error_recovery error
1735  | error_recovery invalid_block
1736  | error_recovery invalid_square_brackets_block
1737  | error_recovery invalid_parentheses_block
1738    ;
1739
1740%%
1741