use std::borrow::Borrow; use crate::io::{CompilerMsg, Span, Spanned}; mod lit; mod token; pub use lit::*; pub use token::*; pub struct Cursor<'a> { pub span: Span, next: Option, tokens: Tokens<'a>, } impl<'a> Cursor<'a> { pub fn new(text: &'a str, file: usize) -> Self { let mut s = Self { span: Span { start: 0, end: 0, file, }, next: None, tokens: Tokens::new(text, file), }; s.next(); s } pub fn next(&mut self) -> Option { let mut next = self.tokens.next(); std::mem::swap(&mut self.next, &mut next); next.map(|inst| { self.span = inst.span; inst.inner }) } pub fn next_if(&mut self, token: impl Borrow) -> bool { if self.peek().is_some_and(|t| t == token.borrow()) { self.next(); true } else { false } } pub fn peek(&self) -> Option<&Token> { self.next.as_ref().map(|i| &i.inner) } pub fn expect_next(&mut self) -> Result { self.next().ok_or_else(CompilerMsg::unexpected_eof) } pub fn expect_peek(&self) -> Result<&Token, CompilerMsg> { self.peek().ok_or_else(CompilerMsg::unexpected_eof) } pub fn expect(&mut self, token: Token) -> Result { let next = self.expect_next()?; if next == token { Ok(next) } else { self.unexpected(&next, &format!("'{token}'")) } } pub fn unexpected(&self, token: &Token, expected: &str) -> Result { Err(CompilerMsg::unexpected_token(token, self.span, expected)) } pub fn peek_start(&mut self) -> usize { self.next.as_ref().map(|i| i.span.start).unwrap_or(0) } pub fn cur_end(&mut self) -> usize { self.span.end } pub fn file(&mut self) -> usize { self.span.file } } impl CompilerMsg { pub fn unexpected_token(token: &Token, span: Span, expected: &str) -> Self { Self { spans: vec![span], msg: format!("Unexpected token '{}', expected {expected}", token), } } pub fn unexpected_eof() -> Self { Self { spans: Vec::new(), msg: "unexpected end of file".to_string(), } } }