use super::{BasicParseError, BasicParseErrorKind, Delimiter};
use super::{ParseError, Parser, Token};
use crate::cow_rc_str::CowRcStr;
use crate::parser::{parse_nested_block, parse_until_after, parse_until_before, ParserState};
pub fn parse_important<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), BasicParseError<'i>> {
input.expect_delim('!')?;
input.expect_ident_matching("important")
}
pub trait DeclarationParser<'i> {
type Declaration;
type Error: 'i;
fn parse_value<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<Self::Declaration, ParseError<'i, Self::Error>>;
}
pub trait AtRuleParser<'i> {
type Prelude;
type AtRule;
type Error: 'i;
fn parse_prelude<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
let _ = name;
let _ = input;
Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name)))
}
fn rule_without_block(
&mut self,
prelude: Self::Prelude,
start: &ParserState,
) -> Result<Self::AtRule, ()> {
let _ = prelude;
let _ = start;
Err(())
}
fn parse_block<'t>(
&mut self,
prelude: Self::Prelude,
start: &ParserState,
input: &mut Parser<'i, 't>,
) -> Result<Self::AtRule, ParseError<'i, Self::Error>> {
let _ = prelude;
let _ = start;
let _ = input;
Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid))
}
}
pub trait QualifiedRuleParser<'i> {
type Prelude;
type QualifiedRule;
type Error: 'i;
fn parse_prelude<'t>(
&mut self,
input: &mut Parser<'i, 't>,
) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
let _ = input;
Err(input.new_error(BasicParseErrorKind::QualifiedRuleInvalid))
}
fn parse_block<'t>(
&mut self,
prelude: Self::Prelude,
start: &ParserState,
input: &mut Parser<'i, 't>,
) -> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
let _ = prelude;
let _ = start;
let _ = input;
Err(input.new_error(BasicParseErrorKind::QualifiedRuleInvalid))
}
}
pub struct DeclarationListParser<'i, 't, 'a, P> {
pub input: &'a mut Parser<'i, 't>,
pub parser: P,
}
impl<'i, 't, 'a, I, P, E: 'i> DeclarationListParser<'i, 't, 'a, P>
where
P: DeclarationParser<'i, Declaration = I, Error = E> + AtRuleParser<'i, AtRule = I, Error = E>,
{
pub fn new(input: &'a mut Parser<'i, 't>, parser: P) -> Self {
DeclarationListParser {
input: input,
parser: parser,
}
}
}
impl<'i, 't, 'a, I, P, E: 'i> Iterator for DeclarationListParser<'i, 't, 'a, P>
where
P: DeclarationParser<'i, Declaration = I, Error = E> + AtRuleParser<'i, AtRule = I, Error = E>,
{
type Item = Result<I, (ParseError<'i, E>, &'i str)>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let start = self.input.state();
match self.input.next_including_whitespace_and_comments() {
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => {
continue
}
Ok(&Token::Ident(ref name)) => {
let name = name.clone();
let result = {
let parser = &mut self.parser;
let callback = |input: &mut Parser<'i, '_>| {
input.expect_colon()?;
parser.parse_value(name, input)
};
parse_until_after(self.input, Delimiter::Semicolon, callback)
};
return Some(result.map_err(|e| (e, self.input.slice_from(start.position()))));
}
Ok(&Token::AtKeyword(ref name)) => {
let name = name.clone();
return Some(parse_at_rule(&start, name, self.input, &mut self.parser));
}
Ok(token) => {
let token = token.clone();
let result = self.input.parse_until_after(Delimiter::Semicolon, |_| {
Err(start.source_location().new_unexpected_token_error(token))
});
return Some(result.map_err(|e| (e, self.input.slice_from(start.position()))));
}
Err(..) => return None,
}
}
}
}
pub struct RuleListParser<'i, 't, 'a, P> {
pub input: &'a mut Parser<'i, 't>,
pub parser: P,
is_stylesheet: bool,
any_rule_so_far: bool,
}
impl<'i, 't, 'a, R, P, E: 'i> RuleListParser<'i, 't, 'a, P>
where
P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E>
+ AtRuleParser<'i, AtRule = R, Error = E>,
{
pub fn new_for_stylesheet(input: &'a mut Parser<'i, 't>, parser: P) -> Self {
RuleListParser {
input: input,
parser: parser,
is_stylesheet: true,
any_rule_so_far: false,
}
}
pub fn new_for_nested_rule(input: &'a mut Parser<'i, 't>, parser: P) -> Self {
RuleListParser {
input: input,
parser: parser,
is_stylesheet: false,
any_rule_so_far: false,
}
}
}
impl<'i, 't, 'a, R, P, E: 'i> Iterator for RuleListParser<'i, 't, 'a, P>
where
P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E>
+ AtRuleParser<'i, AtRule = R, Error = E>,
{
type Item = Result<R, (ParseError<'i, E>, &'i str)>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.is_stylesheet {
self.input.skip_cdc_and_cdo()
} else {
self.input.skip_whitespace()
}
let start = self.input.state();
let at_keyword = match self.input.next_byte()? {
b'@' => match self.input.next_including_whitespace_and_comments() {
Ok(&Token::AtKeyword(ref name)) => Some(name.clone()),
_ => {
self.input.reset(&start);
None
}
},
_ => None,
};
if let Some(name) = at_keyword {
let first_stylesheet_rule = self.is_stylesheet && !self.any_rule_so_far;
self.any_rule_so_far = true;
if first_stylesheet_rule && name.eq_ignore_ascii_case("charset") {
let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
let _: Result<(), ParseError<()>> =
self.input.parse_until_after(delimiters, |_| Ok(()));
} else {
return Some(parse_at_rule(
&start,
name.clone(),
self.input,
&mut self.parser,
));
}
} else {
self.any_rule_so_far = true;
let result = parse_qualified_rule(self.input, &mut self.parser);
return Some(result.map_err(|e| (e, self.input.slice_from(start.position()))));
}
}
}
}
pub fn parse_one_declaration<'i, 't, P, E>(
input: &mut Parser<'i, 't>,
parser: &mut P,
) -> Result<<P as DeclarationParser<'i>>::Declaration, (ParseError<'i, E>, &'i str)>
where
P: DeclarationParser<'i, Error = E>,
{
let start_position = input.position();
input
.parse_entirely(|input| {
let name = input.expect_ident()?.clone();
input.expect_colon()?;
parser.parse_value(name, input)
})
.map_err(|e| (e, input.slice_from(start_position)))
}
pub fn parse_one_rule<'i, 't, R, P, E>(
input: &mut Parser<'i, 't>,
parser: &mut P,
) -> Result<R, ParseError<'i, E>>
where
P: QualifiedRuleParser<'i, QualifiedRule = R, Error = E>
+ AtRuleParser<'i, AtRule = R, Error = E>,
{
input.parse_entirely(|input| {
input.skip_whitespace();
let start = input.state();
let at_keyword = if input.next_byte() == Some(b'@') {
match *input.next_including_whitespace_and_comments()? {
Token::AtKeyword(ref name) => Some(name.clone()),
_ => {
input.reset(&start);
None
}
}
} else {
None
};
if let Some(name) = at_keyword {
parse_at_rule(&start, name, input, parser).map_err(|e| e.0)
} else {
parse_qualified_rule(input, parser)
}
})
}
fn parse_at_rule<'i, 't, P, E>(
start: &ParserState,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
parser: &mut P,
) -> Result<<P as AtRuleParser<'i>>::AtRule, (ParseError<'i, E>, &'i str)>
where
P: AtRuleParser<'i, Error = E>,
{
let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
let callback = |input: &mut Parser<'i, '_>| parser.parse_prelude(name, input);
let result = parse_until_before(input, delimiters, callback);
match result {
Ok(prelude) => {
let result = match input.next() {
Ok(&Token::Semicolon) | Err(_) => {
parser.rule_without_block(prelude, start)
.map_err(|()| input.new_unexpected_token_error(Token::Semicolon))
},
Ok(&Token::CurlyBracketBlock) => {
let callback =
|input: &mut Parser<'i, '_>| parser.parse_block(prelude, start, input);
parse_nested_block(input, callback)
},
Ok(_) => unreachable!(),
};
result.map_err(|e| (e, input.slice_from(start.position())))
},
Err(error) => {
let end_position = input.position();
match input.next() {
Ok(&Token::CurlyBracketBlock) | Ok(&Token::Semicolon) | Err(_) => {}
_ => unreachable!(),
};
Err((error, input.slice(start.position()..end_position)))
},
}
}
fn parse_qualified_rule<'i, 't, P, E>(
input: &mut Parser<'i, 't>,
parser: &mut P,
) -> Result<<P as QualifiedRuleParser<'i>>::QualifiedRule, ParseError<'i, E>>
where
P: QualifiedRuleParser<'i, Error = E>,
{
let start = input.state();
let callback = |input: &mut Parser<'i, '_>| parser.parse_prelude(input);
let prelude = parse_until_before(input, Delimiter::CurlyBracketBlock, callback);
match *input.next()? {
Token::CurlyBracketBlock => {
let prelude = prelude?;
let callback = |input: &mut Parser<'i, '_>| parser.parse_block(prelude, &start, input);
parse_nested_block(input, callback)
}
_ => unreachable!(),
}
}