summaryrefslogtreecommitdiff
path: root/src/parse/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/parser.rs')
-rw-r--r--src/parse/parser.rs64
1 files changed, 42 insertions, 22 deletions
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 9f62175a..bf6eb76f 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -10,7 +10,9 @@ pub struct Parser<'s> {
/// An iterator over the source tokens.
tokens: Tokens<'s>,
/// The next token.
- /// (Only `None` if we are at the end of group or end of file).
+ next: Option<Token<'s>>,
+ /// The peeked token.
+ /// (Same as `next` except if we are at the end of group, then `None`).
peeked: Option<Token<'s>>,
/// The start position of the peeked token.
next_start: Pos,
@@ -28,10 +30,11 @@ impl<'s> Parser<'s> {
/// Create a new parser for the source string.
pub fn new(src: &'s str) -> Self {
let mut tokens = Tokens::new(src, TokenMode::Body);
- let peeked = tokens.next();
+ let next = tokens.next();
Self {
tokens,
- peeked,
+ next,
+ peeked: next,
next_start: Pos::ZERO,
last_end: Pos::ZERO,
modes: vec![],
@@ -118,7 +121,9 @@ impl<'s> Parser<'s> {
Group::Brace => self.eat_assert(Token::LeftBrace),
Group::Subheader => {}
}
+
self.groups.push(group);
+ self.repeek();
}
/// Ends the parsing of a group and returns the span of the whole group.
@@ -130,6 +135,8 @@ impl<'s> Parser<'s> {
debug_assert_eq!(self.peek(), None, "unfinished group");
let group = self.groups.pop().expect("no started group");
+ self.repeek();
+
let end = match group {
Group::Paren => Some(Token::RightParen),
Group::Bracket => Some(Token::RightBracket),
@@ -138,7 +145,7 @@ impl<'s> Parser<'s> {
};
if let Some(token) = end {
- if self.peeked == Some(token) {
+ if self.next == Some(token) {
self.bump();
} else {
self.diag(error!(self.next_start, "expected {}", token.name()));
@@ -203,26 +210,24 @@ impl<'s> Parser<'s> {
}
/// Peek at the next token without consuming it.
- pub fn peek(&mut self) -> Option<Token<'s>> {
- let group = match self.peeked {
- Some(Token::RightParen) => Group::Paren,
- Some(Token::RightBracket) => Group::Bracket,
- Some(Token::RightBrace) => Group::Brace,
- Some(Token::Pipe) => Group::Subheader,
- other => return other,
- };
-
- if self.groups.contains(&group) {
- return None;
- }
-
+ pub fn peek(&self) -> Option<Token<'s>> {
self.peeked
}
+ /// Peek at the span of the next token.
+ ///
+ /// Has length zero if `peek()` returns `None`.
+ pub fn peek_span(&self) -> Span {
+ Span::new(
+ self.next_start,
+ if self.eof() { self.next_start } else { self.tokens.pos() },
+ )
+ }
+
/// Checks whether the next token fulfills a condition.
///
/// Returns `false` if there is no next token.
- pub fn check<F>(&mut self, f: F) -> bool
+ pub fn check<F>(&self, f: F) -> bool
where
F: FnOnce(Token<'s>) -> bool,
{
@@ -230,7 +235,7 @@ impl<'s> Parser<'s> {
}
/// Whether the end of the source string or group is reached.
- pub fn eof(&mut self) -> bool {
+ pub fn eof(&self) -> bool {
self.peek().is_none()
}
@@ -284,22 +289,37 @@ impl<'s> Parser<'s> {
fn bump(&mut self) {
self.last_end = self.tokens.pos();
self.next_start = self.tokens.pos();
- self.peeked = self.tokens.next();
+ self.next = self.tokens.next();
match self.tokens.mode() {
TokenMode::Body => {}
TokenMode::Header => {
while matches!(
- self.peeked,
+ self.next,
Some(Token::Space(_)) |
Some(Token::LineComment(_)) |
Some(Token::BlockComment(_))
) {
self.next_start = self.tokens.pos();
- self.peeked = self.tokens.next();
+ self.next = self.tokens.next();
}
}
}
+
+ self.repeek();
+ }
+
+ fn repeek(&mut self) {
+ self.peeked = self.next;
+ if self.groups.contains(&match self.next {
+ Some(Token::RightParen) => Group::Paren,
+ Some(Token::RightBracket) => Group::Bracket,
+ Some(Token::RightBrace) => Group::Brace,
+ Some(Token::Pipe) => Group::Subheader,
+ _ => return,
+ }) {
+ self.peeked = None;
+ }
}
}