1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281 |
- From b460b58f96310693a06cd180b45c3d5d60c778de Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 10:08:55 -0500
- Subject: [PATCH 01/10] update all dependencies (except for nom)
- Upstream: <https://github.com/rekka/meval-rs/pull/27>.
- ---
- Cargo.toml | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
- diff --git a/Cargo.toml b/Cargo.toml
- index 1b8a828..c395833 100644
- --- a/Cargo.toml
- +++ b/Cargo.toml
- @@ -14,14 +14,14 @@ exclude = ["README.tpl", ".travis.yml"]
- [dependencies]
- fnv = "1.0.5"
- nom = "1.0.0"
- -serde = { version = "1", optional = true }
- +serde = { version = "1.0.136", optional = true }
-
- [dev-dependencies]
- -gnuplot = "0.0.23"
- -serde_test = "1"
- +gnuplot = "0.0.37"
- +serde_test = "1.0.136"
- serde_derive = "1"
- serde_json = "1"
- -toml = "0.4.5"
- +toml = "0.5.8"
-
- [features]
- default = []
- From 978dbcf905bd7d051079e4bc197d75ebd8c9c162 Mon Sep 17 00:00:00 2001
- From: Ishaan <whthownothing@gmail.com>
- Date: Fri, 21 Jan 2022 20:53:17 +0530
- Subject: [PATCH 02/10] removed depracation warnings and substituted
- ---
- src/expr.rs | 26 +++++++++++++-------------
- src/lib.rs | 18 ++++--------------
- src/tokenizer.rs | 11 +++++------
- 3 files changed, 22 insertions(+), 33 deletions(-)
- diff --git a/src/expr.rs b/src/expr.rs
- index 23d56ce..f6b303c 100644
- --- a/src/expr.rs
- +++ b/src/expr.rs
- @@ -156,7 +156,7 @@ impl Expr {
- where
- C: ContextProvider + 'a,
- {
- - try!(self.check_context(((var, 0.), &ctx)));
- + self.check_context(((var, 0.), &ctx))?;
- let var = var.to_owned();
- Ok(move |x| {
- self.eval_with_context(((&var, x), &ctx))
- @@ -194,7 +194,7 @@ impl Expr {
- where
- C: ContextProvider + 'a,
- {
- - try!(self.check_context(([(var1, 0.), (var2, 0.)], &ctx)));
- + self.check_context(([(var1, 0.), (var2, 0.)], &ctx))?;
- let var1 = var1.to_owned();
- let var2 = var2.to_owned();
- Ok(move |x, y| {
- @@ -239,7 +239,7 @@ impl Expr {
- where
- C: ContextProvider + 'a,
- {
- - try!(self.check_context(([(var1, 0.), (var2, 0.), (var3, 0.)], &ctx)));
- + self.check_context(([(var1, 0.), (var2, 0.), (var3, 0.)], &ctx))?;
- let var1 = var1.to_owned();
- let var2 = var2.to_owned();
- let var3 = var3.to_owned();
- @@ -287,7 +287,7 @@ impl Expr {
- where
- C: ContextProvider + 'a,
- {
- - try!(self.check_context(([(var1, 0.), (var2, 0.), (var3, 0.), (var4, 0.)], &ctx)));
- + self.check_context(([(var1, 0.), (var2, 0.), (var3, 0.), (var4, 0.)], &ctx))?;
- let var1 = var1.to_owned();
- let var2 = var2.to_owned();
- let var3 = var3.to_owned();
- @@ -338,10 +338,10 @@ impl Expr {
- where
- C: ContextProvider + 'a,
- {
- - try!(self.check_context((
- + self.check_context((
- [(var1, 0.), (var2, 0.), (var3, 0.), (var4, 0.), (var5, 0.)],
- &ctx
- - )));
- + ))?;
- let var1 = var1.to_owned();
- let var2 = var2.to_owned();
- let var3 = var3.to_owned();
- @@ -389,12 +389,12 @@ impl Expr {
- C: ContextProvider + 'a,
- {
- let n = vars.len();
- - try!(self.check_context((
- + self.check_context((
- vars.into_iter()
- .zip(vec![0.; n].into_iter())
- .collect::<Vec<_>>(),
- &ctx
- - )));
- + ))?;
- let vars = vars.iter().map(|v| v.to_owned()).collect::<Vec<_>>();
- Ok(move |x: &[f64]| {
- self.eval_with_context((
- @@ -447,7 +447,7 @@ impl Expr {
-
- /// Evaluates a string with built-in constants and functions.
- pub fn eval_str<S: AsRef<str>>(expr: S) -> Result<f64, Error> {
- - let expr = try!(Expr::from_str(expr.as_ref()));
- + let expr = Expr::from_str(expr.as_ref())?;
-
- expr.eval_with_context(builtin())
- }
- @@ -456,9 +456,9 @@ impl FromStr for Expr {
- type Err = Error;
- /// Constructs an expression by parsing a string.
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- - let tokens = try!(tokenize(s));
- + let tokens = tokenize(s)?;
-
- - let rpn = try!(to_rpn(&tokens));
- + let rpn = to_rpn(&tokens)?;
-
- Ok(Expr { rpn: rpn })
- }
- @@ -471,7 +471,7 @@ pub fn eval_str_with_context<S: AsRef<str>, C: ContextProvider>(
- expr: S,
- ctx: C,
- ) -> Result<f64, Error> {
- - let expr = try!(Expr::from_str(expr.as_ref()));
- + let expr = Expr::from_str(expr.as_ref())?;
-
- expr.eval_with_context(ctx)
- }
- @@ -856,7 +856,7 @@ impl<'a> Default for Context<'a> {
- }
- }
-
- -type GuardedFunc<'a> = Rc<Fn(&[f64]) -> Result<f64, FuncEvalError> + 'a>;
- +type GuardedFunc<'a> = Rc<dyn Fn(&[f64]) -> Result<f64, FuncEvalError> + 'a>;
-
- /// Trait for types that can specify the number of required arguments for a function with a
- /// variable number of arguments.
- diff --git a/src/lib.rs b/src/lib.rs
- index 2aea3b7..0c8d20d 100644
- --- a/src/lib.rs
- +++ b/src/lib.rs
- @@ -233,15 +233,15 @@ impl fmt::Display for Error {
- write!(f, "Evaluation error: function `{}`: {}", name, e)
- }
- Error::ParseError(ref e) => {
- - try!(write!(f, "Parse error: "));
- + write!(f, "Parse error: ")?;
- e.fmt(f)
- }
- Error::RPNError(ref e) => {
- - try!(write!(f, "RPN error: "));
- + write!(f, "RPN error: ")?;
- e.fmt(f)
- }
- Error::EvalError(ref e) => {
- - try!(write!(f, "Eval error: "));
- + write!(f, "Eval error: ")?;
- e.fmt(f)
- }
- }
- @@ -261,17 +261,7 @@ impl From<RPNError> for Error {
- }
-
- impl std::error::Error for Error {
- - fn description(&self) -> &str {
- - match *self {
- - Error::UnknownVariable(_) => "unknown variable",
- - Error::Function(_, _) => "function evaluation error",
- - Error::EvalError(_) => "eval error",
- - Error::ParseError(ref e) => e.description(),
- - Error::RPNError(ref e) => e.description(),
- - }
- - }
- -
- - fn cause(&self) -> Option<&std::error::Error> {
- + fn cause(&self) -> Option<&dyn std::error::Error> {
- match *self {
- Error::ParseError(ref e) => Some(e),
- Error::RPNError(ref e) => Some(e),
- diff --git a/src/tokenizer.rs b/src/tokenizer.rs
- index d4692e3..f63fcf3 100644
- --- a/src/tokenizer.rs
- +++ b/src/tokenizer.rs
- @@ -5,8 +5,7 @@
- //! The parser should tokenize only well-formed expressions.
- //!
- //! [nom]: https://crates.io/crates/nom
- -use nom::{multispace, slice_to_offsets, IResult, Needed};
- -use std;
- +use nom::{Needed, multispace, slice_to_offsets, IResult};
- use std::fmt;
- use std::str::from_utf8;
-
- @@ -117,16 +116,16 @@ named!(comma<Token>, chain!(tag!(","), || Token::Comma));
- fn ident(input: &[u8]) -> IResult<&[u8], &[u8]> {
- use nom::Err::*;
- use nom::IResult::*;
- - use nom::{ErrorKind, Needed};
- + use nom::ErrorKind;
-
- // first character must be 'a'...'z' | 'A'...'Z' | '_'
- match input.first().cloned() {
- - Some(b'a'...b'z') | Some(b'A'...b'Z') | Some(b'_') => {
- + Some(b'a'..=b'z') | Some(b'A'..=b'Z') | Some(b'_') => {
- let n = input
- .iter()
- .skip(1)
- .take_while(|&&c| match c {
- - b'a'...b'z' | b'A'...b'Z' | b'_' | b'0'...b'9' => true,
- + b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9' => true,
- _ => false,
- })
- .count();
- @@ -145,7 +144,7 @@ named!(
- ))
- );
-
- -/// Parse `func(`, returns `func`.
- +// Parse `func(`, returns `func`.
- named!(
- func<Token>,
- map!(
- From 9cd8b3dd90acfa6281e0c326719de6cbf532fa7f Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 10:21:33 -0500
- Subject: [PATCH 03/10] bump even more dependencies
- ---
- Cargo.toml | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
- diff --git a/Cargo.toml b/Cargo.toml
- index c395833..2cc0eb4 100644
- --- a/Cargo.toml
- +++ b/Cargo.toml
- @@ -12,15 +12,15 @@ version = "0.2.0"
- exclude = ["README.tpl", ".travis.yml"]
-
- [dependencies]
- -fnv = "1.0.5"
- +fnv = "1.0.7"
- nom = "1.0.0"
- serde = { version = "1.0.136", optional = true }
-
- [dev-dependencies]
- gnuplot = "0.0.37"
- serde_test = "1.0.136"
- -serde_derive = "1"
- -serde_json = "1"
- +serde_derive = "1.0.136"
- +serde_json = "1.0.79"
- toml = "0.5.8"
-
- [features]
- From 595ea70b5901d48bd119e9d98aa1e84849ec1945 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 10:34:18 -0500
- Subject: [PATCH 04/10] nom 7.1.0
- based on work from: https://github.com/rekka/meval-rs/pull/22
- ---
- Cargo.toml | 2 +-
- src/lib.rs | 8 +-
- src/shunting_yard.rs | 1 +
- src/tokenizer.rs | 749 ++++++++++++++++++++++++++++---------------
- 4 files changed, 496 insertions(+), 264 deletions(-)
- diff --git a/Cargo.toml b/Cargo.toml
- index 2cc0eb4..60b4064 100644
- --- a/Cargo.toml
- +++ b/Cargo.toml
- @@ -13,7 +13,7 @@ exclude = ["README.tpl", ".travis.yml"]
-
- [dependencies]
- fnv = "1.0.7"
- -nom = "1.0.0"
- +nom = "7.1.0"
- serde = { version = "1.0.136", optional = true }
-
- [dev-dependencies]
- diff --git a/src/lib.rs b/src/lib.rs
- index 0c8d20d..69261b1 100644
- --- a/src/lib.rs
- +++ b/src/lib.rs
- @@ -208,7 +208,7 @@ pub mod de;
-
- pub use expr::*;
- pub use shunting_yard::RPNError;
- -pub use tokenizer::ParseError;
- +pub use tokenizer::TokenParseError;
-
- /// An error produced during parsing or evaluation.
- #[derive(Debug, Clone, PartialEq)]
- @@ -216,7 +216,7 @@ pub enum Error {
- UnknownVariable(String),
- Function(String, FuncEvalError),
- /// An error returned by the parser.
- - ParseError(ParseError),
- + ParseError(TokenParseError),
- /// The shunting-yard algorithm returned an error.
- RPNError(RPNError),
- // A catch all for all other errors during evaluation
- @@ -248,8 +248,8 @@ impl fmt::Display for Error {
- }
- }
-
- -impl From<ParseError> for Error {
- - fn from(err: ParseError) -> Error {
- +impl From<TokenParseError> for Error {
- + fn from(err: TokenParseError) -> Error {
- Error::ParseError(err)
- }
- }
- diff --git a/src/shunting_yard.rs b/src/shunting_yard.rs
- index 5fe3010..90026bf 100644
- --- a/src/shunting_yard.rs
- +++ b/src/shunting_yard.rs
- @@ -1,3 +1,4 @@
- +
- //! Implementation of the shunting-yard algorithm for converting an infix expression to an
- //! expression in reverse Polish notation (RPN).
- //!
- diff --git a/src/tokenizer.rs b/src/tokenizer.rs
- index f63fcf3..0e08337 100644
- --- a/src/tokenizer.rs
- +++ b/src/tokenizer.rs
- @@ -5,44 +5,66 @@
- //! The parser should tokenize only well-formed expressions.
- //!
- //! [nom]: https://crates.io/crates/nom
- -use nom::{Needed, multispace, slice_to_offsets, IResult};
- +
- +use nom::{
- + branch::alt,
- + bytes::complete::is_a,
- + bytes::complete::{escaped, take, tag, take_while},
- + character::complete::{anychar, digit1, multispace0, alphanumeric1, alphanumeric0, char, alpha1, one_of},
- + combinator::{complete, peek, all_consuming, recognize, map, opt, cut, not},
- + error::{context, convert_error, ErrorKind, ParseError, VerboseError},
- + multi::separated_list0,
- + number::complete::double,
- + sequence::{tuple, pair, delimited, preceded, separated_pair, terminated},
- + Err, Needed, IResult
- +};
- +
- use std::fmt;
- use std::str::from_utf8;
- +use std::f64;
-
- /// An error reported by the parser.
- #[derive(Debug, Clone, PartialEq)]
- -pub enum ParseError {
- +pub enum TokenParseError {
- /// A token that is not allowed at the given location (contains the location of the offending
- /// character in the source string).
- UnexpectedToken(usize),
- +
- + UnexpectedStrToken(String),
- /// Missing right parentheses at the end of the source string (contains the number of missing
- /// parens).
- MissingRParen(i32),
- /// Missing operator or function argument at the end of the expression.
- MissingArgument,
- +
- + UnknownError
- }
-
- -impl fmt::Display for ParseError {
- +impl fmt::Display for TokenParseError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- - match *self {
- - ParseError::UnexpectedToken(i) => write!(f, "Unexpected token at byte {}.", i),
- - ParseError::MissingRParen(i) => write!(
- + match &*self {
- + TokenParseError::UnexpectedToken(i) => write!(f, "Unexpected token at byte {}.", i),
- + TokenParseError::UnexpectedStrToken(s) => write!(f, "Unexpected token {}.", s),
- + TokenParseError::MissingRParen(i) => write!(
- f,
- "Missing {} right parenthes{}.",
- i,
- - if i == 1 { "is" } else { "es" }
- + if *i == 1 { "is" } else { "es" }
- ),
- - ParseError::MissingArgument => write!(f, "Missing argument at the end of expression."),
- + TokenParseError::MissingArgument => write!(f, "Missing argument at the end of expression."),
- + TokenParseError::UnknownError => write!(f, "Unknown pass error."),
- }
- }
- }
-
- -impl std::error::Error for ParseError {
- +impl std::error::Error for TokenParseError {
- fn description(&self) -> &str {
- match *self {
- - ParseError::UnexpectedToken(_) => "unexpected token",
- - ParseError::MissingRParen(_) => "missing right parenthesis",
- - ParseError::MissingArgument => "missing argument",
- + TokenParseError::UnexpectedToken(_) => "unexpected token",
- + TokenParseError::UnexpectedStrToken(_) => "Unexpected token",
- + TokenParseError::MissingRParen(_) => "missing right parenthesis",
- + TokenParseError::MissingArgument => "missing argument",
- + TokenParseError::UnknownError => "unknown error",
- }
- }
- }
- @@ -73,6 +95,8 @@ pub enum Token {
- RParen,
- /// Comma: function argument separator
- Comma,
- + /// Decimal Point
- + //DecimalPoint,
-
- /// A number.
- Number(f64),
- @@ -82,179 +106,150 @@ pub enum Token {
- Func(String, Option<usize>),
- }
-
- -named!(
- - binop<Token>,
- - alt!(
- - chain!(tag!("+"), || Token::Binary(Operation::Plus))
- - | chain!(tag!("-"), || Token::Binary(Operation::Minus))
- - | chain!(tag!("*"), || Token::Binary(Operation::Times))
- - | chain!(tag!("/"), || Token::Binary(Operation::Div))
- - | chain!(tag!("%"), || Token::Binary(Operation::Rem))
- - | chain!(tag!("^"), || Token::Binary(Operation::Pow))
- - )
- -);
- -
- -named!(
- - negpos<Token>,
- - alt!(
- - chain!(tag!("+"), || Token::Unary(Operation::Plus))
- - | chain!(tag!("-"), || Token::Unary(Operation::Minus))
- - )
- -);
- -
- -named!(
- - fact<Token>,
- - chain!(tag!("!"), || Token::Unary(Operation::Fact))
- -);
- -named!(lparen<Token>, chain!(tag!("("), || Token::LParen));
- -named!(rparen<Token>, chain!(tag!(")"), || Token::RParen));
- -named!(comma<Token>, chain!(tag!(","), || Token::Comma));
- -
- -/// Parse an identifier:
- -///
- -/// Must start with a letter or an underscore, can be followed by letters, digits or underscores.
- -fn ident(input: &[u8]) -> IResult<&[u8], &[u8]> {
- - use nom::Err::*;
- - use nom::IResult::*;
- - use nom::ErrorKind;
- -
- - // first character must be 'a'...'z' | 'A'...'Z' | '_'
- - match input.first().cloned() {
- - Some(b'a'..=b'z') | Some(b'A'..=b'Z') | Some(b'_') => {
- - let n = input
- - .iter()
- - .skip(1)
- - .take_while(|&&c| match c {
- - b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9' => true,
- - _ => false,
- - })
- - .count();
- - let (parsed, rest) = input.split_at(n + 1);
- - Done(rest, parsed)
- - }
- - None => Incomplete(Needed::Size(1)),
- - _ => Error(Position(ErrorKind::Custom(0), input)),
- - }
- +/// Continuing the trend of starting from the simplest piece and building up,
- +/// we start by creating a parser for the built-in operator functions.
- +fn binop<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + // one_of matches one of the characters we give it
- + let (i, t) = one_of("+-*/%^!")(i)?;
- +
- + // because we are matching single character tokens, we can do the matching logic
- + // on the returned value
- + Ok((
- + i,
- + match t {
- + '+' => Token::Binary(Operation::Plus),
- + '-' => Token::Binary(Operation::Minus),
- + '*' => Token::Binary(Operation::Times),
- + '/' => Token::Binary(Operation::Div),
- + '%' => Token::Binary(Operation::Rem),
- + '^' => Token::Binary(Operation::Pow),
- + '!' => Token::Binary(Operation::Fact),
- + _ => unreachable!(),
- + },
- + ))
- }
-
- -named!(
- - var<Token>,
- - map!(map_res!(complete!(ident), from_utf8), |s: &str| Token::Var(
- - s.into()
- - ))
- -);
- -
- -// Parse `func(`, returns `func`.
- -named!(
- - func<Token>,
- - map!(
- - map_res!(
- - terminated!(
- - complete!(ident),
- - preceded!(opt!(multispace), complete!(tag!("(")))
- - ),
- - from_utf8
- - ),
- - |s: &str| Token::Func(s.into(), None)
- - )
- -);
- +fn lparen<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(tag("("), |_: &str| Token::LParen)(i)
- +}
-
- -/// Matches one or more digit characters `0`...`9`.
- -///
- -/// Never returns `nom::IResult::Incomplete`.
- -///
- -/// Fix of IMHO broken `nom::digit`, which parses an empty string successfully.
- -fn digit_complete(input: &[u8]) -> IResult<&[u8], &[u8]> {
- - use nom::Err::*;
- - use nom::IResult::*;
- - use nom::{is_digit, ErrorKind};
- -
- - let n = input.iter().take_while(|&&c| is_digit(c)).count();
- - if n > 0 {
- - let (parsed, rest) = input.split_at(n);
- - Done(rest, parsed)
- - } else {
- - Error(Position(ErrorKind::Digit, input))
- +fn rparen<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(tag(")"), |_: &str| Token::RParen)(i)
- +}
- +
- +fn comma<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(tag(","), |_: &str| Token::Comma)(i)
- +}
- +
- +/// negpos parse. detects either - or +
- +fn negpos_s<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- +
- + match alt((tag("+"), tag("-"), ))(i) {
- + Ok((remaining_input, operator)) => Ok((remaining_input, operator)),
- + Err(e) => Err(e)
- }
- }
-
- -named!(
- - float<usize>,
- - chain!(
- - a: digit_complete ~
- - b: complete!(chain!(tag!(".") ~ d: digit_complete?,
- - ||{1 + d.map(|s| s.len()).unwrap_or(0)}))? ~
- - e: complete!(exp),
- - ||{a.len() + b.unwrap_or(0) + e.unwrap_or(0)}
- - )
- -);
- -
- -/// Parser that matches the exponential part of a float. If the `input[0] == 'e' | 'E'` then at
- -/// least one digit must match.
- -fn exp(input: &[u8]) -> IResult<&[u8], Option<usize>> {
- - use nom::IResult::*;
- - match alt!(input, tag!("e") | tag!("E")) {
- - Incomplete(_) | Error(_) => Done(input, None),
- - Done(i, _) => match chain!(i, s: alt!(tag!("+") | tag!("-"))? ~
- - e: digit_complete,
- - ||{Some(1 + s.map(|s| s.len()).unwrap_or(0) + e.len())})
- - {
- - Incomplete(Needed::Size(i)) => Incomplete(Needed::Size(i + 1)),
- - o => o,
- +/// negpos parse. detects either - or +
- +fn negpos<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- +
- + match negpos_s(i) {
- + Ok((remaining_input, operator)) => {
- + match operator.as_ref() {
- + "+" => Ok((remaining_input, Token::Unary(Operation::Plus))),
- + "-" => Ok((remaining_input, Token::Unary(Operation::Minus))),
- + _ => panic!("Should never occur")
- + }
- },
- + Err(e) => Err(e)
- }
- }
-
- -fn number(input: &[u8]) -> IResult<&[u8], Token> {
- - use nom::Err;
- - use nom::ErrorKind;
- - use nom::IResult::*;
- - use std::str::FromStr;
- -
- - match float(input) {
- - Done(rest, l) => {
- - // it should be safe to call unwrap here instead of the error checking, since
- - // `float` should match only well-formed numbers
- - from_utf8(&input[..l])
- - .ok()
- - .and_then(|s| f64::from_str(s).ok())
- - .map_or(Error(Err::Position(ErrorKind::Custom(0), input)), |f| {
- - Done(rest, Token::Number(f))
- - })
- - }
- - Error(e) => Error(e),
- - Incomplete(n) => Incomplete(n),
- - }
- +/// factorial parse
- +fn fact<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(tag("!"), |s: &str| Token::Unary(Operation::Fact))(i)
- }
-
- -named!(
- - lexpr<Token>,
- - delimited!(
- - opt!(multispace),
- - alt!(number | func | var | negpos | lparen),
- - opt!(multispace)
- - )
- -);
- -named!(
- - after_rexpr<Token>,
- - delimited!(
- - opt!(multispace),
- - alt!(fact | binop | rparen),
- - opt!(multispace)
- - )
- -);
- -named!(
- - after_rexpr_no_paren<Token>,
- - delimited!(opt!(multispace), alt!(fact | binop), opt!(multispace))
- -);
- -named!(
- - after_rexpr_comma<Token>,
- - delimited!(
- - opt!(multispace),
- - alt!(fact | binop | rparen | comma),
- - opt!(multispace)
- - )
- -);
- +fn ident<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- + let REMAINING_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- + let FIRST_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- +
- + // Returns whole strings matched by the given parser.
- + recognize(
- + // Runs the first parser, if succeeded then runs second, and returns the second result.
- + // Note that returned ok value of `preceded()` is ignored by `recognize()`.
- + preceded(
- + // Parses a single character contained in the given string.
- + one_of(FIRST_CHARS),
- + // Parses the longest slice consisting of the given characters
- + opt(is_a(REMAINING_CHARS)),
- + )
- + )(i)
- + }
- +
- +fn var<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(complete(ident), |s: &str| Token::Var(s.into()))(i)
- +}
- +
- +/// Parse `func(`, returns `func`.
- +fn func<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + map(
- + //recognize(
- + terminated(
- + complete(ident),
- + preceded(multispace0,
- + complete(tag("("))
- + )
- + )
- + //)
- + ,
- + |s: &str| Token::Func(s.into(), None)
- + )(i)
- +}
- +
- +fn number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- + preceded(
- + peek(one_of("0123456789")),
- + map(double, |s| Token::Number(s))
- + )(i)
- +}
- +
- +fn lexpr<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- +
- + delimited(
- + multispace0,
- + alt((number, func, var, negpos, lparen)),
- + multispace0
- + )(i)
- +}
- +
- +
- +fn after_rexpr<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- +
- + delimited(
- + multispace0,
- + alt((fact, binop, rparen)),
- + multispace0
- + )(i)
- +}
- +
- +fn after_rexpr_no_paren<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- +
- + delimited(
- + multispace0,
- + alt((fact, binop)),
- + multispace0
- + )(i)
- +}
- +
- +fn after_rexpr_comma<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- +
- + delimited(
- + multispace0,
- + alt((fact, binop, rparen, comma)),
- + multispace0
- + )(i)
- +}
-
- #[derive(Debug, Clone, Copy)]
- enum TokenizerState {
- @@ -270,6 +265,7 @@ enum ParenState {
- Func,
- }
-
- +
- /// Tokenize a given mathematical expression.
- ///
- /// The parser should return `Ok` only if the expression is well-formed.
- @@ -277,29 +273,27 @@ enum ParenState {
- /// # Failure
- ///
- /// Returns `Err` if the expression is not well-formed.
- -pub fn tokenize<S: AsRef<str>>(input: S) -> Result<Vec<Token>, ParseError> {
- - use self::TokenizerState::*;
- - use nom::Err;
- - use nom::IResult::*;
- - let mut state = LExpr;
- +pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- + let mut state: TokenizerState = TokenizerState::LExpr;
- // number of function arguments left
- let mut paren_stack = vec![];
-
- let mut res = vec![];
-
- - let input = input.as_ref().as_bytes();
- let mut s = input;
-
- while !s.is_empty() {
- +
- let r = match (state, paren_stack.last()) {
- - (LExpr, _) => lexpr(s),
- - (AfterRExpr, None) => after_rexpr_no_paren(s),
- - (AfterRExpr, Some(&ParenState::Subexpr)) => after_rexpr(s),
- - (AfterRExpr, Some(&ParenState::Func)) => after_rexpr_comma(s),
- + (TokenizerState::LExpr, _) => lexpr(s),
- + (TokenizerState::AfterRExpr, None) => after_rexpr_no_paren(s),
- + (TokenizerState::AfterRExpr, Some(&ParenState::Subexpr)) => after_rexpr(s),
- + (TokenizerState::AfterRExpr, Some(&ParenState::Func)) => after_rexpr_comma(s),
- };
-
- match r {
- - Done(rest, t) => {
- + Ok((rest, t)) => {
- +
- match t {
- Token::LParen => {
- paren_stack.push(ParenState::Subexpr);
- @@ -311,133 +305,366 @@ pub fn tokenize<S: AsRef<str>>(input: S) -> Result<Vec<Token>, ParseError> {
- paren_stack.pop().expect("The paren_stack is empty!");
- }
- Token::Var(_) | Token::Number(_) => {
- - state = AfterRExpr;
- + state = TokenizerState::AfterRExpr;
- }
- Token::Binary(_) | Token::Comma => {
- - state = LExpr;
- + state = TokenizerState::LExpr;
- }
- _ => {}
- }
- res.push(t);
- s = rest;
- }
- - Error(Err::Position(_, p)) => {
- - let (i, _) = slice_to_offsets(input, p);
- - return Err(ParseError::UnexpectedToken(i));
- + Err(e) => {
- +
- + match e {
- + Err::Error((value, _)) => {
- + return Err(TokenParseError::UnexpectedStrToken(value.to_string()));
- + },
- + _ => (),
- + }
- +
- + return Err(TokenParseError::UnknownError);
- }
- + // Error(Err::Position(_, p)) => {
- + // let (i, _) = slice_to_offsets(input, p);
- + // return Err(TokenParseError::UnexpectedToken(i));
- + // }
- _ => {
- - panic!(
- - "Unexpected parse result when parsing `{}` at `{}`: {:?}",
- - String::from_utf8_lossy(input),
- - String::from_utf8_lossy(s),
- - r
- - );
- + panic!("Unexpected parse result when parsing `{}` at `{}`: {:?}", input, s, r);
- }
- }
- +
- }
-
- match state {
- - LExpr => Err(ParseError::MissingArgument),
- - _ if !paren_stack.is_empty() => Err(ParseError::MissingRParen(paren_stack.len() as i32)),
- - _ => Ok(res),
- + TokenizerState::LExpr => {
- + Err(TokenParseError::MissingArgument)
- + },
- +
- + _ => {
- + if !paren_stack.is_empty() {
- + return Err(TokenParseError::MissingRParen(paren_stack.len() as i32));
- + }
- +
- + return Ok(res);
- + }
- }
- +
- +
- }
-
- +
- +
- +
- +// ok rest ["+(3--2) "] t Number(2.0)
- +// ok rest ["(3--2) "] t Binary(Plus)
- +// ok rest [51, 45, 45, 50, 41, 32] t LParen
- +// ok rest [45, 45, 50, 41, 32] t Number(3.0)
- +// ok rest [45, 50, 41, 32] t Binary(Minus)
- +// ok rest [50, 41, 32] t Unary(Minus)
- +// ok rest [") "] t Number(2.0)
- +// ok rest [] t RParen
- +// state: AfterRExpr
- +// paren_stack: []
- +// Ok([Number(2.0), Binary(Plus), LParen, Number(3.0), Binary(Minus), Unary(Minus), Number(2.0), RParen])
- +
- +
- #[cfg(test)]
- mod tests {
- use super::*;
- - use super::{binop, func, number, var};
- - use nom::Err::*;
- - use nom::ErrorKind::*;
- - use nom::IResult;
- -
- +
- #[test]
- fn it_works() {
- +
- + assert_eq!(
- + binop("+"),
- + Ok(("", Token::Binary(Operation::Plus)))
- + );
- + assert_eq!(
- + ident("abc32"),
- + Ok(("", "abc32"))
- + );
- + assert_eq!(
- + func("abc("),
- + Ok(("", Token::Func("abc".into(), None)))
- + );
- + assert_eq!(
- + func("abc ("),
- + Ok(("", Token::Func("abc".into(), None)))
- + );
- + assert_eq!(
- + var("abc"),
- + Ok(("", Token::Var("abc".into())))
- + );
- + assert_eq!(
- + fact("!"),
- + Ok(("", Token::Unary(Operation::Fact)))
- + );
- + assert_eq!(
- + negpos_s("+"),
- + Ok(("", "+"))
- + );
- + assert_eq!(
- + negpos_s("-"),
- + Ok(("", "-"))
- + );
- + assert_eq!(
- + negpos_s("+362"),
- + Ok(("362", "+"))
- + );
- + assert_eq!(
- + negpos_s("-5734"),
- + Ok(("5734", "-"))
- + );
- + assert_eq!(
- + negpos("+"),
- + Ok(("", Token::Unary(Operation::Plus)))
- + );
- + assert_eq!(
- + negpos("-"),
- + Ok(("", Token::Unary(Operation::Minus)))
- + );
- + assert_eq!(
- + negpos("+642"),
- + Ok(("642", Token::Unary(Operation::Plus)))
- + );
- + assert_eq!(
- + negpos("-563"),
- + Ok(("563", Token::Unary(Operation::Minus)))
- + );
- + assert_eq!(
- + lparen("("),
- + Ok(("", Token::LParen))
- + );
- + assert_eq!(
- + rparen(")"),
- + Ok(("", Token::RParen))
- + );
- + assert_eq!(
- + comma(","),
- + Ok(("", Token::Comma))
- + );
- assert_eq!(
- - binop(b"+"),
- - IResult::Done(&b""[..], Token::Binary(Operation::Plus))
- + comma(","),
- + Ok(("", Token::Comma))
- );
- assert_eq!(
- - number(b"32143"),
- - IResult::Done(&b""[..], Token::Number(32143f64))
- + number("+1.34e2"),
- + Ok(("", Token::Number(134.0)))
- );
- assert_eq!(
- - var(b"abc"),
- - IResult::Done(&b""[..], Token::Var("abc".into()))
- + number("+1.34e+2"),
- + Ok(("", Token::Number(134.0)))
- );
- assert_eq!(
- - func(b"abc("),
- - IResult::Done(&b""[..], Token::Func("abc".into(), None))
- + number("3E+2"),
- + Ok(("", Token::Number(300.0)))
- );
- assert_eq!(
- - func(b"abc ("),
- - IResult::Done(&b""[..], Token::Func("abc".into(), None))
- + number("+4E+2"),
- + Ok(("", Token::Number(400.0)))
- + );
- + assert_eq!(
- + number("-4.76E+2"),
- + Ok(("", Token::Number(-476.0)))
- + );
- + assert_eq!(
- + number("-4.76"),
- + Ok(("", Token::Number(-4.76)))
- + );
- + assert_eq!(
- + number("+4.76"),
- + Ok(("", Token::Number(4.76)))
- + );
- + assert_eq!(
- + number("1.1"),
- + Ok(("", Token::Number(1.1)))
- + );
- + assert_eq!(
- + number("-1.1"),
- + Ok(("", Token::Number(-1.1)))
- + );
- + assert_eq!(
- + number("123E-02"),
- + Ok(("", Token::Number(1.23)))
- + );
- + assert_eq!(
- + number("+123E-02"),
- + Ok(("", Token::Number(1.23)))
- + );
- + assert_eq!(
- + number("-123E-02"),
- + Ok(("", Token::Number(-1.23)))
- + );
- + assert_eq!(
- + number("abc"),
- + Err(Err::Error(("abc", nom::error::ErrorKind::Float)))
- );
- }
-
- #[test]
- - fn test_var() {
- - for &s in ["abc", "U0", "_034", "a_be45EA", "aAzZ_"].iter() {
- - assert_eq!(
- - var(s.as_bytes()),
- - IResult::Done(&b""[..], Token::Var(s.into()))
- - );
- - }
- + fn test_lexpr() {
- +
- + // number, func, var, negpos, lparen
- + assert_eq!(
- + number("a"),
- + Err(Err::Error(("a", nom::error::ErrorKind::Float)))
- + );
- +
- + assert_eq!(
- + func("a"),
- + Err(Err::Error(("", nom::error::ErrorKind::Tag)))
- + );
- +
- + assert_eq!(
- + var("a"),
- + Ok(("", Token::Var("a".into())))
- + );
- +
- + assert_eq!(
- + lexpr("a"),
- + Ok(("", Token::Var("a".into())))
- + );
- +
- + assert_eq!(
- + lexpr("2+"),
- + Ok(("+", Token::Number(2.0)))
- + );
- +
- + assert_eq!(
- + lexpr("2 +(3--2) "),
- + Ok(("+(3--2) ", Token::Number(2.0)))
- + );
- +
- +
- + println!("{:?}", number("+(3--2) "));
- +
- + assert_eq!(
- + lexpr("+(3--2) "),
- + Ok(("+(3--2) ", Token::Binary(Operation::Plus)))
- + );
-
- - assert_eq!(var(b""), IResult::Error(Position(Complete, &b""[..])));
- - assert_eq!(var(b"0"), IResult::Error(Position(Custom(0), &b"0"[..])));
- }
-
- #[test]
- - fn test_func() {
- - for &s in ["abc(", "u0(", "_034 (", "A_be45EA ("].iter() {
- + fn test_var() {
- + for &s in ["abc", "U0", "_034", "a_be45EA", "aAzZ_"].iter() {
- assert_eq!(
- - func(s.as_bytes()),
- - IResult::Done(
- - &b""[..],
- - Token::Func((&s[0..s.len() - 1]).trim().into(), None)
- - )
- + var(s),
- + Ok(("", Token::Var(s.into())))
- );
- }
-
- - assert_eq!(func(b""), IResult::Error(Position(Complete, &b""[..])));
- - assert_eq!(func(b"("), IResult::Error(Position(Custom(0), &b"("[..])));
- - assert_eq!(func(b"0("), IResult::Error(Position(Custom(0), &b"0("[..])));
- + assert_eq!(var(""), Err(Err::Error(("", nom::error::ErrorKind::OneOf))));
- + assert_eq!(var("0"), Err(Err::Error(("0", nom::error::ErrorKind::OneOf))));
- }
-
- #[test]
- fn test_number() {
- +
- + assert_eq!(
- + number("45"),
- + Ok(("", Token::Number(45.0)))
- + );
- +
- + assert_eq!(
- + number("+(3--2) "),
- + Err(Err::Error(("+(3--2) ", nom::error::ErrorKind::OneOf)))
- + );
- +
- + assert_eq!(
- + number("+3 "),
- + Err(Err::Error(("+3 ", nom::error::ErrorKind::OneOf)))
- + );
- +
- assert_eq!(
- - number(b"32143"),
- - IResult::Done(&b""[..], Token::Number(32143f64))
- + number("(3--2) "),
- + Err(Err::Error(("(3--2) ", nom::error::ErrorKind::OneOf)))
- + );
- +
- + assert_eq!(
- + number("(3) "),
- + Err(Err::Error(("(3) ", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + number("(3) - (2) "),
- + Err(Err::Error(("(3) - (2) ", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + number("32143"),
- + Ok(("", Token::Number(32143f64)))
- + );
- + assert_eq!(
- + number("2."),
- + Ok(("", Token::Number(2.0f64)))
- );
- assert_eq!(
- - number(b"2."),
- - IResult::Done(&b""[..], Token::Number(2.0f64))
- + number("32143.25"),
- + Ok(("", Token::Number(32143.25f64)))
- );
- assert_eq!(
- - number(b"32143.25"),
- - IResult::Done(&b""[..], Token::Number(32143.25f64))
- + number("0.125e9"),
- + Ok(("", Token::Number(0.125e9f64)))
- );
- assert_eq!(
- - number(b"0.125e9"),
- - IResult::Done(&b""[..], Token::Number(0.125e9f64))
- + number("20.5E-3"),
- + Ok(("", Token::Number(20.5E-3f64)))
- );
- assert_eq!(
- - number(b"20.5E-3"),
- - IResult::Done(&b""[..], Token::Number(20.5E-3f64))
- + number("123423e+50"),
- + Ok(("", Token::Number(123423e+50f64)))
- );
- assert_eq!(
- - number(b"123423e+50"),
- - IResult::Done(&b""[..], Token::Number(123423e+50f64))
- + number("0.2"),
- + Ok(("", Token::Number(0.2)))
- );
- + assert_eq!(
- + number(""),
- + Err(Err::Error(("", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + number("+"),
- + Err(Err::Error(("+", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + number("e"),
- + Err(Err::Error(("e", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + number("1E"),
- + Err(Err::Error(("E", nom::error::ErrorKind::Eof)))
- + );
- + assert_eq!(
- + number("1e"),
- + Err(Err::Error(("e", nom::error::ErrorKind::Eof)))
- + );
- + assert_eq!(
- + number("1e+"),
- + Err(Err::Error(("+", nom::error::ErrorKind::Eof)))
- + );
- + assert_eq!(
- + number("1e+-?%"),
- + Err(Err::Error(("-?%", nom::error::ErrorKind::Eof)))
- + );
- + assert_eq!(
- + number("2+"),
- + Err(Err::Error(("+", nom::error::ErrorKind::Eof)))
- + );
- + }
-
- - assert_eq!(number(b""), IResult::Error(Position(Digit, &b""[..])));
- - assert_eq!(number(b".2"), IResult::Error(Position(Digit, &b".2"[..])));
- - assert_eq!(number(b"+"), IResult::Error(Position(Digit, &b"+"[..])));
- - assert_eq!(number(b"e"), IResult::Error(Position(Digit, &b"e"[..])));
- - assert_eq!(number(b"1E"), IResult::Error(Position(Complete, &b"E"[..])));
- - assert_eq!(number(b"1e+"), IResult::Error(Position(Digit, &b""[..])));
- + #[test]
- + fn test_func() {
- + for &s in ["abc(", "u0(", "_034 (", "A_be45EA ("].iter() {
- + assert_eq!(
- + func(s),
- + Ok(("", Token::Func((&s[0..s.len() - 1]).trim().into(), None)))
- + );
- + }
- +
- + assert_eq!(func(""), Err(Err::Error(("", nom::error::ErrorKind::OneOf))));
- + assert_eq!(func("("), Err(Err::Error(("(", nom::error::ErrorKind::OneOf))));
- + assert_eq!(func("0("), Err(Err::Error(("0(", nom::error::ErrorKind::OneOf))));
- }
-
- #[test]
- @@ -445,6 +672,10 @@ mod tests {
- use super::Operation::*;
- use super::Token::*;
-
- + // Ok([Number(2.0), Binary(Plus), Number(2.0), Binary(Div), Number(3.0), Binary(Minus), Number(56.0), Binary(Plus), Func("sin", None), Number(3.0), RParen])
- + // Ok([Number(2.0), Binary(Plus), Number(2.0), Binary(Div), Number(3.0), Binary(Minus), Number(56.0), Binary(Plus), Func("sin", None), Number(3.0), RParen])
- + println!("{:?}", tokenize("2 + 2/3-56 + sin(3)"));
- +
- assert_eq!(tokenize("a"), Ok(vec![Var("a".into())]));
-
- assert_eq!(
- @@ -522,15 +753,15 @@ mod tests {
- ])
- );
-
- - assert_eq!(tokenize("!3"), Err(ParseError::UnexpectedToken(0)));
- + assert_eq!(tokenize("!3"), Err(TokenParseError::UnexpectedStrToken("!3".to_string())));
-
- - assert_eq!(tokenize("()"), Err(ParseError::UnexpectedToken(1)));
- + assert_eq!(tokenize("()"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
-
- - assert_eq!(tokenize(""), Err(ParseError::MissingArgument));
- - assert_eq!(tokenize("2)"), Err(ParseError::UnexpectedToken(1)));
- - assert_eq!(tokenize("2^"), Err(ParseError::MissingArgument));
- - assert_eq!(tokenize("(((2)"), Err(ParseError::MissingRParen(2)));
- - assert_eq!(tokenize("f(2,)"), Err(ParseError::UnexpectedToken(4)));
- - assert_eq!(tokenize("f(,2)"), Err(ParseError::UnexpectedToken(2)));
- + assert_eq!(tokenize(""), Err(TokenParseError::MissingArgument));
- + assert_eq!(tokenize("2)"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
- + assert_eq!(tokenize("2^"), Err(TokenParseError::MissingArgument));
- + assert_eq!(tokenize("(((2)"), Err(TokenParseError::MissingRParen(2)));
- + assert_eq!(tokenize("f(2,)"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
- + assert_eq!(tokenize("f(,2)"), Err(TokenParseError::UnexpectedStrToken(",2)".to_string())));
- }
- -}
- +}
- \ No newline at end of file
- From f888f42034a37f0f8a41fe88d091246ff4b8a574 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 10:39:10 -0500
- Subject: [PATCH 05/10] clippy
- ---
- src/expr.rs | 22 +++++++++++-----------
- src/extra_math.rs | 10 +++++-----
- src/tokenizer.rs | 25 ++++++++++++-------------
- 3 files changed, 28 insertions(+), 29 deletions(-)
- diff --git a/src/expr.rs b/src/expr.rs
- index f6b303c..c151756 100644
- --- a/src/expr.rs
- +++ b/src/expr.rs
- @@ -390,7 +390,7 @@ impl Expr {
- {
- let n = vars.len();
- self.check_context((
- - vars.into_iter()
- + vars.iter()
- .zip(vec![0.; n].into_iter())
- .collect::<Vec<_>>(),
- &ctx
- @@ -399,7 +399,7 @@ impl Expr {
- Ok(move |x: &[f64]| {
- self.eval_with_context((
- vars.iter()
- - .zip(x.into_iter())
- + .zip(x.iter())
- .map(|(v, x)| (v, *x))
- .collect::<Vec<_>>(),
- &ctx,
- @@ -460,7 +460,7 @@ impl FromStr for Expr {
-
- let rpn = to_rpn(&tokens)?;
-
- - Ok(Expr { rpn: rpn })
- + Ok(Expr { rpn })
- }
- }
-
- @@ -599,21 +599,21 @@ pub fn builtin<'a>() -> Context<'a> {
-
- impl<'a, T: ContextProvider> ContextProvider for &'a T {
- fn get_var(&self, name: &str) -> Option<f64> {
- - (&**self).get_var(name)
- + (**self).get_var(name)
- }
-
- fn eval_func(&self, name: &str, args: &[f64]) -> Result<f64, FuncEvalError> {
- - (&**self).eval_func(name, args)
- + (**self).eval_func(name, args)
- }
- }
-
- impl<'a, T: ContextProvider> ContextProvider for &'a mut T {
- fn get_var(&self, name: &str) -> Option<f64> {
- - (&**self).get_var(name)
- + (**self).get_var(name)
- }
-
- fn eval_func(&self, name: &str, args: &[f64]) -> Result<f64, FuncEvalError> {
- - (&**self).eval_func(name, args)
- + (**self).eval_func(name, args)
- }
- }
-
- @@ -1170,20 +1170,20 @@ mod tests {
- );
-
- let expr = Expr::from_str("x + y^2 + z^3").unwrap();
- - let func = expr.clone().bind3("x", "y", "z").unwrap();
- + let func = expr.bind3("x", "y", "z").unwrap();
- assert_eq!(func(1., 2., 3.), 32.);
-
- let expr = Expr::from_str("sin(x)").unwrap();
- - let func = expr.clone().bind("x").unwrap();
- + let func = expr.bind("x").unwrap();
- assert_eq!(func(1.), (1f64).sin());
-
- let expr = Expr::from_str("sin(x,2)").unwrap();
- - match expr.clone().bind("x") {
- + match expr.bind("x") {
- Err(Error::Function(_, FuncEvalError::NumberArgs(1))) => {}
- _ => panic!("bind did not error"),
- }
- let expr = Expr::from_str("hey(x,2)").unwrap();
- - match expr.clone().bind("x") {
- + match expr.bind("x") {
- Err(Error::Function(_, FuncEvalError::UnknownFunction)) => {}
- _ => panic!("bind did not error"),
- }
- diff --git a/src/extra_math.rs b/src/extra_math.rs
- index 63b6296..39d31f7 100644
- --- a/src/extra_math.rs
- +++ b/src/extra_math.rs
- @@ -2,19 +2,19 @@
- // This is to take advantage of the fact that std::f64::MAX >>> std::u64::MAX
- fn factorial_unsafe(num: f64) -> f64 {
- if num == 0. || num == 1. {
- - return 1.;
- + 1.
- } else {
- - return num * factorial_unsafe(num - 1.);
- + num * factorial_unsafe(num - 1.)
- }
- }
-
- pub fn factorial(num: f64) -> Result<f64, &'static str> {
- if num.fract() != 0. || num < 0. {
- - return Err("Number must be non-negative with no fractional component!");
- + Err("Number must be non-negative with no fractional component!")
- } else if num > 170. {
- - return Ok(std::f64::INFINITY);
- + Ok(std::f64::INFINITY)
- } else {
- - return Ok(factorial_unsafe(num));
- + Ok(factorial_unsafe(num))
- }
- }
-
- diff --git a/src/tokenizer.rs b/src/tokenizer.rs
- index 0e08337..322eb15 100644
- --- a/src/tokenizer.rs
- +++ b/src/tokenizer.rs
- @@ -9,18 +9,17 @@
- use nom::{
- branch::alt,
- bytes::complete::is_a,
- - bytes::complete::{escaped, take, tag, take_while},
- - character::complete::{anychar, digit1, multispace0, alphanumeric1, alphanumeric0, char, alpha1, one_of},
- - combinator::{complete, peek, all_consuming, recognize, map, opt, cut, not},
- - error::{context, convert_error, ErrorKind, ParseError, VerboseError},
- - multi::separated_list0,
- + bytes::complete::{tag},
- + character::complete::{multispace0, one_of},
- + combinator::{complete, peek, recognize, map, opt},
- + error::{ErrorKind},
- number::complete::double,
- - sequence::{tuple, pair, delimited, preceded, separated_pair, terminated},
- - Err, Needed, IResult
- + sequence::{delimited, preceded, terminated},
- + Err, IResult
- };
-
- use std::fmt;
- -use std::str::from_utf8;
- +
- use std::f64;
-
- /// An error reported by the parser.
- @@ -155,7 +154,7 @@ fn negpos<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
-
- match negpos_s(i) {
- Ok((remaining_input, operator)) => {
- - match operator.as_ref() {
- + match operator {
- "+" => Ok((remaining_input, Token::Unary(Operation::Plus))),
- "-" => Ok((remaining_input, Token::Unary(Operation::Minus))),
- _ => panic!("Should never occur")
- @@ -167,7 +166,7 @@ fn negpos<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
-
- /// factorial parse
- fn fact<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- - map(tag("!"), |s: &str| Token::Unary(Operation::Fact))(i)
- + map(tag("!"), |_s: &str| Token::Unary(Operation::Fact))(i)
- }
-
- fn ident<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- @@ -210,7 +209,7 @@ fn func<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- fn number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- preceded(
- peek(one_of("0123456789")),
- - map(double, |s| Token::Number(s))
- + map(double, Token::Number)
- )(i)
- }
-
- @@ -347,7 +346,7 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- return Err(TokenParseError::MissingRParen(paren_stack.len() as i32));
- }
-
- - return Ok(res);
- + Ok(res)
- }
- }
-
- @@ -658,7 +657,7 @@ mod tests {
- for &s in ["abc(", "u0(", "_034 (", "A_be45EA ("].iter() {
- assert_eq!(
- func(s),
- - Ok(("", Token::Func((&s[0..s.len() - 1]).trim().into(), None)))
- + Ok(("", Token::Func(s[0..s.len() - 1].trim().into(), None)))
- );
- }
-
- From ad90ef78e9986dbd3c84a0743706384b433a4d38 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 10:39:18 -0500
- Subject: [PATCH 06/10] rustfmt
- ---
- src/expr.rs | 8 +-
- src/shunting_yard.rs | 1 -
- src/tokenizer.rs | 447 +++++++++++++++----------------------------
- 3 files changed, 152 insertions(+), 304 deletions(-)
- diff --git a/src/expr.rs b/src/expr.rs
- index c151756..04b54b5 100644
- --- a/src/expr.rs
- +++ b/src/expr.rs
- @@ -340,7 +340,7 @@ impl Expr {
- {
- self.check_context((
- [(var1, 0.), (var2, 0.), (var3, 0.), (var4, 0.), (var5, 0.)],
- - &ctx
- + &ctx,
- ))?;
- let var1 = var1.to_owned();
- let var2 = var2.to_owned();
- @@ -390,10 +390,8 @@ impl Expr {
- {
- let n = vars.len();
- self.check_context((
- - vars.iter()
- - .zip(vec![0.; n].into_iter())
- - .collect::<Vec<_>>(),
- - &ctx
- + vars.iter().zip(vec![0.; n].into_iter()).collect::<Vec<_>>(),
- + &ctx,
- ))?;
- let vars = vars.iter().map(|v| v.to_owned()).collect::<Vec<_>>();
- Ok(move |x: &[f64]| {
- diff --git a/src/shunting_yard.rs b/src/shunting_yard.rs
- index 90026bf..5fe3010 100644
- --- a/src/shunting_yard.rs
- +++ b/src/shunting_yard.rs
- @@ -1,4 +1,3 @@
- -
- //! Implementation of the shunting-yard algorithm for converting an infix expression to an
- //! expression in reverse Polish notation (RPN).
- //!
- diff --git a/src/tokenizer.rs b/src/tokenizer.rs
- index 322eb15..190fa51 100644
- --- a/src/tokenizer.rs
- +++ b/src/tokenizer.rs
- @@ -7,15 +7,15 @@
- //! [nom]: https://crates.io/crates/nom
-
- use nom::{
- - branch::alt,
- - bytes::complete::is_a,
- - bytes::complete::{tag},
- - character::complete::{multispace0, one_of},
- - combinator::{complete, peek, recognize, map, opt},
- - error::{ErrorKind},
- - number::complete::double,
- - sequence::{delimited, preceded, terminated},
- - Err, IResult
- + branch::alt,
- + bytes::complete::is_a,
- + bytes::complete::tag,
- + character::complete::{multispace0, one_of},
- + combinator::{complete, map, opt, peek, recognize},
- + error::ErrorKind,
- + number::complete::double,
- + sequence::{delimited, preceded, terminated},
- + Err, IResult,
- };
-
- use std::fmt;
- @@ -36,7 +36,7 @@ pub enum TokenParseError {
- /// Missing operator or function argument at the end of the expression.
- MissingArgument,
-
- - UnknownError
- + UnknownError,
- }
-
- impl fmt::Display for TokenParseError {
- @@ -50,7 +50,9 @@ impl fmt::Display for TokenParseError {
- i,
- if *i == 1 { "is" } else { "es" }
- ),
- - TokenParseError::MissingArgument => write!(f, "Missing argument at the end of expression."),
- + TokenParseError::MissingArgument => {
- + write!(f, "Missing argument at the end of expression.")
- + }
- TokenParseError::UnknownError => write!(f, "Unknown pass error."),
- }
- }
- @@ -94,7 +96,7 @@ pub enum Token {
- RParen,
- /// Comma: function argument separator
- Comma,
- - /// Decimal Point
- + /// Decimal Point
- //DecimalPoint,
-
- /// A number.
- @@ -108,24 +110,24 @@ pub enum Token {
- /// Continuing the trend of starting from the simplest piece and building up,
- /// we start by creating a parser for the built-in operator functions.
- fn binop<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- - // one_of matches one of the characters we give it
- - let (i, t) = one_of("+-*/%^!")(i)?;
- -
- - // because we are matching single character tokens, we can do the matching logic
- - // on the returned value
- - Ok((
- - i,
- - match t {
- - '+' => Token::Binary(Operation::Plus),
- - '-' => Token::Binary(Operation::Minus),
- - '*' => Token::Binary(Operation::Times),
- - '/' => Token::Binary(Operation::Div),
- - '%' => Token::Binary(Operation::Rem),
- - '^' => Token::Binary(Operation::Pow),
- - '!' => Token::Binary(Operation::Fact),
- - _ => unreachable!(),
- - },
- - ))
- + // one_of matches one of the characters we give it
- + let (i, t) = one_of("+-*/%^!")(i)?;
- +
- + // because we are matching single character tokens, we can do the matching logic
- + // on the returned value
- + Ok((
- + i,
- + match t {
- + '+' => Token::Binary(Operation::Plus),
- + '-' => Token::Binary(Operation::Minus),
- + '*' => Token::Binary(Operation::Times),
- + '/' => Token::Binary(Operation::Div),
- + '%' => Token::Binary(Operation::Rem),
- + '^' => Token::Binary(Operation::Pow),
- + '!' => Token::Binary(Operation::Fact),
- + _ => unreachable!(),
- + },
- + ))
- }
-
- fn lparen<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- @@ -142,25 +144,21 @@ fn comma<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
-
- /// negpos parse. detects either - or +
- fn negpos_s<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- -
- - match alt((tag("+"), tag("-"), ))(i) {
- + match alt((tag("+"), tag("-")))(i) {
- Ok((remaining_input, operator)) => Ok((remaining_input, operator)),
- - Err(e) => Err(e)
- + Err(e) => Err(e),
- }
- }
-
- /// negpos parse. detects either - or +
- fn negpos<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- -
- - match negpos_s(i) {
- - Ok((remaining_input, operator)) => {
- - match operator {
- - "+" => Ok((remaining_input, Token::Unary(Operation::Plus))),
- - "-" => Ok((remaining_input, Token::Unary(Operation::Minus))),
- - _ => panic!("Should never occur")
- - }
- + match negpos_s(i) {
- + Ok((remaining_input, operator)) => match operator {
- + "+" => Ok((remaining_input, Token::Unary(Operation::Plus))),
- + "-" => Ok((remaining_input, Token::Unary(Operation::Minus))),
- + _ => panic!("Should never occur"),
- },
- - Err(e) => Err(e)
- + Err(e) => Err(e),
- }
- }
-
- @@ -172,19 +170,19 @@ fn fact<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- fn ident<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- let REMAINING_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- let FIRST_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- -
- +
- // Returns whole strings matched by the given parser.
- recognize(
- - // Runs the first parser, if succeeded then runs second, and returns the second result.
- - // Note that returned ok value of `preceded()` is ignored by `recognize()`.
- - preceded(
- - // Parses a single character contained in the given string.
- - one_of(FIRST_CHARS),
- - // Parses the longest slice consisting of the given characters
- - opt(is_a(REMAINING_CHARS)),
- - )
- + // Runs the first parser, if succeeded then runs second, and returns the second result.
- + // Note that returned ok value of `preceded()` is ignored by `recognize()`.
- + preceded(
- + // Parses a single character contained in the given string.
- + one_of(FIRST_CHARS),
- + // Parses the longest slice consisting of the given characters
- + opt(is_a(REMAINING_CHARS)),
- + ),
- )(i)
- - }
- +}
-
- fn var<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- map(complete(ident), |s: &str| Token::Var(s.into()))(i)
- @@ -192,62 +190,35 @@ fn var<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
-
- /// Parse `func(`, returns `func`.
- fn func<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- - map(
- - //recognize(
- - terminated(
- - complete(ident),
- - preceded(multispace0,
- - complete(tag("("))
- - )
- - )
- - //)
- - ,
- - |s: &str| Token::Func(s.into(), None)
- + map(
- + //recognize(
- + terminated(complete(ident), preceded(multispace0, complete(tag("(")))), //)
- + |s: &str| Token::Func(s.into(), None),
- )(i)
- }
-
- fn number<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- - preceded(
- - peek(one_of("0123456789")),
- - map(double, Token::Number)
- - )(i)
- + preceded(peek(one_of("0123456789")), map(double, Token::Number))(i)
- }
-
- fn lexpr<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- -
- delimited(
- - multispace0,
- - alt((number, func, var, negpos, lparen)),
- - multispace0
- + multispace0,
- + alt((number, func, var, negpos, lparen)),
- + multispace0,
- )(i)
- }
-
- -
- fn after_rexpr<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- -
- - delimited(
- - multispace0,
- - alt((fact, binop, rparen)),
- - multispace0
- - )(i)
- + delimited(multispace0, alt((fact, binop, rparen)), multispace0)(i)
- }
-
- fn after_rexpr_no_paren<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- -
- - delimited(
- - multispace0,
- - alt((fact, binop)),
- - multispace0
- - )(i)
- + delimited(multispace0, alt((fact, binop)), multispace0)(i)
- }
-
- fn after_rexpr_comma<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- -
- - delimited(
- - multispace0,
- - alt((fact, binop, rparen, comma)),
- - multispace0
- - )(i)
- + delimited(multispace0, alt((fact, binop, rparen, comma)), multispace0)(i)
- }
-
- #[derive(Debug, Clone, Copy)]
- @@ -264,7 +235,6 @@ enum ParenState {
- Func,
- }
-
- -
- /// Tokenize a given mathematical expression.
- ///
- /// The parser should return `Ok` only if the expression is well-formed.
- @@ -282,7 +252,6 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- let mut s = input;
-
- while !s.is_empty() {
- -
- let r = match (state, paren_stack.last()) {
- (TokenizerState::LExpr, _) => lexpr(s),
- (TokenizerState::AfterRExpr, None) => after_rexpr_no_paren(s),
- @@ -292,7 +261,6 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
-
- match r {
- Ok((rest, t)) => {
- -
- match t {
- Token::LParen => {
- paren_stack.push(ParenState::Subexpr);
- @@ -315,11 +283,10 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- s = rest;
- }
- Err(e) => {
- -
- match e {
- Err::Error((value, _)) => {
- return Err(TokenParseError::UnexpectedStrToken(value.to_string()));
- - },
- + }
- _ => (),
- }
-
- @@ -330,16 +297,16 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- // return Err(TokenParseError::UnexpectedToken(i));
- // }
- _ => {
- - panic!("Unexpected parse result when parsing `{}` at `{}`: {:?}", input, s, r);
- + panic!(
- + "Unexpected parse result when parsing `{}` at `{}`: {:?}",
- + input, s, r
- + );
- }
- }
- -
- }
-
- match state {
- - TokenizerState::LExpr => {
- - Err(TokenParseError::MissingArgument)
- - },
- + TokenizerState::LExpr => Err(TokenParseError::MissingArgument),
-
- _ => {
- if !paren_stack.is_empty() {
- @@ -349,13 +316,8 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- Ok(res)
- }
- }
- -
- -
- }
-
- -
- -
- -
- // ok rest ["+(3--2) "] t Number(2.0)
- // ok rest ["(3--2) "] t Binary(Plus)
- // ok rest [51, 45, 45, 50, 41, 32] t LParen
- @@ -368,134 +330,42 @@ pub fn tokenize(input: &str) -> Result<Vec<Token>, TokenParseError> {
- // paren_stack: []
- // Ok([Number(2.0), Binary(Plus), LParen, Number(3.0), Binary(Minus), Unary(Minus), Number(2.0), RParen])
-
- -
- #[cfg(test)]
- mod tests {
- use super::*;
- -
- +
- #[test]
- fn it_works() {
- -
- - assert_eq!(
- - binop("+"),
- - Ok(("", Token::Binary(Operation::Plus)))
- - );
- - assert_eq!(
- - ident("abc32"),
- - Ok(("", "abc32"))
- - );
- - assert_eq!(
- - func("abc("),
- - Ok(("", Token::Func("abc".into(), None)))
- - );
- - assert_eq!(
- - func("abc ("),
- - Ok(("", Token::Func("abc".into(), None)))
- - );
- - assert_eq!(
- - var("abc"),
- - Ok(("", Token::Var("abc".into())))
- - );
- - assert_eq!(
- - fact("!"),
- - Ok(("", Token::Unary(Operation::Fact)))
- - );
- - assert_eq!(
- - negpos_s("+"),
- - Ok(("", "+"))
- - );
- - assert_eq!(
- - negpos_s("-"),
- - Ok(("", "-"))
- - );
- - assert_eq!(
- - negpos_s("+362"),
- - Ok(("362", "+"))
- - );
- - assert_eq!(
- - negpos_s("-5734"),
- - Ok(("5734", "-"))
- - );
- - assert_eq!(
- - negpos("+"),
- - Ok(("", Token::Unary(Operation::Plus)))
- - );
- - assert_eq!(
- - negpos("-"),
- - Ok(("", Token::Unary(Operation::Minus)))
- - );
- - assert_eq!(
- - negpos("+642"),
- - Ok(("642", Token::Unary(Operation::Plus)))
- - );
- - assert_eq!(
- - negpos("-563"),
- - Ok(("563", Token::Unary(Operation::Minus)))
- - );
- - assert_eq!(
- - lparen("("),
- - Ok(("", Token::LParen))
- - );
- - assert_eq!(
- - rparen(")"),
- - Ok(("", Token::RParen))
- - );
- - assert_eq!(
- - comma(","),
- - Ok(("", Token::Comma))
- - );
- - assert_eq!(
- - comma(","),
- - Ok(("", Token::Comma))
- - );
- - assert_eq!(
- - number("+1.34e2"),
- - Ok(("", Token::Number(134.0)))
- - );
- - assert_eq!(
- - number("+1.34e+2"),
- - Ok(("", Token::Number(134.0)))
- - );
- - assert_eq!(
- - number("3E+2"),
- - Ok(("", Token::Number(300.0)))
- - );
- - assert_eq!(
- - number("+4E+2"),
- - Ok(("", Token::Number(400.0)))
- - );
- - assert_eq!(
- - number("-4.76E+2"),
- - Ok(("", Token::Number(-476.0)))
- - );
- - assert_eq!(
- - number("-4.76"),
- - Ok(("", Token::Number(-4.76)))
- - );
- - assert_eq!(
- - number("+4.76"),
- - Ok(("", Token::Number(4.76)))
- - );
- - assert_eq!(
- - number("1.1"),
- - Ok(("", Token::Number(1.1)))
- - );
- - assert_eq!(
- - number("-1.1"),
- - Ok(("", Token::Number(-1.1)))
- - );
- - assert_eq!(
- - number("123E-02"),
- - Ok(("", Token::Number(1.23)))
- - );
- - assert_eq!(
- - number("+123E-02"),
- - Ok(("", Token::Number(1.23)))
- - );
- - assert_eq!(
- - number("-123E-02"),
- - Ok(("", Token::Number(-1.23)))
- - );
- + assert_eq!(binop("+"), Ok(("", Token::Binary(Operation::Plus))));
- + assert_eq!(ident("abc32"), Ok(("", "abc32")));
- + assert_eq!(func("abc("), Ok(("", Token::Func("abc".into(), None))));
- + assert_eq!(func("abc ("), Ok(("", Token::Func("abc".into(), None))));
- + assert_eq!(var("abc"), Ok(("", Token::Var("abc".into()))));
- + assert_eq!(fact("!"), Ok(("", Token::Unary(Operation::Fact))));
- + assert_eq!(negpos_s("+"), Ok(("", "+")));
- + assert_eq!(negpos_s("-"), Ok(("", "-")));
- + assert_eq!(negpos_s("+362"), Ok(("362", "+")));
- + assert_eq!(negpos_s("-5734"), Ok(("5734", "-")));
- + assert_eq!(negpos("+"), Ok(("", Token::Unary(Operation::Plus))));
- + assert_eq!(negpos("-"), Ok(("", Token::Unary(Operation::Minus))));
- + assert_eq!(negpos("+642"), Ok(("642", Token::Unary(Operation::Plus))));
- + assert_eq!(negpos("-563"), Ok(("563", Token::Unary(Operation::Minus))));
- + assert_eq!(lparen("("), Ok(("", Token::LParen)));
- + assert_eq!(rparen(")"), Ok(("", Token::RParen)));
- + assert_eq!(comma(","), Ok(("", Token::Comma)));
- + assert_eq!(comma(","), Ok(("", Token::Comma)));
- + assert_eq!(number("+1.34e2"), Ok(("", Token::Number(134.0))));
- + assert_eq!(number("+1.34e+2"), Ok(("", Token::Number(134.0))));
- + assert_eq!(number("3E+2"), Ok(("", Token::Number(300.0))));
- + assert_eq!(number("+4E+2"), Ok(("", Token::Number(400.0))));
- + assert_eq!(number("-4.76E+2"), Ok(("", Token::Number(-476.0))));
- + assert_eq!(number("-4.76"), Ok(("", Token::Number(-4.76))));
- + assert_eq!(number("+4.76"), Ok(("", Token::Number(4.76))));
- + assert_eq!(number("1.1"), Ok(("", Token::Number(1.1))));
- + assert_eq!(number("-1.1"), Ok(("", Token::Number(-1.1))));
- + assert_eq!(number("123E-02"), Ok(("", Token::Number(1.23))));
- + assert_eq!(number("+123E-02"), Ok(("", Token::Number(1.23))));
- + assert_eq!(number("-123E-02"), Ok(("", Token::Number(-1.23))));
- assert_eq!(
- number("abc"),
- Err(Err::Error(("abc", nom::error::ErrorKind::Float)))
- @@ -504,38 +374,21 @@ mod tests {
-
- #[test]
- fn test_lexpr() {
- -
- // number, func, var, negpos, lparen
- assert_eq!(
- number("a"),
- Err(Err::Error(("a", nom::error::ErrorKind::Float)))
- );
-
- - assert_eq!(
- - func("a"),
- - Err(Err::Error(("", nom::error::ErrorKind::Tag)))
- - );
- + assert_eq!(func("a"), Err(Err::Error(("", nom::error::ErrorKind::Tag))));
-
- - assert_eq!(
- - var("a"),
- - Ok(("", Token::Var("a".into())))
- - );
- + assert_eq!(var("a"), Ok(("", Token::Var("a".into()))));
-
- - assert_eq!(
- - lexpr("a"),
- - Ok(("", Token::Var("a".into())))
- - );
- + assert_eq!(lexpr("a"), Ok(("", Token::Var("a".into()))));
-
- - assert_eq!(
- - lexpr("2+"),
- - Ok(("+", Token::Number(2.0)))
- - );
- + assert_eq!(lexpr("2+"), Ok(("+", Token::Number(2.0))));
-
- - assert_eq!(
- - lexpr("2 +(3--2) "),
- - Ok(("+(3--2) ", Token::Number(2.0)))
- - );
- -
- + assert_eq!(lexpr("2 +(3--2) "), Ok(("+(3--2) ", Token::Number(2.0))));
-
- println!("{:?}", number("+(3--2) "));
-
- @@ -543,29 +396,24 @@ mod tests {
- lexpr("+(3--2) "),
- Ok(("+(3--2) ", Token::Binary(Operation::Plus)))
- );
- -
- }
-
- #[test]
- fn test_var() {
- for &s in ["abc", "U0", "_034", "a_be45EA", "aAzZ_"].iter() {
- - assert_eq!(
- - var(s),
- - Ok(("", Token::Var(s.into())))
- - );
- + assert_eq!(var(s), Ok(("", Token::Var(s.into()))));
- }
-
- assert_eq!(var(""), Err(Err::Error(("", nom::error::ErrorKind::OneOf))));
- - assert_eq!(var("0"), Err(Err::Error(("0", nom::error::ErrorKind::OneOf))));
- + assert_eq!(
- + var("0"),
- + Err(Err::Error(("0", nom::error::ErrorKind::OneOf)))
- + );
- }
-
- #[test]
- fn test_number() {
- -
- - assert_eq!(
- - number("45"),
- - Ok(("", Token::Number(45.0)))
- - );
- + assert_eq!(number("45"), Ok(("", Token::Number(45.0))));
-
- assert_eq!(
- number("+(3--2) "),
- @@ -590,34 +438,13 @@ mod tests {
- number("(3) - (2) "),
- Err(Err::Error(("(3) - (2) ", nom::error::ErrorKind::OneOf)))
- );
- - assert_eq!(
- - number("32143"),
- - Ok(("", Token::Number(32143f64)))
- - );
- - assert_eq!(
- - number("2."),
- - Ok(("", Token::Number(2.0f64)))
- - );
- - assert_eq!(
- - number("32143.25"),
- - Ok(("", Token::Number(32143.25f64)))
- - );
- - assert_eq!(
- - number("0.125e9"),
- - Ok(("", Token::Number(0.125e9f64)))
- - );
- - assert_eq!(
- - number("20.5E-3"),
- - Ok(("", Token::Number(20.5E-3f64)))
- - );
- - assert_eq!(
- - number("123423e+50"),
- - Ok(("", Token::Number(123423e+50f64)))
- - );
- - assert_eq!(
- - number("0.2"),
- - Ok(("", Token::Number(0.2)))
- - );
- + assert_eq!(number("32143"), Ok(("", Token::Number(32143f64))));
- + assert_eq!(number("2."), Ok(("", Token::Number(2.0f64))));
- + assert_eq!(number("32143.25"), Ok(("", Token::Number(32143.25f64))));
- + assert_eq!(number("0.125e9"), Ok(("", Token::Number(0.125e9f64))));
- + assert_eq!(number("20.5E-3"), Ok(("", Token::Number(20.5E-3f64))));
- + assert_eq!(number("123423e+50"), Ok(("", Token::Number(123423e+50f64))));
- + assert_eq!(number("0.2"), Ok(("", Token::Number(0.2))));
- assert_eq!(
- number(""),
- Err(Err::Error(("", nom::error::ErrorKind::OneOf)))
- @@ -661,9 +488,18 @@ mod tests {
- );
- }
-
- - assert_eq!(func(""), Err(Err::Error(("", nom::error::ErrorKind::OneOf))));
- - assert_eq!(func("("), Err(Err::Error(("(", nom::error::ErrorKind::OneOf))));
- - assert_eq!(func("0("), Err(Err::Error(("0(", nom::error::ErrorKind::OneOf))));
- + assert_eq!(
- + func(""),
- + Err(Err::Error(("", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + func("("),
- + Err(Err::Error(("(", nom::error::ErrorKind::OneOf)))
- + );
- + assert_eq!(
- + func("0("),
- + Err(Err::Error(("0(", nom::error::ErrorKind::OneOf)))
- + );
- }
-
- #[test]
- @@ -752,15 +588,30 @@ mod tests {
- ])
- );
-
- - assert_eq!(tokenize("!3"), Err(TokenParseError::UnexpectedStrToken("!3".to_string())));
- + assert_eq!(
- + tokenize("!3"),
- + Err(TokenParseError::UnexpectedStrToken("!3".to_string()))
- + );
-
- - assert_eq!(tokenize("()"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
- + assert_eq!(
- + tokenize("()"),
- + Err(TokenParseError::UnexpectedStrToken(")".to_string()))
- + );
-
- assert_eq!(tokenize(""), Err(TokenParseError::MissingArgument));
- - assert_eq!(tokenize("2)"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
- + assert_eq!(
- + tokenize("2)"),
- + Err(TokenParseError::UnexpectedStrToken(")".to_string()))
- + );
- assert_eq!(tokenize("2^"), Err(TokenParseError::MissingArgument));
- assert_eq!(tokenize("(((2)"), Err(TokenParseError::MissingRParen(2)));
- - assert_eq!(tokenize("f(2,)"), Err(TokenParseError::UnexpectedStrToken(")".to_string())));
- - assert_eq!(tokenize("f(,2)"), Err(TokenParseError::UnexpectedStrToken(",2)".to_string())));
- + assert_eq!(
- + tokenize("f(2,)"),
- + Err(TokenParseError::UnexpectedStrToken(")".to_string()))
- + );
- + assert_eq!(
- + tokenize("f(,2)"),
- + Err(TokenParseError::UnexpectedStrToken(",2)".to_string()))
- + );
- }
- -}
- \ No newline at end of file
- +}
- From f6b868d04aa3e034f51dfd322e66c75b6d413e5f Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Wed, 16 Feb 2022 15:03:07 -0500
- Subject: [PATCH 07/10] add 'log' function (does the same thing as log10)
- ---
- src/expr.rs | 1 +
- 1 file changed, 1 insertion(+)
- diff --git a/src/expr.rs b/src/expr.rs
- index 04b54b5..ad29be0 100644
- --- a/src/expr.rs
- +++ b/src/expr.rs
- @@ -723,6 +723,7 @@ impl<'a> Context<'a> {
- ctx.func("exp", f64::exp);
- ctx.func("ln", f64::ln);
- ctx.func("log10", f64::log10);
- + ctx.func("log", f64::log10);
- ctx.func("abs", f64::abs);
- ctx.func("sin", f64::sin);
- ctx.func("cos", f64::cos);
- From 00cd188a9a2b98a01b686e03ed9c375b2760a0b0 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Thu, 17 Feb 2022 11:24:00 -0500
- Subject: [PATCH 08/10] update README.md
- ---
- README.md | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/README.md b/README.md
- index 5571842..22d4633 100644
- --- a/README.md
- +++ b/README.md
- @@ -104,7 +104,7 @@ supported:
- - functions implemented using functions of the same name in [Rust std library][std-float]:
-
- - `sqrt`, `abs`
- - - `exp`, `ln`, `log10`
- + - `exp`, `ln`, `log10` (`log10` can also be called as `log`)
- - `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`
- - `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`
- - `floor`, `ceil`, `round`
- From 115b1ef88d57ac827f8f62eff97e026455c32791 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Tue, 22 Feb 2022 10:17:50 -0500
- Subject: [PATCH 09/10] don't specify specific serde version
- ---
- Cargo.toml | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
- diff --git a/Cargo.toml b/Cargo.toml
- index 60b4064..8d62d0d 100644
- --- a/Cargo.toml
- +++ b/Cargo.toml
- @@ -14,13 +14,13 @@ exclude = ["README.tpl", ".travis.yml"]
- [dependencies]
- fnv = "1.0.7"
- nom = "7.1.0"
- -serde = { version = "1.0.136", optional = true }
- +serde = { version = "1", optional = true }
-
- [dev-dependencies]
- gnuplot = "0.0.37"
- -serde_test = "1.0.136"
- -serde_derive = "1.0.136"
- -serde_json = "1.0.79"
- +serde_test = "1"
- +serde_derive = "1"
- +serde_json = "1"
- toml = "0.5.8"
-
- [features]
- From 6bf579fd402928745cf4f24e5c975bece3285179 Mon Sep 17 00:00:00 2001
- From: Simon Gardling <titaniumtown@gmail.com>
- Date: Thu, 3 Mar 2022 10:32:47 -0500
- Subject: [PATCH 10/10] fix variable naming
- ---
- src/tokenizer.rs | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
- diff --git a/src/tokenizer.rs b/src/tokenizer.rs
- index 190fa51..9dfd304 100644
- --- a/src/tokenizer.rs
- +++ b/src/tokenizer.rs
- @@ -168,8 +168,8 @@ fn fact<'a>(i: &'a str) -> IResult<&'a str, Token, (&'a str, ErrorKind)> {
- }
-
- fn ident<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- - let REMAINING_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- - let FIRST_CHARS: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- + let remaining_chars: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- + let first_chars: &str = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- // Returns whole strings matched by the given parser.
- recognize(
- @@ -177,9 +177,9 @@ fn ident<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
- // Note that returned ok value of `preceded()` is ignored by `recognize()`.
- preceded(
- // Parses a single character contained in the given string.
- - one_of(FIRST_CHARS),
- + one_of(first_chars),
- // Parses the longest slice consisting of the given characters
- - opt(is_a(REMAINING_CHARS)),
- + opt(is_a(remaining_chars)),
- ),
- )(i)
- }
|