generated from PlexSheep/baserepo
Compare commits
No commits in common. "50fea61bb017a621cc42f238c66d6d292ad33349" and "43ac1e3fb84585bbeadaf7e7f97916e73d074b4d" have entirely different histories.
50fea61bb0
...
43ac1e3fb8
5 changed files with 504 additions and 15 deletions
|
@ -1,9 +1,9 @@
|
||||||
name: Cargo Check, Format, Fix and Test
|
name: Cargo Format, Check and Test
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
name: cargo CI
|
name: cargo fmt
|
||||||
permissions:
|
permissions:
|
||||||
# Give the default GITHUB_TOKEN write permission to commit and push the
|
# Give the default GITHUB_TOKEN write permission to commit and push the
|
||||||
# added or changed files to the repository.
|
# added or changed files to the repository.
|
||||||
|
@ -11,17 +11,22 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- run: cargo check --all-features --all-targets
|
|
||||||
- run: rustup component add rustfmt
|
- run: rustup component add rustfmt
|
||||||
- run: cargo fix --all-features --all-targets
|
- run: cargo fmt
|
||||||
- run: cargo fmt --all
|
|
||||||
- run: cargo test --all-features --all-targets
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
with:
|
with:
|
||||||
# Optional. Commit message for the created commit.
|
# Optional. Commit message for the created commit.
|
||||||
# Defaults to "Apply automatic changes"
|
# Defaults to "Apply automatic changes"
|
||||||
commit_message: automatic cargo CI changes
|
commit_message: Automatical formatting
|
||||||
commit_user_name: Gitea CI
|
check:
|
||||||
commit_user_email: noreply@cscherr.de
|
name: cargo check
|
||||||
commit_author: Gitea CI <noreply@cscherr.de>
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo check --all-features --verbose
|
||||||
|
test:
|
||||||
|
name: cargo test
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo test --all-features --verbose
|
||||||
|
|
226
members/libpt-ccc/src/base.rs
Normal file
226
members/libpt-ccc/src/base.rs
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
//! # Results and Errors for the calculate module
|
||||||
|
//!
|
||||||
|
//! This module defines the errors and results that can be processed from any given term.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pub use num_traits::PrimInt;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||||
|
use libpt_log::*;
|
||||||
|
#[allow(unused_imports)] // import more complex math stuff from there
|
||||||
|
use libpt_math;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Quick Result with a ccc error
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Supported Operations
|
||||||
|
///
|
||||||
|
/// This `enum` contains all operations supported in this module.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Operator {
|
||||||
|
/// Mathmatical addition
|
||||||
|
Addition,
|
||||||
|
/// Mathmatical subtraction
|
||||||
|
Subtraction,
|
||||||
|
/// Mathmatical multiplication
|
||||||
|
Multiplication,
|
||||||
|
/// Mathmatical division
|
||||||
|
Division,
|
||||||
|
/// Mathmatical modulo, finite field arithmetic
|
||||||
|
Modulo,
|
||||||
|
/// Any function, seel [`Function`]
|
||||||
|
Function(Function),
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Supported Functions
|
||||||
|
///
|
||||||
|
/// This `enum` contains all functions supported in this module.
|
||||||
|
///
|
||||||
|
/// A function has a name followed by braces directly afterwards.
|
||||||
|
/// A function may have 0 to 31 Arguments.
|
||||||
|
///
|
||||||
|
/// Example: `sqrt(19)`, `floor(19.9)`
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Function {
|
||||||
|
/// Draw the mathmatical root, attribute n is the nth root
|
||||||
|
Root(u16),
|
||||||
|
/// round up
|
||||||
|
Floor,
|
||||||
|
/// round down
|
||||||
|
Ceil,
|
||||||
|
/// round to nearest integer
|
||||||
|
/// (commercial rounding)
|
||||||
|
Round,
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Top Level Error Type
|
||||||
|
///
|
||||||
|
/// Contains many variants of other errors, that can occur when using the crate.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The term has bad syntax
|
||||||
|
SyntaxError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Represents some kind of computed value
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Value {
|
||||||
|
/// Variable value
|
||||||
|
Variable(VarVal),
|
||||||
|
/// Numerical value
|
||||||
|
Numerical(NumVal),
|
||||||
|
/// Complex number value
|
||||||
|
Complex(ComplVal),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents some kind of numeric value
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum NumVal {
|
||||||
|
/// Value > 0
|
||||||
|
Signed(i128),
|
||||||
|
/// Value can be negative
|
||||||
|
Unsigned(u128),
|
||||||
|
/// Value is not an integer
|
||||||
|
Float(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Represents a Value with at least one variable,
|
||||||
|
///
|
||||||
|
/// currently not implemented
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VarVal {}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Represents a Value with a complex number,
|
||||||
|
///
|
||||||
|
/// currently not implemented
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ComplVal {}
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl<T: num_traits::PrimInt> From<T> for NumVal
|
||||||
|
where
|
||||||
|
u128: TryFrom<T>,
|
||||||
|
u128: TryFrom<T>,
|
||||||
|
{
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
if T::min_value().is_zero() {
|
||||||
|
// unsigned data types
|
||||||
|
// `u128` is the largest unsigned datatype, any other type will fit.
|
||||||
|
NumVal::Unsigned(value.to_u128().unwrap())
|
||||||
|
} else {
|
||||||
|
// signed data types
|
||||||
|
// `i128` is the largest unsigned datatype, any other type will fit.
|
||||||
|
NumVal::Signed(value.to_i128().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// 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
|
||||||
|
u128: TryFrom<T>,
|
||||||
|
u128: TryFrom<T>,
|
||||||
|
{
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
NumVal::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl From<NumVal> for Value {
|
||||||
|
fn from(value: NumVal) -> Self {
|
||||||
|
Value::Numerical(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Display for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Value::Numerical(val) => {
|
||||||
|
write!(f, "{}", val)
|
||||||
|
}
|
||||||
|
Value::Complex(val) => {
|
||||||
|
write!(f, "{}", val)
|
||||||
|
}
|
||||||
|
Value::Variable(val) => {
|
||||||
|
write!(f, "{}", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Display for NumVal {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
NumVal::Float(val) => {
|
||||||
|
write!(f, "{val}")
|
||||||
|
}
|
||||||
|
NumVal::Signed(val) => {
|
||||||
|
write!(f, "{val}")
|
||||||
|
}
|
||||||
|
NumVal::Unsigned(val) => {
|
||||||
|
write!(f, "{val}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Display for ComplVal {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Display for VarVal {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -19,7 +19,14 @@
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
use libpt_log;
|
pub mod base;
|
||||||
|
pub use base::{Error, Result, Value};
|
||||||
|
pub mod term;
|
||||||
|
pub use term::*;
|
||||||
|
|
||||||
|
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||||
|
use libpt_log::*;
|
||||||
|
#[allow(unused_imports)] // import more complex math stuff from there
|
||||||
use libpt_math;
|
use libpt_math;
|
||||||
|
|
||||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -33,8 +40,44 @@ use libpt_math;
|
||||||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## A Calculator struct
|
||||||
|
///
|
||||||
|
/// 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 ////////////////////////////////////////////////////////////////////////////////
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Calculator {
|
||||||
|
/// Do a single calculation without doing anything else
|
||||||
|
pub fn oneshot(t: String) -> Result<Value> {
|
||||||
|
trace!(orig = t, "parsing original string to Term");
|
||||||
|
let t = Term::new(t)?;
|
||||||
|
trace!("term has been parsed, starting Calculation");
|
||||||
|
debug!("parsed term: {t:#?}");
|
||||||
|
Self::calc(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Calculate a [`Term`]
|
||||||
|
///
|
||||||
|
/// This method makes use of the
|
||||||
|
/// [shunting yard algorithm](https://en.wikipedia.org/wiki/Shunting_yard_algorithm) to
|
||||||
|
/// Calculate the final value of any term.
|
||||||
|
///
|
||||||
|
/// This method only processes a single term at a time, without caching.
|
||||||
|
pub fn calc(mut t: Term) -> Result<Value> {
|
||||||
|
trace!("Calculating term {t:?}");
|
||||||
|
t.prepare()?;
|
||||||
|
t.process()?;
|
||||||
|
if t.result.is_none() {
|
||||||
|
let reason = format!("Term was processed but no result was assigned.");
|
||||||
|
// FIXME: unfitting error type
|
||||||
|
return Err(Error::SyntaxError(reason));
|
||||||
|
}
|
||||||
|
return t.result.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
218
members/libpt-ccc/src/term.rs
Normal file
218
members/libpt-ccc/src/term.rs
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
//! # A term that can be the input for calculation
|
||||||
|
//!
|
||||||
|
//! Short description
|
||||||
|
//!
|
||||||
|
//! Details
|
||||||
|
//!
|
||||||
|
//! ## Section 1
|
||||||
|
//!
|
||||||
|
//! ## Section 2
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pub use super::{
|
||||||
|
base::{self, *},
|
||||||
|
Error, Result, Value,
|
||||||
|
};
|
||||||
|
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||||
|
use libpt_log::*;
|
||||||
|
#[allow(unused_imports)] // import more complex math stuff from there
|
||||||
|
use libpt_math;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Parsed value to be calculated
|
||||||
|
///
|
||||||
|
/// This enum represents anything that goes to the output queue of [`Term::prepare()`] and will
|
||||||
|
/// then be used to actually calculate something in [`Term::process()`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Token {
|
||||||
|
/// Some kind of operator
|
||||||
|
#[allow(unused)] // tmp
|
||||||
|
Operator(Operator),
|
||||||
|
/// A concrete value that we can calculate something with. May be a constant, integer, float,
|
||||||
|
/// etc.
|
||||||
|
/// The Token has a value that can be used in calculation
|
||||||
|
Value(super::base::Value),
|
||||||
|
/// A variable of some kind that will be present in the result
|
||||||
|
#[allow(unused)] // tmp
|
||||||
|
Variable(char),
|
||||||
|
}
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Term that can be calculated
|
||||||
|
///
|
||||||
|
/// Represents a signular term, that can be calculated. Terms will be evaluated by the [`Term::prepare`]
|
||||||
|
/// function, afterwards calculated (as much as possible) in the [`Term::process`] function.
|
||||||
|
///
|
||||||
|
#[derive(Debug)]
|
||||||
|
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>>,
|
||||||
|
/////////////////////////////////////
|
||||||
|
///// internal values following /////
|
||||||
|
/////////////////////////////////////
|
||||||
|
#[allow(unused)] // tmp
|
||||||
|
operator_stack: Vec<Operator>,
|
||||||
|
output_queue: VecDeque<Token>,
|
||||||
|
}
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl Term {
|
||||||
|
/// Build a new term from an expression
|
||||||
|
///
|
||||||
|
/// Invalid terms will result in an [`Err`].
|
||||||
|
pub fn new(orig: String) -> Result<Term> {
|
||||||
|
return Ok(Term {
|
||||||
|
original: orig,
|
||||||
|
text: String::new(), // will be initialized in `prepare()`
|
||||||
|
result: None,
|
||||||
|
operator_stack: Vec::new(),
|
||||||
|
output_queue: VecDeque::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare the term for the processing.
|
||||||
|
pub fn prepare(&mut self) -> Result<()> {
|
||||||
|
trace!("preparing term: {:#?}", self);
|
||||||
|
self.text = Self::filter(&self.original)?;
|
||||||
|
|
||||||
|
// Storage for unfinished tokens
|
||||||
|
let _unfinished_chars: Vec<char> = Vec::new();
|
||||||
|
|
||||||
|
for (_index, c) in self.original.chars().enumerate() {
|
||||||
|
// 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
|
||||||
|
_ => {
|
||||||
|
let reason = format!("The meaning of '{c}' could not be identified.");
|
||||||
|
warn!(reason);
|
||||||
|
return Err(Error::SyntaxError(reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process a prepared term, calculating it's result
|
||||||
|
pub fn process(&mut self) -> Result<()> {
|
||||||
|
debug!("processing term: {:#?}", self);
|
||||||
|
debug!("queue: {:#?}", self.output_queue);
|
||||||
|
// TODO: process RPN and set result
|
||||||
|
self.result = Some(Ok(19.into()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a character into a token
|
||||||
|
///
|
||||||
|
/// Returns: A tuple with a [`Token`] and a [`bool`]. If the bool is false, the [`Token`] is
|
||||||
|
/// marked as "incomplete", meaning that the character cannot be used yet.
|
||||||
|
#[allow(unused)] // tmp
|
||||||
|
fn to_tok(_s: Vec<char>) -> Result<Token> {
|
||||||
|
Ok(19.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// only leave relevant chars for calculation
|
||||||
|
// 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 Ok(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if we should ignore this character
|
||||||
|
fn is_ignore(c: &char) -> bool {
|
||||||
|
match *c {
|
||||||
|
' ' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// allowed special chars
|
||||||
|
fn is_allowed_special_c(c: &char) -> bool {
|
||||||
|
match *c {
|
||||||
|
'+' | '-' | '*' | '/' | '%' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Helper methods for Tokens
|
||||||
|
impl Token {}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl<T> From<T> for Token
|
||||||
|
where
|
||||||
|
T: Into<Value>,
|
||||||
|
T: PrimInt,
|
||||||
|
u128: TryFrom<T>,
|
||||||
|
{
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Token::Value(base::Value::from(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -13,6 +13,3 @@ keywords.workspace = true
|
||||||
categories.workspace = true
|
categories.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
|
||||||
cucumber = "0.20.2"
|
|
||||||
libpt-log = {path = "../libpt-log" }
|
|
||||||
|
|
Reference in a new issue