Skip to content

Commit 970e1ca

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 2fdced2 commit 970e1ca

File tree

4 files changed

+230
-210
lines changed

4 files changed

+230
-210
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: 108 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use std::ops::Range;
66
use std::ascii::AsciiExt;
77
use std::ops::BitOr;
88
use std::borrow::Cow;
9-
use std::ops;
109
use tokenizer::{self, Token, NumericValue, PercentageValue, Tokenizer, SourceLocation};
1110

1211

@@ -61,46 +60,21 @@ impl<'a, T> ParseError<'a, T> {
6160
}
6261
}
6362

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;
73-
74-
fn deref<'b>(&'b self) -> &'b T {
75-
match *self {
76-
MaybeOwned::Owned(ref t) => t,
77-
MaybeOwned::Borrowed(ref pointer) => &**pointer,
78-
}
79-
}
80-
}
81-
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-
}
88-
}
89-
}
63+
/// The owned input for a parser.
64+
pub struct ParserInput<'t>(Tokenizer<'t>);
9065

91-
impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
92-
fn clone(&self) -> MaybeOwned<'a, T> {
93-
MaybeOwned::Owned((**self).clone())
66+
impl<'t> ParserInput<'t> {
67+
/// Create a new input for a parser.
68+
pub fn new(input: &'t str) -> ParserInput<'t> {
69+
ParserInput(Tokenizer::new(input))
9470
}
9571
}
9672

97-
9873
/// A CSS parser that borrows its `&str` input,
9974
/// yields `Token`s,
10075
/// and keeps track of nested blocks and functions.
101-
#[derive(Clone)]
10276
pub struct Parser<'i: 't, 't> {
103-
tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
77+
tokenizer: &'t mut ParserInput<'i>,
10478
/// If `Some(_)`, .parse_nested_block() can be called.
10579
at_start_of: Option<BlockType>,
10680
/// For parsers from `parse_until` or `parse_nested_block`
@@ -203,12 +177,12 @@ impl Delimiters {
203177
}
204178
}
205179

206-
impl<'i, 't> Parser<'i, 't> {
180+
impl<'i: 't, 't> Parser<'i, 't> {
207181
/// Create a new parser
208182
#[inline]
209-
pub fn new(input: &'i str) -> Parser<'i, 'i> {
183+
pub fn new(input: &'t mut ParserInput<'i>) -> Parser<'i, 't> {
210184
Parser {
211-
tokenizer: MaybeOwned::Owned(Tokenizer::new(input)),
185+
tokenizer: input,
212186
at_start_of: None,
213187
stop_before: Delimiter::None,
214188
}
@@ -244,7 +218,7 @@ impl<'i, 't> Parser<'i, 't> {
244218
#[inline]
245219
pub fn position(&self) -> SourcePosition {
246220
SourcePosition {
247-
position: self.tokenizer.position(),
221+
position: (self.tokenizer.0).position(),
248222
at_start_of: self.at_start_of,
249223
}
250224
}
@@ -255,35 +229,35 @@ impl<'i, 't> Parser<'i, 't> {
255229
/// Should only be used with `SourcePosition` values from the same `Parser` instance.
256230
#[inline]
257231
pub fn reset(&mut self, new_position: SourcePosition) {
258-
self.tokenizer.reset(new_position.position);
232+
(self.tokenizer.0).reset(new_position.position);
259233
self.at_start_of = new_position.at_start_of;
260234
}
261235

262236
/// Start looking for `var()` functions. (See the `.seen_var_functions()` method.)
263237
#[inline]
264238
pub fn look_for_var_functions(&mut self) {
265-
self.tokenizer.look_for_var_functions()
239+
(self.tokenizer.0).look_for_var_functions()
266240
}
267241

268242
/// Return whether a `var()` function has been seen by the tokenizer since
269243
/// either `look_for_var_functions` was called, and stop looking.
270244
#[inline]
271245
pub fn seen_var_functions(&mut self) -> bool {
272-
self.tokenizer.seen_var_functions()
246+
(self.tokenizer.0).seen_var_functions()
273247
}
274248

275249
/// Start looking for viewport percentage lengths. (See the `seen_viewport_percentages`
276250
/// method.)
277251
#[inline]
278252
pub fn look_for_viewport_percentages(&mut self) {
279-
self.tokenizer.look_for_viewport_percentages()
253+
(self.tokenizer.0).look_for_viewport_percentages()
280254
}
281255

282256
/// Return whether a `vh`, `vw`, `vmin`, or `vmax` dimension has been seen by the tokenizer
283257
/// since `look_for_viewport_percentages` was called, and stop looking.
284258
#[inline]
285259
pub fn seen_viewport_percentages(&mut self) -> bool {
286-
self.tokenizer.seen_viewport_percentages()
260+
(self.tokenizer.0).seen_viewport_percentages()
287261
}
288262

289263
/// Execute the given closure, passing it the parser.
@@ -304,25 +278,25 @@ impl<'i, 't> Parser<'i, 't> {
304278
/// Return a slice of the CSS input
305279
#[inline]
306280
pub fn slice(&self, range: Range<SourcePosition>) -> &'i str {
307-
self.tokenizer.slice(range.start.position..range.end.position)
281+
(self.tokenizer.0).slice(range.start.position..range.end.position)
308282
}
309283

310284
/// Return a slice of the CSS input, from the given position to the current one.
311285
#[inline]
312286
pub fn slice_from(&self, start_position: SourcePosition) -> &'i str {
313-
self.tokenizer.slice_from(start_position.position)
287+
(self.tokenizer.0).slice_from(start_position.position)
314288
}
315289

316290
/// Return the line and column number within the input for the current position.
317291
#[inline]
318292
pub fn current_source_location(&self) -> SourceLocation {
319-
self.tokenizer.current_source_location()
293+
(self.tokenizer.0).current_source_location()
320294
}
321295

322296
/// Return the line and column number within the input for the given position.
323297
#[inline]
324298
pub fn source_location(&self, target: SourcePosition) -> SourceLocation {
325-
self.tokenizer.source_location(target.position)
299+
(self.tokenizer.0).source_location(target.position)
326300
}
327301

328302
/// Return the next token in the input that is neither whitespace or a comment,
@@ -363,13 +337,13 @@ impl<'i, 't> Parser<'i, 't> {
363337
/// comments should always be ignored between tokens.
364338
pub fn next_including_whitespace_and_comments(&mut self) -> Result<Token<'i>, BasicParseError<'i>> {
365339
if let Some(block_type) = self.at_start_of.take() {
366-
consume_until_end_of_block(block_type, &mut *self.tokenizer);
340+
consume_until_end_of_block(block_type, &mut self.tokenizer.0);
367341
}
368-
let byte = self.tokenizer.next_byte();
342+
let byte = (self.tokenizer.0).next_byte();
369343
if self.stop_before.contains(Delimiters::from_byte(byte)) {
370344
return Err(BasicParseError::EndOfInput)
371345
}
372-
let token = try!(self.tokenizer.next().map_err(|()| BasicParseError::EndOfInput));
346+
let token = try!((self.tokenizer.0).next().map_err(|()| BasicParseError::EndOfInput));
373347
if let Some(block_type) = BlockType::opening(&token) {
374348
self.at_start_of = Some(block_type);
375349
}
@@ -400,10 +374,10 @@ impl<'i, 't> Parser<'i, 't> {
400374
/// or if a closure call leaves some input before the next comma or the end of the input.
401375
#[inline]
402376
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>> {
377+
where F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
404378
let mut values = vec![];
405379
loop {
406-
values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
380+
values.push(try!(self.parse_until_before(Delimiter::Comma, &mut parse_one)));
407381
match self.next() {
408382
Err(_) => return Ok(values),
409383
Ok(Token::Comma) => continue,
@@ -426,31 +400,7 @@ impl<'i, 't> Parser<'i, 't> {
426400
#[inline]
427401
pub fn parse_nested_block<F, T, E>(&mut self, parse: F) -> Result <T, ParseError<'i, E>>
428402
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
403+
parse_nested_block(self, parse)
454404
}
455405

456406
/// Limit parsing to until a given delimiter. (E.g. a semicolon for a property value.)
@@ -464,34 +414,7 @@ impl<'i, 't> Parser<'i, 't> {
464414
pub fn parse_until_before<F, T, E>(&mut self, delimiters: Delimiters, parse: F)
465415
-> Result <T, ParseError<'i, E>>
466416
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, 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
417+
parse_until_before(self, delimiters, parse)
495418
}
496419

497420
/// Like `parse_until_before`, but also consume the delimiter token.
@@ -727,6 +650,87 @@ impl<'i, 't> Parser<'i, 't> {
727650
}
728651
}
729652

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

731735
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
732736
let mut stack = vec![block_type];
@@ -747,20 +751,3 @@ fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer)
747751
}
748752
}
749753
}
750-
751-
pub fn parse_until_after<'i, 't, F, T, E>(parser: &mut Parser<'i, 't>,
752-
delimiters: Delimiters,
753-
parse: F)
754-
-> Result <T, ParseError<'i, E>>
755-
where F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>> {
756-
let result = parser.parse_until_before(delimiters, parse);
757-
let next_byte = parser.tokenizer.next_byte();
758-
if next_byte.is_some() && !parser.stop_before.contains(Delimiters::from_byte(next_byte)) {
759-
debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte)));
760-
parser.tokenizer.advance(1);
761-
if next_byte == Some(b'{') {
762-
consume_until_end_of_block(BlockType::CurlyBracket, &mut *parser.tokenizer);
763-
}
764-
}
765-
result
766-
}

0 commit comments

Comments
 (0)