summaryrefslogtreecommitdiff
path: root/src/parse/scanner.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-12-31 17:05:00 +0100
committerLaurenz <laurmaedje@gmail.com>2020-12-31 17:48:56 +0100
commit4069f0744dc24c05d5a6fd6d0530984c4c7ff881 (patch)
tree64fb7211e638462779b03b4ae5b2ea0cc25d23d7 /src/parse/scanner.rs
parentba3d43f7b2a18984be27f3d472884a19f3adce4c (diff)
Parsing improvements 🧽
- Simplified scanner code - Peek eagerly - Skip whitespace and comments automatically in header mode - Parse simple block expressions - Move literal definitions into expression module - Raw resolving tests
Diffstat (limited to 'src/parse/scanner.rs')
-rw-r--r--src/parse/scanner.rs42
1 files changed, 19 insertions, 23 deletions
diff --git a/src/parse/scanner.rs b/src/parse/scanner.rs
index 02562839..c4ba2cfd 100644
--- a/src/parse/scanner.rs
+++ b/src/parse/scanner.rs
@@ -2,25 +2,23 @@
use std::fmt::{self, Debug, Formatter};
use std::slice::SliceIndex;
-use std::str::Chars;
/// A low-level featureful char-based scanner.
#[derive(Clone)]
pub struct Scanner<'s> {
src: &'s str,
- iter: Chars<'s>,
index: usize,
}
impl<'s> Scanner<'s> {
/// Create a new char scanner.
pub fn new(src: &'s str) -> Self {
- Self { src, iter: src.chars(), index: 0 }
+ Self { src, index: 0 }
}
/// Consume the next char.
pub fn eat(&mut self) -> Option<char> {
- let next = self.iter.next();
+ let next = self.peek();
if let Some(c) = next {
self.index += c.len_utf8();
}
@@ -32,11 +30,10 @@ impl<'s> Scanner<'s> {
/// Returns whether the char was consumed.
pub fn eat_if(&mut self, c: char) -> bool {
// Don't decode the char twice through peek() and eat().
- if self.iter.next() == Some(c) {
+ if self.peek() == Some(c) {
self.index += c.len_utf8();
true
} else {
- self.reset();
false
}
}
@@ -58,18 +55,21 @@ impl<'s> Scanner<'s> {
}
/// Eat chars while the condition is true.
- pub fn eat_while(&mut self, mut f: impl FnMut(char) -> bool) -> &'s str {
+ pub fn eat_while<F>(&mut self, mut f: F) -> &'s str
+ where
+ F: FnMut(char) -> bool,
+ {
self.eat_until(|c| !f(c))
}
/// Eat chars until the condition is true.
- pub fn eat_until(&mut self, mut f: impl FnMut(char) -> bool) -> &'s str {
+ pub fn eat_until<F>(&mut self, mut f: F) -> &'s str
+ where
+ F: FnMut(char) -> bool,
+ {
let start = self.index;
- while let Some(c) = self.iter.next() {
+ while let Some(c) = self.peek() {
if f(c) {
- // Undo the previous `next()` without peeking all the time
- // during iteration.
- self.reset();
break;
}
self.index += c.len_utf8();
@@ -80,29 +80,31 @@ impl<'s> Scanner<'s> {
/// Uneat the last eaten char.
pub fn uneat(&mut self) {
self.index = self.last_index();
- self.reset();
}
/// Peek at the next char without consuming it.
pub fn peek(&self) -> Option<char> {
- self.iter.clone().next()
+ self.src[self.index ..].chars().next()
}
/// Peek at the nth-next char without consuming anything.
pub fn peek_nth(&self, n: usize) -> Option<char> {
- self.iter.clone().nth(n)
+ self.src[self.index ..].chars().nth(n)
}
/// Checks whether the next char fulfills a condition.
///
/// Returns `false` if there is no next char.
- pub fn check(&self, f: impl FnOnce(char) -> bool) -> bool {
+ pub fn check<F>(&self, f: F) -> bool
+ where
+ F: FnOnce(char) -> bool,
+ {
self.peek().map(f).unwrap_or(false)
}
/// Whether the end of the source string is reached.
pub fn eof(&self) -> bool {
- self.iter.as_str().is_empty()
+ self.index == self.src.len()
}
/// The previous index in the source string.
@@ -122,7 +124,6 @@ impl<'s> Scanner<'s> {
/// Jump to an index in the source string.
pub fn jump(&mut self, index: usize) {
self.index = index;
- self.reset();
}
/// The full source string.
@@ -152,11 +153,6 @@ impl<'s> Scanner<'s> {
pub fn rest(&self) -> &'s str {
&self.src[self.index ..]
}
-
- /// Go back to the where the index says.
- fn reset(&mut self) {
- self.iter = self.src[self.index ..].chars();
- }
}
impl Debug for Scanner<'_> {