tenda-scanner 0.1.0

Scanner for the Tenda programming language
Documentation
use std::iter::Peekable;
use std::str::Chars;
use tenda_common::{source::IdentifiedSource, span::SourceSpan};

use crate::token::{Literal, Token, TokenKind};

pub struct SourceIter<'a> {
    iter: Peekable<Chars<'a>>,
    source_id: IdentifiedSource,
    start_position: usize,
    end_position: usize,
}

impl<'a> SourceIter<'a> {
    pub fn new(input: &'a str, source_id: IdentifiedSource) -> Self {
        Self {
            iter: input.chars().peekable(),
            source_id,
            start_position: 0,
            end_position: 0,
        }
    }

    pub fn consume_token(&mut self, kind: TokenKind, lexeme: &str) -> Token {
        Token::new(kind, lexeme.to_string(), None, self.consume_span())
    }

    pub fn consume_token_with_literal(
        &mut self,
        kind: TokenKind,
        lexeme: String,
        literal: Literal,
    ) -> Token {
        Token::new(kind, lexeme, Some(literal), self.consume_span())
    }

    pub fn consume_eof(&mut self) -> Token {
        Token::eoi(self.consume_span())
    }

    pub fn consume_span(&mut self) -> SourceSpan {
        let span = SourceSpan::new(self.start_position, self.end_position, self.source_id);

        self.start_position = self.end_position;

        span
    }

    pub fn ignore_char(&mut self) {
        self.start_position = self.end_position;
    }

    pub fn peek(&mut self) -> Option<&char> {
        self.iter.peek()
    }
}

impl Iterator for SourceIter<'_> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(c) = self.iter.next() {
            self.end_position += c.len_utf8();

            Some(c)
        } else {
            None
        }
    }
}