#![allow(missing_docs)]
use alkale::{
format_notification, map_single_char_token,
notification::{NotificationBuilder, NotificationSeverity},
span::Spanned,
token::Token,
FinalizedLexerResult, LexerResult, SourceCodeScanner,
};
#[derive(Debug, Clone)]
pub enum ExprToken<'a> {
OpenParen, CloseParen, Add, Sub, Mul, Div, Variable(&'a str), Number(f64), }
fn expression_lexer<'a: 'b, 'b>(source: &'a str) -> FinalizedLexerResult<ExprToken<'b>> {
let context = SourceCodeScanner::new(source);
let mut result = LexerResult::new();
while context.has_next() {
map_single_char_token!(&context, &mut result,
'(' => ExprToken::OpenParen,
')' => ExprToken::CloseParen,
'+' => ExprToken::Add,
'-' => ExprToken::Sub,
'*' => ExprToken::Mul,
'/' => ExprToken::Div,
);
if let Some(Spanned { span, data }) = context.try_consume_standard_identifier() {
result.push_token(Token::new(ExprToken::Variable(data), span));
continue;
}
if let Some(Spanned { data, span }) = context.try_parse_float() {
if let Ok(number) = data {
result.push_token(Token::new(ExprToken::Number(number), span));
} else {
NotificationBuilder::new("Floating-point number is malformed")
.severity(NotificationSeverity::Error)
.span(span)
.report(&mut result);
}
continue;
}
if let Some(Spanned { data, span }) = context.next_span() {
if !data.is_whitespace() {
format_notification!("Unrecognized character '{data}'")
.severity(NotificationSeverity::Error)
.span(span)
.report(&mut result);
}
}
}
result.finalize()
}
fn main() {
let program = "23 * (012 - x) / 1_2_3 + 5e-3";
let result = expression_lexer(program);
println!("{:#?}", result.notifications());
println!("{:#?}", result.tokens());
}