Skip to content

Commit 08d510d

Browse files
committed
Have at-rule without block handled in two stages as well
1 parent 85827c0 commit 08d510d

File tree

2 files changed

+37
-18
lines changed

2 files changed

+37
-18
lines changed

src/rules_and_declarations.rs

+27-11
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ pub fn parse_important<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), BasicPa
2323
/// The return value for `AtRuleParser::parse_prelude`.
2424
/// Indicates whether the at-rule is expected to have a `{ /* ... */ }` block
2525
/// or end with a `;` semicolon.
26-
pub enum AtRuleType<P, R> {
26+
pub enum AtRuleType<P, PB> {
2727
/// The at-rule is expected to end with a `;` semicolon. Example: `@import`.
2828
///
29-
/// The value is the finished representation of an at-rule
30-
/// as returned by `RuleListParser::next` or `DeclarationListParser::next`.
31-
WithoutBlock(R),
29+
/// The value is the representation of all data of the rule which would be
30+
/// handled in rule_without_block.
31+
WithoutBlock(P),
3232

3333
/// The at-rule is expected to have a a `{ /* ... */ }` block. Example: `@media`
3434
///
3535
/// The value is the representation of the "prelude" part of the rule.
36-
WithBlock(P),
36+
WithBlock(PB),
3737
}
3838

3939
/// A trait to provide various parsing of declaration values.
@@ -78,8 +78,11 @@ pub trait DeclarationParser<'i> {
7878
/// so that `impl AtRuleParser<(), ()> for ... {}` can be used
7979
/// for using `DeclarationListParser` to parse a declartions list with only qualified rules.
8080
pub trait AtRuleParser<'i> {
81-
/// The intermediate representation of an at-rule prelude.
82-
type Prelude;
81+
/// The intermediate representation of prelude of an at-rule without block;
82+
type PreludeNoBlock;
83+
84+
/// The intermediate representation of prelude of an at-rule with block;
85+
type PreludeBlock;
8386

8487
/// The finished representation of an at-rule.
8588
type AtRule;
@@ -105,12 +108,25 @@ pub trait AtRuleParser<'i> {
105108
/// that ends wherever the prelude should end.
106109
/// (Before the next semicolon, the next `{`, or the end of the current block.)
107110
fn parse_prelude<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
108-
-> Result<AtRuleType<Self::Prelude, Self::AtRule>, ParseError<'i, Self::Error>> {
111+
-> Result<AtRuleType<Self::PreludeNoBlock, Self::PreludeBlock>,
112+
ParseError<'i, Self::Error>> {
109113
let _ = name;
110114
let _ = input;
111115
Err(ParseError::Basic(BasicParseError::AtRuleInvalid(name)))
112116
}
113117

118+
/// End an at-rule which doesn't have block. Return the finished
119+
/// representation of the at-rule.
120+
///
121+
/// This is only called when `parse_prelude` returned `WithoutBlock`, and
122+
/// either the `;` semicolon indeed follows the prelude, or parser is at
123+
/// the end of the input.
124+
fn rule_without_block(&mut self, prelude: Self::PreludeNoBlock) -> Self::AtRule {
125+
let _ = prelude;
126+
panic!("The `AtRuleParser::rule_without_block` method must be overriden \
127+
if `AtRuleParser::parse_prelude` ever returns `AtRuleType::WithoutBlock`.")
128+
}
129+
114130
/// Parse the content of a `{ /* ... */ }` block for the body of the at-rule.
115131
///
116132
/// Return the finished representation of the at-rule
@@ -119,7 +135,7 @@ pub trait AtRuleParser<'i> {
119135
///
120136
/// This is only called when `parse_prelude` returned `WithBlock`, and a block
121137
/// was indeed found following the prelude.
122-
fn parse_block<'t>(&mut self, prelude: Self::Prelude, input: &mut Parser<'i, 't>)
138+
fn parse_block<'t>(&mut self, prelude: Self::PreludeBlock, input: &mut Parser<'i, 't>)
123139
-> Result<Self::AtRule, ParseError<'i, Self::Error>> {
124140
let _ = prelude;
125141
let _ = input;
@@ -443,9 +459,9 @@ fn parse_at_rule<'i: 't, 't, P, E>(start: &ParserState, name: CowRcStr<'i>,
443459
parser.parse_prelude(name, input)
444460
});
445461
match result {
446-
Ok(AtRuleType::WithoutBlock(rule)) => {
462+
Ok(AtRuleType::WithoutBlock(prelude)) => {
447463
match input.next() {
448-
Ok(&Token::Semicolon) | Err(_) => Ok(rule),
464+
Ok(&Token::Semicolon) | Err(_) => Ok(parser.rule_without_block(prelude)),
449465
Ok(&Token::CurlyBracketBlock) => Err(PreciseParseError {
450466
error: ParseError::Basic(BasicParseError::UnexpectedToken(Token::CurlyBracketBlock)),
451467
slice: input.slice_from(start.position()),

src/tests.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -745,27 +745,30 @@ impl<'i> DeclarationParser<'i> for JsonParser {
745745
}
746746

747747
impl<'i> AtRuleParser<'i> for JsonParser {
748-
type Prelude = Vec<Json>;
748+
type PreludeNoBlock = Vec<Json>;
749+
type PreludeBlock = Vec<Json>;
749750
type AtRule = Json;
750751
type Error = ();
751752

752753
fn parse_prelude<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
753-
-> Result<AtRuleType<Vec<Json>, Json>, ParseError<'i, ()>> {
754-
let mut prelude = vec![
754+
-> Result<AtRuleType<Vec<Json>, Vec<Json>>, ParseError<'i, ()>> {
755+
let prelude = vec![
755756
"at-rule".to_json(),
756757
name.to_json(),
757758
Json::Array(component_values_to_json(input)),
758759
];
759760
match_ignore_ascii_case! { &*name,
760761
"media" | "foo-with-block" => Ok(AtRuleType::WithBlock(prelude)),
761762
"charset" => Err(BasicParseError::AtRuleInvalid(name.clone()).into()),
762-
_ => {
763-
prelude.push(Json::Null);
764-
Ok(AtRuleType::WithoutBlock(Json::Array(prelude)))
765-
}
763+
_ => Ok(AtRuleType::WithoutBlock(prelude)),
766764
}
767765
}
768766

767+
fn rule_without_block(&mut self, mut prelude: Vec<Json>) -> Json {
768+
prelude.push(Json::Null);
769+
Json::Array(prelude)
770+
}
771+
769772
fn parse_block<'t>(&mut self, mut prelude: Vec<Json>, input: &mut Parser<'i, 't>)
770773
-> Result<Json, ParseError<'i, ()>> {
771774
prelude.push(Json::Array(component_values_to_json(input)));

0 commit comments

Comments
 (0)