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