css_parse/traits/rule_variants.rs
1use crate::{BadDeclaration, Cursor, Parser, Peek, Result, State, T, ToCursors, ToSpan, diagnostics};
2
3/// A trait that can be used for AST nodes representing a Declaration's Value. It offers some
4/// convenience functions for handling such values.
5pub trait RuleVariants<'a>: Sized + ToCursors + ToSpan {
6 /// Like [crate::Parse::parse()] but with the additional context of the `name` [Cursor]. This cursor is known to be
7 /// an [AtKeyword][crate::token_macros::AtKeyword], therefore this should return a `Self` reflecting a AtRule. If the
8 /// AtRule is not _known_, or otherwise fails then this should [Err] and [RuleVariants::parse_unknown_at_rule()] can
9 /// be called.
10 ///
11 /// The default implementation of this method is to return an Unexpected [Err].
12 fn parse_at_rule(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
13 let c = p.peek_n(1);
14 Err(diagnostics::Unexpected(c))?
15 }
16
17 /// Like [crate::Parse::parse()] but with the additional context of the `name` [Cursor]. This cursor is known to be
18 /// an AtKeyword and that [RuleVariants::parse_at_rule()] failed. This should therefore return a Self that represents
19 /// an Unknwon AtRule, or otherwise [Err].
20 ///
21 /// The default implementation of this method is to return an Unexpected [Err].
22 fn parse_unknown_at_rule(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
23 let c = p.peek_n(1);
24 Err(diagnostics::Unexpected(c))?
25 }
26
27 /// Like [crate::Parse::parse()] but with the additional context that the next cursor is _not_ an
28 /// [AtKeyword][crate::token_macros::AtKeyword], therefore this can attempt to parse a Qualified Rule. If the rule
29 /// fails to parse, then [RuleVariants::parse_unknown_qualified_rule()] will be called.
30 ///
31 /// The default implementation of this method is to return an Unexpected [Err].
32 fn parse_qualified_rule(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
33 let c = p.peek_n(1);
34 Err(diagnostics::Unexpected(c))?
35 }
36
37 /// Like [crate::Parse::parse()] but with the additional context that the next cursor is _not_ an
38 /// [AtKeyword][crate::token_macros::AtKeyword], and that [RuleVariants::parse_qualified_rule()] has failed.
39 /// Therefore this should attempt to parse an Unknown Qualified Rule, or [Err].
40 ///
41 /// The default implementation of this method is to return an Unexpected [Err].
42 fn parse_unknown_qualified_rule(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
43 let c = p.peek_n(1);
44 Err(diagnostics::Unexpected(c))?
45 }
46
47 /// If all of the parse steps have failed, including parsing the Unknown Qualified Rule, we may want to consume a bad
48 /// declaration (especially if the parser is in a nested context). This is done automatically on failing to parse
49 /// an Unknown Qualified Rule, and this method is given the [BadDeclaration].
50 ///
51 /// This should attempt to build a Self that represents the [BadDeclaration], or return [None] so
52 /// [RuleVariants::parse_rule_variants()] can [Err].
53 ///
54 /// The default implementation of this method is to return [None].
55 fn bad_declaration(_: BadDeclaration<'a>) -> Option<Self> {
56 None
57 }
58
59 fn parse_rule_variants(p: &mut Parser<'a>) -> Result<Self> {
60 let checkpoint = p.checkpoint();
61 let c: Cursor = p.peek_next();
62 if <T![AtKeyword]>::peek(p, c) {
63 Self::parse_at_rule(p, c).or_else(|_| {
64 p.rewind(checkpoint);
65 Self::parse_unknown_at_rule(p, c)
66 })
67 } else {
68 Self::parse_qualified_rule(p, c)
69 .or_else(|_| {
70 p.rewind(checkpoint);
71 Self::parse_unknown_qualified_rule(p, c)
72 })
73 .or_else(|_| {
74 p.rewind(checkpoint);
75 let state = p.set_state(State::Nested);
76 let declaration = p.parse::<BadDeclaration>();
77 p.set_state(state);
78 if let Some(s) = Self::bad_declaration(declaration?) {
79 Ok(s)
80 } else {
81 Err(diagnostics::Unexpected(c))?
82 }
83 })
84 }
85 }
86}