Keep the already-parsed list of terms in custom property values so that we don't...
[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     MediaQueryExp* mediaQueryExp;
41     Vector<CSSParser::SourceSize>* sourceSizeList;
42     Vector<std::unique_ptr<MediaQueryExp>>* mediaQueryExpList;
43     StyleKeyframe* keyframe;
44     Vector<RefPtr<StyleKeyframe>>* keyframeRuleList;
45     CSSPropertyID id;
46     CSSParserSelector* selector;
47     Vector<std::unique_ptr<CSSParserSelector>>* selectorList;
48     bool boolean;
49     CSSSelector::Match match;
50     int integer;
51     char character;
52     CSSParserValueList* valueList;
53     Vector<CSSParserString>* stringList;
54     CSSParser::Location location;
55 }
56
57 %{
58
59 static inline int cssyyerror(void*, const char*)
60 {
61     return 1;
62 }
63
64 #if YYDEBUG > 0
65
66 static inline bool isCSSTokenAString(int yytype)
67 {
68     switch (yytype) {
69     case IDENT:
70     case STRING:
71     case NTH:
72     case HEX:
73     case IDSEL:
74     case DIMEN:
75     case INVALIDDIMEN:
76     case URI:
77     case FUNCTION:
78     case ANYFUNCTION:
79     case NOTFUNCTION:
80     case CALCFUNCTION:
81     case MATCHESFUNCTION:
82     case MAXFUNCTION:
83     case MINFUNCTION:
84     case NTHCHILDFUNCTIONS:
85     case NTHCHILDSELECTORSEPARATOR:
86     case LANGFUNCTION:
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 32
128 #else
129 %expect 31
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
243 #if ENABLE_CSS_SELECTORS_LEVEL4
244 %token <string> DIRFUNCTION
245 %token <string> ROLEFUNCTION
246 #endif
247
248 %token <string> CUSTOM_PROPERTY
249
250 %token <string> UNICODERANGE
251
252 %type <relation> combinator
253
254 %type <rule> block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule
255 %destructor { if ($$) $$->deref(); } block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule
256
257 %type <ruleList> block_rule_list block_valid_rule_list
258 %destructor { delete $$; } block_rule_list block_valid_rule_list
259
260 %type <string> ident_or_string maybe_ns_prefix namespace_selector string_or_uri
261
262 %type <marginBox> margin_sym
263
264 %type <mediaList> media_list maybe_media_list
265 %destructor { if ($$) $$->deref(); } media_list maybe_media_list
266
267 %type <mediaQuery> media_query
268 %destructor { delete $$; } media_query
269
270 %type <mediaQueryRestrictor> maybe_media_restrictor
271
272 %type <mediaQueryExp> media_query_exp base_media_query_exp
273 %destructor { delete $$; } media_query_exp base_media_query_exp
274
275 %type <sourceSizeList> source_size_list
276 %destructor { delete $$; } source_size_list
277
278 %type <mediaQueryExp> maybe_source_media_query_exp
279 %destructor { delete $$; } maybe_source_media_query_exp
280
281 %type <value> source_size_length
282 %destructor { destroy($$); } source_size_length
283
284 %type <mediaQueryExpList> media_query_exp_list maybe_and_media_query_exp_list
285 %destructor { delete $$; } media_query_exp_list maybe_and_media_query_exp_list
286
287 %type <string> keyframe_name
288
289 %type <keyframe> keyframe_rule
290 %destructor { if ($$) $$->deref(); } keyframe_rule
291
292 %type <keyframeRuleList> keyframes_rule
293 %destructor { delete $$; } keyframes_rule
294
295 // These parser values never need to be destroyed because they are never functions or value lists.
296 %type <value> calc_func_term key unary_term
297
298 // These parser values need to be destroyed because they might be functions.
299 %type <value> calc_function function min_or_max_function term
300 %destructor { destroy($$); } calc_function function min_or_max_function term
301
302 %type <id> property
303
304 %type <selector> attrib class page_selector pseudo pseudo_page complex_selector complex_selector_with_trailing_whitespace compound_selector specifier specifier_list
305 %destructor { delete $$; } attrib class page_selector pseudo pseudo_page complex_selector complex_selector_with_trailing_whitespace compound_selector specifier specifier_list
306
307 %type <selectorList> selector_list nested_selector_list simple_selector_list nth_selector_ending
308 %destructor { delete $$; } selector_list nested_selector_list simple_selector_list
309 %destructor { delete $$; } nth_selector_ending
310
311 %type <boolean> attrib_flags declaration declaration_list decl_list priority
312
313 %type <match> match
314
315 %type <integer> unary_operator maybe_unary_operator
316
317 %type <character> operator calc_func_operator
318
319 %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
320 %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
321
322 %type <string> lang_range
323 %type <stringList> comma_separated_lang_ranges
324 %destructor { delete $$; } comma_separated_lang_ranges
325
326 %type <string> min_or_max
327
328 %type <string> element_name
329
330 %type <location> error_location
331
332 #if ENABLE_CSS_GRID_LAYOUT
333
334 %type <valueList> ident_list
335 %destructor { delete $$; } ident_list
336
337 %type <value> track_names_list
338 %destructor { destroy($$); } track_names_list
339
340 #endif
341
342 %token SUPPORTS_AND
343 %token SUPPORTS_NOT
344 %token SUPPORTS_OR
345 %token SUPPORTS_SYM
346 %token WEBKIT_SUPPORTS_CONDITION_SYM
347
348 %type <rule> supports
349 %destructor { if ($$) $$->deref(); } supports
350
351 %type <boolean> supports_condition supports_condition_in_parens supports_conjunction supports_declaration_condition supports_disjunction supports_error supports_negation
352
353 #if ENABLE_CSS_DEVICE_ADAPTATION
354
355 %type <rule> viewport
356 %destructor { if ($$) $$->deref(); } viewport
357
358 #endif
359
360 #if ENABLE_VIDEO_TRACK
361
362 %token <string> CUEFUNCTION
363
364 #endif
365
366 %%
367
368 stylesheet:
369     maybe_space maybe_charset maybe_sgml rule_list
370   | webkit_rule maybe_space
371   | webkit_decls maybe_space
372   | webkit_value maybe_space
373   | webkit_mediaquery maybe_space
374   | webkit_source_size_list maybe_space
375   | webkit_selector maybe_space
376   | webkit_keyframe_rule maybe_space
377   | webkit_supports_condition maybe_space
378   ;
379
380 webkit_rule: WEBKIT_RULE_SYM '{' maybe_space valid_rule maybe_space '}' { parser->m_rule = adoptRef($4); } ;
381
382 webkit_keyframe_rule: KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' { parser->m_keyframe = adoptRef($4); } ;
383
384 webkit_decls: WEBKIT_DECLS_SYM '{' maybe_space_before_declaration declaration_list '}' ;
385
386 webkit_value:
387     WEBKIT_VALUE_SYM '{' maybe_space expr '}' {
388         if ($4) {
389             parser->m_valueList = std::unique_ptr<CSSParserValueList>($4);
390             int oldParsedProperties = parser->m_parsedProperties.size();
391             if (!parser->parseValue(parser->m_id, parser->m_important))
392                 parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
393             parser->m_valueList = nullptr;
394         }
395     }
396 ;
397
398 webkit_mediaquery: WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' { parser->m_mediaQuery = std::unique_ptr<MediaQuery>($4); } ;
399
400 webkit_selector:
401     WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' {
402         if ($4) {
403             if (parser->m_selectorListForParseSelector)
404                 parser->m_selectorListForParseSelector->adoptSelectorVector(*$4);
405             parser->recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4));
406         }
407     }
408 ;
409
410 webkit_supports_condition: WEBKIT_SUPPORTS_CONDITION_SYM WHITESPACE maybe_space supports_condition '}' { parser->m_supportsCondition = $4; } ;
411
412 /* for expressions that require at least one whitespace to be present, like the + and - operators in calc expressions */
413 space: WHITESPACE | space WHITESPACE ;
414
415 maybe_space: /* empty */ %prec UNIMPORTANT_TOK | maybe_space WHITESPACE ;
416
417 maybe_sgml: /* empty */ | maybe_sgml SGML_CD | maybe_sgml WHITESPACE ;
418
419 maybe_charset: /* empty */ | charset ;
420
421 closing_brace: '}' | %prec LOWEST_PREC TOKEN_EOF ;
422
423 closing_parenthesis: ')' | %prec LOWEST_PREC TOKEN_EOF ;
424
425 closing_bracket: ']' | %prec LOWEST_PREC TOKEN_EOF;
426
427 charset:
428   CHARSET_SYM maybe_space STRING maybe_space ';' {
429      if (parser->m_styleSheet)
430          parser->m_styleSheet->parserSetEncodingFromCharsetRule($3);
431      if (parser->isExtractingSourceData() && parser->m_currentRuleDataStack->isEmpty() && parser->m_ruleSourceDataResult)
432          parser->addNewRuleToSourceTree(CSSRuleSourceData::createUnknown());
433   }
434   | CHARSET_SYM error invalid_block
435   | CHARSET_SYM error ';'
436 ;
437
438 // Ignore any @charset rule not at the beginning of the style sheet.
439 ignored_charset: CHARSET_SYM maybe_space STRING maybe_space ';' | CHARSET_SYM maybe_space ';' ;
440
441 rule_list:
442     /* empty */
443     | rule_list rule maybe_sgml {
444         if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
445             if (parser->m_styleSheet)
446                 parser->m_styleSheet->parserAppendRule(rule.releaseNonNull());
447         }
448     }
449     ;
450
451 valid_rule:
452     ruleset
453   | media
454   | page
455   | font_face
456   | keyframes
457   | namespace { $$ = nullptr; }
458   | import
459   | region
460   | supports
461 #if ENABLE_CSS_DEVICE_ADAPTATION
462   | viewport
463 #endif
464   ;
465
466 rule:
467     valid_rule {
468         $$ = $1;
469         parser->m_hadSyntacticallyValidCSSRule = true;
470     }
471     | ignored_charset { $$ = nullptr; }
472     | invalid_rule { $$ = nullptr; }
473     | invalid_at { $$ = nullptr; }
474     ;
475
476 block_rule_list: 
477     /* empty */ { $$ = nullptr; }
478   | block_rule_list block_rule maybe_sgml {
479       $$ = $1;
480       if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
481           if (!$$)
482               $$ = new Vector<RefPtr<StyleRuleBase>>;
483           $$->append(rule.release());
484       }
485   }
486   ;
487
488 block_valid_rule_list:
489     /* empty */ { $$ = nullptr; }
490   | block_valid_rule_list block_valid_rule maybe_sgml {
491       $$ = $1;
492       if (RefPtr<StyleRuleBase> rule = adoptRef($2)) {
493           if (!$$)
494               $$ = new Vector<RefPtr<StyleRuleBase>>;
495           $$->append(rule.release());
496       }
497   }
498   ;
499
500 block_valid_rule:
501     ruleset
502   | page
503   | font_face
504   | media
505   | keyframes
506   | supports
507 #if ENABLE_CSS_DEVICE_ADAPTATION
508   | viewport
509 #endif
510   ;
511
512 block_rule: block_valid_rule | invalid_rule { $$ = nullptr; } | invalid_at { $$ = nullptr; } | namespace { $$ = nullptr; } | import | region ;
513
514 at_import_header_end_maybe_space:
515     maybe_space {
516         parser->markRuleHeaderEnd();
517         parser->markRuleBodyStart();
518     }
519     ;
520
521 before_import_rule:
522     /* empty */ {
523         parser->markRuleHeaderStart(CSSRuleSourceData::IMPORT_RULE);
524     }
525     ;
526
527 import:
528     before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list ';' {
529         $$ = parser->createImportRule($4, adoptRef($6)).leakRef();
530     }
531   | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list TOKEN_EOF {
532         $$ = parser->createImportRule($4, adoptRef($6)).leakRef();
533     }
534   | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list invalid_block {
535         $$ = nullptr;
536         parser->popRuleData();
537         if ($6)
538             $6->deref();
539     }
540   | before_import_rule IMPORT_SYM error ';' {
541         $$ = nullptr;
542         parser->popRuleData();
543     }
544   | before_import_rule IMPORT_SYM error invalid_block {
545         $$ = nullptr;
546         parser->popRuleData();
547     }
548   ;
549
550 namespace:
551     NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' { parser->addNamespace($3, $4); }
552     | NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space invalid_block
553     | NAMESPACE_SYM error invalid_block
554     | NAMESPACE_SYM error ';'
555     ;
556
557 maybe_ns_prefix: /* empty */ { $$.clear(); } | IDENT maybe_space;
558
559 string_or_uri: STRING | URI ;
560
561 maybe_media_value: /*empty*/ { $$ = nullptr; } | ':' maybe_space expr maybe_space { $$ = $3; } ;
562
563 webkit_source_size_list:
564     WEBKIT_SIZESATTR_SYM WHITESPACE source_size_list maybe_space '}' {
565         parser->m_sourceSizeList = std::unique_ptr<Vector<CSSParser::SourceSize>>($3);
566     }
567     ;
568
569 source_size_list:
570     maybe_source_media_query_exp source_size_length {
571         $$ = new Vector<CSSParser::SourceSize>;
572         $$->append(parser->sourceSize(std::unique_ptr<MediaQueryExp>($1), $2));
573     }
574     | source_size_list maybe_space ',' maybe_space maybe_source_media_query_exp source_size_length {
575         $$ = $1;
576         $$->append(parser->sourceSize(std::unique_ptr<MediaQueryExp>($5), $6));
577     }
578     ;
579
580 maybe_source_media_query_exp:
581     /* empty */ {
582         $$ = new MediaQueryExp;
583     }
584     | base_media_query_exp maybe_space;
585
586 source_size_length: unary_term | calc_function;
587
588 base_media_query_exp: '(' maybe_space IDENT maybe_space maybe_media_value ')' {
589         std::unique_ptr<CSSParserValueList> mediaValue($5);
590         $3.lower();
591         $$ = new MediaQueryExp($3, mediaValue.get());
592     }
593     ;
594
595 media_query_exp:
596     maybe_media_restrictor maybe_space base_media_query_exp maybe_space {
597         if ($1 != MediaQuery::None) {
598             // If restrictor is specified, media query expression is invalid.
599             // Create empty media query expression and continue parsing media query.
600             delete $3;
601             $$ = new MediaQueryExp;
602         } else
603             $$ = $3;
604     }
605     ;
606
607 media_query_exp_list:
608     media_query_exp {
609         $$ = new Vector<std::unique_ptr<MediaQueryExp>>;
610         $$->append(std::unique_ptr<MediaQueryExp>($1));
611     }
612     | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp {
613         $$ = $1;
614         $$->append(std::unique_ptr<MediaQueryExp>($5));
615     }
616     ;
617
618 maybe_and_media_query_exp_list:
619     /*empty*/ {
620         $$ = new Vector<std::unique_ptr<MediaQueryExp>>;
621     }
622     | MEDIA_AND maybe_space media_query_exp_list {
623         $$ = $3;
624     }
625     ;
626
627 maybe_media_restrictor:
628     /*empty*/ {
629         $$ = MediaQuery::None;
630     }
631     | MEDIA_ONLY {
632         $$ = MediaQuery::Only;
633     }
634     | MEDIA_NOT {
635         $$ = MediaQuery::Not;
636     }
637     ;
638
639 media_query:
640     media_query_exp_list {
641         $$ = new MediaQuery(MediaQuery::None, "all", std::unique_ptr<Vector<std::unique_ptr<MediaQueryExp>>>($1));
642     }
643     |
644     maybe_media_restrictor maybe_space IDENT maybe_space maybe_and_media_query_exp_list {
645         $3.lower();
646         $$ = new MediaQuery($1, $3, std::unique_ptr<Vector<std::unique_ptr<MediaQueryExp>>>($5));
647     }
648     ;
649
650 maybe_media_list: /* empty */ { $$ = &MediaQuerySet::create().leakRef(); } | media_list ;
651
652 media_list:
653     media_query {
654         $$ = &MediaQuerySet::create().leakRef();
655         $$->addMediaQuery(std::unique_ptr<MediaQuery>($1));
656         parser->updateLastMediaLine($$);
657     }
658     | media_list ',' maybe_space media_query {
659         $$ = $1;
660         std::unique_ptr<MediaQuery> mediaQuery($4);
661         if ($$) {
662             $$->addMediaQuery(WTF::move(mediaQuery));
663             parser->updateLastMediaLine($$);
664         }
665     }
666     | media_list error {
667         $$ = nullptr;
668         if ($1)
669             $1->deref();
670     }
671     ;
672
673 at_rule_body_start:
674     /* empty */ {
675         parser->markRuleBodyStart();
676     }
677     ;
678
679 before_media_rule:
680     /* empty */ {
681         parser->markRuleHeaderStart(CSSRuleSourceData::MEDIA_RULE);
682     }
683     ;
684
685 at_rule_header_end_maybe_space:
686     maybe_space {
687         parser->markRuleHeaderEnd();
688     }
689     ;
690
691 media:
692     before_media_rule MEDIA_SYM maybe_space media_list at_rule_header_end '{' at_rule_body_start maybe_space block_rule_list save_block {
693         $$ = parser->createMediaRule(adoptRef($4), std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($9).get()).leakRef();
694     }
695     | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space block_rule_list save_block {
696         $$ = parser->createEmptyMediaRule(std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($7).get()).leakRef();
697     }
698     | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space ';' {
699         $$ = nullptr;
700         parser->popRuleData();
701     }
702     ;
703
704 supports:
705     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 {
706         $$ = parser->createSupportsRule($4, std::unique_ptr<Vector<RefPtr<StyleRuleBase>>>($9).get()).leakRef();
707     }
708     | before_supports_rule SUPPORTS_SYM supports_error {
709         $$ = nullptr;
710         parser->popRuleData();
711         parser->popSupportsRuleData();
712     }
713     ;
714
715 supports_error: 
716     error ';' {
717         $$ = false;
718     }
719     | error invalid_block {
720         $$ = false;
721     }
722     ;
723
724 before_supports_rule:
725     /* empty */ {
726         parser->markRuleHeaderStart(CSSRuleSourceData::SUPPORTS_RULE);
727         parser->markSupportsRuleHeaderStart();
728     }
729     ;
730
731 at_supports_rule_header_end:
732     /* empty */ {
733         parser->markRuleHeaderEnd();
734         parser->markSupportsRuleHeaderEnd();
735     }
736     ;
737
738 supports_condition: supports_condition_in_parens | supports_negation | supports_conjunction | supports_disjunction ;
739
740 supports_negation: SUPPORTS_NOT maybe_space supports_condition_in_parens { $$ = !$3; } ;
741
742 supports_conjunction:
743     supports_condition_in_parens SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; }
744     | supports_conjunction SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; }
745     ;
746
747 supports_disjunction:
748     supports_condition_in_parens SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; }
749     | supports_disjunction SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; }
750     ;
751
752 supports_condition_in_parens:
753     '(' maybe_space supports_condition ')' maybe_space { $$ = $3; }
754     | supports_declaration_condition { $$ = $1; }
755     | '(' error ')' { $$ = false; }
756     ;
757
758 supports_declaration_condition:
759     '(' maybe_space property ':' maybe_space expr priority ')' maybe_space {
760         $$ = false;
761         CSSParser* p = static_cast<CSSParser*>(parser);
762         std::unique_ptr<CSSParserValueList> propertyValue($6);
763         if ($3 && propertyValue) {
764             p->m_valueList = WTF::move(propertyValue);
765             int oldParsedProperties = p->m_parsedProperties.size();
766             $$ = p->parseValue($3, $7);
767             // We just need to know if the declaration is supported as it is written. Rollback any additions.
768             if ($$)
769                 p->rollbackLastProperties(p->m_parsedProperties.size() - oldParsedProperties);
770             p->m_valueList = nullptr;
771         }
772         p->markPropertyEnd($7, false);
773     }
774     ;
775
776 before_keyframes_rule:
777     /* empty */ {
778         parser->markRuleHeaderStart(CSSRuleSourceData::KEYFRAMES_RULE);
779     }
780     ;
781
782 keyframes:
783     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 {
784         $$ = parser->createKeyframesRule($4, std::unique_ptr<Vector<RefPtr<StyleKeyframe>>>($9)).leakRef();
785     }
786     ;
787
788 keyframe_name: IDENT | STRING ;
789
790 keyframes_rule:
791     /* empty */ { $$ = new Vector<RefPtr<StyleKeyframe>>; }
792     | keyframes_rule keyframe_rule maybe_space {
793         $$ = $1;
794         if (RefPtr<StyleKeyframe> keyframe = adoptRef($2))
795             $$->append(keyframe.release());
796     }
797     ;
798
799 keyframe_rule: key_list maybe_space '{' maybe_space declaration_list closing_brace { $$ = parser->createKeyframe(*std::unique_ptr<CSSParserValueList>($1)).leakRef(); } ;
800
801 key_list:
802     key {
803         $$ = new CSSParserValueList;
804         $$->addValue($1);
805     }
806     | key_list maybe_space ',' maybe_space key {
807         $$ = $1;
808         ASSERT($5.unit != CSSParserValue::Function); // No need to call destroy.
809         if ($$)
810             $$->addValue($5);
811     }
812     ;
813
814 key:
815     maybe_unary_operator PERCENTAGE { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1 * $2; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
816     | IDENT {
817         $$.id = CSSValueInvalid; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER;
818         CSSParserString& str = $1;
819         if (str.equalIgnoringCase("from"))
820             $$.fValue = 0;
821         else if (str.equalIgnoringCase("to"))
822             $$.fValue = 100;
823         else {
824             $$.unit = 0;
825             YYERROR;
826         }
827     }
828     | error {
829         $$.unit = 0;
830     }
831     ;
832
833 before_page_rule:
834     /* empty */ {
835         parser->markRuleHeaderStart(CSSRuleSourceData::PAGE_RULE);
836     }
837     ;
838
839 page:
840     before_page_rule PAGE_SYM maybe_space page_selector at_rule_header_end_maybe_space
841     '{' at_rule_body_start maybe_space_before_declaration declarations_and_margins closing_brace {
842         if ($4)
843             $$ = parser->createPageRule(std::unique_ptr<CSSParserSelector>($4)).leakRef();
844         else {
845             // Clear properties in the invalid @page rule.
846             parser->clearProperties();
847             // Also clear margin at-rules here once we fully implement margin at-rules parsing.
848             $$ = nullptr;
849             parser->popRuleData();
850         }
851     }
852     | before_page_rule PAGE_SYM error invalid_block {
853         parser->popRuleData();
854         $$ = nullptr;
855     }
856     | before_page_rule PAGE_SYM error ';' {
857         parser->popRuleData();
858         $$ = nullptr;
859     }
860     ;
861
862 page_selector:
863     IDENT {
864         $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
865         $$->setForPage();
866     }
867     | IDENT pseudo_page {
868         $$ = $2;
869         if ($$) {
870             $$->prependTagSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
871             $$->setForPage();
872         }
873     }
874     | pseudo_page {
875         $$ = $1;
876         if ($$)
877             $$->setForPage();
878     }
879     | /* empty */ {
880         $$ = new CSSParserSelector;
881         $$->setForPage();
882     }
883     ;
884
885 declarations_and_margins: declaration_list | declarations_and_margins margin_box maybe_space declaration_list ;
886
887 margin_box:
888     margin_sym {
889         parser->startDeclarationsForMarginBox();
890     } maybe_space '{' maybe_space declaration_list closing_brace {
891         parser->createMarginAtRule($1);
892     }
893     ;
894
895 margin_sym:
896     TOPLEFTCORNER_SYM {
897         $$ = CSSSelector::TopLeftCornerMarginBox;
898     }
899     | TOPLEFT_SYM {
900         $$ = CSSSelector::TopLeftMarginBox;
901     }
902     | TOPCENTER_SYM {
903         $$ = CSSSelector::TopCenterMarginBox;
904     }
905     | TOPRIGHT_SYM {
906         $$ = CSSSelector::TopRightMarginBox;
907     }
908     | TOPRIGHTCORNER_SYM {
909         $$ = CSSSelector::TopRightCornerMarginBox;
910     }
911     | BOTTOMLEFTCORNER_SYM {
912         $$ = CSSSelector::BottomLeftCornerMarginBox;
913     }
914     | BOTTOMLEFT_SYM {
915         $$ = CSSSelector::BottomLeftMarginBox;
916     }
917     | BOTTOMCENTER_SYM {
918         $$ = CSSSelector::BottomCenterMarginBox;
919     }
920     | BOTTOMRIGHT_SYM {
921         $$ = CSSSelector::BottomRightMarginBox;
922     }
923     | BOTTOMRIGHTCORNER_SYM {
924         $$ = CSSSelector::BottomRightCornerMarginBox;
925     }
926     | LEFTTOP_SYM {
927         $$ = CSSSelector::LeftTopMarginBox;
928     }
929     | LEFTMIDDLE_SYM {
930         $$ = CSSSelector::LeftMiddleMarginBox;
931     }
932     | LEFTBOTTOM_SYM {
933         $$ = CSSSelector::LeftBottomMarginBox;
934     }
935     | RIGHTTOP_SYM {
936         $$ = CSSSelector::RightTopMarginBox;
937     }
938     | RIGHTMIDDLE_SYM {
939         $$ = CSSSelector::RightMiddleMarginBox;
940     }
941     | RIGHTBOTTOM_SYM {
942         $$ = CSSSelector::RightBottomMarginBox;
943     }
944     ;
945
946 before_font_face_rule:
947     /* empty */ {
948         parser->markRuleHeaderStart(CSSRuleSourceData::FONT_FACE_RULE);
949     }
950     ;
951
952 font_face:
953     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 {
954         $$ = parser->createFontFaceRule().leakRef();
955     }
956     | before_font_face_rule FONT_FACE_SYM error invalid_block {
957         $$ = nullptr;
958         parser->popRuleData();
959     }
960     | before_font_face_rule FONT_FACE_SYM error ';' {
961         $$ = nullptr;
962         parser->popRuleData();
963     }
964 ;
965
966 #if ENABLE_CSS_DEVICE_ADAPTATION
967
968 before_viewport_rule:
969     /* empty */ {
970         parser->markViewportRuleBodyStart();
971         parser->markRuleHeaderStart(CSSRuleSourceData::VIEWPORT_RULE);
972     }
973     ;
974
975 viewport:
976     before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM at_rule_header_end_maybe_space
977     '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace {
978         $$ = parser->createViewportRule().leakRef();
979         parser->markViewportRuleBodyEnd();
980     }
981     | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error invalid_block {
982         $$ = nullptr;
983         parser->popRuleData();
984         parser->markViewportRuleBodyEnd();
985     }
986     | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error ';' {
987         $$ = nullptr;
988         parser->popRuleData();
989         parser->markViewportRuleBodyEnd();
990     }
991 ;
992
993 #endif
994
995 before_region_rule:
996     /* empty */ {
997         parser->markRuleHeaderStart(CSSRuleSourceData::REGION_RULE);
998     }
999     ;
1000
1001 region:
1002     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 {
1003         std::unique_ptr<Vector<RefPtr<StyleRuleBase>>> ruleList($9);
1004         if ($4)
1005             $$ = parser->createRegionRule(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($4).get(), ruleList.get()).leakRef();
1006         else {
1007             $$ = nullptr;
1008             parser->popRuleData();
1009         }
1010     }
1011 ;
1012
1013 combinator:
1014     '+' maybe_space { $$ = CSSParserSelectorCombinator::DirectAdjacent; }
1015   | '~' maybe_space { $$ = CSSParserSelectorCombinator::IndirectAdjacent; }
1016   | '>' maybe_space { $$ = CSSParserSelectorCombinator::Child; }
1017 #if ENABLE_CSS_SELECTORS_LEVEL4
1018   | '>' '>' maybe_space { $$ = CSSParserSelectorCombinator::DescendantDoubleChild; }
1019 #endif
1020   ;
1021
1022 maybe_unary_operator: unary_operator | { $$ = 1; } ;
1023
1024 unary_operator: '-' { $$ = -1; } | '+' { $$ = 1; } ;
1025
1026 maybe_space_before_declaration: maybe_space { parser->markPropertyStart(); } ;
1027
1028 before_selector_list:
1029     {
1030         parser->markRuleHeaderStart(CSSRuleSourceData::STYLE_RULE);
1031         parser->markSelectorStart();
1032     }
1033   ;
1034
1035 at_rule_header_end: { parser->markRuleHeaderEnd(); } ;
1036
1037 at_selector_end: { parser->markSelectorEnd(); } ;
1038
1039 ruleset:
1040     before_selector_list selector_list at_selector_end at_rule_header_end '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace {
1041         $$ = parser->createStyleRule($2).leakRef();
1042         parser->recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>($2));
1043     }
1044   ;
1045
1046 before_selector_group_item: { parser->markSelectorStart(); } ;
1047
1048 selector_list:
1049     complex_selector %prec UNIMPORTANT_TOK {
1050         $$ = nullptr;
1051         if ($1) {
1052             $$ = parser->createSelectorVector().release();
1053             $$->append(std::unique_ptr<CSSParserSelector>($1));
1054             parser->updateLastSelectorLineAndPosition();
1055         }
1056     }
1057     | selector_list at_selector_end ',' maybe_space before_selector_group_item complex_selector %prec UNIMPORTANT_TOK {
1058         std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> selectorList($1);
1059         std::unique_ptr<CSSParserSelector> selector($6);
1060         $$ = nullptr;
1061         if (selectorList && selector) {
1062             $$ = selectorList.release();
1063             $$->append(WTF::move(selector));
1064             parser->updateLastSelectorLineAndPosition();
1065         }
1066     }
1067     | selector_list error {
1068         $$ = nullptr;
1069         delete $1;
1070     }
1071    ;
1072
1073 before_nested_selector_list: { parser->startNestedSelectorList(); } ;
1074 after_nested_selector_list: { parser->endNestedSelectorList(); } ;
1075
1076 nested_selector_list:
1077     before_nested_selector_list selector_list after_nested_selector_list {
1078         $$ = $2;
1079     }
1080     ;
1081
1082 lang_range: IDENT | STRING ;
1083
1084 comma_separated_lang_ranges:
1085     lang_range %prec UNIMPORTANT_TOK {
1086         $$ = new Vector<CSSParserString>;
1087         $$->append($1);
1088     }
1089     | comma_separated_lang_ranges maybe_space ',' maybe_space lang_range %prec UNIMPORTANT_TOK {
1090         $$ = $1;
1091         if ($$)
1092             $1->append($5);
1093     }
1094     | comma_separated_lang_ranges error {
1095         $$ = nullptr;
1096         delete $1;
1097     }
1098     ;
1099
1100 complex_selector_with_trailing_whitespace:
1101     complex_selector WHITESPACE;
1102
1103 complex_selector:
1104     compound_selector
1105     | complex_selector_with_trailing_whitespace
1106     | complex_selector_with_trailing_whitespace compound_selector {
1107         std::unique_ptr<CSSParserSelector> left($1);
1108         std::unique_ptr<CSSParserSelector> right($2);
1109         $$ = nullptr;
1110         if (left && right) {
1111             right->appendTagHistory(CSSParserSelectorCombinator::DescendantSpace, WTF::move(left));
1112             $$ = right.release();
1113         }
1114     }
1115     | complex_selector combinator compound_selector {
1116         std::unique_ptr<CSSParserSelector> left($1);
1117         std::unique_ptr<CSSParserSelector> right($3);
1118         $$ = nullptr;
1119         if (left && right) {
1120             right->appendTagHistory($2, WTF::move(left));
1121             $$ = right.release();
1122         }
1123     }
1124     | complex_selector error {
1125         $$ = nullptr;
1126         delete $1;
1127     }
1128     ;
1129
1130 namespace_selector:
1131     '|' { $$.clear(); }
1132     | '*' '|' { static LChar star = '*'; $$.init(&star, 1); }
1133     | IDENT '|'
1134 ;
1135
1136 compound_selector:
1137     element_name {
1138         $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
1139     }
1140     | element_name specifier_list {
1141         $$ = $2;
1142         if ($$)
1143             parser->rewriteSpecifiersWithElementName(nullAtom, $1, *$$);
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(WTF::move(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(WTF::move(list), WTF::move(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 == CSSQuirksMode)
1218             $1.lower();
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 == CSSQuirksMode)
1228                 $1.lower();
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 == CSSQuirksMode)
1242             $2.lower();
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     // 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 ':' maybe_space expr priority {
1542         $$ = false;
1543         bool isPropertyParsed = false;
1544         std::unique_ptr<CSSParserValueList> propertyValue($5);
1545         if (propertyValue) {
1546             parser->m_valueList = WTF::move(propertyValue);
1547             int oldParsedProperties = parser->m_parsedProperties.size();
1548             parser->setCustomPropertyName($1);
1549             $$ = parser->parseValue(CSSPropertyCustom, $6);
1550             if (!$$)
1551                 parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties);
1552             else
1553                 isPropertyParsed = true;
1554             parser->m_valueList = nullptr;
1555         }
1556         parser->markPropertyEnd($6, 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 = WTF::move(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 expr: valid_expr | valid_expr expr_recovery { $$ = nullptr; delete $1; } ;
1628
1629 valid_expr:
1630     term {
1631         $$ = new CSSParserValueList;
1632         $$->addValue($1);
1633     }
1634     | valid_expr operator term {
1635         $$ = $1;
1636         if (!$$)
1637             destroy($3);
1638         else {
1639             if ($2) {
1640                 CSSParserValue v;
1641                 v.id = CSSValueInvalid;
1642                 v.unit = CSSParserValue::Operator;
1643                 v.iValue = $2;
1644                 $$->addValue(v);
1645             }
1646             $$->addValue($3);
1647         }
1648     }
1649   ;
1650
1651 expr_recovery: error error_location error_recovery ;
1652
1653 operator: '/' maybe_space { $$ = '/'; } | ',' maybe_space { $$ = ','; } | /* empty */ { $$ = 0; } ;
1654
1655 term:
1656   unary_term maybe_space
1657   | unary_operator unary_term maybe_space { $$ = $2; $$.fValue *= $1; }
1658   | STRING maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
1659   | IDENT maybe_space { $$ = makeIdentValue($1); }
1660   /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
1661   | DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1662   | unary_operator DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1663   | URI maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
1664   | UNICODERANGE maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; }
1665   | HEX maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; }
1666   | '#' maybe_space { $$.id = CSSValueInvalid; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */
1667   /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1668   | function maybe_space
1669   | calc_function maybe_space
1670   | min_or_max_function maybe_space
1671   | '%' maybe_space { /* Handle width: %; */
1672       $$.id = CSSValueInvalid; $$.unit = 0;
1673   }
1674 #if ENABLE_CSS_GRID_LAYOUT
1675   | track_names_list maybe_space
1676 #endif
1677   ;
1678
1679 unary_term:
1680   INTEGER { $$.id = CSSValueInvalid; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1681   | FLOATTOKEN { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1682   | PERCENTAGE { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
1683   | PXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
1684   | CMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
1685   | MMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
1686   | INS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
1687   | PTS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
1688   | PCS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
1689   | DEGS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
1690   | RADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
1691   | GRADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
1692   | TURNS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; }
1693   | MSECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
1694   | SECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
1695   | HERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
1696   | KHERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
1697   | EMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
1698   | QEMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; }
1699   | EXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
1700   | REMS {
1701       $$.id = CSSValueInvalid;
1702       $$.fValue = $1;
1703       $$.unit = CSSPrimitiveValue::CSS_REMS;
1704       if (parser->m_styleSheet)
1705           parser->m_styleSheet->parserSetUsesRemUnits();
1706   }
1707   | CHS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CHS; }
1708   | VW { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VW; }
1709   | VH { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VH; }
1710   | VMIN { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMIN; }
1711   | VMAX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMAX; }
1712   | DPPX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPPX; }
1713   | DPI { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPI; }
1714   | DPCM { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPCM; }
1715   | FR { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_FR; }
1716   ;
1717
1718 function:
1719     FUNCTION maybe_space expr closing_parenthesis {
1720         CSSParserFunction* f = new CSSParserFunction;
1721         f->name = $1;
1722         f->args = std::unique_ptr<CSSParserValueList>($3);
1723         $$.id = CSSValueInvalid;
1724         $$.unit = CSSParserValue::Function;
1725         $$.function = f;
1726     } |
1727     FUNCTION maybe_space closing_parenthesis {
1728         CSSParserFunction* f = new CSSParserFunction;
1729         f->name = $1;
1730         f->args = std::unique_ptr<CSSParserValueList>(new CSSParserValueList);
1731         $$.id = CSSValueInvalid;
1732         $$.unit = CSSParserValue::Function;
1733         $$.function = f;
1734     } |
1735     FUNCTION maybe_space expr_recovery closing_parenthesis {
1736         CSSParserFunction* f = new CSSParserFunction;
1737         f->name = $1;
1738         f->args = nullptr;
1739         $$.id = CSSValueInvalid;
1740         $$.unit = CSSParserValue::Function;
1741         $$.function = f;
1742   }
1743   ;
1744
1745 calc_func_term:
1746   unary_term
1747   | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
1748   ;
1749
1750 /*
1751  * The grammar requires spaces around binary ‘+’ and ‘-’ operators.
1752  * The '*' and '/' operators do not require spaces.
1753  * http://www.w3.org/TR/css3-values/#calc-syntax
1754  */
1755 calc_func_operator:
1756     space '+' space {
1757         $$ = '+';
1758     }
1759     | space '-' space {
1760         $$ = '-';
1761     }
1762     | calc_maybe_space '*' maybe_space {
1763         $$ = '*';
1764     }
1765     | calc_maybe_space '/' maybe_space {
1766         $$ = '/';
1767     }
1768   ;
1769
1770 calc_maybe_space: /* empty */ | WHITESPACE ;
1771
1772 calc_func_paren_expr:
1773     '(' maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1774         $$ = nullptr;
1775         if ($3) {
1776             $$ = $3;
1777             CSSParserValue v;
1778             v.id = CSSValueInvalid;
1779             v.unit = CSSParserValue::Operator;
1780             v.iValue = '(';
1781             $$->insertValueAt(0, v);
1782             v.iValue = ')';
1783             $$->addValue(v);
1784         }
1785     }
1786   ;
1787
1788 calc_func_expr: valid_calc_func_expr | valid_calc_func_expr expr_recovery { $$ = nullptr; delete $1; } ;
1789
1790 valid_calc_func_expr:
1791     calc_func_term {
1792         $$ = new CSSParserValueList;
1793         $$->addValue($1);
1794     }
1795     | calc_func_expr calc_func_operator calc_func_term {
1796         std::unique_ptr<CSSParserValueList> expression($1);
1797         $$ = nullptr;
1798         if (expression && $2) {
1799             $$ = expression.release();
1800             CSSParserValue v;
1801             v.id = CSSValueInvalid;
1802             v.unit = CSSParserValue::Operator;
1803             v.iValue = $2;
1804             $$->addValue(v);
1805             $$->addValue($3);
1806         } else {
1807             destroy($3);
1808         }
1809
1810     }
1811     | calc_func_expr calc_func_operator calc_func_paren_expr {
1812         std::unique_ptr<CSSParserValueList> left($1);
1813         std::unique_ptr<CSSParserValueList> right($3);
1814         $$ = nullptr;
1815         if (left && $2 && right) {
1816             CSSParserValue v;
1817             v.id = CSSValueInvalid;
1818             v.unit = CSSParserValue::Operator;
1819             v.iValue = $2;
1820             left->addValue(v);
1821             left->extend(*right);
1822             $$ = left.release();
1823         }
1824     }
1825     | calc_func_paren_expr
1826   ;
1827
1828 calc_func_expr_list:
1829     calc_func_expr calc_maybe_space
1830     | calc_func_expr_list ',' maybe_space calc_func_expr calc_maybe_space {
1831         std::unique_ptr<CSSParserValueList> list($1);
1832         std::unique_ptr<CSSParserValueList> expression($4);
1833         $$ = nullptr;
1834         if (list && expression) {
1835             $$ = list.release();
1836             CSSParserValue v;
1837             v.id = CSSValueInvalid;
1838             v.unit = CSSParserValue::Operator;
1839             v.iValue = ',';
1840             $$->addValue(v);
1841             $$->extend(*expression);
1842         }
1843     }
1844   ;
1845
1846 calc_function:
1847     CALCFUNCTION maybe_space calc_func_expr calc_maybe_space closing_parenthesis {
1848         CSSParserFunction* f = new CSSParserFunction;
1849         f->name = $1;
1850         f->args = std::unique_ptr<CSSParserValueList>($3);
1851         $$.id = CSSValueInvalid;
1852         $$.unit = CSSParserValue::Function;
1853         $$.function = f;
1854     }
1855     | CALCFUNCTION maybe_space expr_recovery closing_parenthesis {
1856         $$.id = CSSValueInvalid;
1857         $$.unit = 0;
1858         YYERROR;
1859     }
1860     ;
1861
1862
1863 min_or_max: MINFUNCTION | MAXFUNCTION ;
1864
1865 min_or_max_function:
1866     min_or_max maybe_space calc_func_expr_list closing_parenthesis {
1867         CSSParserFunction* f = new CSSParserFunction;
1868         f->name = $1;
1869         f->args = std::unique_ptr<CSSParserValueList>($3);
1870         $$.id = CSSValueInvalid;
1871         $$.unit = CSSParserValue::Function;
1872         $$.function = f;
1873     }
1874     | min_or_max maybe_space expr_recovery closing_parenthesis {
1875         $$.id = CSSValueInvalid;
1876         $$.unit = 0;
1877         YYERROR;
1878     }
1879     ;
1880
1881 /* error handling rules */
1882
1883 save_block: closing_brace | error closing_brace ;
1884
1885 invalid_at: ATKEYWORD error invalid_block | ATKEYWORD error ';' ;
1886
1887 invalid_rule: error invalid_block ;
1888
1889 invalid_block: '{' error_recovery closing_brace { parser->invalidBlockHit(); } ;
1890
1891 invalid_square_brackets_block: '[' error_recovery closing_bracket ;
1892
1893 invalid_parentheses_block: opening_parenthesis error_recovery closing_parenthesis;
1894
1895 opening_parenthesis:
1896     '(' | FUNCTION | CALCFUNCTION | MATCHESFUNCTION | MAXFUNCTION | MINFUNCTION | ANYFUNCTION | NOTFUNCTION | LANGFUNCTION
1897 #if ENABLE_CSS_SELECTORS_LEVEL4
1898     | DIRFUNCTION | ROLEFUNCTION
1899 #endif
1900 #if ENABLE_VIDEO_TRACK
1901     | CUEFUNCTION
1902 #endif
1903     ;
1904
1905 error_location: { $$ = parser->currentLocation(); } ;
1906
1907 error_recovery:
1908     /* empty */
1909   | error_recovery error
1910   | error_recovery invalid_block
1911   | error_recovery invalid_square_brackets_block
1912   | error_recovery invalid_parentheses_block
1913     ;
1914
1915 %%