[CSS Parser] Eliminate in-place lowercasing in the parser.
[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         $$->setValue($1, parser->m_context.mode == HTMLQuirksMode);
1218     }
1219   | HEX {
1220         if ($1[0] >= '0' && $1[0] <= '9')
1221             $$ = nullptr;
1222         else {
1223             $$ = new CSSParserSelector;
1224             $$->setMatch(CSSSelector::Id);
1225             $$->setValue($1, parser->m_context.mode == HTMLQuirksMode);
1226         }
1227     }
1228   | class
1229   | attrib
1230   | pseudo
1231     ;
1232
1233 class:
1234     '.' IDENT {
1235         $$ = new CSSParserSelector;
1236         $$->setMatch(CSSSelector::Class);
1237         $$->setValue($2, parser->m_context.mode == HTMLQuirksMode);
1238     }
1239   ;
1240
1241 attrib:
1242     '[' maybe_space IDENT maybe_space ']' {
1243         $$ = new CSSParserSelector;
1244         $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument);
1245         $$->setMatch(CSSSelector::Set);
1246     }
1247     | '[' maybe_space IDENT maybe_space match maybe_space ident_or_string maybe_space attrib_flags ']' {
1248         $$ = new CSSParserSelector;
1249         $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument);
1250         $$->setMatch($5);
1251         $$->setValue($7);
1252         $$->setAttributeValueMatchingIsCaseInsensitive($9);
1253     }
1254     | '[' maybe_space namespace_selector IDENT maybe_space ']' {
1255         $$ = new CSSParserSelector;
1256         $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument);
1257         $$->setMatch(CSSSelector::Set);
1258     }
1259     | '[' maybe_space namespace_selector IDENT maybe_space match maybe_space ident_or_string maybe_space attrib_flags ']' {
1260         $$ = new CSSParserSelector;
1261         $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument);
1262         $$->setMatch($6);
1263         $$->setValue($8);
1264         $$->setAttributeValueMatchingIsCaseInsensitive($10);
1265     }
1266   ;
1267
1268 attrib_flags:
1269     IDENT maybe_space {
1270         if (UNLIKELY($1.length() != 1 || !isASCIIAlphaCaselessEqual($1[0], 'i')))
1271             YYERROR;
1272         $$ = true;
1273     }
1274     |
1275     /* empty */ {
1276         $$ = false;
1277     }
1278
1279 match:
1280     '=' {
1281         $$ = CSSSelector::Exact;
1282     }
1283     | INCLUDES {
1284         $$ = CSSSelector::List;
1285     }
1286     | DASHMATCH {
1287         $$ = CSSSelector::Hyphen;
1288     }
1289     | BEGINSWITH {
1290         $$ = CSSSelector::Begin;
1291     }
1292     | ENDSWITH {
1293         $$ = CSSSelector::End;
1294     }
1295     | CONTAINS {
1296         $$ = CSSSelector::Contain;
1297     }
1298     ;
1299
1300 ident_or_string: IDENT | STRING ;
1301
1302 pseudo_page:
1303     ':' IDENT {
1304         $$ = CSSParserSelector::parsePagePseudoSelector($2);
1305     }
1306
1307 nth_selector_ending:
1308     ')' {
1309         $$ = nullptr;
1310     }
1311     | space ')' {
1312         $$ = nullptr;
1313     }
1314     | space NTHCHILDSELECTORSEPARATOR space nested_selector_list maybe_space ')' {
1315         if ($4)
1316             $$ = $4;
1317         else
1318             YYERROR;
1319     }
1320     ;
1321
1322 pseudo:
1323     ':' IDENT {
1324         $$ = CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector($2);
1325     }
1326     | ':' ':' IDENT {
1327         $$ = CSSParserSelector::parsePseudoElementSelector($3);
1328     }
1329 #if ENABLE_VIDEO_TRACK
1330     // used by ::cue(:past/:future)
1331     | ':' ':' CUEFUNCTION maybe_space simple_selector_list maybe_space ')' {
1332         $$ = CSSParserSelector::parsePseudoElementCueFunctionSelector($3, $5);
1333     }
1334 #endif
1335     | ':' ':' SLOTTEDFUNCTION maybe_space compound_selector maybe_space ')' {
1336         $$ = CSSParserSelector::parsePseudoElementSlottedFunctionSelector($3, $5);
1337     }
1338     | ':' HOSTFUNCTION maybe_space compound_selector maybe_space ')' {
1339         $$ = CSSParserSelector::parsePseudoClassHostFunctionSelector($2, $4);
1340     }
1341     // use by :-webkit-any.
1342     // FIXME: should we support generic selectors here or just simple_selectors?
1343     // Use simple_selector_list for now to match -moz-any.
1344     // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0566.html for some
1345     // related discussion with respect to :not.
1346     | ':' ANYFUNCTION maybe_space simple_selector_list maybe_space ')' {
1347         $$ = nullptr;
1348         if ($4) {
1349             auto selector = std::make_unique<CSSParserSelector>();
1350             selector->setMatch(CSSSelector::PseudoClass);
1351             selector->adoptSelectorVector(*std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4));
1352             selector->setPseudoClassValue($2);
1353             if (selector->pseudoClassType() == CSSSelector::PseudoClassAny)
1354                 $$ = selector.release();
1355         }
1356     }
1357     | ':' MATCHESFUNCTION maybe_space nested_selector_list maybe_space ')' {
1358         $$ = nullptr;
1359         if ($4) {
1360             auto selector = std::make_unique<CSSParserSelector>();
1361             selector->setMatch(CSSSelector::PseudoClass);
1362             selector->adoptSelectorVector(*std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4));
1363             selector->setPseudoClassValue($2);
1364             if (selector->pseudoClassType() == CSSSelector::PseudoClassMatches)
1365                 $$ = selector.release();
1366         }
1367     }
1368     | ':' LANGFUNCTION maybe_space comma_separated_lang_ranges maybe_space ')' {
1369         $$ = nullptr;
1370         if ($4) {
1371             auto selector = std::make_unique<CSSParserSelector>();
1372             selector->setMatch(CSSSelector::PseudoClass);
1373             selector->setLangArgumentList(*std::unique_ptr<Vector<CSSParserString>>($4));
1374             selector->setPseudoClassValue($2);
1375             if (selector->pseudoClassType() == CSSSelector::PseudoClassLang)
1376                 $$ = selector.release();
1377         }
1378     }
1379
1380 #if ENABLE_CSS_SELECTORS_LEVEL4
1381     | ':' DIRFUNCTION maybe_space IDENT maybe_space ')' {
1382         $$ = nullptr;
1383         auto selector = std::make_unique<CSSParserSelector>();
1384         selector->setMatch(CSSSelector::PseudoClass);
1385         selector->setArgument($4);
1386         selector->setPseudoClassValue($2);
1387         if (selector->pseudoClassType() == CSSSelector::PseudoClassDir)
1388             $$ = selector.release();
1389     }
1390
1391     | ':' ROLEFUNCTION maybe_space IDENT maybe_space ')' {
1392         $$ = nullptr;
1393         auto selector = std::make_unique<CSSParserSelector>();
1394         selector->setMatch(CSSSelector::PseudoClass);
1395         selector->setArgument($4);
1396         selector->setPseudoClassValue($2);
1397         if (selector->pseudoClassType() == CSSSelector::PseudoClassRole)
1398             $$ = selector.release();
1399     }
1400 #endif
1401
1402     // Definition of :nth-child().
1403     | ':' NTHCHILDFUNCTIONS maybe_space NTH nth_selector_ending {
1404         $$ = nullptr;
1405         std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> ending($5);
1406         if (selectorListDoesNotMatchAnyPseudoElement(ending.get())) {
1407             auto selector = std::make_unique<CSSParserSelector>();
1408             selector->setMatch(CSSSelector::PseudoClass);
1409             selector->setArgument($4);
1410             selector->setPseudoClassValue($2);
1411             if (ending)
1412                 selector->adoptSelectorVector(*ending);
1413             CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType();
1414             if (pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild)
1415                 $$ = selector.release();
1416         }
1417     }
1418     | ':' NTHCHILDFUNCTIONS maybe_space maybe_unary_operator INTEGER nth_selector_ending {
1419         $$ = nullptr;
1420         std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> ending($6);
1421         if (selectorListDoesNotMatchAnyPseudoElement(ending.get())) {
1422             auto selector = std::make_unique<CSSParserSelector>();
1423             selector->setMatch(CSSSelector::PseudoClass);
1424             selector->setArgument(AtomicString::number($4 * $5));
1425             selector->setPseudoClassValue($2);
1426             if (ending)
1427                 selector->adoptSelectorVector(*ending);
1428             CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType();
1429             if (pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild)
1430                 $$ = selector.release();
1431         }
1432     }
1433     | ':' NTHCHILDFUNCTIONS maybe_space IDENT nth_selector_ending {
1434         $$ = nullptr;
1435         std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> ending($5);
1436         if (isValidNthToken($4) && selectorListDoesNotMatchAnyPseudoElement(ending.get())) {
1437             auto selector = std::make_unique<CSSParserSelector>();
1438             selector->setMatch(CSSSelector::PseudoClass);
1439             selector->setArgument($4);
1440             selector->setPseudoClassValue($2);
1441             if (ending)
1442                selector->adoptSelectorVector(*ending);
1443             CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType();
1444             if (pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild)
1445                 $$ = selector.release();
1446         }
1447     }
1448
1449     // used by :nth-*(ax+b)
1450     | ':' FUNCTION maybe_space NTH maybe_space ')' {
1451         $$ = nullptr;
1452         auto selector = std::make_unique<CSSParserSelector>();
1453         selector->setMatch(CSSSelector::PseudoClass);
1454         selector->setArgument($4);
1455         selector->setPseudoClassValue($2);
1456         if (selector->pseudoClassType() != CSSSelector::PseudoClassUnknown)
1457             $$ = selector.release();
1458     }
1459     // used by :nth-*
1460     | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' {
1461         $$ = nullptr;
1462         auto selector = std::make_unique<CSSParserSelector>();
1463         selector->setMatch(CSSSelector::PseudoClass);
1464         selector->setArgument(AtomicString::number($4 * $5));
1465         selector->setPseudoClassValue($2);
1466         if (selector->pseudoClassType() != CSSSelector::PseudoClassUnknown)
1467             $$ = selector.release();
1468     }
1469     // used by :nth-*(odd/even) and :lang
1470     | ':' FUNCTION maybe_space IDENT maybe_space ')' {
1471         auto selector = std::make_unique<CSSParserSelector>();
1472         selector->setMatch(CSSSelector::PseudoClass);
1473         selector->setArgument($4);
1474         selector->setPseudoClassValue($2);
1475         CSSSelector::PseudoClassType type = selector->pseudoClassType();
1476         if (type == CSSSelector::PseudoClassUnknown)
1477             selector = nullptr;
1478         else if (type == CSSSelector::PseudoClassNthChild ||
1479                  type == CSSSelector::PseudoClassNthOfType ||
1480                  type == CSSSelector::PseudoClassNthLastChild ||
1481                  type == CSSSelector::PseudoClassNthLastOfType) {
1482             if (!isValidNthToken($4))
1483                 selector = nullptr;
1484         }
1485         $$ = selector.release();
1486     }
1487     // Definition of :not().
1488     | ':' NOTFUNCTION maybe_space nested_selector_list maybe_space ')' {
1489         $$ = nullptr;
1490         if ($4) {
1491             std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> list($4);
1492             if (selectorListDoesNotMatchAnyPseudoElement(list.get())) {
1493                 auto selector = std::make_unique<CSSParserSelector>();
1494                 selector->setMatch(CSSSelector::PseudoClass);
1495                 selector->setPseudoClassValue($2);
1496                 selector->adoptSelectorVector(*list);
1497                 if (selector->pseudoClassType() == CSSSelector::PseudoClassNot)
1498                     $$ = selector.release();
1499             }
1500         }
1501     }
1502   ;
1503
1504 declaration_list:
1505     /* empty */ { $$ = false; }
1506     | declaration
1507     | decl_list declaration { $$ = $1 || $2; }
1508     | decl_list
1509     | decl_list_recovery { $$ = false; }
1510     | decl_list decl_list_recovery
1511     ;
1512
1513 decl_list:
1514     declaration ';' maybe_space {
1515         parser->markPropertyStart();
1516         $$ = $1;
1517     }
1518     | decl_list_recovery ';' maybe_space {
1519         parser->markPropertyStart();
1520         $$ = false;
1521     }
1522     | decl_list declaration ';' maybe_space {
1523         parser->markPropertyStart();
1524         $$ = $1;
1525         if ($2)
1526             $$ = $2;
1527     }
1528     | decl_list decl_list_recovery ';' maybe_space {
1529         parser->markPropertyStart();
1530         $$ = $1;
1531     }
1532     ;
1533
1534 decl_list_recovery:
1535     error error_location error_recovery {
1536         parser->syntaxError($2, CSSParser::PropertyDeclarationError);
1537     }
1538     ;
1539
1540 declaration:
1541     CUSTOM_PROPERTY maybe_space ':' whitespace_or_expr priority {
1542         $$ = false;
1543         bool isPropertyParsed = false;
1544         std::unique_ptr<CSSParserValueList> propertyValue($4);
1545         if (propertyValue) {
1546             parser->m_valueList = WTFMove(propertyValue);
1547             int oldParsedProperties = parser->m_parsedProperties.size();
1548             parser->setCustomPropertyName($1);
1549             $$ = parser->parseValue(CSSPropertyCustom, $5);
1550             if (!$$)
1551                 parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
1552             else
1553                 isPropertyParsed = true;
1554             parser->m_valueList = nullptr;
1555         }
1556         parser->markPropertyEnd($5, isPropertyParsed);
1557     }
1558     | property ':' maybe_space expr priority {
1559         $$ = false;
1560         bool isPropertyParsed = false;
1561         std::unique_ptr<CSSParserValueList> propertyValue($4);
1562         if ($1 && propertyValue) {
1563             parser->m_valueList = WTFMove(propertyValue);
1564             int oldParsedProperties = parser->m_parsedProperties.size();
1565             $$ = parser->parseValue($1, $5);
1566             if (!$$)
1567                 parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
1568             else
1569                 isPropertyParsed = true;
1570             parser->m_valueList = nullptr;
1571         }
1572         parser->markPropertyEnd($5, isPropertyParsed);
1573     }
1574     | property declaration_recovery { $$ = false; }
1575     | property ':' maybe_space expr priority declaration_recovery {
1576         // When we encounter something like p {color: red !important fail;} we should drop the declaration.
1577         parser->markPropertyEnd(false, false);
1578         delete $4;
1579         $$ = false;
1580     }
1581     | IMPORTANT_SYM maybe_space declaration_recovery {
1582         // Handle this case -- div { text-align: center; !important } -- by just reducing away the stray !important.
1583         $$ = false;
1584     }
1585     | property ':' maybe_space declaration_recovery {
1586         // If we come across rules with invalid values like this case: p { weight: *; }, just discard the rule.
1587         parser->markPropertyEnd(false, false);
1588         $$ = false;
1589     }
1590   ;
1591
1592 declaration_recovery: error error_location error_recovery { parser->syntaxError($2); } ;
1593
1594 property: IDENT maybe_space { $$ = cssPropertyID($1); } ;
1595
1596 priority: IMPORTANT_SYM maybe_space { $$ = true; } | /* empty */ { $$ = false; } ;
1597
1598 #if ENABLE_CSS_GRID_LAYOUT
1599
1600 ident_list:
1601     IDENT maybe_space {
1602         $$ = new CSSParserValueList;
1603         $$->addValue(makeIdentValue($1));
1604     }
1605     | ident_list IDENT maybe_space {
1606         $$ = $1;
1607         $$->addValue(makeIdentValue($2));
1608     }
1609     ;
1610
1611 track_names_list:
1612     '[' maybe_space closing_bracket {
1613         $$.setFromValueList(std::make_unique<CSSParserValueList>());
1614     }
1615     | '[' maybe_space ident_list closing_bracket {
1616         $$.setFromValueList(std::unique_ptr<CSSParserValueList>($3));
1617     }
1618     | '[' maybe_space expr_recovery closing_bracket {
1619         $$.id = CSSValueInvalid;
1620         $$.unit = 0;
1621         YYERROR;
1622     }
1623   ;
1624
1625 #endif
1626
1627 whitespace_or_expr:
1628     WHITESPACE maybe_expr {
1629         if ($2)
1630             $$ = $2;
1631         else {
1632             CSSParserValue val;
1633             val.id = CSSValueInvalid;
1634             val.unit = CSSPrimitiveValue::CSS_PARSER_WHITESPACE;
1635             val.string.init(emptyString());
1636             $$ = new CSSParserValueList;
1637             $$->addValue(val);
1638         }
1639     }
1640     | maybe_space expr { $$ = $2; }
1641     ;
1642
1643 maybe_expr: /* empty */ { $$ = nullptr; } | expr { $$ = $1; };
1644
1645 expr: valid_expr | valid_expr expr_recovery { $$ = nullptr; delete $1; } ;
1646
1647 valid_expr:
1648     term {
1649         $$ = new CSSParserValueList;
1650         $$->addValue($1);
1651     }
1652     | valid_expr operator term {
1653         $$ = $1;
1654         if (!$$)
1655             destroy($3);
1656         else {
1657             if ($2) {
1658                 CSSParserValue v;
1659                 v.id = CSSValueInvalid;
1660                 v.unit = CSSParserValue::Operator;
1661                 v.iValue = $2;
1662                 $$->addValue(v);
1663             }
1664             $$->addValue($3);
1665         }
1666     }
1667   ;
1668
1669 expr_recovery: error error_location error_recovery ;
1670
1671 operator: '/' maybe_space { $$ = '/'; } | ',' maybe_space { $$ = ','; } | /* empty */ { $$ = 0; } ;
1672
1673 term:
1674   unary_term maybe_space
1675   | unary_operator unary_term maybe_space { $$ = $2; $$.fValue *= $1; }
1676   | STRING maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
1677   | IDENT maybe_space { $$ = makeIdentValue($1); }
1678   /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
1679   | DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1680   | unary_operator DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1681   | URI maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
1682   | UNICODERANGE maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; }
1683   | HEX maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; }
1684   | '#' maybe_space { $$.id = CSSValueInvalid; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */
1685   /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1686   | function maybe_space
1687   | calc_function maybe_space
1688   | variable_function maybe_space
1689   | min_or_max_function maybe_space
1690   | '%' maybe_space { /* Handle width: %; */
1691       $$.id = CSSValueInvalid; $$.unit = 0;
1692   }
1693 #if ENABLE_CSS_GRID_LAYOUT
1694   | track_names_list maybe_space
1695 #endif
1696   ;
1697
1698 unary_term:
1699   INTEGER { $$.id = CSSValueInvalid; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1700   | FLOATTOKEN { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1701   | PERCENTAGE { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
1702   | PXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
1703   | CMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
1704   | MMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
1705   | INS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
1706   | PTS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
1707   | PCS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
1708   | DEGS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
1709   | RADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
1710   | GRADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
1711   | TURNS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; }
1712   | MSECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
1713   | SECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
1714   | HERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
1715   | KHERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
1716   | EMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
1717   | QEMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; }
1718   | EXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
1719   | REMS {
1720       $$.id = CSSValueInvalid;
1721       $$.fValue = $1;
1722       $$.unit = CSSPrimitiveValue::CSS_REMS;
1723   }
1724   | CHS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CHS; }
1725   | VW { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VW; }
1726   | VH { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VH; }
1727   | VMIN { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMIN; }
1728   | VMAX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMAX; }
1729   | DPPX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPPX; }
1730   | DPI { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPI; }
1731   | DPCM { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPCM; }
1732   | FR { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_FR; }
1733   ;
1734
1735 function:
1736     FUNCTION maybe_space expr closing_parenthesis {
1737         CSSParserFunction* f = new CSSParserFunction;
1738         f->name = $1;
1739         f->args = std::unique_ptr<CSSParserValueList>($3);
1740         $$.id = CSSValueInvalid;
1741         $$.unit = CSSParserValue::Function;
1742         $$.function = f;
1743     } |
1744     FUNCTION maybe_space closing_parenthesis {
1745         CSSParserFunction* f = new CSSParserFunction;
1746         f->name = $1;
1747         f->args = std::make_unique<CSSParserValueList>();
1748         $$.id = CSSValueInvalid;
1749         $$.unit = CSSParserValue::Function;
1750         $$.function = f;
1751     } |
1752     FUNCTION maybe_space expr_recovery closing_parenthesis {
1753         CSSParserFunction* f = new CSSParserFunction;
1754         f->name = $1;
1755         f->args = nullptr;
1756         $$.id = CSSValueInvalid;
1757         $$.unit = CSSParserValue::Function;
1758         $$.function = f;
1759   }
1760   ;
1761
1762 variable_function:
1763     VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space closing_parenthesis {
1764         CSSParserVariable* var = new CSSParserVariable;
1765         var->name = $3;
1766         var->args = nullptr;
1767         $$.id = CSSValueInvalid;
1768         $$.unit = CSSParserValue::Variable;
1769         $$.variable = var;
1770     }
1771     | VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space ',' maybe_space expr closing_parenthesis {
1772         CSSParserVariable* var = new CSSParserVariable;
1773         var->name = $3;
1774         var->args = std::unique_ptr<CSSParserValueList>($7);
1775         $$.id = CSSValueInvalid;
1776         $$.unit = CSSParserValue::Variable;
1777         $$.variable = var;
1778     }
1779     | VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space ',' maybe_space closing_parenthesis {
1780         CSSParserVariable* var = new CSSParserVariable;
1781         var->name = $3;
1782         var->args = std::make_unique<CSSParserValueList>();
1783         $$.id = CSSValueInvalid;
1784         $$.unit = CSSParserValue::Variable;
1785         $$.variable = var;
1786     }
1787     // Error handling cases
1788     | VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space ',' closing_parenthesis {
1789         $$.id = CSSValueInvalid;
1790         $$.unit = 0;
1791         YYERROR;
1792     }
1793     | VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space ',' maybe_space invalid_var_fallback maybe_space closing_parenthesis {
1794         $$.id = CSSValueInvalid;
1795         $$.unit = 0;
1796         YYERROR;
1797     }
1798     | VARFUNCTION maybe_space CUSTOM_PROPERTY maybe_space ',' maybe_space priority closing_parenthesis {
1799         $$.id = CSSValueInvalid;
1800         $$.unit = 0;
1801         YYERROR;
1802     }
1803     | VARFUNCTION maybe_space expr closing_parenthesis {
1804         $$.id = CSSValueInvalid;
1805         $$.unit = 0;
1806         delete $3;
1807         YYERROR;
1808     }
1809     | VARFUNCTION maybe_space expr_recovery closing_parenthesis {
1810         $$.id = CSSValueInvalid;
1811         $$.unit = 0;
1812         YYERROR;
1813     }
1814     ;
1815
1816 invalid_var_fallback:
1817     '!' | ';';
1818
1819 calc_func_term:
1820     unary_term
1821     | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
1822     | variable_function
1823     ;
1824
1825 /*
1826  * The grammar requires spaces around binary ‘+’ and ‘-’ operators.
1827  * The '*' and '/' operators do not require spaces.
1828  * http://www.w3.org/TR/css3-values/#calc-syntax
1829  */
1830 calc_func_operator:
1831     space '+' space {
1832         $$ = '+';
1833     }
1834     | space '-' space {
1835         $$ = '-';
1836     }
1837     | calc_maybe_space '*' maybe_space {
1838         $$ = '*';
1839     }
1840     | calc_maybe_space '/' maybe_space {
1841         $$ = '/';
1842     }
1843   ;
1844
1845 calc_maybe_space: /* empty */ | WHITESPACE ;
1846
1847 calc_func_paren_expr:
1848     '(' maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1849         $$ = nullptr;
1850         if ($3) {
1851             $$ = $3;
1852             CSSParserValue v;
1853             v.id = CSSValueInvalid;
1854             v.unit = CSSParserValue::Operator;
1855             v.iValue = '(';
1856             $$->insertValueAt(0, v);
1857             v.iValue = ')';
1858             $$->addValue(v);
1859         }
1860     }
1861   ;
1862
1863 calc_func_expr: valid_calc_func_expr | valid_calc_func_expr expr_recovery { $$ = nullptr; delete $1; } ;
1864
1865 valid_calc_func_expr:
1866     calc_func_term {
1867         $$ = new CSSParserValueList;
1868         $$->addValue($1);
1869     }
1870     | calc_func_expr calc_func_operator calc_func_term {
1871         std::unique_ptr<CSSParserValueList> expression($1);
1872         $$ = nullptr;
1873         if (expression && $2) {
1874             $$ = expression.release();
1875             CSSParserValue v;
1876             v.id = CSSValueInvalid;
1877             v.unit = CSSParserValue::Operator;
1878             v.iValue = $2;
1879             $$->addValue(v);
1880             $$->addValue($3);
1881         } else {
1882             destroy($3);
1883         }
1884
1885     }
1886     | calc_func_expr calc_func_operator calc_func_paren_expr {
1887         std::unique_ptr<CSSParserValueList> left($1);
1888         std::unique_ptr<CSSParserValueList> right($3);
1889         $$ = nullptr;
1890         if (left && $2 && right) {
1891             CSSParserValue v;
1892             v.id = CSSValueInvalid;
1893             v.unit = CSSParserValue::Operator;
1894             v.iValue = $2;
1895             left->addValue(v);
1896             left->extend(*right);
1897             $$ = left.release();
1898         }
1899     }
1900     | calc_func_paren_expr
1901   ;
1902
1903 calc_func_expr_list:
1904     calc_func_expr calc_maybe_space
1905     | calc_func_expr_list ',' maybe_space calc_func_expr calc_maybe_space {
1906         std::unique_ptr<CSSParserValueList> list($1);
1907         std::unique_ptr<CSSParserValueList> expression($4);
1908         $$ = nullptr;
1909         if (list && expression) {
1910             $$ = list.release();
1911             CSSParserValue v;
1912             v.id = CSSValueInvalid;
1913             v.unit = CSSParserValue::Operator;
1914             v.iValue = ',';
1915             $$->addValue(v);
1916             $$->extend(*expression);
1917         }
1918     }
1919   ;
1920
1921 calc_function:
1922     CALCFUNCTION maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1923         CSSParserFunction* f = new CSSParserFunction;
1924         f->name = $1;
1925         f->args = std::unique_ptr<CSSParserValueList>($3);
1926         $$.id = CSSValueInvalid;
1927         $$.unit = CSSParserValue::Function;
1928         $$.function = f;
1929     }
1930     | CALCFUNCTION maybe_space expr_recovery closing_parenthesis {
1931         $$.id = CSSValueInvalid;
1932         $$.unit = 0;
1933         YYERROR;
1934     }
1935     ;
1936
1937
1938 min_or_max: MINFUNCTION | MAXFUNCTION ;
1939
1940 min_or_max_function:
1941     min_or_max maybe_space calc_func_expr_list closing_parenthesis {
1942         CSSParserFunction* f = new CSSParserFunction;
1943         f->name = $1;
1944         f->args = std::unique_ptr<CSSParserValueList>($3);
1945         $$.id = CSSValueInvalid;
1946         $$.unit = CSSParserValue::Function;
1947         $$.function = f;
1948     }
1949     | min_or_max maybe_space expr_recovery closing_parenthesis {
1950         $$.id = CSSValueInvalid;
1951         $$.unit = 0;
1952         YYERROR;
1953     }
1954     ;
1955
1956 /* error handling rules */
1957
1958 save_block: closing_brace | error closing_brace ;
1959
1960 invalid_at: ATKEYWORD error invalid_block | ATKEYWORD error ';' ;
1961
1962 invalid_rule: error invalid_block ;
1963
1964 invalid_block: '{' error_recovery closing_brace { parser->invalidBlockHit(); } ;
1965
1966 invalid_square_brackets_block: '[' error_recovery closing_bracket ;
1967
1968 invalid_parentheses_block: opening_parenthesis error_recovery closing_parenthesis;
1969
1970 opening_parenthesis:
1971     '(' | FUNCTION | VARFUNCTION | CALCFUNCTION | MATCHESFUNCTION | MAXFUNCTION | MINFUNCTION | ANYFUNCTION | NOTFUNCTION | LANGFUNCTION
1972 #if ENABLE_CSS_SELECTORS_LEVEL4
1973     | DIRFUNCTION | ROLEFUNCTION
1974 #endif
1975 #if ENABLE_VIDEO_TRACK
1976     | CUEFUNCTION
1977 #endif
1978     ;
1979
1980 error_location: { $$ = parser->currentLocation(); } ;
1981
1982 error_recovery:
1983     /* empty */
1984   | error_recovery error
1985   | error_recovery invalid_block
1986   | error_recovery invalid_square_brackets_block
1987   | error_recovery invalid_parentheses_block
1988     ;
1989
1990 %%