Files
orchid/orchidlang/src/parse/numeric.rs
2024-07-18 16:07:36 +02:00

58 lines
1.9 KiB
Rust

//! Parse a float or integer. These functions are also used for the macro
//! priority numbers
use std::num::IntErrorKind;
use std::ops::Range;
use ordered_float::NotNan;
use super::context::ParseCtx;
use super::errors::{ExpectedDigit, LiteralOverflow, NaNLiteral, ParseErrorKind};
use super::lex_plugin::LexPluginReq;
#[allow(unused)] // for doc
use super::lex_plugin::LexerPlugin;
use super::lexer::{split_filter, Entry, LexRes, Lexeme};
use crate::error::{ProjectErrorObj, ProjectResult};
use crate::foreign::atom::AtomGenerator;
use crate::foreign::inert::Inert;
use crate::libs::std::number::Numeric;
impl NumError {
/// Convert into [ProjectErrorObj]
pub fn into_proj(
self,
len: usize,
tail: &str,
ctx: &(impl ParseCtx + ?Sized),
) -> ProjectErrorObj {
let start = ctx.source().len() - tail.len() - len + self.range.start;
let location = ctx.range_loc(&(start..start + self.range.len()));
match self.kind {
NumErrorKind::NaN => NaNLiteral.pack(location),
NumErrorKind::InvalidDigit => ExpectedDigit.pack(location),
NumErrorKind::Overflow => LiteralOverflow.pack(location),
}
}
}
/// [LexerPlugin] for a number literal
#[derive(Clone)]
pub struct NumericLexer;
impl LexerPlugin for NumericLexer {
fn lex<'b>(&self, req: &'_ dyn LexPluginReq<'b>) -> Option<ProjectResult<LexRes<'b>>> {
req.tail().chars().next().filter(|c| numstart(*c)).map(|_| {
let (num_str, tail) = split_filter(req.tail(), numchar);
let ag = match parse_num(num_str) {
Ok(Numeric::Float(f)) => AtomGenerator::cloner(Inert(f)),
Ok(Numeric::Uint(i)) => AtomGenerator::cloner(Inert(i)),
Err(e) => return Err(e.into_proj(num_str.len(), tail, req.ctx())),
};
let range = req.ctx().range(num_str.len(), tail);
let entry = Entry { lexeme: Lexeme::Atom(ag), range };
Ok(LexRes { tail, tokens: vec![entry] })
})
}
}