mod byte;
mod char;
pub mod compound;
mod ident;
pub mod keywords;
mod reader;
mod unicode;
mod strings;
#[cfg(test)]
mod test;
pub use reader::{BytesReader, CharError};
use crate::syn::error::{SyntaxError, bail};
use crate::syn::token::{Span, Token, TokenKind};
pub struct Lexer<'a> {
pub(super) reader: BytesReader<'a>,
last_offset: u32,
pub(super) error: Option<SyntaxError>,
}
impl<'a> Lexer<'a> {
pub fn new(source: &'a [u8]) -> Lexer<'a> {
assert!(source.len() <= u32::MAX as usize, "source code exceeded maximum size");
let reader = BytesReader::new(source);
Lexer {
reader,
last_offset: 0,
error: None,
}
}
pub fn reset(&mut self) {
self.last_offset = 0;
self.error = None;
}
pub fn change_source<'b>(self, source: &'b [u8]) -> Lexer<'b> {
assert!(source.len() <= u32::MAX as usize, "source code exceeded maximum size");
let reader = BytesReader::<'b>::new(source);
Lexer {
reader,
last_offset: 0,
error: self.error,
}
}
pub fn next_token(&mut self) -> Token {
let Some(byte) = self.reader.next() else {
return self.eof_token();
};
if byte.is_ascii() {
self.lex_ascii(byte)
} else {
self.lex_char(byte)
}
}
fn eof_token(&mut self) -> Token {
Token {
kind: TokenKind::Eof,
span: Span {
offset: self.last_offset,
len: 0,
},
}
}
fn invalid_token(&mut self, error: SyntaxError) -> Token {
self.error = Some(error);
self.finish_token(TokenKind::Invalid)
}
pub(crate) fn current_span(&self) -> Span {
let new_offset = self.reader.offset();
let len = new_offset - self.last_offset;
Span {
offset: self.last_offset,
len,
}
}
pub(crate) fn span_since(&self, offset: u32) -> Span {
let new_offset = self.reader.offset();
let len = new_offset - offset;
Span {
offset,
len,
}
}
fn advance_span(&mut self) -> Span {
let span = self.current_span();
self.last_offset = self.reader.offset();
span
}
fn finish_token(&mut self, kind: TokenKind) -> Token {
Token {
kind,
span: self.advance_span(),
}
}
pub(crate) fn backup_after(&mut self, span: Span) {
let offset = span.offset + span.len;
self.reader.backup(offset);
self.last_offset = offset;
}
fn eat(&mut self, byte: u8) -> bool {
if self.reader.peek() == Some(byte) {
self.reader.next();
true
} else {
false
}
}
fn eat_when<F: FnOnce(u8) -> bool>(&mut self, f: F) -> bool {
let Some(x) = self.reader.peek() else {
return false;
};
if f(x) {
self.reader.next();
true
} else {
false
}
}
fn expect(&mut self, c: char) -> Result<(), SyntaxError> {
match self.reader.peek() {
Some(x) => {
let offset = self.reader.offset();
self.reader.next();
let char = self.reader.convert_to_char(x)?;
if char == c {
return Ok(());
}
let len = self.reader.offset() - offset;
bail!(
"Unexpected character `{char}` expected `{c}`",
@Span {
offset,
len
}
)
}
None => {
bail!("Unexpected end of file, expected character `{c}`", @self.current_span())
}
}
}
pub fn span_str(&self, span: Span) -> &'a str {
std::str::from_utf8(self.span_bytes(span)).expect("invalid span segment for source")
}
pub fn span_bytes(&self, span: Span) -> &'a [u8] {
self.reader.span(span)
}
pub fn assert_finished(&self) -> Result<(), SyntaxError> {
if !self.reader.is_empty() {
let offset = self.reader.offset();
let len = self.reader.remaining().len() as u32;
let span = Span {
offset,
len,
};
bail!("Trailing characters", @span)
}
Ok(())
}
}
impl Iterator for Lexer<'_> {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
let token = self.next_token();
if token.is_eof() {
return None;
}
Some(token)
}
}