Skip to content

Commit 63bdb44

Browse files
committed
Make Parser always borrow its input.
Rewrite some public APIs to support returning error types that contain borrowed pointers to the parser's input.
1 parent 6836a71 commit 63bdb44

File tree

3 files changed

+157
-138
lines changed

3 files changed

+157
-138
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub use from_bytes::{stylesheet_encoding, EncodingSupport};
8989
pub use color::{RGBA, Color, parse_color_keyword};
9090
pub use nth::parse_nth;
9191
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
92-
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition, ParseError, BasicParseError};
92+
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition, ParseError, BasicParseError, ParserInput};
9393
pub use unicode_range::UnicodeRange;
9494

9595
// For macros

src/parser.rs

Lines changed: 106 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -61,46 +61,35 @@ impl<'a, T> ParseError<'a, T> {
6161
}
6262
}
6363

64-
/// Like std::borrow::Cow, except the borrowed variant contains a mutable
65-
/// reference.
66-
enum MaybeOwned<'a, T: 'a> {
67-
Owned(T),
68-
Borrowed(&'a mut T),
69-
}
70-
71-
impl<'a, T> ops::Deref for MaybeOwned<'a, T> {
72-
type Target = T;
64+
/// The owned input for a parser.
65+
pub struct ParserInput<'t>(Tokenizer<'t>);
7366

74-
fn deref<'b>(&'b self) -> &'b T {
75-
match *self {
76-
MaybeOwned::Owned(ref t) => t,
77-
MaybeOwned::Borrowed(ref pointer) => &**pointer,
78-
}
67+
impl<'t> ParserInput<'t> {
68+
/// Create a new input for a parser.
69+
pub fn new(input: &'t str) -> ParserInput<'t> {
70+
ParserInput(Tokenizer::new(input))
7971
}
8072
}
8173

82-
impl<'a, T> ops::DerefMut for MaybeOwned<'a, T> {
83-
fn deref_mut<'b>(&'b mut self) -> &'b mut T {
84-
match *self {
85-
MaybeOwned::Owned(ref mut t) => t,
86-
MaybeOwned::Borrowed(ref mut pointer) => &mut **pointer,
87-
}
74+
impl<'t> ops::Deref for ParserInput<'t> {
75+
type Target = Tokenizer<'t>;
76+
77+
fn deref(&self) -> &Tokenizer<'t> {
78+
&self.0
8879
}
8980
}
9081

91-
impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
92-
fn clone(&self) -> MaybeOwned<'a, T> {
93-
MaybeOwned::Owned((**self).clone())
82+
impl<'t> ops::DerefMut for ParserInput<'t> {
83+
fn deref_mut(&mut self) -> &mut Tokenizer<'t> {
84+
&mut self.0
9485
}
9586
}
9687

97-
9888
/// A CSS parser that borrows its `&str` input,
9989
/// yields `Token`s,
10090
/// and keeps track of nested blocks and functions.
101-
#[derive(Clone)]
10291
pub struct Parser<'i: 't, 't> {
103-
tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
92+
tokenizer: &'t mut ParserInput<'i>,
10493
/// If `Some(_)`, .parse_nested_block() can be called.
10594
at_start_of: Option<BlockType>,
10695
/// For parsers from `parse_until` or `parse_nested_block`
@@ -203,12 +192,12 @@ impl Delimiters {
203192
}
204193
}
205194

206-
impl<'i, 't> Parser<'i, 't> {
195+
impl<'i: 't, 't> Parser<'i, 't> {
207196
/// Create a new parser
208197
#[inline]
209-
pub fn new(input: &'i str) -> Parser<'i, 'i> {
198+
pub fn new(input: &'t mut ParserInput<'i>) -> Parser<'i, 't> {
210199
Parser {
211-
tokenizer: MaybeOwned::Owned(Tokenizer::new(input)),
200+
tokenizer: input,
212201
at_start_of: None,
213202
stop_before: Delimiter::None,
214203
}
@@ -400,10 +389,10 @@ impl<'i, 't> Parser<'i, 't> {
400389
/// or if a closure call leaves some input before the next comma or the end of the input.
401390
#[inline]
402391
pub fn parse_comma_separated<F, T, E>(&mut self, mut parse_one: F) -> Result<Vec<T>, ParseError<'i, E>>
403-
where F: for <'ii, 'tt> FnMut(&mut Parser<'ii, 'tt>) -> Result<T, ParseError<'ii, E>> {
392+
where F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
404393
let mut values = vec![];
405394
loop {
406-
values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
395+
values.push(try!(self.parse_until_before(Delimiter::Comma, &mut parse_one)));
407396
match self.next() {
408397
Err(_) => return Ok(values),
409398
Ok(Token::Comma) => continue,
@@ -426,31 +415,7 @@ impl<'i, 't> Parser<'i, 't> {
426415
#[inline]
427416
pub fn parse_nested_block<F, T, E>(&mut self, parse: F) -> Result <T, ParseError<'i, E>>
428417
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
429-
let block_type = self.at_start_of.take().expect("\
430-
A nested parser can only be created when a Function, \
431-
ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
432-
token was just consumed.\
433-
");
434-
let closing_delimiter = match block_type {
435-
BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket,
436-
BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket,
437-
BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis,
438-
};
439-
let result;
440-
// Introduce a new scope to limit duration of nested_parser’s borrow
441-
{
442-
let mut nested_parser = Parser {
443-
tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
444-
at_start_of: None,
445-
stop_before: closing_delimiter,
446-
};
447-
result = nested_parser.parse_entirely(parse);
448-
if let Some(block_type) = nested_parser.at_start_of {
449-
consume_until_end_of_block(block_type, &mut *nested_parser.tokenizer);
450-
}
451-
}
452-
consume_until_end_of_block(block_type, &mut *self.tokenizer);
453-
result
418+
parse_nested_block(self, parse)
454419
}
455420

456421
/// Limit parsing to until a given delimiter. (E.g. a semicolon for a property value.)
@@ -463,35 +428,8 @@ impl<'i, 't> Parser<'i, 't> {
463428
#[inline]
464429
pub fn parse_until_before<F, T, E>(&mut self, delimiters: Delimiters, parse: F)
465430
-> Result <T, ParseError<'i, E>>
466-
where F: for<'ii, 'tt> FnOnce(&mut Parser<'ii, 'tt>) -> Result<T, ParseError<'ii, E>> {
467-
let delimiters = self.stop_before | delimiters;
468-
let result;
469-
// Introduce a new scope to limit duration of nested_parser’s borrow
470-
{
471-
let mut delimited_parser = Parser {
472-
tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
473-
at_start_of: self.at_start_of.take(),
474-
stop_before: delimiters,
475-
};
476-
result = delimited_parser.parse_entirely(parse);
477-
if let Some(block_type) = delimited_parser.at_start_of {
478-
consume_until_end_of_block(block_type, &mut *delimited_parser.tokenizer);
479-
}
480-
}
481-
// FIXME: have a special-purpose tokenizer method for this that does less work.
482-
loop {
483-
if delimiters.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
484-
break
485-
}
486-
if let Ok(token) = self.tokenizer.next() {
487-
if let Some(block_type) = BlockType::opening(&token) {
488-
consume_until_end_of_block(block_type, &mut *self.tokenizer);
489-
}
490-
} else {
491-
break
492-
}
493-
}
494-
result
431+
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
432+
parse_until_before(self, delimiters, parse)
495433
}
496434

497435
/// Like `parse_until_before`, but also consume the delimiter token.
@@ -502,17 +440,8 @@ impl<'i, 't> Parser<'i, 't> {
502440
#[inline]
503441
pub fn parse_until_after<F, T, E>(&mut self, delimiters: Delimiters, parse: F)
504442
-> Result <T, ParseError<'i, E>>
505-
where F: for<'ii, 'tt> FnOnce(&mut Parser<'ii, 'tt>) -> Result<T, ParseError<'ii, E>> {
506-
let result = self.parse_until_before(delimiters, parse);
507-
let next_byte = self.tokenizer.next_byte();
508-
if next_byte.is_some() && !self.stop_before.contains(Delimiters::from_byte(next_byte)) {
509-
debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte)));
510-
self.tokenizer.advance(1);
511-
if next_byte == Some(b'{') {
512-
consume_until_end_of_block(BlockType::CurlyBracket, &mut *self.tokenizer);
513-
}
514-
}
515-
result
443+
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
444+
parse_until_after(self, delimiters, parse)
516445
}
517446

518447
/// Parse a <whitespace-token> and return its value.
@@ -736,6 +665,87 @@ impl<'i, 't> Parser<'i, 't> {
736665
}
737666
}
738667

668+
pub fn parse_until_before<'i: 't, 't, F, T, E>(parser: &mut Parser<'i, 't>,
669+
delimiters: Delimiters,
670+
parse: F)
671+
-> Result <T, ParseError<'i, E>>
672+
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
673+
let delimiters = parser.stop_before | delimiters;
674+
let result;
675+
// Introduce a new scope to limit duration of nested_parser’s borrow
676+
{
677+
let mut delimited_parser = Parser {
678+
tokenizer: parser.tokenizer,
679+
at_start_of: parser.at_start_of.take(),
680+
stop_before: delimiters,
681+
};
682+
result = delimited_parser.parse_entirely(parse);
683+
if let Some(block_type) = delimited_parser.at_start_of {
684+
consume_until_end_of_block(block_type, &mut *delimited_parser.tokenizer);
685+
}
686+
}
687+
// FIXME: have a special-purpose tokenizer method for this that does less work.
688+
loop {
689+
if delimiters.contains(Delimiters::from_byte(parser.tokenizer.next_byte())) {
690+
break
691+
}
692+
if let Ok(token) = parser.tokenizer.next() {
693+
if let Some(block_type) = BlockType::opening(&token) {
694+
consume_until_end_of_block(block_type, &mut *parser.tokenizer);
695+
}
696+
} else {
697+
break
698+
}
699+
}
700+
result
701+
}
702+
703+
pub fn parse_until_after<'i: 't, 't, F, T, E>(parser: &mut Parser<'i, 't>,
704+
delimiters: Delimiters,
705+
parse: F)
706+
-> Result <T, ParseError<'i, E>>
707+
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
708+
let result = parser.parse_until_before(delimiters, parse);
709+
let next_byte = parser.tokenizer.next_byte();
710+
if next_byte.is_some() && !parser.stop_before.contains(Delimiters::from_byte(next_byte)) {
711+
debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte)));
712+
parser.tokenizer.advance(1);
713+
if next_byte == Some(b'{') {
714+
consume_until_end_of_block(BlockType::CurlyBracket, &mut *parser.tokenizer);
715+
}
716+
}
717+
result
718+
}
719+
720+
pub fn parse_nested_block<'i: 't, 't, F, T, E>(parser: &mut Parser<'i, 't>, parse: F)
721+
-> Result <T, ParseError<'i, E>>
722+
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
723+
let block_type = parser.at_start_of.take().expect("\
724+
A nested parser can only be created when a Function, \
725+
ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
726+
token was just consumed.\
727+
");
728+
let closing_delimiter = match block_type {
729+
BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket,
730+
BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket,
731+
BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis,
732+
};
733+
let result;
734+
// Introduce a new scope to limit duration of nested_parser’s borrow
735+
{
736+
let mut nested_parser = Parser {
737+
tokenizer: parser.tokenizer,
738+
at_start_of: None,
739+
stop_before: closing_delimiter,
740+
};
741+
result = nested_parser.parse_entirely(parse);
742+
if let Some(block_type) = nested_parser.at_start_of {
743+
consume_until_end_of_block(block_type, &mut *nested_parser.tokenizer);
744+
}
745+
}
746+
consume_until_end_of_block(block_type, &mut *parser.tokenizer);
747+
result
748+
}
739749

740750
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
741751
let mut stack = vec![block_type];

0 commit comments

Comments
 (0)