use cow_rc_str::CowRcStr;
use parser::{parse_until_before, parse_until_after, parse_nested_block, ParserState};
use std::ascii::AsciiExt;
use super::{Token, Parser, Delimiter, ParseError, BasicParseError, SourceLocation};
pub fn parse_important<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), BasicParseError<'i>> {
input.expect_delim('!')?;
input.expect_ident_matching("important")
}
pub enum AtRuleType<P, PB> {
WithoutBlock(P),
WithBlock(PB),
}
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 PreludeNoBlock;
type PreludeBlock;
type AtRule;
type Error: 'i;
fn parse_prelude<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
-> Result<AtRuleType<Self::PreludeNoBlock, Self::PreludeBlock>,
ParseError<'i, Self::Error>> {
let _ = name;
let _ = input;
Err(ParseError::Basic(BasicParseError::AtRuleInvalid(name)))
}
fn rule_without_block(&mut self, prelude: Self::PreludeNoBlock) -> Self::AtRule {
let _ = prelude;
panic!("The `AtRuleParser::rule_without_block` method must be overriden \
if `AtRuleParser::parse_prelude` ever returns `AtRuleType::WithoutBlock`.")
}
fn parse_block<'t>(&mut self, prelude: Self::PreludeBlock, input: &mut Parser<'i, 't>)
-> Result<Self::AtRule, ParseError<'i, Self::Error>> {
let _ = prelude;
let _ = input;
Err(ParseError::Basic(BasicParseError::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(ParseError::Basic(BasicParseError::QualifiedRuleInvalid))
}
fn parse_block<'t>(&mut self, prelude: Self::Prelude, input: &mut Parser<'i, 't>)
-> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
let _ = prelude;
let _ = input;
Err(ParseError::Basic(BasicParseError::QualifiedRuleInvalid))
}
}
pub struct DeclarationListParser<'i: 't, 't: 'a, 'a, P> {
pub input: &'a mut Parser<'i, 't>,
pub parser: P,
}
impl<'i: 't, 't: 'a, '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, 't: 'a, '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, PreciseParseError<'i, E>>;
fn next(&mut self) -> Option<Result<I, PreciseParseError<'i, E>>> {
loop {
let start = self.input.state();
let ident = match self.input.next_including_whitespace_and_comments() {
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => continue,
Ok(&Token::Ident(ref name)) => Ok(Ok(name.clone())),
Ok(&Token::AtKeyword(ref name)) => Ok(Err(name.clone())),
Ok(token) => Err(token.clone()),
Err(_) => return None,
};
match ident {
Ok(Ok(name)) => {
return Some({
let parser = &mut self.parser;
parse_until_after::<'i, 't, _, _, _>(self.input, Delimiter::Semicolon, |input| {
input.expect_colon()?;
parser.parse_value(name, input)
})
}.map_err(|e| PreciseParseError {
error: e,
slice: self.input.slice_from(start.position()),
location: start.source_location(),
}))
}
Ok(Err(name)) => {
return Some(parse_at_rule(&start, name, self.input, &mut self.parser))
}
Err(token) => {
return Some(self.input.parse_until_after(Delimiter::Semicolon,
|_| Err(ParseError::Basic(BasicParseError::UnexpectedToken(token.clone()))))
.map_err(|e| PreciseParseError {
error: e,
slice: self.input.slice_from(start.position()),
location: start.source_location(),
}))
}
}
}
}
}
pub struct RuleListParser<'i: 't, 't: 'a, 'a, P> {
pub input: &'a mut Parser<'i, 't>,
pub parser: P,
is_stylesheet: bool,
any_rule_so_far: bool,
}
impl<'i: 't, 't: 'a, '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, 't: 'a, '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, PreciseParseError<'i, E>>;
fn next(&mut self) -> Option<Result<R, PreciseParseError<'i, E>>> {
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() {
Some(b'@') => {
match self.input.next_including_whitespace_and_comments() {
Ok(&Token::AtKeyword(ref name)) => at_keyword = Some(name.clone()),
_ => at_keyword = None,
}
if at_keyword.is_none() {
self.input.reset(&start)
}
}
Some(_) => at_keyword = None,
None => return 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;
return Some(parse_qualified_rule(self.input, &mut self.parser)
.map_err(|e| PreciseParseError {
error: e,
slice: self.input.slice_from(start.position()),
location: start.source_location(),
}))
}
}
}
}
pub fn parse_one_declaration<'i, 't, P, E>(input: &mut Parser<'i, 't>, parser: &mut P)
-> Result<<P as DeclarationParser<'i>>::Declaration,
PreciseParseError<'i, E>>
where P: DeclarationParser<'i, Error = E> {
let start_position = input.position();
let start_location = input.current_source_location();
input.parse_entirely(|input| {
let name = input.expect_ident()?.clone();
input.expect_colon()?;
parser.parse_value(name, input)
}).map_err(|e| PreciseParseError {
error: e,
slice: input.slice_from(start_position),
location: start_location,
})
}
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) => at_keyword = Some(name.clone()),
_ => at_keyword = None,
}
if at_keyword.is_none() {
input.reset(&start)
}
} else {
at_keyword = None
}
if let Some(name) = at_keyword {
parse_at_rule(&start, name, input, parser).map_err(|e| e.error)
} else {
parse_qualified_rule(input, parser)
}
})
}
pub struct PreciseParseError<'i, E: 'i> {
pub error: ParseError<'i, E>,
pub slice: &'i str,
pub location: SourceLocation,
}
fn parse_at_rule<'i: 't, 't, P, E>(start: &ParserState, name: CowRcStr<'i>,
input: &mut Parser<'i, 't>, parser: &mut P)
-> Result<<P as AtRuleParser<'i>>::AtRule, PreciseParseError<'i, E>>
where P: AtRuleParser<'i, Error = E> {
let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
let result = parse_until_before::<'i, 't, _, _, _>(input, delimiters, |input| {
parser.parse_prelude(name, input)
});
match result {
Ok(AtRuleType::WithoutBlock(prelude)) => {
match input.next() {
Ok(&Token::Semicolon) | Err(_) => Ok(parser.rule_without_block(prelude)),
Ok(&Token::CurlyBracketBlock) => Err(PreciseParseError {
error: ParseError::Basic(BasicParseError::UnexpectedToken(Token::CurlyBracketBlock)),
slice: input.slice_from(start.position()),
location: start.source_location(),
}),
Ok(_) => unreachable!()
}
}
Ok(AtRuleType::WithBlock(prelude)) => {
match input.next() {
Ok(&Token::CurlyBracketBlock) => {
parse_nested_block::<'i, 't, _, _, _>(input, move |input| parser.parse_block(prelude, input))
.map_err(|e| PreciseParseError {
error: e,
slice: input.slice_from(start.position()),
location: start.source_location(),
})
}
Ok(&Token::Semicolon) => Err(PreciseParseError {
error: ParseError::Basic(BasicParseError::UnexpectedToken(Token::Semicolon)),
slice: input.slice_from(start.position()),
location: start.source_location(),
}),
Err(e) => Err(PreciseParseError {
error: ParseError::Basic(e),
slice: input.slice_from(start.position()),
location: start.source_location(),
}),
Ok(_) => unreachable!()
}
}
Err(error) => {
let end_position = input.position();
match input.next() {
Ok(&Token::CurlyBracketBlock) | Ok(&Token::Semicolon) | Err(_) => {},
_ => unreachable!()
};
Err(PreciseParseError {
error: error,
slice: input.slice(start.position()..end_position),
location: start.source_location(),
})
}
}
}
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 prelude = parse_until_before::<'i, 't, _, _, _>(input, Delimiter::CurlyBracketBlock, |input| {
parser.parse_prelude(input)
});
match *input.next()? {
Token::CurlyBracketBlock => {
let prelude = prelude?;
parse_nested_block::<'i, 't, _, _, _>(input, move |input| parser.parse_block(prelude, input))
}
_ => unreachable!()
}
}