summaryrefslogtreecommitdiff
path: root/chewed/src/parse.rs
diff options
context:
space:
mode:
Diffstat (limited to 'chewed/src/parse.rs')
-rw-r--r--chewed/src/parse.rs73
1 files changed, 65 insertions, 8 deletions
diff --git a/chewed/src/parse.rs b/chewed/src/parse.rs
index f6bbd66..58bb94c 100644
--- a/chewed/src/parse.rs
+++ b/chewed/src/parse.rs
@@ -1,10 +1,15 @@
-use std::iter::Peekable;
+use super::{
+ error::{ParseError, TakeError},
+ position::LineCol,
+};
-use super::error::{ParseError, TakeError};
+pub trait Parser {
+ fn next(&mut self) -> Option<char>;
-pub trait Parser: Iterator<Item = char> {
fn peek(&mut self) -> Option<char>;
+ fn pos(&self) -> LineCol;
+
fn take<P: Parse>(&mut self) -> Result<P, TakeError> {
P::take(self)
}
@@ -28,10 +33,10 @@ pub trait Parser: Iterator<Item = char> {
let mut out = String::from(&s[..count]);
out.push(got);
- return Err(TakeError::BadString(out, s));
+ return Err(TakeError::BadString(self.pos(), out, s));
}
} else {
- return Err(TakeError::EndOfStream);
+ return Err(TakeError::EndOfStream(self.pos()));
}
}
@@ -39,9 +44,61 @@ pub trait Parser: Iterator<Item = char> {
}
}
-impl<I: Iterator<Item = char>> Parser for Peekable<I> {
+pub struct IterWrapper<T: ?Sized> {
+ pos: LineCol,
+ next: Option<char>,
+ iter: T,
+}
+
+impl<T: Iterator<Item = char>> IterWrapper<T> {
+ pub fn new(iter: T) -> Self {
+ Self {
+ pos: LineCol::default(),
+ next: None,
+ iter,
+ }
+ }
+}
+
+impl<I: ?Sized + Iterator<Item = char>> Parser for IterWrapper<I> {
+ fn next(&mut self) -> Option<char> {
+ match self.next.take().or_else(|| self.iter.next()) {
+ x @ Some('\n')
+ | x @ Some('\x0B')
+ | x @ Some('\x0C')
+ | x @ Some('\u{85}')
+ | x @ Some('\u{2028}')
+ | x @ Some('\u{2029}') => {
+ self.pos.line += 1;
+ self.pos.col = 0;
+ x
+ }
+ Some('\x0D') => {
+ if self.peek() == Some('\n') {
+ self.pos.col += 1;
+ } else {
+ self.pos.line += 1;
+ self.pos.col = 0;
+ }
+ Some('\x0D')
+ }
+ x => {
+ self.pos.col += 1;
+ x
+ }
+ }
+ }
+
fn peek(&mut self) -> Option<char> {
- Peekable::peek(self).copied()
+ if self.next.is_none() {
+ self.next = self.iter.next();
+ }
+
+ self.next.as_ref().copied()
+ }
+
+ fn pos(&self) -> LineCol {
+ self.pos
}
}
@@ -52,7 +109,7 @@ pub trait Parse: Sized {
let res = Self::take(&mut input)?;
if input.peek().is_some() {
- Err(ParseError::InputContinues)
+ Err(ParseError::InputContinues(input.pos()))
} else {
Ok(res)
}