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