1use crate::ns::*;
2use num_traits::ToPrimitive;
3
4pub struct CssParser<'input> {
5 tokenizer: CssTokenizer<'input>,
6 previous_token: (Token, Location),
7 token: (Token, Location),
8 locations: Vec<Location>,
9 expecting_token_error: bool,
10}
11
12impl<'input> CssParser<'input> {
13 pub fn new(compilation_unit: &'input Rc<CompilationUnit>, options: &ParserOptions) -> Self {
15 Self {
16 tokenizer: CssTokenizer::new(compilation_unit, options),
17 previous_token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
18 token: (Token::Eof, Location::with_offset(&compilation_unit, 0)),
19 locations: vec![],
20 expecting_token_error: false,
21 }
22 }
23
24 fn options(&self) -> ParserOptions {
25 ParserOptions {
26 ..default()
27 }
28 }
29
30 fn compilation_unit(&self) -> &Rc<CompilationUnit> {
31 self.tokenizer.compilation_unit()
32 }
33
34 fn token_location(&self) -> Location {
35 self.token.1.clone()
36 }
37
38 fn mark_location(&mut self) {
39 self.locations.push(self.token.1.clone());
40 }
41
42 fn duplicate_location(&mut self) {
43 self.locations.push(self.locations.last().unwrap().clone());
44 }
45
46 fn push_location(&mut self, location: &Location) {
47 self.locations.push(location.clone());
48 }
49
50 fn pop_location(&mut self) -> Location {
51 self.locations.pop().unwrap().combine_with(self.previous_token.1.clone())
52 }
53
54 fn add_syntax_error(&self, location: &Location, kind: DiagnosticKind, arguments: Vec<Rc<dyn DiagnosticArgument>>) {
55 if self.compilation_unit().prevent_equal_offset_error(location) {
56 return;
57 }
58 self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments));
59 }
60
61 fn next(&mut self) {
71 self.previous_token = self.token.clone();
72 self.token = self.tokenizer.scan();
73 }
74
75 fn peek(&self, token: Token) -> bool {
76 self.token.0 == token
77 }
78
79 fn peek_identifier(&self) -> Option<(String, Location)> {
80 if let Token::Identifier(id) = self.token.0.clone() {
81 let location = self.token.1.clone();
82 Some((id, location))
83 } else {
84 None
85 }
86 }
87
88 fn peek_keyword(&self, name: &str) -> bool {
89 if let Token::Identifier(id) = self.token.0.clone() { id == name && self.token.1.character_count() == name.len() } else { false }
90 }
91
92 fn consume(&mut self, token: Token) -> bool {
93 if self.token.0 == token {
94 self.next();
95 true
96 } else {
97 false
98 }
99 }
100
101 fn consume_identifier(&mut self) -> Option<(String, Location)> {
102 if let Token::Identifier(id) = self.token.0.clone() {
103 let location = self.token.1.clone();
104 self.next();
105 Some((id, location))
106 } else {
107 None
108 }
109 }
110
111 fn consume_keyword(&mut self, name: &str) -> bool {
112 if let Token::Identifier(name1) = self.token.0.clone() {
113 if name1 == name {
114 self.next();
115 return true;
116 }
117 }
118 false
119 }
120
121 fn expect(&mut self, token: Token) {
123 if self.token.0 != token {
124 self.expecting_token_error = true;
125 self.add_syntax_error(&self.token_location(), DiagnosticKind::Expecting, diagarg![token.clone(), self.token.0.clone()]);
126 } else {
127 self.expecting_token_error = false;
128 self.next();
129 }
130 }
131
132 fn expect_identifier(&mut self) -> (String, Location) {
133 if let Token::Identifier(id) = self.token.0.clone() {
134 self.expecting_token_error = false;
135 let location = self.token.1.clone();
136 self.next();
137 (id, location)
138 } else {
139 self.expecting_token_error = true;
140 self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingIdentifier, diagarg![self.token.0.clone()]);
141 (INVALIDATED_IDENTIFIER.to_owned(), self.tokenizer.cursor_location())
142 }
143 }
144
145 fn expect_unitless_number(&mut self) -> Option<f64> {
146 if let Token::CssNumber { value, .. } = self.token.0.clone() {
147 self.expecting_token_error = false;
148 self.next();
149 Some(value)
150 } else {
151 self.expecting_token_error = true;
152 self.add_syntax_error(&self.token_location(), DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
153 None
154 }
155 }
156
157 fn expect_string(&mut self) -> (String, Location) {
158 if let Token::String(v) = self.token.0.clone() {
159 self.expecting_token_error = false;
160 let location = self.token.1.clone();
161 self.next();
162 (v, location)
163 } else {
164 self.expecting_token_error = true;
165 self.add_syntax_error(&self.token_location(), DiagnosticKind::ExpectingStringLiteral, diagarg![self.token.0.clone()]);
166 ("".into(), self.tokenizer.cursor_location())
167 }
168 }
169
170 pub fn expect_eof(&mut self) {
171 self.expect(Token::Eof);
172 }
173
174 fn create_invalidated_directive(&self, location: &Location) -> Rc<CssDirective> {
175 Rc::new(CssDirective::Invalidated(InvalidatedNode {
176 location: location.clone(),
177 }))
178 }
179
180 fn create_invalidated_property_value(&self, location: &Location) -> Rc<CssPropertyValue> {
181 Rc::new(CssPropertyValue::Invalidated(InvalidatedNode {
182 location: location.clone(),
183 }))
184 }
185
186 fn create_invalidated_selector(&self, location: &Location) -> Rc<CssSelector> {
187 Rc::new(CssSelector::Invalidated(InvalidatedNode {
188 location: location.clone(),
189 }))
190 }
191
192 fn create_invalidated_selector_condition(&self, location: &Location) -> Rc<CssSelectorCondition> {
193 Rc::new(CssSelectorCondition::Invalidated(InvalidatedNode {
194 location: location.clone(),
195 }))
196 }
197
198 fn create_invalidated_media_query_condition(&self, location: &Location) -> Rc<CssMediaQueryCondition> {
199 Rc::new(CssMediaQueryCondition::Invalidated(InvalidatedNode {
200 location: location.clone(),
201 }))
202 }
203
204 fn eof(&self) -> bool {
205 matches!(self.token.0, Token::Eof)
206 }
207
208 pub fn parse_document(&mut self) -> Rc<CssDocument> {
209 self.mark_location();
210 let just_eof = self.peek(Token::Eof);
211 let mut directives: Vec<Rc<CssDirective>> = vec![];
212 while !self.eof() {
213 directives.push(self.parse_directive());
214 }
215 let loc = self.pop_location();
216 Rc::new(CssDocument {
217 location: if just_eof {
218 self.token.1.clone()
219 } else {
220 loc
221 },
222 directives,
223 })
224 }
225
226 fn parse_directive(&mut self) -> Rc<CssDirective> {
227 if let Some(rule) = self.parse_opt_rule() {
228 Rc::new(CssDirective::Rule(rule))
229 } else if self.peek(Token::CssAtNamespace) {
230 self.mark_location();
231 self.next();
232 let prefix = self.expect_identifier();
233 let uri = if self.expecting_token_error {
234 (String::new(), self.tokenizer.cursor_location())
235 } else {
236 self.expect_string()
237 };
238 if !self.expecting_token_error {
239 self.expect(Token::CssSemicolons);
240 }
241 let loc = self.pop_location();
242 Rc::new(CssDirective::NamespaceDefinition(CssNamespaceDefinition {
243 location: loc,
244 prefix,
245 uri,
246 }))
247 } else if self.peek(Token::CssAtMedia) {
248 self.parse_media_query()
249 } else if self.peek(Token::CssAtFontFace) {
250 self.parse_font_face()
251 } else if self.peek(Token::CssAtImport) {
252 self.parse_import()
253 } else {
254 self.add_syntax_error(&self.token.1, DiagnosticKind::ExpectingDirective, diagarg![self.token.0.clone()]);
255 let d = self.create_invalidated_directive(&self.tokenizer.cursor_location());
256 self.next();
257 d
258 }
259 }
260
261 fn parse_media_query(&mut self) -> Rc<CssDirective> {
262 self.mark_location();
263 self.next();
264 let mut conditions: Vec<Rc<CssMediaQueryCondition>> = vec![];
265 let condition = self.parse_opt_media_query_condition();
266 if let Some(condition) = condition {
267 conditions.push(condition);
268 } else {
269 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
270 }
271 loop {
272 if let Some(condition) = self.parse_opt_media_query_condition() {
273 conditions.push(condition);
274 } else if self.eof() || self.peek(Token::BlockOpen) {
275 break;
276 } else if !self.consume(Token::Comma) {
277 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
278 self.next();
279 }
280 }
281 let mut rules: Vec<Rc<CssRule>> = vec![];
282 self.expect(Token::BlockOpen);
283 if !self.expecting_token_error {
284 while !(self.eof() || self.peek(Token::BlockClose)) {
285 if let Some(rule) = self.parse_opt_rule() {
286 rules.push(Rc::new(rule));
287 } else {
288 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
289 self.next();
290 }
291 }
292 self.expect(Token::BlockClose);
293 }
294 Rc::new(CssDirective::MediaQuery(CssMediaQuery {
295 location: self.pop_location(),
296 conditions,
297 rules,
298 }))
299 }
300
301 fn parse_font_face(&mut self) -> Rc<CssDirective> {
302 self.mark_location();
303 self.next();
304 let mut properties: Vec<Rc<CssProperty>> = vec![];
305 self.expect(Token::BlockOpen);
306 if !self.expecting_token_error {
307 self.consume(Token::CssSemicolons);
308 while !(self.eof() || self.peek(Token::BlockClose)) {
309 properties.push(self.parse_property());
310 if !self.consume(Token::CssSemicolons) {
311 break;
312 }
313 }
314 self.expect(Token::BlockClose);
315 }
316 Rc::new(CssDirective::FontFace(CssFontFace {
317 location: self.pop_location(),
318 properties,
319 }))
320 }
321
322 fn parse_import(&mut self) -> Rc<CssDirective> {
323 self.mark_location();
324 self.next();
325
326 let mut url: Option<String> = None;
327 if self.consume_keyword("url") {
328 if let Ok(facade) = self.parse_arguments() {
329 url = Some(facade.parse_text().0);
330 }
331 }
332
333 self.expect(Token::Semicolon);
334
335 Rc::new(CssDirective::Import(CssImport {
336 location: self.pop_location(),
337 url,
338 }))
339 }
340
341 fn parse_opt_media_query_condition(&mut self) -> Option<Rc<CssMediaQueryCondition>> {
342 let mut base: Option<Rc<CssMediaQueryCondition>> = None;
343 if self.peek_keyword("only") {
344 self.mark_location();
345 self.next();
346 let id = self.expect_identifier();
347 base = Some(Rc::new(CssMediaQueryCondition::OnlyId {
348 location: self.pop_location(),
349 id,
350 }));
351 }
352 if let Some(id) = self.consume_identifier() {
353 base = Some(Rc::new(CssMediaQueryCondition::Id(id)));
354 }
355 if self.peek(Token::ParenOpen) {
356 self.mark_location();
357 let property = self.parse_arguments().unwrap().parse_property();
358 let loc = self.pop_location();
359 base = Some(Rc::new(CssMediaQueryCondition::ParenProperty((property, loc))));
360 }
361 if let Some(mut base) = base.clone() {
362 while self.consume_keyword("and") {
363 self.push_location(&base.location());
364 if let Some(right) = self.parse_opt_media_query_condition() {
365 base = Rc::new(CssMediaQueryCondition::And {
366 location: self.pop_location(),
367 left: base,
368 right,
369 });
370 } else {
371 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
372 base = Rc::new(CssMediaQueryCondition::And {
373 location: self.pop_location(),
374 left: base,
375 right: self.create_invalidated_media_query_condition(&self.tokenizer.cursor_location()),
376 });
377 }
378 }
379 return Some(base);
380 }
381 base
382 }
383
384 fn parse_arguments(&mut self) -> Result<CssParserFacade, ParserError> {
385 if !self.peek(Token::ParenOpen) {
386 self.add_syntax_error(&self.token.1, DiagnosticKind::Expecting, diagarg![Token::ParenOpen, self.token.0.clone()]);
387 return Err(ParserError::Common);
388 }
389 let (byte_range, token) = self.tokenizer.scan_arguments();
390 self.previous_token = self.token.clone();
391 self.token = token;
392 self.next();
393 Ok(CssParserFacade(self.compilation_unit(), ParserOptions {
394 byte_range: Some(byte_range),
395 ..self.options()
396 }))
397 }
398
399 fn parse_opt_rule(&mut self) -> Option<CssRule> {
400 let mut selectors: Vec<Rc<CssSelector>> = vec![self.parse_opt_selector()?];
401 while self.consume(Token::Comma) {
402 if let Some(s) = self.parse_opt_selector() {
403 selectors.push(s);
404 } else {
405 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
406 }
407 }
408 let mut properties: Vec<Rc<CssProperty>> = vec![];
409 self.expect(Token::BlockOpen);
410 if !self.expecting_token_error {
411 self.consume(Token::CssSemicolons);
412 while !(self.eof() || self.peek(Token::BlockClose)) {
413 properties.push(self.parse_property());
414 if !self.consume(Token::CssSemicolons) {
415 break;
416 }
417 }
418 self.expect(Token::BlockClose);
419 }
420 self.push_location(&selectors[0].location());
421 Some(CssRule {
422 location: self.pop_location(),
423 selectors,
424 properties,
425 })
426 }
427
428 fn parse_opt_selector(&mut self) -> Option<Rc<CssSelector>> {
429 let mut base = self.parse_opt_base_selector()?;
430
431 loop {
433 if self.consume(Token::Gt) {
435 self.push_location(&base.location());
436 let right: Rc<CssSelector> = self.parse_base_selector();
437 base = Rc::new(CssSelector::Combinator(CssCombinatorSelector {
438 location: self.pop_location(),
439 left: base,
440 right,
441 combinator_type: CssCombinatorType::Child,
442 }));
443 } else if let Some(right) = self.parse_opt_base_selector() {
445 self.push_location(&base.location());
446 base = Rc::new(CssSelector::Combinator(CssCombinatorSelector {
447 location: self.pop_location(),
448 left: base,
449 right,
450 combinator_type: CssCombinatorType::Descendant,
451 }));
452 } else {
453 break;
454 }
455 }
456
457 Some(base)
458 }
459
460 fn parse_base_selector(&mut self) -> Rc<CssSelector> {
461 let s = self.tokenizer.cursor_location();
462 let r = self.parse_opt_base_selector();
463 if let Some(r) = r {
464 r
465 } else {
466 self.add_syntax_error(&s, DiagnosticKind::ExpectingCssSelector, diagarg![]);
467 self.create_invalidated_selector(&s)
468 }
469 }
470
471 fn parse_opt_base_selector(&mut self) -> Option<Rc<CssSelector>> {
472 self.mark_location();
473 let mut namespace_prefix: Option<(String, Location)> = None;
474 let mut element_name: Option<(String, Location)> = self.consume_identifier();
475 let mut conditions: Vec<Rc<CssSelectorCondition>> = vec![];
476 if self.consume(Token::Pipe) {
477 namespace_prefix = element_name.clone();
478 element_name = Some(self.expect_identifier());
479 }
480 while (element_name.is_none() && conditions.is_empty()) || (self.token.1.first_offset() - self.previous_token.1.last_offset() == 0) {
482 if let Some(condition) = self.parse_opt_selector_condition() {
483 conditions.push(condition);
484 } else {
485 break;
486 }
487 }
488 if element_name.is_none() && conditions.is_empty() {
489 self.pop_location();
490 return None;
491 }
492 Some(Rc::new(CssSelector::Base(CssBaseSelector {
493 location: self.pop_location(),
494 namespace_prefix,
495 element_name,
496 conditions,
497 })))
498 }
499
500 fn parse_selector_condition(&mut self) -> Rc<CssSelectorCondition> {
501 let Some(c) = self.parse_opt_selector_condition() else {
502 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
503 return self.create_invalidated_selector_condition(&self.tokenizer.cursor_location());
504 };
505 c
506 }
507
508 fn parse_opt_selector_condition(&mut self) -> Option<Rc<CssSelectorCondition>> {
509 if self.peek(Token::Dot) {
510 self.mark_location();
511 self.next();
512 let class_name = self.expect_identifier().0;
513 return Some(Rc::new(CssSelectorCondition::Class((class_name, self.pop_location()))));
514 }
515 if let Token::CssHashWord(id_value) = self.token.0.clone() {
516 let loc = self.token.1.clone();
517 self.next();
518 return Some(Rc::new(CssSelectorCondition::Id((id_value, loc))));
519 }
520 if self.peek(Token::Colon) {
521 self.mark_location();
522 self.next();
523 if self.consume_keyword("nth-child") {
524 let condition = if let Ok(a) = self.parse_arguments() {
525 a.parse_nth_child_kind()
526 } else {
527 CssNthChildKind::Invalidated
528 };
529 return Some(Rc::new(CssSelectorCondition::NthChild((condition, self.pop_location()))));
530 } else if self.consume_keyword("not") {
531 let condition = if let Ok(a) = self.parse_arguments() {
532 a.parse_selector_condition()
533 } else {
534 self.duplicate_location();
535 let loc = self.pop_location();
536 self.create_invalidated_selector_condition(&loc)
537 };
538 return Some(Rc::new(CssSelectorCondition::Not {
539 location: self.pop_location(),
540 condition,
541 }));
542 } else {
543 let name = self.expect_identifier().0;
544 return Some(Rc::new(CssSelectorCondition::Pseudo((name, self.pop_location()))));
545 }
546 }
547 if self.peek(Token::ColonColon) {
548 self.mark_location();
549 self.next();
550 let name = self.expect_identifier().0;
551 return Some(Rc::new(CssSelectorCondition::PseudoElement((name, self.pop_location()))));
552 }
553 if self.peek(Token::SquareOpen) {
554 self.mark_location();
555 self.next();
556 let name = self.expect_identifier();
557 let mut operator: Option<CssAttributeOperator> = None;
558 let mut value: Option<(String, Location)> = None;
559 while let Some(t1) = self.consume_attribute_operator() {
560 operator = Some(t1);
561 }
562 while let Token::String(s1) = self.token.0.clone() {
563 value = Some((s1, self.token.1.clone()));
564 self.next();
565 }
566 self.expect(Token::SquareClose);
567 return Some(Rc::new(CssSelectorCondition::Attribute {
568 location: self.pop_location(),
569 name,
570 operator,
571 value,
572 }));
573 }
574 None
575 }
576
577 fn consume_attribute_operator(&mut self) -> Option<CssAttributeOperator> {
578 if self.consume(Token::CssBeginsWith) {
579 Some(CssAttributeOperator::BeginsWith)
580 } else if self.consume(Token::CssEndsWith) {
581 Some(CssAttributeOperator::EndsWith)
582 } else if self.consume(Token::CssContains) {
583 Some(CssAttributeOperator::Contains)
584 } else if self.consume(Token::CssListMatch) {
585 Some(CssAttributeOperator::ListMatch)
586 } else if self.consume(Token::CssHreflangMatch) {
587 Some(CssAttributeOperator::HreflangMatch)
588 } else if self.consume(Token::Assign) {
589 Some(CssAttributeOperator::Equals)
590 } else {
591 None
592 }
593 }
594
595 fn parse_property(&mut self) -> Rc<CssProperty> {
596 self.mark_location();
597 let name = self.expect_identifier();
598 let mut value = self.create_invalidated_property_value(&self.tokenizer.cursor_location());
599 if !self.expecting_token_error {
600 self.expect(Token::Colon);
601 if !self.expecting_token_error {
602 value = self.parse_property_value(CssOperatorPrecedence::Array);
603 }
604 }
605 Rc::new(CssProperty::new(self.pop_location(), name, value))
606 }
607
608 fn parse_property_value(&mut self, min_precedence: CssOperatorPrecedence) -> Rc<CssPropertyValue> {
609 let Some(v) = self.parse_opt_property_value(min_precedence) else {
610 self.add_syntax_error(&self.token.1, DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
611 return self.create_invalidated_property_value(&self.tokenizer.cursor_location());
612 };
613 v
614 }
615
616 fn parse_opt_property_value(&mut self, min_precedence: CssOperatorPrecedence) -> Option<Rc<CssPropertyValue>> {
617 let base: Option<Rc<CssPropertyValue>>;
618 let t1 = self.token.0.clone();
619
620 if let Token::CssHashWord(word) = t1 {
623 self.mark_location();
624 self.next();
625 let loc = self.pop_location();
626 if let Ok(v) = CssColorPropertyValue::from_hex(loc.clone(), &word) {
627 base = Some(Rc::new(CssPropertyValue::Color(v)));
628 } else {
629 base = Some(self.create_invalidated_property_value(&loc));
630 }
631 } else if let Token::String(value) = t1 {
634 self.mark_location();
635 self.next();
636 base = Some(Rc::new(CssPropertyValue::String(CssStringPropertyValue {
637 location: self.pop_location(),
638 value
639 })));
640 } else if let Token::CssNumber { value, unit } = t1 {
642 self.mark_location();
643 self.next();
644 let loc = self.pop_location();
645 base = Some(Rc::new(CssPropertyValue::Number(CssNumberPropertyValue {
646 location: loc,
647 value,
648 unit,
649 })));
650 } else if let Some(id) = self.peek_identifier() {
651 self.mark_location();
652 self.next();
653 let color_int = css_color_constant_to_int(&id.0);
654 if let Some(color_int) = color_int {
656 base = Some(Rc::new(CssPropertyValue::Color(CssColorPropertyValue {
657 location: self.pop_location(),
658 color_int,
659 })));
660 } else if id.0 == "rgb" && self.peek(Token::ParenOpen) {
662 if let Some(color_int) = self.parse_arguments().unwrap().parse_rgb() {
663 base = Some(Rc::new(CssPropertyValue::RgbColor(CssRgbColorPropertyValue {
664 location: self.pop_location(),
665 color_int,
666 })));
667 } else {
668 let loc = self.pop_location();
669 base = Some(self.create_invalidated_property_value(&loc));
670 }
671 } else if id.0 == "ClassReference" && self.peek(Token::ParenOpen) {
672 let name = self.parse_arguments().unwrap().parse_text();
673 base = Some(Rc::new(CssPropertyValue::ClassReference(CssClassReferencePropertyValue {
674 location: self.pop_location(),
675 name,
676 })));
677 } else if id.0 == "PropertyReference" && self.peek(Token::ParenOpen) {
678 let name = self.parse_arguments().unwrap().parse_text();
679 base = Some(Rc::new(CssPropertyValue::PropertyReference(CssPropertyReferencePropertyValue {
680 location: self.pop_location(),
681 name,
682 })));
683 } else if id.0 == "url" && self.peek(Token::ParenOpen) {
684 let url = self.parse_arguments().unwrap().parse_text();
685 let mut format: Option<(String, Location)> = None;
686 if self.consume_keyword("format") {
687 if let Ok(a) = self.parse_arguments() {
688 format = Some(a.parse_text());
689 }
690 }
691 base = Some(Rc::new(CssPropertyValue::Url(CssUrlPropertyValue {
692 location: self.pop_location(),
693 url,
694 format,
695 })));
696 } else if id.0 == "local" && self.peek(Token::ParenOpen) {
697 let name = self.parse_arguments().unwrap().parse_text();
698 base = Some(Rc::new(CssPropertyValue::Local(CssLocalPropertyValue {
699 location: self.pop_location(),
700 name,
701 })));
702 } else if id.0 == "Embed" && self.peek(Token::ParenOpen) {
703 let entries = self.parse_arguments().unwrap().parse_embed_entries();
704 base = Some(Rc::new(CssPropertyValue::Embed(CssEmbedPropertyValue {
705 location: self.pop_location(),
706 entries,
707 })));
708 } else {
709 if self.peek(Token::ParenOpen) {
710 self.add_syntax_error(&self.token_location(), DiagnosticKind::Unexpected, diagarg![self.token.0.clone()]);
711 self.parse_arguments().unwrap();
712 }
713 base = Some(Rc::new(CssPropertyValue::Identifier(CssIdentifierPropertyValue {
714 location: self.pop_location(),
715 value: id.0,
716 })));
717 }
718 } else if self.peek(Token::Plus) || self.peek(Token::Minus)
719 || self.peek(Token::Times) || self.peek(Token::Div) {
720 base = Some(self.create_invalidated_property_value(&self.token.1));
721 self.next();
722 } else {
723 return None;
724 }
725
726 let mut base = base.unwrap();
727
728 loop {
729 if self.peek(Token::Comma) && min_precedence.includes(&CssOperatorPrecedence::Array) {
730 self.push_location(&base.location());
731 let mut elements: Vec<Rc<CssPropertyValue>> = vec![base];
732 while self.consume(Token::Comma) {
733 elements.push(self.parse_property_value(CssOperatorPrecedence::MultiValue));
734 }
735 base = Rc::new(CssPropertyValue::Array(CssArrayPropertyValue {
736 location: self.pop_location(),
737 elements,
738 }));
739 } else if min_precedence.includes(&CssOperatorPrecedence::MultiValue) {
740 if let Some(mv1) = self.parse_opt_property_value(CssOperatorPrecedence::MultiValue.add(1).unwrap()) {
741 self.push_location(&base.location());
742 let mut values: Vec<Rc<CssPropertyValue>> = vec![base, mv1];
743 while let Some(mv1) = self.parse_opt_property_value(CssOperatorPrecedence::MultiValue.add(1).unwrap()) {
744 values.push(mv1);
745 }
746 base = Rc::new(CssPropertyValue::MultiValue(CssMultiValuePropertyValue {
747 location: self.pop_location(),
748 values,
749 }));
750 } else {
751 break;
752 }
753 } else {
754 break;
755 }
756 }
757
758 Some(base)
759 }
760
761 fn parse_embed_entry(&mut self) -> Rc<CssEmbedEntry> {
762 self.mark_location();
763 if let Some(key) = self.consume_identifier() {
764 if self.consume(Token::Assign) {
765 let value = self.expect_string();
766 Rc::new(CssEmbedEntry {
767 location: self.pop_location(),
768 key: Some(key),
769 value,
770 })
771 } else {
772 Rc::new(CssEmbedEntry {
773 location: self.pop_location(),
774 key: None,
775 value: key,
776 })
777 }
778 } else {
779 let value = self.expect_string();
780 Rc::new(CssEmbedEntry {
781 location: self.pop_location(),
782 key: None,
783 value,
784 })
785 }
786 }
787}
788
789fn rgb_bytes_to_integer(r: f64, g: f64, b: f64) -> u32 {
790 (calc_rgb_byte(r) << 16) | (calc_rgb_byte(g) << 8) | calc_rgb_byte(b)
791}
792
793fn calc_rgb_byte(value: f64) -> u32 {
794 if value.round() == value {
796 value.round().to_u32().unwrap_or(0).clamp(0, 255)
797 } else {
799 (value * 255.0).round().to_u32().unwrap_or(0).clamp(0, 255)
800 }
801}
802
803pub struct CssParserFacade<'input>(pub &'input Rc<CompilationUnit>, pub ParserOptions);
805
806impl<'input> CssParserFacade<'input> {
807 fn create_parser(&self) -> CssParser<'input> {
808 CssParser::new(self.0, &self.1)
809 }
810
811 pub fn parse_document(&self) -> Rc<CssDocument> {
813 let mut parser = self.create_parser();
814 parser.next();
815 parser.parse_document()
816 }
817
818 pub fn parse_text(&self) -> (String, Location) {
820 let mut parser = self.create_parser();
821 while parser.tokenizer.consume_whitespace() {
822 }
824 let d = parser.tokenizer.characters().peek_or_zero();
825 if ['"', '\''].contains(&d) {
826 parser.next();
827 let mut v: (String, Location) = ("".into(), parser.tokenizer.cursor_location());
828 while let Token::String(v1) = parser.token.0.clone() {
829 v = (v1, parser.token.1.clone());
830 parser.next();
831 }
832 parser.expect_eof();
833 v
834 } else {
835 let mut s = String::new();
836 let i = parser.tokenizer.characters().index();
837 while let Some(ch) = parser.tokenizer.characters_mut().next() {
838 s.push(ch);
839 }
840 let j = parser.tokenizer.characters().index();
841 (s, Location::with_offsets(parser.compilation_unit(), i, j))
842 }
843 }
844
845 pub fn parse_selector_condition(&self) -> Rc<CssSelectorCondition> {
847 let mut parser = self.create_parser();
848 parser.next();
849 let r = parser.parse_selector_condition();
850 parser.expect_eof();
851 r
852 }
853
854 pub fn parse_property(&self) -> Rc<CssProperty> {
855 let mut parser = self.create_parser();
856 parser.next();
857 let r = parser.parse_property();
858 parser.expect_eof();
859 r
860 }
861
862 pub fn parse_property_value(&self) -> Rc<CssPropertyValue> {
863 let mut parser = self.create_parser();
864 parser.next();
865 let r = parser.parse_property_value(CssOperatorPrecedence::Array);
866 parser.expect_eof();
867 r
868 }
869
870 pub fn parse_rgb(&self) -> Option<u32> {
871 let mut parser = self.create_parser();
872 parser.next();
873 let r = parser.expect_unitless_number()?;
874 let g: f64;
875 let b: f64;
876 if parser.consume(Token::Comma) {
877 g = parser.expect_unitless_number()?;
878 parser.expect(Token::Comma);
879 b = parser.expect_unitless_number()?;
880 } else {
881 g = parser.expect_unitless_number()?;
882 b = parser.expect_unitless_number()?;
883 }
884 parser.expect_eof();
885 Some(rgb_bytes_to_integer(r, g, b))
886 }
887
888 pub fn parse_embed_entries(&self) -> Vec<Rc<CssEmbedEntry>> {
889 let mut parser = self.create_parser();
890 let mut entries: Vec<Rc<CssEmbedEntry>> = vec![];
891 parser.next();
892 if !parser.eof() {
893 entries.push(parser.parse_embed_entry());
894 }
895 while parser.consume(Token::Comma) {
896 entries.push(parser.parse_embed_entry());
897 }
898 parser.expect_eof();
899 entries
900 }
901
902 pub fn parse_nth_child_kind(&self) -> CssNthChildKind {
903 let mut parser = self.create_parser();
904 parser.next();
905 if parser.consume_keyword("odd") {
906 return CssNthChildKind::Odd;
907 }
908 if parser.consume_keyword("even") {
909 return CssNthChildKind::Even;
910 }
911 if let Token::CssNumber { value, .. } = parser.token.0.clone() {
912 parser.next();
913 return CssNthChildKind::Number(value.round().to_u32().unwrap_or(0));
914 }
915 parser.expect_eof();
916 CssNthChildKind::Invalidated
917 }
918}