103 lines
2.4 KiB
Rust
103 lines
2.4 KiB
Rust
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<TokenInst>,
|
|
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<Token> {
|
|
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<Token>) -> 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<Token, CompilerMsg> {
|
|
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: impl Borrow<Token>) -> Result<Token, CompilerMsg> {
|
|
let token = token.borrow();
|
|
let next = self.expect_next()?;
|
|
if next == *token {
|
|
Ok(next)
|
|
} else {
|
|
self.unexpected(&next, &format!("'{token}'"))
|
|
}
|
|
}
|
|
|
|
pub fn unexpected<T>(&self, token: &Token, expected: &str) -> Result<T, CompilerMsg> {
|
|
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(),
|
|
}
|
|
}
|
|
}
|