From 090e831465e9d1750c8dbfa34281fa02894f6e5e Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 15:22:51 +0000 Subject: [PATCH 1/6] lib/error: use anyhow as an error stub --- Cargo.toml | 2 +- src/error.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index 5ee344f..a8eae12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1" [dev-dependencies] -anyhow = "1" pretty_assertions = "0.7" diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..35f2467 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,2 @@ +pub type Error = anyhow::Error; +pub type Result = std::result::Result; -- 2.40.1 From d2e7fdfc68639c7bbccad2c5eb39e9be7a991199 Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 15:23:29 +0000 Subject: [PATCH 2/6] lib/reader: first go at a reader impl We need to track our column and mark how far through we've read at the very least. --- src/lib.rs | 2 + src/reader.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/reader.rs diff --git a/src/lib.rs b/src/lib.rs index 2d06385..f862ab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #![allow(dead_code)] +mod error; +mod reader; mod scanner; mod token; diff --git a/src/reader.rs b/src/reader.rs new file mode 100644 index 0000000..a78055b --- /dev/null +++ b/src/reader.rs @@ -0,0 +1,101 @@ +use std::collections::VecDeque; + +use anyhow::bail; + +use crate::error::Result; + +#[derive(Debug)] +struct Reader { + src: I, + buffer: VecDeque, + column: usize, + mark: usize, +} + +impl Reader +where + I: Iterator>, +{ + pub fn new(src: I) -> Self { + Self { + src, + buffer: VecDeque::new(), + column: 0, + mark: 0, + } + } + + /// Number of chars seen so far + pub fn mark(&self) -> usize { + self.mark + } + + /// How deep into a line we currently are + pub fn column(&self) -> usize { + self.column + } + + /// Reserve amt chars, returning an error if it could not reserve the + /// requested amount + pub fn reserve_exact(&mut self, amt: usize) -> Result<()> { + let reserved = self.reserve(amt)?; + + if reserved != amt { + bail!("only reserved {}/{} chars @{}", reserved, amt, self.mark()); + } + + Ok(()) + } + + /// Attempt to reserve up to amt chars, returning the actual number added + pub fn reserve(&mut self, amt: usize) -> Result { + let mut done = 1; + while done <= amt { + match self.src.next() { + Some(Ok(c)) => self.buffer.push_front(c), + Some(Err(e)) => return Err(e), + None => return Ok(done), + } + + done += 1; + } + + Ok(done) + } + + fn next_char(&mut self) -> Result> { + match self.read_one()? { + Some('\n') => { + self.column = 0; + self.mark += 1; + + Ok(Some('\n')) + } + Some(c) => { + self.column += 1; + self.mark += 1; + + Ok(Some(c)) + } + None => Ok(None), + } + } + + fn read_one(&mut self) -> Result> { + match self.buffer.is_empty() { + true => self.src.next().transpose(), + false => Ok(self.buffer.pop_back()), + } + } +} + +impl Iterator for Reader +where + I: Iterator>, +{ + type Item = Result; + + fn next(&mut self) -> Option { + self.next_char().transpose() + } +} -- 2.40.1 From b0ee9390fd3f20254a630f5efe87cf025d547453 Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 16:23:59 +0000 Subject: [PATCH 3/6] lib/reader: add unit tests --- src/reader.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/reader.rs b/src/reader.rs index a78055b..6b43b54 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -99,3 +99,97 @@ where self.next_char().transpose() } } + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::{assert_eq, assert_ne}; + + macro_rules! data { + ($data:expr) => { + $data.chars().map(Ok) + }; + () => { + "1234567890".chars().map(Ok) + }; + } + + #[test] + fn amount() { + let data = data!(); + let r = Reader::new(data); + + assert_eq!(r.into_iter().count(), 10); + } + + #[test] + fn reserve() { + let data = data!(); + let mut r = Reader::new(data); + + let amount = r.reserve(20).expect("impossible to error"); + + assert_ne!(amount, 20); + assert_eq!(amount, 10); + } + + #[test] + fn reserve_partial() { + let data = data!(); + let mut r = Reader::new(data); + + let amount = r.reserve(5).expect("impossible to error"); + + assert_eq!(amount, 5); + } + + #[test] + fn reserve_one() { + let data = data!(); + let mut r = Reader::new(data); + + let amount = r.reserve(1).expect("impossible to error"); + + assert_eq!(amount, 1); + } + + #[test] + fn reserve_zero() { + let data = data!(); + let mut r = Reader::new(data); + + let amount = r.reserve(0).expect("impossible to error"); + + assert_eq!(amount, 0); + } + + #[test] + fn column() { + let data = data!("abc\nefg\nhijkl"); + let expected = vec![1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5]; + let mut r = Reader::new(data); + + assert_eq!(r.column(), 0); + + for indent in expected { + let c = r.next().unwrap().expect("impossible to error"); + + assert_eq!(r.column(), indent, "@ char: {}, mark: {}", c, r.mark()); + } + } + + #[test] + fn mark() { + let data = data!(); + let expected = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let mut r = Reader::new(data); + + assert_eq!(r.mark(), 0); + + for mark in expected { + let c = r.next().unwrap().expect("impossible to error"); + + assert_eq!(r.mark(), mark, "@ char: {}, mark: {}", c, r.mark()); + } + } +} -- 2.40.1 From d9810190da789b734d24d832203535ab402fdba3 Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 16:24:45 +0000 Subject: [PATCH 4/6] lib/reader: fmt --- src/reader.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/reader.rs b/src/reader.rs index 6b43b54..cc9094e 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -49,8 +49,9 @@ where /// Attempt to reserve up to amt chars, returning the actual number added pub fn reserve(&mut self, amt: usize) -> Result { - let mut done = 1; - while done <= amt { + let mut done = 0; + + while done < amt { match self.src.next() { Some(Ok(c)) => self.buffer.push_front(c), Some(Err(e)) => return Err(e), -- 2.40.1 From 20aa3b584336fcfa505704a8af632ee87a08c1d5 Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 16:38:51 +0000 Subject: [PATCH 5/6] lib/reader: fix column @newline --- src/reader.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/reader.rs b/src/reader.rs index cc9094e..696f156 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -10,6 +10,8 @@ struct Reader { buffer: VecDeque, column: usize, mark: usize, + + reset_column: bool, } impl Reader @@ -22,6 +24,8 @@ where buffer: VecDeque::new(), column: 0, mark: 0, + + reset_column: false, } } @@ -66,13 +70,16 @@ where fn next_char(&mut self) -> Result> { match self.read_one()? { - Some('\n') => { - self.column = 0; - self.mark += 1; - - Ok(Some('\n')) - } Some(c) => { + if self.reset_column { + self.reset_column = false; + self.column = 0; + } + + if c == '\n' { + self.reset_column = true; + } + self.column += 1; self.mark += 1; @@ -167,7 +174,7 @@ mod tests { #[test] fn column() { let data = data!("abc\nefg\nhijkl"); - let expected = vec![1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5]; + let expected = vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5]; let mut r = Reader::new(data); assert_eq!(r.column(), 0); -- 2.40.1 From 90e979c531213fa458a082792c5d1b239385ecde Mon Sep 17 00:00:00 2001 From: Bazaah Date: Thu, 3 Jun 2021 16:49:09 +0000 Subject: [PATCH 6/6] lib/reader: comments --- src/reader.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/reader.rs b/src/reader.rs index 696f156..3176e27 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -71,11 +71,13 @@ where fn next_char(&mut self) -> Result> { match self.read_one()? { Some(c) => { + // We hit a line end previously, reset column size if self.reset_column { self.reset_column = false; self.column = 0; } + // We just hit a line end, arm column reset if c == '\n' { self.reset_column = true; } -- 2.40.1