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