use primitives::Guard;
use types::{Buffer, Input};
pub trait Numbering: Clone {
type Token: Copy + PartialEq;
fn update<'a, B>(&mut self, &'a B)
where B: Buffer<Token=Self::Token>;
fn add(&mut self, Self::Token);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct LineNumber(
/// The current line, zero-indexed.
pub u64,
);
impl LineNumber {
pub fn new() -> Self {
LineNumber(0)
}
}
impl Default for LineNumber {
fn default() -> Self {
LineNumber::new()
}
}
impl Numbering for LineNumber {
type Token = u8;
fn update<'a, B>(&mut self, b: &'a B)
where B: Buffer<Token=Self::Token> {
let mut n = 0;
b.iterate(|c| if c == b'\n' {
n += 1;
});
self.0 += n
}
fn add(&mut self, t: Self::Token) {
if t == b'\n' {
self.0 += 1
}
}
}
#[derive(Debug)]
pub struct InputPosition<I: Input, N: Numbering<Token=I::Token>> {
input: I,
num: N,
}
impl<I: Input, N: Numbering<Token=I::Token>> InputPosition<I, N> {
pub fn new(i: I, n: N) -> Self {
InputPosition {
input: i,
num: n,
}
}
pub fn position(&self) -> N {
self.num.clone()
}
}
impl<I: Input, N: Numbering<Token=I::Token>> Input for InputPosition<I, N> {
type Token = I::Token;
type Marker = (N, I::Marker);
type Buffer = I::Buffer;
#[inline]
fn _peek(&mut self, g: Guard) -> Option<Self::Token> {
self.input._peek(g)
}
#[inline]
fn _pop(&mut self, g: Guard) -> Option<Self::Token> {
self.input._pop(g).map(|t| {
self.num.add(t);
t
})
}
#[inline]
fn _consume(&mut self, g: Guard, n: usize) -> Option<Self::Buffer> {
self.input._consume(g, n).map(|b| {
self.num.update(&b);
b
})
}
#[inline]
fn _consume_while<F>(&mut self, g: Guard, f: F) -> Self::Buffer
where F: FnMut(Self::Token) -> bool {
let b = self.input._consume_while(g, f);
self.num.update(&b);
b
}
#[inline]
fn _consume_from(&mut self, g: Guard, m: Self::Marker) -> Self::Buffer {
self.input._consume_from(g, m.1)
}
#[inline]
fn _consume_remaining(&mut self, g: Guard) -> Self::Buffer {
let b = self.input._consume_remaining(g);
self.num.update(&b);
b
}
#[inline]
fn _mark(&self, g: Guard) -> Self::Marker {
(self.num.clone(), self.input._mark(g))
}
#[inline]
fn _restore(self, g: Guard, m: Self::Marker) -> Self {
InputPosition {
input: self.input._restore(g, m.1),
num: m.0,
}
}
}
#[cfg(test)]
mod test {
use types::{Input, ParseResult};
use super::{InputPosition, LineNumber};
use primitives::IntoInner;
#[test]
fn basic_test() {
use combinators::many;
use parsers::{Error, any, take_while1, string};
let i = InputPosition::new(&b"test a\ntest b\n\ntest c\n"[..], Default::default());
fn parser<I: Input<Token=u8>>(i: InputPosition<I, LineNumber>)
-> ParseResult<InputPosition<I, LineNumber>, (char, LineNumber), Error<u8>> {
parse!{i;
string(b"test");
take_while1(|c| c == b' ' || c == b'\t');
let t_name = any();
i -> {
let p = i.position();
i.ret((t_name as char, p))
} <* take_while1(|c| c == b'\n');
}
}
assert_eq!(many(i, parser).into_inner().1, Ok(vec![
('a', LineNumber(0)),
('b', LineNumber(1)),
('c', LineNumber(3))]));
}
}