use crate::{
session::{ SESSION, MessageKind, },
source::{ SOURCE_MANAGER, SourceLocation, SourceRegion, SourceKey, },
token::{ Token, TokenData, },
util::{ Unref, },
};
mod lexlets;
use lexlets::LexletResult;
pub use lexlets::InvalidLexicalSymbol;
#[derive(Debug, Clone, Copy)]
pub struct LexerLocale {
location: SourceLocation,
prev: Option<char>,
curr: Option<char>,
next: Option<char>,
}
pub struct Lexer<'a> {
source_key: SourceKey,
chars: &'a [char],
length: usize,
stored_locale: Option<LexerLocale>,
locale: LexerLocale,
markers: Vec<SourceLocation>,
}
impl<'a> Lexer<'a> {
pub fn new (source_key: SourceKey) -> Self {
let source = SOURCE_MANAGER.get(source_key).expect("Internal error, invalid SourceKey passed to Lexer");
let chars = source.chars();
let length = chars.len();
let curr = chars.get(0).unref();
let next = chars.get(1).unref();
Self {
source_key,
chars,
length,
stored_locale: None,
locale: LexerLocale {
location: SourceLocation { index: 0, line: 0, column: 0 },
prev: None,
curr,
next,
},
markers: Vec::new(),
}
}
pub fn prev_char (&self) -> Option<char> {
self.locale.prev
}
pub fn curr_char (&self) -> Option<char> {
self.locale.curr
}
pub fn peek_char (&self) -> Option<char> {
self.locale.next
}
pub fn advance (&mut self) -> Option<char> {
if self.locale.location.index <= self.length {
self.locale.location.index += 1;
if self.locale.curr.unwrap() == '\n' {
self.locale.location.line += 1;
self.locale.location.column = 0;
} else {
self.locale.location.column += 1;
}
}
self.locale.prev = self.locale.curr;
self.locale.curr = self.locale.next;
self.locale.next = self.chars.get(self.locale.location.index + 1).unref();
self.locale.curr
}
#[track_caller]
pub fn save_locale (&mut self) {
assert!(self.stored_locale.is_none());
self.stored_locale.replace(self.locale);
}
#[track_caller]
pub fn load_locale (&mut self) {
self.locale = self.stored_locale.take().unwrap();
}
#[track_caller]
pub fn discard_saved_locale (&mut self) {
self.stored_locale.take().unwrap();
}
pub fn push_marker (&mut self) {
self.markers.push(self.locale.location);
}
pub fn pop_marker (&mut self) -> Option<SourceLocation> {
self.markers.pop()
}
pub fn pop_marker_region (&mut self) -> Option<SourceRegion> {
self.pop_marker().map(|start| SourceRegion { source: Some(self.source_key), start, end: self.locale.location })
}
pub fn curr_location (&self) -> SourceLocation {
self.locale.location
}
pub fn curr_region (&self) -> SourceRegion {
SourceRegion {
source: Some(self.source_key),
start: self.markers.last().unref().unwrap_or(self.locale.location),
end: self.locale.location
}
}
pub fn message (&mut self, kind: MessageKind, content: String) {
SESSION.message(
Some(self.curr_region()),
kind,
content
)
}
pub fn message_pop (&mut self, kind: MessageKind, content: String) {
SESSION.message(
Some(SourceRegion {
source: Some(self.source_key),
start: self.pop_marker().unwrap_or(self.locale.location),
end: self.locale.location
}),
kind,
content
)
}
pub fn message_at (&self, origin: SourceRegion, kind: MessageKind, content: String) {
SESSION.message(
Some(origin),
kind,
content
)
}
pub fn error (&mut self, content: String) {
self.message(
MessageKind::Error,
content
)
}
pub fn error_pop (&mut self, content: String) {
self.message_pop(MessageKind::Error, content)
}
pub fn error_at (&self, origin: SourceRegion, content: String) {
self.message_at(origin, MessageKind::Error, content)
}
pub fn warning (&mut self, content: String) {
self.message(
MessageKind::Warning,
content
)
}
pub fn warning_pop (&mut self, content: String) {
self.message_pop(MessageKind::Warning, content)
}
pub fn warning_at (&self, origin: SourceRegion, content: String) {
self.message_at(origin, MessageKind::Warning, content)
}
pub fn notice (&mut self, content: String) {
self.message(
MessageKind::Notice,
content
)
}
pub fn notice_pop (&mut self, content: String) {
self.message_pop(MessageKind::Notice, content)
}
pub fn notice_at (&self, origin: SourceRegion, content: String) {
self.message_at(origin, MessageKind::Notice, content)
}
pub fn lex_token (&mut self) -> Result<Option<Token>, InvalidLexicalSymbol> {
if self.curr_char().is_none() { return Ok(None) }
for lexlet in Self::LEXLETS.iter() {
match lexlet(self) {
LexletResult::Some(token) => return Ok(Some(token)),
LexletResult::Err(sym) => return Err(sym),
LexletResult::None => continue
}
}
Ok(None)
}
pub fn lex_stream (&mut self) -> Vec<Token> {
let mut tokens = Vec::new();
loop {
match self.lex_token() {
Ok(tok_or_eof) => if let Some(token) = tok_or_eof {
tokens.push(token)
} else {
break tokens
},
Err(InvalidLexicalSymbol { symbol, origin }) => {
tokens.push(Token::new(TokenData::Invalid, origin));
self.error_at(origin, format!("Unexpected lexical symbol {:?}", symbol))
}
}
}
}
}