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