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.rs124
1 files changed, 64 insertions, 60 deletions
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 6269ad73..27346587 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,6 +1,7 @@
use std::fmt::{self, Debug, Formatter};
+use std::ops::Range;
-use super::{Scanner, TokenMode, Tokens};
+use super::{search_column, TokenMode, Tokens};
use crate::diag::{Diag, DiagSet};
use crate::syntax::{Pos, Span, Token};
@@ -17,10 +18,10 @@ pub struct Parser<'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,
/// The end position of the last (non-whitespace if in code mode) token.
- last_end: Pos,
+ prev_end: usize,
+ /// The start position of the peeked token.
+ next_start: usize,
}
/// A logical group of tokens, e.g. `[...]`.
@@ -28,7 +29,7 @@ pub struct Parser<'s> {
struct GroupEntry {
/// The start position of the group. Used by `Parser::end_group` to return
/// The group's full span.
- pub start: Pos,
+ pub start: usize,
/// The kind of group this is. This decides which tokens will end the group.
/// For example, a [`Group::Paren`] will be ended by
/// [`Token::RightParen`].
@@ -59,12 +60,12 @@ impl<'s> Parser<'s> {
let next = tokens.next();
Self {
diags: DiagSet::new(),
- next,
tokens,
- last_end: Pos::ZERO,
- peeked: next,
- next_start: Pos::ZERO,
groups: vec![],
+ next,
+ peeked: next,
+ prev_end: 0,
+ next_start: 0,
}
}
@@ -76,9 +77,9 @@ impl<'s> Parser<'s> {
/// Eat the next token and add a diagnostic that it is not the expected
/// `thing`.
pub fn expected(&mut self, what: &str) {
- let before = self.next_start;
+ let before = self.next_start();
if let Some(found) = self.eat() {
- let after = self.last_end;
+ let after = self.prev_end();
self.diag(error!(
before .. after,
"expected {}, found {}",
@@ -86,20 +87,20 @@ impl<'s> Parser<'s> {
found.name(),
));
} else {
- self.expected_at(what, self.next_start);
+ self.expected_at(what, self.next_start());
}
}
/// Add a diagnostic that `what` was expected at the given position.
- pub fn expected_at(&mut self, what: &str, pos: Pos) {
- self.diag(error!(pos, "expected {}", what));
+ pub fn expected_at(&mut self, what: &str, pos: impl Into<Pos>) {
+ self.diag(error!(pos.into(), "expected {}", what));
}
/// Eat the next token and add a diagnostic that it is unexpected.
pub fn unexpected(&mut self) {
- let before = self.next_start;
+ let before = self.next_start();
if let Some(found) = self.eat() {
- let after = self.last_end;
+ let after = self.prev_end();
self.diag(error!(before .. after, "unexpected {}", found.name()));
}
}
@@ -110,11 +111,10 @@ impl<'s> Parser<'s> {
/// `eat()` and `peek()` return `None`. Parsing can only continue with
/// a matching call to `end_group`.
///
- /// # Panics
/// This panics if the next token does not start the given group.
pub fn start_group(&mut self, kind: Group, mode: TokenMode) {
self.groups.push(GroupEntry {
- start: self.next_start,
+ start: self.next_start(),
kind,
outer_mode: self.tokens.mode(),
});
@@ -133,7 +133,6 @@ impl<'s> Parser<'s> {
/// End the parsing of a group.
///
- /// # Panics
/// This panics if no group was started.
pub fn end_group(&mut self) -> Span {
let prev_mode = self.tokens.mode();
@@ -156,17 +155,16 @@ impl<'s> Parser<'s> {
self.bump();
rescan = false;
} else if required {
- self.diag(error!(self.next_start, "expected {}", end.name()));
+ self.diag(error!(self.next_start(), "expected {}", end.name()));
}
}
// Rescan the peeked token if the mode changed.
if rescan {
- self.tokens.jump(self.last_end);
- self.bump();
+ self.jump(self.prev_end());
}
- Span::new(group.start, self.last_end)
+ Span::new(group.start, self.prev_end())
}
/// The tokenization mode outside of the current group.
@@ -193,7 +191,7 @@ impl<'s> Parser<'s> {
/// Peek at the next token if it follows immediately after the last one
/// without any whitespace in between.
pub fn peek_direct(&self) -> Option<Token<'s>> {
- if self.next_start == self.last_end {
+ if self.next_start() == self.prev_end() {
self.peeked
} else {
None
@@ -204,15 +202,17 @@ impl<'s> Parser<'s> {
///
/// 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() },
- )
+ self.peek_range().into()
}
/// Peek at the source of the next token.
pub fn peek_src(&self) -> &'s str {
- self.get(self.peek_span())
+ self.tokens.scanner().get(self.peek_range())
+ }
+
+ /// Peek at the source range (start and end index) of the next token.
+ pub fn peek_range(&self) -> Range<usize> {
+ self.next_start() .. self.next_end()
}
/// Checks whether the next token fulfills a condition.
@@ -255,11 +255,11 @@ impl<'s> Parser<'s> {
mapped
}
- /// Eat the next token and return its span.
+ /// Eat the next token and return its source range.
pub fn eat_span(&mut self) -> Span {
- let start = self.next_start;
+ let start = self.next_start();
self.eat();
- Span::new(start, self.last_end)
+ Span::new(start, self.prev_end())
}
/// Consume the next token if it is the given one and produce a diagnostic
@@ -267,7 +267,7 @@ impl<'s> Parser<'s> {
pub fn expect(&mut self, t: Token) -> bool {
let eaten = self.eat_if(t);
if !eaten {
- self.expected_at(t.name(), self.last_end);
+ self.expected_at(t.name(), self.prev_end());
}
eaten
}
@@ -290,45 +290,48 @@ impl<'s> Parser<'s> {
}
}
- /// The position at which the next token starts.
- pub fn start(&self) -> Pos {
- self.next_start
- }
-
- /// The position at which the last token ended.
+ /// The index at which the last token ended.
///
/// Refers to the end of the last _non-whitespace_ token in code mode.
- pub fn end(&self) -> Pos {
- self.last_end
+ pub fn prev_end(&self) -> usize {
+ self.prev_end
}
- /// The span from `start` to the end of the last token.
- pub fn span(&self, start: Pos) -> Span {
- Span::new(start, self.last_end)
+ /// The index at which the next token starts.
+ pub fn next_start(&self) -> usize {
+ self.next_start
}
- /// Jump to a position in the source string.
- pub fn jump(&mut self, pos: Pos) {
- self.tokens.jump(pos);
- self.bump();
+ /// The index at which the next token will end.
+ ///
+ /// Is the same as [`next_start()`][Self::next_start] if `peek()` returns
+ /// `None`.
+ pub fn next_end(&self) -> usize {
+ self.tokens.index()
}
- /// Slice a part out of the source string.
- pub fn get(&self, span: impl Into<Span>) -> &'s str {
- self.tokens.scanner().get(span.into().to_range())
+ /// Determine the column for the given index in the source.
+ pub fn column(&self, index: usize) -> usize {
+ search_column(self.tokens.scanner().get(.. index))
}
- /// The underlying scanner.
- pub fn scanner(&self) -> Scanner<'s> {
- let mut scanner = self.tokens.scanner().clone();
- scanner.jump(self.next_start.to_usize());
- scanner
+ /// The span from `start` to [`self.prev_end()`](Self::prev_end).
+ pub fn span(&self, start: impl Into<Pos>) -> Span {
+ Span::new(start, self.prev_end())
+ }
+
+ /// Jump to an index in the string.
+ ///
+ /// You need to know the correct column.
+ fn jump(&mut self, index: usize) {
+ self.tokens.jump(index);
+ self.bump();
}
/// Move to the next token.
fn bump(&mut self) {
- self.last_end = self.tokens.pos();
- self.next_start = self.tokens.pos();
+ self.prev_end = self.tokens.index();
+ self.next_start = self.tokens.index();
self.next = self.tokens.next();
if self.tokens.mode() == TokenMode::Code {
@@ -339,7 +342,7 @@ impl<'s> Parser<'s> {
Some(Token::BlockComment(_)) => true,
_ => false,
} {
- self.next_start = self.tokens.pos();
+ self.next_start = self.tokens.index();
self.next = self.tokens.next();
}
}
@@ -381,7 +384,8 @@ impl<'s> Parser<'s> {
impl Debug for Parser<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let s = self.scanner();
+ let mut s = self.tokens.scanner();
+ s.jump(self.next_start());
write!(f, "Parser({}|{})", s.eaten(), s.rest())
}
}