use std::ascii::AsciiExt;
use std::ops::Range;
use std::borrow::Cow;
use super::{Token, Parser, Delimiter, SourcePosition};
pub fn parse_important(input: &mut Parser) -> Result<(), ()> {
try!(input.expect_delim('!'));
input.expect_ident_matching("important")
}
pub enum AtRuleType<P, R> {
WithoutBlock(R),
WithBlock(P),
OptionalBlock(P),
}
pub trait DeclarationParser {
type Declaration;
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Self::Declaration, ()>;
}
pub trait AtRuleParser {
type Prelude;
type AtRule;
fn parse_prelude(&mut self, name: &str, input: &mut Parser)
-> Result<AtRuleType<Self::Prelude, Self::AtRule>, ()> {
let _ = name;
let _ = input;
Err(())
}
fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
-> Result<Self::AtRule, ()> {
let _ = prelude;
let _ = input;
Err(())
}
fn rule_without_block(&mut self, prelude: Self::Prelude) -> Self::AtRule {
let _ = prelude;
panic!("The `AtRuleParser::rule_without_block` method must be overriden \
if `AtRuleParser::parse_prelude` ever returns `AtRuleType::OptionalBlock`.")
}
}
pub trait QualifiedRuleParser {
type Prelude;
type QualifiedRule;
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
let _ = input;
Err(())
}
fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
-> Result<Self::QualifiedRule, ()> {
let _ = prelude;
let _ = input;
Err(())
}
}
pub struct DeclarationListParser<'i: 't, 't: 'a, 'a, P> {
pub input: &'a mut Parser<'i, 't>,
pub parser: P,
}
impl<'i, 't, 'a, I, P> DeclarationListParser<'i, 't, 'a, P>
where P: DeclarationParser<Declaration = I> + AtRuleParser<AtRule = I> {
pub fn new(input: &'a mut Parser<'i, 't>, parser: P) -> Self {
DeclarationListParser {
input: input,
parser: parser,
}
}
}
impl<'i, 't, 'a, I, P> Iterator for DeclarationListParser<'i, 't, 'a, P>
where P: DeclarationParser<Declaration = I> + AtRuleParser<AtRule = I> {
type Item = Result<I, Range<SourcePosition>>;
fn next(&mut self) -> Option<Result<I, Range<SourcePosition>>> {
loop {
let start_position = self.input.position();
match self.input.next_including_whitespace_and_comments() {
Ok(Token::WhiteSpace(_)) | Ok(Token::Comment(_)) | Ok(Token::Semicolon) => {}
Ok(Token::Ident(name)) => {
return Some({
let parser = &mut self.parser;
self.input.parse_until_after(Delimiter::Semicolon, |input| {
try!(input.expect_colon());
parser.parse_value(&*name, input)
})
}.map_err(|()| start_position..self.input.position()))
}
Ok(Token::AtKeyword(name)) => {
return Some(parse_at_rule(start_position, name, self.input, &mut self.parser))
}
Ok(_) => {
return Some(self.input.parse_until_after(Delimiter::Semicolon, |_| Err(()))
.map_err(|()| start_position..self.input.position()))
}
Err(()) => return None,
}
}
}
}
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> RuleListParser<'i, 't, 'a, P>
where P: QualifiedRuleParser<QualifiedRule = R> + AtRuleParser<AtRule = R> {
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> Iterator for RuleListParser<'i, 't, 'a, P>
where P: QualifiedRuleParser<QualifiedRule = R> + AtRuleParser<AtRule = R> {
type Item = Result<R, Range<SourcePosition>>;
fn next(&mut self) -> Option<Result<R, Range<SourcePosition>>> {
loop {
let start_position = self.input.position();
match self.input.next_including_whitespace_and_comments() {
Ok(Token::WhiteSpace(_)) | Ok(Token::Comment(_)) => {}
Ok(Token::CDO) | Ok(Token::CDC) if self.is_stylesheet => {}
Ok(Token::AtKeyword(name)) => {
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 _ = self.input.parse_until_after(delimiters, |_input| Ok(()));
} else {
return Some(parse_at_rule(start_position, name, self.input, &mut self.parser))
}
}
Ok(_) => {
self.any_rule_so_far = true;
self.input.reset(start_position);
return Some(parse_qualified_rule(self.input, &mut self.parser)
.map_err(|()| start_position..self.input.position()))
}
Err(()) => return None,
}
}
}
}
pub fn parse_one_declaration<P>(input: &mut Parser, parser: &mut P)
-> Result<<P as DeclarationParser>::Declaration,
Range<SourcePosition>>
where P: DeclarationParser {
let start_position = input.position();
input.parse_entirely(|input| {
let name = try!(input.expect_ident());
try!(input.expect_colon());
parser.parse_value(&*name, input)
}).map_err(|()| start_position..input.position())
}
pub fn parse_one_rule<R, P>(input: &mut Parser, parser: &mut P) -> Result<R, ()>
where P: QualifiedRuleParser<QualifiedRule = R> + AtRuleParser<AtRule = R> {
input.parse_entirely(|input| {
loop {
let start_position = input.position();
match try!(input.next_including_whitespace_and_comments()) {
Token::WhiteSpace(_) | Token::Comment(_) => {}
Token::AtKeyword(name) => {
return parse_at_rule(start_position, name, input, parser).map_err(|_| ())
}
_ => {
input.reset(start_position);
return parse_qualified_rule(input, parser).map_err(|_| ())
}
}
}
})
}
fn parse_at_rule<P>(start_position: SourcePosition, name: Cow<str>,
input: &mut Parser, parser: &mut P)
-> Result<<P as AtRuleParser>::AtRule, Range<SourcePosition>>
where P: AtRuleParser {
let delimiters = Delimiter::Semicolon | Delimiter::CurlyBracketBlock;
let result = input.parse_until_before(delimiters, |input| {
parser.parse_prelude(&*name, input)
});
match result {
Ok(AtRuleType::WithoutBlock(rule)) => {
match input.next() {
Ok(Token::Semicolon) | Err(()) => Ok(rule),
Ok(Token::CurlyBracketBlock) => Err(start_position..input.position()),
Ok(_) => unreachable!()
}
}
Ok(AtRuleType::WithBlock(prelude)) => {
match input.next() {
Ok(Token::CurlyBracketBlock) => {
input.parse_nested_block(move |input| parser.parse_block(prelude, input))
.map_err(|()| start_position..input.position())
}
Ok(Token::Semicolon) | Err(()) => Err(start_position..input.position()),
Ok(_) => unreachable!()
}
}
Ok(AtRuleType::OptionalBlock(prelude)) => {
match input.next() {
Ok(Token::Semicolon) | Err(()) => Ok(parser.rule_without_block(prelude)),
Ok(Token::CurlyBracketBlock) => {
input.parse_nested_block(move |input| parser.parse_block(prelude, input))
.map_err(|()| start_position..input.position())
}
_ => unreachable!()
}
}
Err(()) => {
let end_position = input.position();
match input.next() {
Ok(Token::CurlyBracketBlock) | Ok(Token::Semicolon) | Err(()) => {}
_ => unreachable!()
}
Err(start_position..end_position)
}
}
}
fn parse_qualified_rule<P>(input: &mut Parser, parser: &mut P)
-> Result<<P as QualifiedRuleParser>::QualifiedRule, ()>
where P: QualifiedRuleParser {
let prelude = input.parse_until_before(Delimiter::CurlyBracketBlock, |input| {
parser.parse_prelude(input)
});
match try!(input.next()) {
Token::CurlyBracketBlock => {
let prelude = try!(prelude);
input.parse_nested_block(move |input| parser.parse_block(prelude, input))
}
_ => unreachable!()
}
}