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}