rscel 1.0.8

Cel interpreter in rust
Documentation
use std::str::Chars;

use super::source_location::SourceLocation;

pub struct StringScanner<'l> {
    input: &'l str,
    iterator: Chars<'l>,
    current: Option<char>,
    line: usize,
    column: usize,
    eof: bool,
}

impl<'l> StringScanner<'l> {
    pub fn from_input(input: &'l str) -> StringScanner<'l> {
        StringScanner {
            input,
            iterator: input.chars(),
            current: None,
            line: 0,
            column: 0,
            eof: false,
        }
    }

    pub fn peek(&mut self) -> Option<char> {
        if self.current.is_none() {
            self.current = self.collect_next();
        }

        self.current
    }

    pub fn next(&mut self) -> Option<char> {
        if self.current.is_none() {
            self.current = self.collect_next();
        }

        match self.current {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 0;
                } else {
                    self.column += 1;
                }

                self.current = None;
                Some(c)
            }
            None => None,
        }
    }

    pub fn location(&self) -> SourceLocation {
        SourceLocation::new(self.line, self.column)
    }

    fn collect_next(&mut self) -> Option<char> {
        if self.eof {
            return None;
        }

        match self.iterator.next() {
            Some(val) => Some(val),
            None => {
                self.eof = true;
                None
            }
        }
    }

    pub fn input(&self) -> &'l str {
        self.input
    }
}

#[cfg(test)]
mod test {
    use crate::compiler::source_location::SourceLocation;

    use super::StringScanner;

    #[test]
    fn string_scanner_location() {
        let mut scanner = StringScanner::from_input("foo + bar");

        assert_eq!(scanner.location(), SourceLocation::new(0, 0));

        let c = scanner.peek().unwrap();
        assert_eq!(c, 'f');
        assert_eq!(scanner.location(), SourceLocation::new(0, 0));

        let _ = scanner.next().unwrap();
        assert_eq!(scanner.location(), SourceLocation::new(0, 1));
    }
}