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