From 0a837400e0ffa7fca1a1902b34f375d0dc5b5f6b Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Fri, 8 Jan 2021 18:00:34 +0000 Subject: Add positions to chewed errors. --- chewed/src/parse.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 8 deletions(-) (limited to 'chewed/src/parse.rs') 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; -pub trait Parser: Iterator { fn peek(&mut self) -> Option; + fn pos(&self) -> LineCol; + fn take(&mut self) -> Result { P::take(self) } @@ -28,10 +33,10 @@ pub trait Parser: Iterator { 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 { } } -impl> Parser for Peekable { +pub struct IterWrapper { + pos: LineCol, + next: Option, + iter: T, +} + +impl> IterWrapper { + pub fn new(iter: T) -> Self { + Self { + pos: LineCol::default(), + next: None, + iter, + } + } +} + +impl> Parser for IterWrapper { + fn next(&mut self) -> Option { + 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 { - 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) } -- cgit v1.2.3