generated from PlexSheep/baserepo
basic filter and error display
This commit is contained in:
parent
ff560c63ff
commit
f8f88e79c3
|
@ -129,6 +129,13 @@ fn main() {
|
|||
|
||||
debug!("exporssion: {}", expr);
|
||||
let r = Calculator::oneshot(expr);
|
||||
println!("{}", r.unwrap());
|
||||
match r {
|
||||
Ok(r) => {
|
||||
println!("{r}");
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Could not compute: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -72,7 +72,7 @@ pub enum Function {
|
|||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
SyntaxError
|
||||
SyntaxError(String)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -120,6 +120,17 @@ impl<T: num_traits::PrimInt> From<T> for NumVal where
|
|||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Display Errors with a nice little reason
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::SyntaxError(reason) => {
|
||||
write!(f, "Syntax Error: {}", reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl<T: PrimInt> From<T> for Value where
|
||||
|
|
|
@ -40,6 +40,7 @@ use crate::logger::{trace, debug, info, warn, error};
|
|||
/// This struct does not do anything at the moment, but aims to be the target for high level
|
||||
/// control. Instead of using the [`Calculator`], you could just use the [`Term`] struct for
|
||||
/// lower level control.
|
||||
#[derive(Debug)]
|
||||
pub struct Calculator;
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -65,8 +66,9 @@ impl Calculator {
|
|||
t.prepare()?;
|
||||
t.process()?;
|
||||
if t.result.is_none() {
|
||||
error!("Term was processed but no result was assigned.");
|
||||
return Err(Error::SyntaxError)
|
||||
let reason = format!("Term was processed but no result was assigned.");
|
||||
// FIXME: unfitting error type
|
||||
return Err(Error::SyntaxError(reason))
|
||||
}
|
||||
return t.result.unwrap()
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ enum Token {
|
|||
pub struct Term {
|
||||
/// the original expression to calculate
|
||||
pub original: String,
|
||||
/// the filtered text of the expression, only with relevant information
|
||||
pub text: String,
|
||||
/// the calculated result, may be of diffrent types, see [`crate::math::calculator::result`].
|
||||
pub result: Option<Result<Value>>,
|
||||
/////////////////////////////////////
|
||||
|
@ -76,6 +78,7 @@ impl Term {
|
|||
return Ok(
|
||||
Term {
|
||||
original: orig,
|
||||
text: String::new(), // will be initialized in `prepare()`
|
||||
result: None,
|
||||
operator_stack: Vec::new(),
|
||||
output_queue: VecDeque::new()
|
||||
|
@ -85,22 +88,20 @@ impl Term {
|
|||
|
||||
/// Prepare the term for the processing.
|
||||
pub fn prepare(&mut self) -> Result<()> {
|
||||
// TODO: shunting yard
|
||||
trace!("preparing term: {:#?}", self);
|
||||
self.text = Self::filter(&self.original)?;
|
||||
|
||||
// Storage for unfinished tokens
|
||||
let mut unfinished_chars: Vec<char> = Vec::new();
|
||||
|
||||
for (index, c) in self.original.chars().enumerate() {
|
||||
if !c.is_alphanumeric() {
|
||||
// TODO: allow any unicode char to be a variable
|
||||
warn!("'{c}' is not a valid character, only alphanumeric input is allowed.");
|
||||
return Err(Error::SyntaxError);
|
||||
}
|
||||
// this will be a mess, but it has to be before i can sort the mess.
|
||||
match c {
|
||||
// TODO: make function to check if character is an operator, use it
|
||||
_ => {
|
||||
warn!("The meaning of '{c}' could not be identified.");
|
||||
return Err(Error::SyntaxError);
|
||||
let reason = format!("The meaning of '{c}' could not be identified.");
|
||||
warn!(reason);
|
||||
return Err(Error::SyntaxError(reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,14 +126,54 @@ impl Term {
|
|||
}
|
||||
|
||||
/// only leave relevant chars for calculation
|
||||
fn filter(s: String) -> String {
|
||||
// TODO: make function to check if character is an operator, use it
|
||||
fn filter(s: &str) -> Result<String> {
|
||||
// pre checks
|
||||
// NOTE: Apperently, "alphanumeric" in Rust is a pretty broad term.
|
||||
// Even CJK characters or Japanese Kana are allowed:
|
||||
// - 'さ' alphanumeric
|
||||
// - '数' alphanumeric
|
||||
// - '学' alphanumeric
|
||||
// - '+' not alphanumeric
|
||||
for c in s.chars() {
|
||||
#[cfg(debug_assertions)] {
|
||||
debug!("filter checks for '{c}':
|
||||
alphanumeric: {}
|
||||
allowed special: {}
|
||||
EXCEPT IF
|
||||
ascii control: {}
|
||||
",
|
||||
!c.is_alphanumeric(),
|
||||
!Self::is_allowed_special_c(&c),
|
||||
c.is_ascii_control(),
|
||||
)
|
||||
}
|
||||
if
|
||||
(
|
||||
!c.is_alphanumeric() ||
|
||||
!Self::is_allowed_special_c(&c)
|
||||
)
|
||||
&&
|
||||
(
|
||||
c.is_ascii_control()
|
||||
)
|
||||
{
|
||||
// TODO: allow any unicode char to be a variable
|
||||
let reason = format!("'{c}' is not a valid character, only alphanumeric, punctuation, operators are allowed.");
|
||||
warn!(reason);
|
||||
return Err(Error::SyntaxError(reason));
|
||||
}
|
||||
}
|
||||
|
||||
// filter out single chars
|
||||
let mut filtered = String::new();
|
||||
for c in s.chars() {
|
||||
if !Self::is_ignore(&c) {
|
||||
filtered.push(c);
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
|
||||
return Ok(filtered)
|
||||
}
|
||||
|
||||
/// check if we should ignore this character
|
||||
|
@ -142,6 +183,14 @@ impl Term {
|
|||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// allowed special chars
|
||||
fn is_allowed_special_c(c: &char) -> bool {
|
||||
match *c {
|
||||
'+' | '-' | '*' | '/' | '%' => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Reference in New Issue