1use std::collections::VecDeque;
19use std::fmt;
20
21use crate::engine::css::values::CssIdent;
22
23use super::tokenizer::{Token, Tokenizer};
24use super::values::{CssValue, Unit};
25
26#[derive(Debug, Clone)]
31pub enum CssNodeType {
32 Stylesheet,
34
35 Rule {
37 selectors: Vec<ComplexSelector>,
39 },
40
41 AtRule {
43 name: String,
45
46 params: AtQuery,
47 },
48
49 Declaration {
51 name: String,
53
54 value: CssValue,
55 },
56}
57
58#[derive(Debug, Clone)]
59pub enum AtQuery {
60 Keyword(String), Condition {
62 name: String, value: CssValue, },
65 Group(Vec<AtQuery>), }
67
68#[derive(Debug)]
73pub struct CssNode {
74 node: CssNodeType,
76
77 children: Vec<CssNode>,
79}
80
81impl CssNode {
82 pub fn node(&self) -> &CssNodeType {
83 &self.node
84 }
85 pub fn children(&self) -> &Vec<CssNode> {
86 &self.children
87 }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Hash)]
91pub struct Selector {
92 pub tag: Option<String>,
97
98 pub id: Option<String>,
100
101 pub classes: Vec<String>,
103
104 pub pseudo_class: Option<String>,
106
107 pub pseudo_element: Option<String>,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub enum Combinator {
116 Descendant,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Hash)]
121pub struct SelectorPart {
122 pub selector: Selector,
124
125 pub combinator: Option<Combinator>,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
149pub struct ComplexSelector {
150 pub parts: Vec<SelectorPart>,
151}
152
153pub struct Parser<'a> {
155 tokenizer: Tokenizer<'a>,
157
158 brace_depth: usize,
160
161 lookahead: VecDeque<Token>,
165}
166
167#[derive(Debug, Clone, PartialEq, Eq)]
169pub enum ParserErrorKind {
170 UnexpectedToken {
172 expected: &'static str,
173 found: String, },
175
176 UnexpectedEOF,
178
179 InvalidSyntax,
181
182 MismatchedDelimiter { expected: char, found: char },
184}
185
186impl fmt::Display for ParserErrorKind {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 write!(f, "{:?}", self)
189 }
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct ParserError {
195 pub kind: ParserErrorKind,
197 pub context: Vec<String>,
199}
200
201impl ParserError {
202 pub fn with_context(mut self, ctx: impl Into<String>) -> Self {
203 self.context.push(ctx.into());
204 self
205 }
206}
207
208impl fmt::Display for ParserError {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 let mut ctx = self.context.clone();
211 ctx.reverse();
212 write!(
213 f,
214 "CssParserError: {}, (Context:[{}])",
215 self.kind,
216 ctx.join(" <-")
217 )
218 }
219}
220
221impl std::error::Error for ParserError {}
222
223pub type ParseResult<T> = Result<T, ParserError>;
225
226impl<'a> Parser<'a> {
227 pub fn new(input: &'a str) -> Self {
229 Self {
230 tokenizer: Tokenizer::new(input),
231 brace_depth: 0,
232 lookahead: VecDeque::new(),
233 }
234 }
235
236 fn ensure_lookahead(&mut self, n: usize) {
237 while self.lookahead.len() <= n {
238 let tok = self.tokenizer.next_token();
239 self.lookahead.push_back(tok);
240 }
241 }
242
243 fn peek_next_token(&mut self, cursor_size: usize) -> &Token {
244 self.ensure_lookahead(cursor_size);
245 &self.lookahead[cursor_size]
246 }
247
248 fn peek_token(&mut self) -> &Token {
250 self.peek_next_token(0)
251 }
252
253 fn consume_token(&mut self) -> Token {
254 if let Some(tok) = self.lookahead.pop_front() {
255 tok
256 } else {
257 self.tokenizer.next_token()
258 }
259 }
260
261 pub fn parse(&mut self) -> ParseResult<CssNode> {
271 let mut stylesheet = CssNode {
272 node: CssNodeType::Stylesheet,
273 children: vec![],
274 };
275
276 loop {
277 let token = self.peek_token().clone();
278
279 match token {
280 Token::EOF => break,
281 Token::Whitespace | Token::Comment(_) => {
282 self.consume_token();
283 }
284 Token::AtKeyword(_) => {
285 let node = self
286 .parse_at_rule()
287 .map_err(|e| e.with_context("parse: failed to parse at-rule"))?;
288 log::debug!(target: "CssParser", "AtRule parsed: {:?}", &node);
289 stylesheet.children.push(node);
290 }
291 _ => {
292 let node = self
293 .parse_rule()
294 .map_err(|e| e.with_context("parse: failed to parse rule"))?;
295 log::debug!(target: "CssParser", "Rule parsed: {:?}", &node);
296 stylesheet.children.push(node);
297 }
298 }
299 }
300
301 Ok(stylesheet)
302 }
303
304 fn parse_at_rule(&mut self) -> ParseResult<CssNode> {
305 let at_name = if let Token::AtKeyword(name) = self.consume_token() {
307 name
308 } else {
309 return Err(ParserError {
310 kind: ParserErrorKind::UnexpectedToken {
311 expected: "@keyword",
312 found: format!("{:?}", self.peek_token()),
313 },
314 context: vec![],
315 });
316 };
317
318 let mut prelude = vec![];
320 let mut paren_depth = 0;
321
322 loop {
323 match self.peek_token() {
324 Token::Delim('{') if paren_depth == 0 => break,
325 Token::Delim(';') if paren_depth == 0 => break,
326 Token::Delim('(') => {
327 paren_depth += 1;
328 prelude.push(self.consume_token());
329 }
330 Token::Delim(')') => {
331 paren_depth -= 1;
332 prelude.push(self.consume_token());
333 }
334 Token::EOF => break,
335 _ => prelude.push(self.consume_token()),
336 }
337 }
338
339 let params = Self::parse_at_query(prelude).map_err(|e| {
341 e.with_context("parse_at_rule: failed to parse params via parse_at_query")
342 })?;
343
344 let children = if self.peek_token() == &Token::Delim('{') {
346 self.consume_token();
347 self.brace_depth += 1;
348
349 let mut children = vec![];
350 while self.peek_token() != &Token::Delim('}') {
351 match self.peek_token() {
352 Token::EOF => {
353 return Err(ParserError {
354 kind: ParserErrorKind::UnexpectedEOF,
355 context: vec![],
356 });
357 }
358 Token::Whitespace => {
359 self.consume_token();
360 }
361 Token::AtKeyword(_) => {
362 let node = self.parse_at_rule().map_err(|e| {
363 e.with_context("parse_at_rule: failed to parse nested at-rule")
364 })?;
365 children.push(node);
366 }
367 _ => {
368 let mut cursor = 0;
369 let mut is_declaration = false;
370
371 loop {
372 match self.peek_next_token(cursor) {
373 Token::Delim('{') => {
374 break;
375 }
376 Token::Delim('}') => {
377 is_declaration = true;
378 break;
379 }
380 Token::EOF => {
381 return Err(ParserError {
382 kind: ParserErrorKind::UnexpectedEOF,
383 context: vec![],
384 });
385 }
386 _ => {}
387 }
388 cursor += 1;
389 }
390
391 let nodes = if is_declaration {
392 self.parse_declaration_list().map_err(|e| {
393 e.with_context(
394 "parse_at_rule: failed to parse declaration in block",
395 )
396 })?
397 } else {
398 vec![self.parse_rule().map_err(|e| {
399 e.with_context("parse_at_rule: failed to parse rule in block")
400 })?]
401 };
402
403 children.extend(nodes);
404 }
405 }
406 }
407
408 self.consume_token(); self.brace_depth -= 1;
410 children
411 } else {
412 if self.consume_token() != Token::Delim(';') {
413 return Err(ParserError {
414 kind: ParserErrorKind::UnexpectedToken {
415 expected: ";",
416 found: format!("{:?}", self.peek_token()),
417 },
418 context: vec![],
419 });
420 }
421 vec![]
422 };
423
424 Ok(CssNode {
425 node: CssNodeType::AtRule {
426 name: at_name,
427 params,
428 },
429 children,
430 })
431 }
432
433 fn parse_at_query(tokens: Vec<Token>) -> ParseResult<AtQuery> {
434 let mut cursor = 0;
435 let items = Self::parse_at_query_list(&tokens, &mut cursor)?;
436 Ok(AtQuery::Group(items))
437 }
438
439 fn parse_at_query_list(tokens: &[Token], cursor: &mut usize) -> ParseResult<Vec<AtQuery>> {
440 let mut items = Vec::new();
441
442 while *cursor < tokens.len() {
443 match &tokens[*cursor] {
444 Token::Whitespace => {
445 *cursor += 1;
446 }
447
448 Token::Delim('(') => {
449 *cursor += 1;
450 let group = Self::parse_at_query_list(tokens, cursor)?;
451 items.push(AtQuery::Group(group));
452 }
453
454 Token::Delim(')') => {
455 *cursor += 1;
456 break;
457 }
458
459 Token::Ident(_) => {
460 items.push(Self::parse_at_query_item(tokens, cursor)?);
461 }
462
463 _ => {
464 *cursor += 1;
465 }
466 }
467 }
468
469 Ok(items)
470 }
471
472 fn parse_at_query_item(tokens: &[Token], cursor: &mut usize) -> ParseResult<AtQuery> {
473 let name = match &tokens[*cursor] {
474 Token::Ident(s) => s.clone(),
475 _ => unreachable!(),
476 };
477 *cursor += 1;
478
479 if matches!(tokens.get(*cursor), Some(Token::Delim(':'))) {
480 *cursor += 1;
481 let value = Self::parse_at_query_value(tokens, cursor)?;
482 Ok(AtQuery::Condition { name, value })
483 } else {
484 Ok(AtQuery::Keyword(name))
485 }
486 }
487
488 fn parse_at_query_value(tokens: &[Token], cursor: &mut usize) -> ParseResult<CssValue> {
489 let mut buf = Vec::new();
490 let mut paren_depth = 0;
491
492 while *cursor < tokens.len() {
493 match &tokens[*cursor] {
494 Token::Delim('(') => {
495 paren_depth += 1;
496 buf.push(tokens[*cursor].clone());
497 *cursor += 1;
498 }
499 Token::Delim(')') if paren_depth == 0 => break,
500 Token::Delim(')') => {
501 paren_depth -= 1;
502 buf.push(tokens[*cursor].clone());
503 *cursor += 1;
504 }
505 _ => {
506 buf.push(tokens[*cursor].clone());
507 *cursor += 1;
508 }
509 }
510 }
511
512 Self::parse_tokens_to_css_value(buf)
513 }
514
515 fn parse_rule(&mut self) -> ParseResult<CssNode> {
519 let selectors = self.parse_selector_list();
521
522 match self.consume_token() {
524 Token::Delim('{') => self.brace_depth += 1,
525 token => {
526 return Err(ParserError {
527 kind: ParserErrorKind::UnexpectedToken {
528 expected: "{",
529 found: format!("{:?}", token),
530 },
531 context: vec![format!(
532 "While parsing rule with selectors: {}",
533 selectors
534 .iter()
535 .map(|s| format!("{:?}", s))
536 .collect::<Vec<_>>()
537 .join(", ")
538 )],
539 });
540 }
541 }
542
543 let mut children = vec![];
545 loop {
546 let token = self.peek_token().clone();
547 match token {
548 Token::Delim('}') => {
549 self.consume_token();
550 self.brace_depth -= 1;
551 break;
552 }
553 Token::EOF => {
554 return Err(ParserError {
555 kind: ParserErrorKind::UnexpectedEOF,
556 context: vec![],
557 });
558 }
559 _ => {
560 let mut decls = self.parse_declaration_list().map_err(|e| {
561 e.with_context("parse_rule: failed to parse declaration list")
562 })?;
563 children.append(&mut decls);
564 }
565 }
566 }
567
568 Ok(CssNode {
569 node: CssNodeType::Rule { selectors },
570 children,
571 })
572 }
573
574 fn parse_selector_list(&mut self) -> Vec<ComplexSelector> {
578 let mut selectors = vec![];
579 let mut parts = vec![];
580
581 let mut current_selector: Option<Selector> = None;
582 let mut current_combinator: Option<Combinator> = None;
583
584 loop {
585 let token = self.peek_token().clone();
586 match token {
587 Token::Ident(name) => {
588 let sel = current_selector.get_or_insert_with(|| Selector {
589 tag: None,
590 id: None,
591 classes: vec![],
592 pseudo_class: None,
593 pseudo_element: None,
594 });
595
596 if sel.tag.is_none() {
597 sel.tag = Some(name);
598 }
599
600 self.consume_token();
601 }
602
603 Token::Hash(id) => {
604 let sel = current_selector.get_or_insert_with(|| Selector {
605 tag: None,
606 id: None,
607 classes: vec![],
608 pseudo_class: None,
609 pseudo_element: None,
610 });
611 sel.id = Some(id);
612 self.consume_token();
613 }
614
615 Token::Delim('.') => {
616 self.consume_token();
617 if let Token::Ident(class) = self.consume_token() {
618 let sel = current_selector.get_or_insert_with(|| Selector {
619 tag: None,
620 id: None,
621 classes: vec![],
622 pseudo_class: None,
623 pseudo_element: None,
624 });
625 sel.classes.push(class);
626 }
627 }
628
629 Token::Delim(':') => {
630 self.consume_token();
631 if self.peek_token() == &Token::Delim(':') {
632 self.consume_token();
634 if let Token::Ident(name) = self.consume_token() {
635 let sel = current_selector.get_or_insert_with(|| Selector {
636 tag: None,
637 id: None,
638 classes: vec![],
639 pseudo_class: None,
640 pseudo_element: None,
641 });
642 sel.pseudo_element = Some(name);
643 }
644 } else if let Token::Ident(name) = self.consume_token() {
645 let sel = current_selector.get_or_insert_with(|| Selector {
646 tag: None,
647 id: None,
648 classes: vec![],
649 pseudo_class: None,
650 pseudo_element: None,
651 });
652 sel.pseudo_class = Some(name);
653 }
654 }
655
656 Token::Whitespace | Token::Comment(_) => {
657 if let Some(sel) = current_selector.take() {
659 parts.push(SelectorPart {
660 selector: sel,
661 combinator: current_combinator.take(),
662 });
663 }
664 current_combinator = Some(Combinator::Descendant);
665 self.consume_token();
666 }
667
668 Token::Delim(',') => {
669 if let Some(sel) = current_selector.take() {
670 parts.push(SelectorPart {
671 selector: sel,
672 combinator: current_combinator.take(),
673 });
674 }
675 parts.reverse();
676 selectors.push(ComplexSelector {
677 parts: parts.clone(),
678 });
679 parts.clear();
680 current_combinator = None;
681 self.consume_token();
682
683 while matches!(self.peek_token(), Token::Whitespace | Token::Comment(_)) {
684 self.consume_token();
685 }
686 }
687
688 Token::Delim('{') | Token::EOF => {
689 if let Some(sel) = current_selector.take() {
690 parts.push(SelectorPart {
691 selector: sel,
692 combinator: current_combinator.take(),
693 });
694 }
695 if !parts.is_empty() {
696 parts.reverse();
697 selectors.push(ComplexSelector { parts });
698 }
699 break;
700 }
701
702 _ => {
703 self.consume_token();
704 }
705 }
706 }
707
708 selectors
709 }
710
711 fn parse_declaration_list(&mut self) -> ParseResult<Vec<CssNode>> {
713 let mut declarations = vec![];
714 let mut parsing_name = true;
715 let mut name = String::new();
716 let mut value_tokens = vec![];
717
718 loop {
719 let token = self.peek_token().clone();
720 match token {
721 Token::Delim(':') if parsing_name => {
722 parsing_name = false;
723 self.consume_token();
724 }
725 Token::Delim(';') if !parsing_name => {
726 self.consume_token(); declarations.push(CssNode {
728 node: CssNodeType::Declaration {
729 name: std::mem::take(&mut name),
730 value: Self::parse_tokens_to_css_value(std::mem::take(
731 &mut value_tokens,
732 ))
733 .map_err(|e| {
734 e.with_context(
735 "parse_declaration: failed to parse declaration value list",
736 )
737 })?,
738 },
739 children: vec![],
740 });
741 parsing_name = true;
742 }
743 Token::Delim('}') | Token::EOF => {
744 if !parsing_name && !name.is_empty() {
745 declarations.push(CssNode {
746 node: CssNodeType::Declaration {
747 name: std::mem::take(&mut name),
748 value: Self::parse_tokens_to_css_value(std::mem::take(
749 &mut value_tokens,
750 ))?,
751 },
752 children: vec![],
753 });
754 }
755 break;
756 }
757
758 Token::Ident(s) if parsing_name => {
759 name.push_str(&s);
760 self.consume_token();
761 }
762 _ => {
763 if !parsing_name {
764 value_tokens.push(self.consume_token());
765 } else {
766 self.consume_token(); }
768 }
769 }
770 }
771
772 Ok(declarations)
773 }
774
775 fn parse_tokens_to_css_value(tokens: Vec<Token>) -> ParseResult<CssValue> {
776 let mut values = vec![];
777 let mut iter = tokens.into_iter().peekable();
778
779 while let Some(token) = iter.next() {
780 log::debug!(target: "CssParser", "parse_tokens_to_css_value: token={:?}", token);
781
782 match token {
783 Token::Ident(s) => values.push(CssValue::Keyword(s.into())),
784
785 Token::Delim(',') => {
786 continue;
788 }
789
790 Token::Delim('(') | Token::Delim(')') => {
791 continue;
793 }
794
795 Token::Delim(c) => {
796 let mut s = [0_u8; 4];
797 let s = c.encode_utf8(&mut s);
798
799 values.push(CssValue::Keyword(s.into()));
800 }
801
802 Token::Number(n) => values.push(CssValue::Number(n)),
803
804 Token::String(s) => values.push(CssValue::String(s)),
805
806 Token::Dimension(value, unit) => {
807 let unit = match unit.as_str() {
808 "px" => Unit::Px,
809 "em" => Unit::Em,
810 "rem" => Unit::Rem,
811 "%" => Unit::Percent,
812 "vw" => Unit::Vw,
813 "vh" => Unit::Vh,
814 "deg" => Unit::Deg,
815 _ => Unit::Px,
816 };
817 values.push(CssValue::Length(value, unit));
818 }
819
820 Token::Hash(s) => values.push(CssValue::Color(s)),
821
822 Token::Function(name) => {
823 let mut depth = 0;
825 let mut func_tokens = vec![];
826
827 for tok in iter.by_ref() {
828 match &tok {
829 Token::Delim('(') => {
830 depth += 1;
831 func_tokens.push(tok);
832 }
833 Token::Delim(')') => {
834 func_tokens.push(tok);
835 depth -= 1;
836 if depth == 0 {
837 break;
838 }
839 }
840 _ => func_tokens.push(tok),
841 }
842 }
843
844 let arg_value = Self::parse_tokens_to_css_value(func_tokens)
845 .map_err(|e| e.with_context("parse function args"))?;
846
847 let args = match arg_value {
848 CssValue::List(list) => list,
849 other => vec![other],
850 };
851
852 values.push(CssValue::Function(name, args));
853 }
854
855 _ => continue,
856 }
857 }
858
859 Ok(match values.len() {
861 0 => CssValue::Keyword(CssIdent::new_static("")),
862 1 => values.remove(0),
863 _ => CssValue::List(values),
864 })
865 }
866}
867
868impl fmt::Display for CssNode {
870 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
871 fmt_tree_node(self, f, &[])
872 }
873}
874
875fn fmt_tree_node(
877 node: &CssNode,
878 f: &mut fmt::Formatter<'_>,
879 ancestors_last: &[bool],
880) -> fmt::Result {
881 let is_last = *ancestors_last.last().unwrap_or(&true);
882 let connector = if ancestors_last.is_empty() {
883 ""
884 } else if is_last {
885 "└── "
886 } else {
887 "├── "
888 };
889
890 let mut prefix = String::new();
891 for &ancestor_last in &ancestors_last[..ancestors_last.len().saturating_sub(1)] {
892 prefix.push_str(if ancestor_last { " " } else { "│ " });
893 }
894
895 writeln!(f, "{}{}{:?}", prefix, connector, node.node())?;
896
897 let child_count = node.children().len();
898 for (i, child) in node.children().iter().enumerate() {
899 let child_is_last = i == child_count - 1;
900 let mut new_ancestors = ancestors_last.to_vec();
901 new_ancestors.push(child_is_last);
902 fmt_tree_node(child, f, &new_ancestors)?;
903 }
904
905 Ok(())
906}