diff --git a/Cargo.lock b/Cargo.lock index a9b834a..2c1cefa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "assert_approx_eq" version = "1.1.0" @@ -14,85 +25,201 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "block-buffer" -version = "0.7.3" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "block-padding", - "byte-tools", - "byteorder", "generic-array", ] [[package]] -name = "block-padding" -version = "0.1.5" +name = "bumpalo" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] -name = "byte-tools" -version = "0.3.1" +name = "cc" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] -name = "byteorder" -version = "1.3.4" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "time", + "wasm-bindgen", "winapi", ] [[package]] -name = "digest" -version = "0.8.1" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "typenum", +] + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", ] [[package]] -name = "fake-simd" -version = "0.1.2" +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] [[package]] name = "generic-array" -version = "0.12.3" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", + "version_check", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.80" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] -name = "maplit" -version = "1.0.2" +name = "link-cplusplus" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] [[package]] name = "num-integer" @@ -114,25 +241,26 @@ dependencies = [ ] [[package]] -name = "opaque-debug" -version = "0.2.3" +name = "once_cell" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "pest" -version = "2.1.3" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "4257b4a04d91f7e9e6290be5d3da4804dd5784fafde3a497d73eb2b4a158c30a" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "241cda393b0cdd65e62e07e12454f1f25d57017dcc514b1514cd3c4645e3a0a6" dependencies = [ "pest", "pest_generator", @@ -140,9 +268,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e5277315f6b4f27e0e6744feb5d5ba1891e7164871033d3c8344c6783b349a" +checksum = "46b53634d8c8196302953c74d5352f33d0c512a9499bd2ce468fc9f4128fa27c" dependencies = [ "pest", "pest_meta", @@ -153,54 +281,88 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "0ef4f1332a8d4678b41966bb4cc1d0676880e84183a1ecc3f4b69f03e99c7a51" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1", + "sha2", ] [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.3" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] -name = "sha-1" -version = "0.8.2" +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "sha2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "block-buffer", + "cfg-if", + "cpufeatures", "digest", - "fake-simd", - "opaque-debug", ] [[package]] name = "syn" -version = "1.0.16" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -216,21 +378,33 @@ dependencies = [ [[package]] name = "typenum" -version = "1.11.2" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.2" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-ident" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "unicode-width" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -238,6 +412,60 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + [[package]] name = "winapi" version = "0.3.9" @@ -254,6 +482,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 1a8cd9f..ee9d4e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [package] -name = "xlformula_engine" -version = "0.1.17" -authors = ["Jirada Herbst "] -edition = "2018" -license = "MIT OR Apache-2.0" +name = "xlformula_engine" +version = "0.1.17" +authors = ["Jirada Herbst "] +edition = "2018" +license = "MIT OR Apache-2.0" description = "A tool to parse and evaluate Excel formulas" -readme = "README.md" -homepage = "https://github.com/jiradaherbst/XLFormula-Engine" -repository = "https://github.com/jiradaherbst/XLFormula-Engine" -keywords = ["formula", "parser", "excel", "pest"] +readme = "README.md" +homepage = "https://github.com/jiradaherbst/XLFormula-Engine" +repository = "https://github.com/jiradaherbst/XLFormula-Engine" +keywords = ["formula", "parser", "excel", "pest"] [dependencies] -pest = "2.1.3" -pest_derive = "2.1.0" +pest = "2.5.3" +pest_derive = "2.5.3" assert_approx_eq = "1.1.0" -chrono = "0.4.19" +chrono = "0.4.23" diff --git a/src/calculate.rs b/src/calculate.rs index cd28a89..c201230 100644 --- a/src/calculate.rs +++ b/src/calculate.rs @@ -1,7 +1,8 @@ use crate::parse_formula; use crate::types; +// use crate::{NoCustomFunction, NoReference}; use chrono::{DateTime, Duration, FixedOffset}; -type NoCustomFunction<'a> = &'a fn(String, Vec) -> types::Value; +// type NoCustomFunction<'a> = &'a fn(String, Vec) -> types::Value; fn calculate_divide_operator(num1: f32, num2: f32) -> f32 { num1 / num2 @@ -317,9 +318,9 @@ fn calculate_comparison_operator( types::Value::Text(l) => match rhs { types::Value::Text(r) => { if l.eq(&r) { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -327,16 +328,16 @@ fn calculate_comparison_operator( types::Value::Number(l) => match rhs { types::Value::Number(r) => { if f(l, r) { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Blank => { if f(l, 0.0) { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -344,12 +345,12 @@ fn calculate_comparison_operator( types::Value::Blank => match rhs { types::Value::Number(r) => { if f(0.0, r) { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } - types::Value::Blank => types::Value::Boolean(types::Boolean::True), + types::Value::Blank => types::Value::Boolean(true), _ => types::Value::Error(types::Error::Value), }, types::Value::Boolean(_) => types::Value::Error(types::Error::Value), @@ -359,29 +360,22 @@ fn calculate_comparison_operator( } } -fn to_bool(value: types::Boolean) -> bool { - match value { - types::Boolean::True => true, - types::Boolean::False => false, - } -} - fn calculate_boolean_operator_rhs_boolean( - l: types::Boolean, + l: bool, rh: types::Value, f: fn(bool1: bool, bool2: bool) -> bool, ) -> types::Value { match rh { types::Value::Boolean(r) => { - if f(to_bool(l), to_bool(r)) { - types::Value::Boolean(types::Boolean::True) + if f(l, r) { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Error(_) => match l { - types::Boolean::True => types::Value::Boolean(types::Boolean::True), - types::Boolean::False => types::Value::Boolean(types::Boolean::False), + true => types::Value::Boolean(true), + false => types::Value::Boolean(false), }, types::Value::Iterator(mut value_vec) => { if let Some(mut temp) = value_vec.pop() { @@ -391,10 +385,10 @@ fn calculate_boolean_operator_rhs_boolean( let rhs = cast_value_to_boolean(temp); match rhs { types::Value::Boolean(r) => { - if f(to_bool(l), to_bool(r)) { - types::Value::Boolean(types::Boolean::True) + if f(l, r) { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -404,10 +398,10 @@ fn calculate_boolean_operator_rhs_boolean( } } types::Value::Blank => { - if to_bool(l) { - types::Value::Boolean(types::Boolean::True) + if l { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -417,10 +411,10 @@ fn calculate_boolean_operator_rhs_boolean( fn calculate_boolean_operator_rhs_error(rh: types::Value) -> types::Value { match rh { types::Value::Boolean(r) => { - if to_bool(r) { - types::Value::Boolean(types::Boolean::True) + if r { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Error(_) => types::Value::Error(types::Error::Cast), @@ -442,10 +436,10 @@ fn calculate_boolean_operator_rhs_iterator( let lhs = cast_value_to_boolean(temp); match lhs { types::Value::Boolean(l) => { - if f(to_bool(l), to_bool(r)) { - types::Value::Boolean(types::Boolean::True) + if f(l, r) { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -473,11 +467,9 @@ fn calculate_boolean_operator( types::Value::Iterator(lhs_vec) => { calculate_boolean_operator_rhs_iterator(cast_value_to_boolean(rhs), lhs_vec, f) } - types::Value::Blank => calculate_boolean_operator_rhs_boolean( - types::Boolean::True, - cast_value_to_boolean(rhs), - f, - ), + types::Value::Blank => { + calculate_boolean_operator_rhs_boolean(true, cast_value_to_boolean(rhs), f) + } _ => types::Value::Error(types::Error::Value), } } @@ -496,11 +488,9 @@ fn calculate_boolean_operator_or( types::Value::Iterator(lhs_vec) => { calculate_boolean_operator_rhs_iterator(cast_value_to_boolean(rhs), lhs_vec, f) } - types::Value::Blank => calculate_boolean_operator_rhs_boolean( - types::Boolean::False, - cast_value_to_boolean(rhs), - f, - ), + types::Value::Blank => { + calculate_boolean_operator_rhs_boolean(false, cast_value_to_boolean(rhs), f) + } _ => types::Value::Error(types::Error::Value), } } @@ -519,11 +509,9 @@ fn calculate_boolean_operator_xor( types::Value::Iterator(lhs_vec) => { calculate_boolean_operator_rhs_iterator(cast_value_to_boolean(rhs), lhs_vec, f) } - types::Value::Blank => calculate_boolean_operator_rhs_boolean( - types::Boolean::False, - cast_value_to_boolean(rhs), - f, - ), + types::Value::Blank => { + calculate_boolean_operator_rhs_boolean(false, cast_value_to_boolean(rhs), f) + } _ => types::Value::Error(types::Error::Value), } } @@ -543,10 +531,10 @@ fn calculate_abs(value: types::Value) -> types::Value { fn calculate_negation(value: types::Value) -> types::Value { match value { types::Value::Boolean(l) => { - if !(to_bool(l)) { - types::Value::Boolean(types::Boolean::True) + if !l { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Error(_) => value, @@ -554,10 +542,10 @@ fn calculate_negation(value: types::Value) -> types::Value { let l = cast_text_to_boolean(&t); match l { Some(l) => { - if !(to_bool(l)) { - types::Value::Boolean(types::Boolean::True) + if !l { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } None => types::Value::Error(types::Error::Cast), @@ -565,14 +553,14 @@ fn calculate_negation(value: types::Value) -> types::Value { } types::Value::Number(l) => { if l == 0.0 { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Iterator(_) => types::Value::Error(types::Error::Value), types::Value::Date(_) => types::Value::Error(types::Error::Value), - types::Value::Blank => types::Value::Boolean(types::Boolean::True), + types::Value::Blank => types::Value::Boolean(true), } } @@ -591,11 +579,11 @@ fn calculate_negate(value: types::Value) -> types::Value { } } -fn cast_text_to_boolean(s: &str) -> Option { +fn cast_text_to_boolean(s: &str) -> Option { if s.eq_ignore_ascii_case("TRUE") { - Some(types::Boolean::True) + Some(true) } else if s.eq_ignore_ascii_case("FALSE") { - Some(types::Boolean::False) + Some(false) } else { None } @@ -609,10 +597,10 @@ fn cast_value_to_boolean(value: types::Value) -> types::Value { let l = cast_text_to_boolean(&t); match l { Some(l) => { - if to_bool(l) { - types::Value::Boolean(types::Boolean::True) + if l { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } None => types::Value::Error(types::Error::Cast), @@ -620,9 +608,9 @@ fn cast_value_to_boolean(value: types::Value) -> types::Value { } types::Value::Number(l) => { if l != 0.0 { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } types::Value::Iterator(mut value_vec) => { @@ -650,10 +638,10 @@ fn convert_iterator_to_result( } match cast_value_to_boolean(temp) { types::Value::Boolean(bool_result) => { - if to_bool(bool_result) { - types::Value::Boolean(types::Boolean::True) + if bool_result { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -678,10 +666,10 @@ fn convert_iterator_to_result_or( } match cast_value_to_boolean(temp) { types::Value::Boolean(bool_result) => { - if to_bool(bool_result) { - types::Value::Boolean(types::Boolean::True) + if bool_result { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -706,10 +694,10 @@ fn convert_iterator_to_result_xor( } match cast_value_to_boolean(temp) { types::Value::Boolean(bool_result) => { - if to_bool(bool_result) { - types::Value::Boolean(types::Boolean::True) + if bool_result { + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } _ => types::Value::Error(types::Error::Value), @@ -724,15 +712,16 @@ fn convert_iterator_to_result_xor( fn get_values( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> (types::Value, types::Value) { ( match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, ) @@ -740,25 +729,27 @@ fn get_values( fn get_value( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), } } fn get_date_values( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> (types::Value, types::Value) { ( match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, ) @@ -766,24 +757,25 @@ fn get_date_values( fn get_number_and_string_values( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> (types::Value, types::Value) { if exp.values.len() == 1 { ( types::Value::Number(1.0), match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, ) } else { ( match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }, ) @@ -792,19 +784,20 @@ fn get_number_and_string_values( fn get_iff_values( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> (types::Value, types::Value, types::Value) { ( match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Blank, }, match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Blank, }, match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Blank, }, ) @@ -812,26 +805,29 @@ fn get_iff_values( fn calculate_iterator( mut vec: Vec, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { + // println!("iterator"); let mut value_vec = Vec::new(); while let Some(top) = vec.pop() { - value_vec.push(calculate_formula(top, f)); + value_vec.push(calculate_formula(top, f, r)); } types::Value::Iterator(value_vec) } fn calculate_reference( string: String, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { - match f { - Some(f) => match f(string) { + // println!("reference"); + match r { + Some(r) => match r(string) { types::Value::Number(x) => types::Value::Number(x), - types::Value::Text(s) => calculate_formula( - parse_formula::parse_string_to_formula(&s, None::), - Some(f), - ), + types::Value::Text(s) => { + calculate_formula(parse_formula::parse_string_to_formula(&s), f, Some(r)) + } types::Value::Boolean(x) => types::Value::Boolean(x), types::Value::Error(types::Error::Value) => types::Value::Error(types::Error::Value), types::Value::Iterator(v) => types::Value::Iterator(v), @@ -845,48 +841,51 @@ fn calculate_reference( fn calculate_bool( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_bool: fn(bool1: bool, bool2: bool) -> bool, ) -> types::Value { let mut result = match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }; result = cast_value_to_boolean(result); while let Some(top) = exp.values.pop() { - result = calculate_boolean_operator(result, calculate_formula(top, f), f_bool); + result = calculate_boolean_operator(result, calculate_formula(top, f, r), f_bool); } convert_iterator_to_result(result, f_bool) } fn calculate_or( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_bool: fn(bool1: bool, bool2: bool) -> bool, ) -> types::Value { let mut result = match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }; result = cast_value_to_boolean(result); while let Some(top) = exp.values.pop() { - result = calculate_boolean_operator_or(result, calculate_formula(top, f), f_bool); + result = calculate_boolean_operator_or(result, calculate_formula(top, f, r), f_bool); } convert_iterator_to_result_or(result, f_bool) } fn calculate_xor( mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_bool: fn(bool1: bool, bool2: bool) -> bool, ) -> types::Value { let mut result = match exp.values.pop() { - Some(formula) => calculate_formula(formula, f), + Some(formula) => calculate_formula(formula, f, r), None => types::Value::Error(types::Error::Argument), }; result = cast_value_to_boolean(result); while let Some(top) = exp.values.pop() { - result = calculate_boolean_operator_xor(result, calculate_formula(top, f), f_bool); + result = calculate_boolean_operator_xor(result, calculate_formula(top, f, r), f_bool); } convert_iterator_to_result_xor(result, f_bool) } @@ -894,12 +893,16 @@ fn calculate_xor( fn calculate_collective_operator( mut collective_value: types::Value, mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_collective: fn(num1: f32, num2: f32) -> f32, ) -> types::Value { while let Some(top) = exp.values.pop() { - collective_value = - calculate_numeric_operator(collective_value, calculate_formula(top, f), f_collective); + collective_value = calculate_numeric_operator( + collective_value, + calculate_formula(top, f, r), + f_collective, + ); } collective_value } @@ -907,13 +910,14 @@ fn calculate_collective_operator( fn calculate_collective_product_operator( mut collective_value: types::Value, mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_collective: fn(num1: f32, num2: f32) -> f32, ) -> types::Value { while let Some(top) = exp.values.pop() { collective_value = calculate_numeric_product_operator( collective_value, - calculate_formula(top, f), + calculate_formula(top, f, r), f_collective, ); } @@ -926,7 +930,8 @@ fn calculate_collective_product_operator( fn calculate_average( mut collective_value: types::Value, mut exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, f_collective: fn(num1: f32, num2: f32) -> f32, ) -> types::Value { let mut element_count = 0; @@ -935,7 +940,7 @@ fn calculate_average( collective_value = calculate_average_operator( &mut element_count, collective_value, - calculate_formula(top, f), + calculate_formula(top, f, r), f_collective, ); } @@ -1009,7 +1014,7 @@ fn calculate_iff(iff_arguments: (types::Value, types::Value, types::Value)) -> t let (false_value, true_value, bool_expression) = iff_arguments; match bool_expression { types::Value::Boolean(bool_value) => { - if to_bool(bool_value) { + if bool_value { true_value } else { false_value @@ -1032,38 +1037,65 @@ fn calculate_iff(iff_arguments: (types::Value, types::Value, types::Value)) -> t fn calculate_function( func: types::Function, exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { + // println!("calc func"); match func { - types::Function::Abs => calculate_abs(get_value(exp, f)), + types::Function::Abs => calculate_abs(get_value(exp, f, r)), types::Function::Sum => { - calculate_collective_operator(types::Value::Number(0.0), exp, f, |n1, n2| n1 + n2) + calculate_collective_operator(types::Value::Number(0.0), exp, f, r, |n1, n2| n1 + n2) } types::Function::Product => { - calculate_collective_product_operator(types::Value::Blank, exp, f, |n1, n2| n1 * n2) + calculate_collective_product_operator(types::Value::Blank, exp, f, r, |n1, n2| n1 * n2) } types::Function::Average => { - calculate_average(types::Value::Number(0.00), exp, f, |n1, n2| n1 + n2) + calculate_average(types::Value::Number(0.00), exp, f, r, |n1, n2| n1 + n2) + } + types::Function::Or => calculate_or(exp, f, r, |n1, n2| n1 || n2), + types::Function::And => calculate_bool(exp, f, r, |n1, n2| n1 && n2), + types::Function::Xor => calculate_xor(exp, f, r, |n1, n2| n1 ^ n2), + types::Function::Not => calculate_negation(get_value(exp, f, r)), + types::Function::Negate => calculate_negate(get_value(exp, f, r)), + types::Function::Days => calculate_days(get_date_values(exp, f, r)), + types::Function::Right => calculate_right(get_number_and_string_values(exp, f, r)), + types::Function::Left => calculate_left(get_number_and_string_values(exp, f, r)), + types::Function::Iff => calculate_iff(get_iff_values(exp, f, r)), + types::Function::Custom(name) => { + let values: Vec = exp + .values + .iter() + .map(|v| calculate_formula(v.clone(), f, r)) + .collect(); + + match f { + Some(f) => match f(name, values) { + types::Value::Number(x) => types::Value::Number(x), + types::Value::Text(s) => types::Value::Text(s), + types::Value::Boolean(x) => types::Value::Boolean(x), + types::Value::Error(types::Error::Value) => { + types::Value::Error(types::Error::Value) + } + types::Value::Iterator(v) => types::Value::Iterator(v), + types::Value::Date(d) => types::Value::Date(d), + types::Value::Blank => types::Value::Blank, + _ => types::Value::Error(types::Error::Reference), + }, + None => types::Value::Error(types::Error::Reference), + } } - types::Function::Or => calculate_or(exp, f, |n1, n2| n1 || n2), - types::Function::And => calculate_bool(exp, f, |n1, n2| n1 && n2), - types::Function::Xor => calculate_xor(exp, f, |n1, n2| n1 ^ n2), - types::Function::Not => calculate_negation(get_value(exp, f)), - types::Function::Negate => calculate_negate(get_value(exp, f)), - types::Function::Days => calculate_days(get_date_values(exp, f)), - types::Function::Right => calculate_right(get_number_and_string_values(exp, f)), - types::Function::Left => calculate_left(get_number_and_string_values(exp, f)), - types::Function::Iff => calculate_iff(get_iff_values(exp, f)), } } fn calculate_operation( exp: types::Expression, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { - match exp.op { + // println!("operation"); + match &exp.op { types::Operator::Plus => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match value1 { types::Value::Date(d) => add_days_to_date(d, value2), _ => calculate_numeric_operator(value1, value2, |n1, n2| n1 + n2), @@ -1071,7 +1103,7 @@ fn calculate_operation( } types::Operator::Minus => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match value1 { types::Value::Date(d) => subtract_days_from_date(d, value2), _ => calculate_numeric_operator(value1, value2, |n1, n2| n1 - n2), @@ -1079,26 +1111,26 @@ fn calculate_operation( } types::Operator::Multiply => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); calculate_numeric_operator(value1, value2, |n1, n2| n1 * n2) } types::Operator::Divide => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match value2 { types::Value::Number(x) if x == 0.0 => types::Value::Error(types::Error::Div0), _ => calculate_numeric_operator(value1, value2, calculate_divide_operator), } } types::Operator::Power => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); calculate_numeric_operator(value1, value2, calculate_power_operator) } types::Operator::Concat => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); calculate_string_operator(value1, value2, calculate_concat_operator) } types::Operator::Equal => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 == d2) @@ -1107,7 +1139,7 @@ fn calculate_operation( } } types::Operator::NotEqual => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 != d2) @@ -1116,7 +1148,7 @@ fn calculate_operation( } } types::Operator::Greater => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 > d2) @@ -1125,7 +1157,7 @@ fn calculate_operation( } } types::Operator::Less => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 < d2) @@ -1134,7 +1166,7 @@ fn calculate_operation( } } types::Operator::GreaterOrEqual => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 >= d2) @@ -1143,7 +1175,7 @@ fn calculate_operation( } } types::Operator::LessOrEqual => { - let (value2, value1) = get_values(exp, f); + let (value2, value1) = get_values(exp, f, r); match (value1.clone(), value2.clone()) { (types::Value::Date(l), types::Value::Date(r)) => { compare_dates(l, r, |d1, d2| d1 <= d2) @@ -1151,7 +1183,7 @@ fn calculate_operation( _ => calculate_comparison_operator(value1, value2, |n1, n2| n1 <= n2), } } - types::Operator::Function(func) => calculate_function(func, exp, f), + types::Operator::Function(func) => calculate_function(func.clone(), exp, f, r), } } @@ -1161,23 +1193,28 @@ fn compare_dates( f: fn(d1: DateTime, d2: DateTime) -> bool, ) -> types::Value { if f(date1, date2) { - types::Value::Boolean(types::Boolean::True) + types::Value::Boolean(true) } else { - types::Value::Boolean(types::Boolean::False) + types::Value::Boolean(false) } } /// Evaluates a string that was parsed and stored in Expression Struct. -/// Takes an optional closure with the trait bound Fn(String) -> types::Value. +/// Takes an optional closure of custom functions with the trait bound Fn(String, Vec) -> types::Value. +/// Takes an optional closure of custom variables with the trait bound Fn(String) -> types::Value. pub fn calculate_formula( formula: types::Formula, - f: Option<&impl Fn(String) -> types::Value>, + f: Option<&impl Fn(String, Vec) -> types::Value>, + r: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { match formula { - types::Formula::Operation(exp) => calculate_operation(exp, f), - types::Formula::Value(val) => val, - types::Formula::Reference(string) => calculate_reference(string, f), - types::Formula::Iterator(vec) => calculate_iterator(vec, f), + types::Formula::Operation(exp) => calculate_operation(exp, f, r), + types::Formula::Value(val) => { + // println!("value"); + val + } + types::Formula::Reference(string) => calculate_reference(string, f, r), + types::Formula::Iterator(vec) => calculate_iterator(vec, f, r), } } @@ -1194,6 +1231,14 @@ pub fn result_to_string(_value: types::Value) -> String { } } +/// Converts a result from Value Enum to a printable string. +pub fn result_to_number(value: types::Value) -> Result { + match value { + types::Value::Number(number) => Ok(number), + _ => Err(types::Error::Argument), + } +} + fn show_number(number: f32) -> String { if number.is_infinite() { String::from("#DIV/0!") @@ -1213,10 +1258,10 @@ fn show_error(error: types::Error) -> String { } } -fn show_boolean(boolean: types::Boolean) -> String { +fn show_boolean(boolean: bool) -> String { match boolean { - types::Boolean::True => String::from("TRUE"), - types::Boolean::False => String::from("FALSE"), + true => String::from("TRUE"), + false => String::from("FALSE"), } } diff --git a/src/lib.rs b/src/lib.rs index 7b5d93e..2c2c64b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,16 +39,16 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"=1+2", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=1+2"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=(1*(2+3))*2", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=(1*(2+3))*2"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=1+3/0", None::); // error (#DIV/0!) -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=1+3/0"); // error (#DIV/0!) +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //!The last string is evaluated to #DIV/0!. @@ -61,12 +61,12 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"=\"Hello \" & \" World!\"", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=\"Hello \" & \" World!\""); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=1 + \"Hello\"", None::); // error (#CAST!) -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=1 + \"Hello\""); // error (#CAST!) +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //!Concatenating number and string results in a #CAST! error. @@ -79,12 +79,12 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"1.2", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"1.2"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"Hello World", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"Hello World"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -96,32 +96,32 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"=ABS(-1)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=ABS(-1)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=SUM(1,2,\"3\")", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=SUM(1,2,\"3\")"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=PRODUCT(ABS(1),2*1, 3,4*1)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=PRODUCT(ABS(1),2*1, 3,4*1)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\", 3)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\", 3)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\", 3)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\", 3)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\")", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\")"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=IF(TRUE,1,0)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=IF(TRUE,1,0)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -133,16 +133,16 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"=2>=1", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=2>=1"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=OR(1>1,1<>1)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=OR(1>1,1<>1)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=AND(\"test\",\"True\", 1, true) ", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=AND(\"test\",\"True\", 1, true) "); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -159,8 +159,8 @@ //!"B" => types::Value::Number(3.0), //!_ => types::Value::Error(types::Error::Value), //!}; -//!let formula = parse_formula::parse_string_to_formula(&"=A+B", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=A+B"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -172,16 +172,16 @@ //!use xlformula_engine::NoReference; //!use xlformula_engine::NoCustomFunction; //! -//!let formula = parse_formula::parse_string_to_formula(&"={1,2,3}+{1,2,3}", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"={1,2,3}+{1,2,3}"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=XOR({0,0,0})", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=XOR({0,0,0})"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=AVERAGE({1,2,3},1,2,3)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!let formula = parse_formula::parse_string_to_formula(&"=AVERAGE({1,2,3},1,2,3)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -204,16 +204,16 @@ //!_ => types::Value::Error(types::Error::Value), //!}; //! -//!let formula = parse_formula::parse_string_to_formula(&"=DAYS(end, start)", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=DAYS(end, start)"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=start+1", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=start+1"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //! -//!let formula = parse_formula::parse_string_to_formula(&"=end-3", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=end-3"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //! Ok(()) //!} @@ -227,26 +227,26 @@ //!use xlformula_engine::types; //!use xlformula_engine::NoReference; //! -//!let custom_functions = |s: String, params: Vec| match s.as_str() { -//!"Increase" => types::Value::Number(params[0] + 1.0), -//!"SimpleSum" => types::Value::Number(params[0] + params[1]), +//!let custom_functions = |s: String, params: Vec| match s.as_str() { +//!"Increase" => types::Value::Number(params[0].as_num().unwrap() + 1.0), +//!"SimpleSum" => types::Value::Number(params[0].as_num().unwrap() + params[1].as_num().unwrap()), //!"EqualFive" => types::Value::Number(5.0), //!_ => types::Value::Error(types::Error::Value), //!}; //! //!let formula = -//!parse_formula::parse_string_to_formula(&"=Increase(1)+1", Some(&custom_functions)); -//!let result = calculate::calculate_formula(formula, None::); +//!parse_formula::parse_string_to_formula(&"=Increase(1)+1"); +//!let result = calculate::calculate_formula(formula, Some(&custom_functions), None::); //!println!("Result is {}", calculate::result_to_string(result)); //! //!let formula = -//!parse_formula::parse_string_to_formula(&"=EqualFive()+1", Some(&custom_functions)); -//!let result = calculate::calculate_formula(formula, None::); +//!parse_formula::parse_string_to_formula(&"=EqualFive()+1"); +//!let result = calculate::calculate_formula(formula, Some(&custom_functions), None::); //!println!("Result is {}", calculate::result_to_string(result)); //! //!let formula = -//!parse_formula::parse_string_to_formula(&"=SimpleSum(1,2)", Some(&custom_functions)); -//!let result = calculate::calculate_formula(formula, None::); +//!parse_formula::parse_string_to_formula(&"=SimpleSum(1,2)"); +//!let result = calculate::calculate_formula(formula, Some(&custom_functions), None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` //! @@ -266,28 +266,28 @@ //!_ => types::Value::Error(types::Error::Value), //!}; //! -//!let custom_functions = |s: String, params: Vec| match s.as_str() { +//!let custom_functions = |s: String, params: Vec| match s.as_str() { //!"BLANK" => types::Value::Blank, //!_ => types::Value::Error(types::Error::Value), //!}; //! -//!let formula = parse_formula::parse_string_to_formula(&"=SUM(B, 1)", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=SUM(B, 1)"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //! //!let formula = -//!parse_formula::parse_string_to_formula(&"=SUM(BLANK(), 1)", Some(&custom_functions)); -//!let result = calculate::calculate_formula(formula, None::); +//!parse_formula::parse_string_to_formula(&"=SUM(BLANK(), 1)"); +//!let result = calculate::calculate_formula(formula, Some(&custom_functions), None::); //!println!("Result is {}", calculate::result_to_string(result)); //! //!//takes list as input -//!let formula = parse_formula::parse_string_to_formula(&"=SUM({B, 1})", None::); -//!let result = calculate::calculate_formula(formula, Some(&data_function)); +//!let formula = parse_formula::parse_string_to_formula(&"=SUM({B, 1})"); +//!let result = calculate::calculate_formula(formula, None::, Some(&data_function)); //!println!("Result is {}", calculate::result_to_string(result)); //! //!let formula = -//!parse_formula::parse_string_to_formula(&"=SUM(1, 2, , 3)", None::); -//!let result = calculate::calculate_formula(formula, None::); +//!parse_formula::parse_string_to_formula(&"=SUM(1, 2, , 3)"); +//!let result = calculate::calculate_formula(formula, None::, None::); //!println!("Result is {}", calculate::result_to_string(result)); //!``` @@ -304,4 +304,4 @@ pub mod types; pub mod parse_formula; pub type NoReference<'a> = &'a fn(String) -> types::Value; -pub type NoCustomFunction<'a> = &'a fn(String, Vec) -> types::Value; +pub type NoCustomFunction<'a> = &'a fn(String, Vec) -> types::Value; diff --git a/src/main.rs b/src/main.rs index a4695be..bfef011 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,118 +4,151 @@ use chrono::{DateTime, FixedOffset}; use xlformula_engine::calculate; use xlformula_engine::parse_formula; use xlformula_engine::types; -use xlformula_engine::NoCustomFunction; -use xlformula_engine::NoReference; +use xlformula_engine::{NoCustomFunction, NoReference}; fn main() -> Result<(), ParseError> { - let formula = parse_formula::parse_string_to_formula(&"=1+2", None::); - let result = calculate::calculate_formula(formula, None::); - println!("Result is {}", calculate::result_to_string(result)); + let formula = parse_formula::parse_string_to_formula(&"=1"); + let result = + calculate::calculate_formula(formula, None::, None::); + println!("Result is {}", calculate::result_to_number(result).unwrap()); let data_function = |s: String| match s.as_str() { - "A" => types::Value::Text("=1+B".to_string()), - "B" => types::Value::Number(3.0), - "C" => types::Value::Text("=1+A".to_string()), + "A" => types::Value::Text("TEXT".to_string()), + "B" => types::Value::Number(3.2), _ => types::Value::Error(types::Error::Value), }; - let formula = parse_formula::parse_string_to_formula(&"=A+B", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + + let formula = parse_formula::parse_string_to_formula(&"=A"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=SUM(A,B,C)", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + + let formula = parse_formula::parse_string_to_formula(&"=B"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); + println!("Result is {}", calculate::result_to_number(result).unwrap()); + + let custom_functions = |s: String, params: Vec| match s.as_str() { + "ONE" => types::Value::Number(params[0].as_num().unwrap() + 1.0), + "TWO" => types::Value::Number(params[0].as_num().unwrap() + params[1].as_num().unwrap()), + _ => types::Value::Error(types::Error::Value), + }; + + let formula = parse_formula::parse_string_to_formula(&"=ONE(1)"); + // println!("=ONE(1) > {:?}", formula); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=1+2", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=TWO(1.2,2.1)"); + // println!("=TWO(1.2, 2.1) > {:?}", formula); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=(1*(2+3))*2", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=ONE(B)"); + // println!("=ONE(B) > {:?}", formula); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=1+3/0", None::); // error (#DIV/0!) - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=A+B"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); + println!("Result is {}", calculate::result_to_string(result)); + let formula = parse_formula::parse_string_to_formula(&"=SUM(A,B,C)"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=\"Hello \" & \" World!\"", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=1+2"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=1 + \"Hello\"", None::); // error (#CAST!) - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=(1*(2+3))*2"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"1.2", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=1+3/0"); // error (#DIV/0!) + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"Hello World", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=\"Hello \" & \" World!\""); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=ABS(-1)", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=1 + \"Hello\""); // error (#CAST!) + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=SUM(1,2,\"3\")", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"1.2"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=PRODUCT(ABS(1),2*1, 3,4*1)", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"Hello World"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=2>=1", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=ABS(-1)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=OR(1>1,1<>1)", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=SUM(1,2,\"3\")"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=AND(\"test\",\"True\", 1, true) ", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=PRODUCT(ABS(1),2*1, 3,4*1)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=SUM({1,2,3}, 4, {5,6,7})", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=2>=1"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=AVERAGE({1,2,3},1,2,3)", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=OR(1>1,1<>1)"); + let result = + calculate::calculate_formula(formula, None::, None::); + println!("Result is {}", calculate::result_to_string(result)); + + let formula = parse_formula::parse_string_to_formula(&"=AND(\"test\",\"True\", 1, true) "); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=XOR({0,0,0})", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=SUM({1,2,3}, 4, {5,6,7})"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"={1,2,3}+{1,2,3}", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=AVERAGE({1,2,3},1,2,3)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"={0,0}+{1,2,3}", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=XOR({0,0,0})"); + let result = + calculate::calculate_formula(formula, None::, None::); + println!("Result is {}", calculate::result_to_string(result)); + + let formula = parse_formula::parse_string_to_formula(&"={1,2,3}+{1,2,3}"); + let result = + calculate::calculate_formula(formula, None::, None::); + println!("Result is {}", calculate::result_to_string(result)); + + let formula = parse_formula::parse_string_to_formula(&"={0,0}+{1,2,3}"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); // error (#ARG!) let start: DateTime = DateTime::parse_from_rfc3339("2019-03-01T02:00:00.000Z")?; @@ -126,76 +159,79 @@ fn main() -> Result<(), ParseError> { _ => types::Value::Error(types::Error::Value), }; - let formula = - parse_formula::parse_string_to_formula(&"=DAYS(end, start)", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=DAYS(end, start)"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=start+1", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=start+1"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula(&"=end-3", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=end-3"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let custom_functions = |s: String, params: Vec| match s.as_str() { - "Increase" => types::Value::Number(params[0] + 1.0), - "SimpleSum" => types::Value::Number(params[0] + params[1]), + let custom_functions = |s: String, params: Vec| match s.as_str() { + "Increase" => types::Value::Number(params[0].as_num().unwrap() + 1.0), + "SimpleSum" => { + types::Value::Number(params[0].as_num().unwrap() + params[1].as_num().unwrap()) + } "EqualFive" => types::Value::Number(5.0), _ => types::Value::Error(types::Error::Value), }; - let formula = - parse_formula::parse_string_to_formula(&"=Increase(1)+1", Some(&custom_functions)); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=Increase(1)+1"); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=EqualFive()+1", Some(&custom_functions)); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=EqualFive()+1"); + // println!("Formula[=EqualFive()+1] = {:?}", formula); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=SimpleSum(1,2)", Some(&custom_functions)); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=SimpleSum(1,2)"); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), None::); println!("Result is {}", calculate::result_to_string(result)); - let custom_function = |s: String, _params: Vec| match s.as_str() { + let custom_function = |s: String, _params: Vec| match s.as_str() { "EqualFive" => types::Value::Number(5.0), _ => types::Value::Error(types::Error::Value), }; - let formula = parse_formula::parse_string_to_formula(&"=EqualFive()", Some(&custom_function)); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=EqualFive()"); + let result = calculate::calculate_formula(formula, Some(&custom_function), None::); println!("Result is {}", calculate::result_to_string(result)); ///////////// RIGHT function - let formula = - parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\", 3)", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\", 3)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\")", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=RIGHT(\"apple\")"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = parse_formula::parse_string_to_formula( - &"=\"P\"&RIGHT(\"000\"&1,3)", - None::, - ); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=\"P\"&RIGHT(\"000\"&1,3)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); ///////////// LEFT function - let formula = - parse_formula::parse_string_to_formula(&"=LEFT(\"apple\", 3)", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\", 3)"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=LEFT(\"apple\")", None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=LEFT(\"apple\")"); + let result = + calculate::calculate_formula(formula, None::, None::); println!("Result is {}", calculate::result_to_string(result)); ///////////// Handle blank in calculation @@ -204,41 +240,43 @@ fn main() -> Result<(), ParseError> { _ => types::Value::Error(types::Error::Value), }; - let custom_functions = |s: String, params: Vec| match s.as_str() { - "Increase" => types::Value::Number(params[0] + 1.0), + let custom_functions = |s: String, params: Vec| match s.as_str() { + "Increase" => types::Value::Number(params[0].as_num().unwrap() + 1.0), "BLANK" => types::Value::Blank, _ => types::Value::Error(types::Error::Value), }; - let formula = parse_formula::parse_string_to_formula(&"=SUM(B, 1)", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=SUM(B, 1)"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=SUM(BLANK(), 1)", Some(&custom_functions)); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(&"=SUM(BLANK(), 1)"); + let result = + calculate::calculate_formula(formula, Some(&custom_functions), None::); println!("Result is {}", calculate::result_to_string(result)); let data_function = |s: String| match s.as_str() { - "T" => types::Value::Boolean(types::Boolean::True), + "T" => types::Value::Boolean(true), "B" => types::Value::Blank, - "F" => types::Value::Boolean(types::Boolean::False), + "F" => types::Value::Boolean(false), _ => types::Value::Error(types::Error::Value), }; - let formula = parse_formula::parse_string_to_formula(&"=OR({F,B})", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=OR({F,B})"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); - let formula = - parse_formula::parse_string_to_formula(&"=SUM(1, 2, , 3)", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=SUM(1, 2, , 3)"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); ///////////// IF function - let formula = - parse_formula::parse_string_to_formula(&"=IF(TRUE,1,0)", None::); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let formula = parse_formula::parse_string_to_formula(&"=IF(TRUE,1,0)"); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); let data_function = |s: String| match s.as_str() { @@ -249,10 +287,10 @@ fn main() -> Result<(), ParseError> { let formula = parse_formula::parse_string_to_formula( &"=IF(ReferenceKey=\"10\",\"\",ReferenceKey&\" - \")&ReferenceName", - None::, ); - let result = calculate::calculate_formula(formula, Some(&data_function)); + let result = + calculate::calculate_formula(formula, None::, Some(&data_function)); println!("Result is {}", calculate::result_to_string(result)); Ok(()) diff --git a/src/parse_formula.rs b/src/parse_formula.rs index cf36c2b..94b26a9 100644 --- a/src/parse_formula.rs +++ b/src/parse_formula.rs @@ -1,4 +1,6 @@ -extern crate pest; +use pest::pratt_parser::Assoc; +use pest::pratt_parser::Op; +use pest::pratt_parser::PrattParser; use pest::Parser; #[derive(Parser)] #[grammar = "grammar.pest"] @@ -6,10 +8,6 @@ pub struct GrammarParser; use crate::types; -use pest::prec_climber::Assoc; -use pest::prec_climber::Operator; -use pest::prec_climber::PrecClimber; - /// Use this function to catch a parse error. fn parse_string(s: &str) -> Option> { let parse_result = GrammarParser::parse(Rule::formula, s); @@ -40,11 +38,11 @@ fn parse_string_constant(parse_result: pest::iterators::Pair) -> types::Fo /// Parses a string and stores it in Formula Enum. pub fn parse_string_to_formula( s: &str, - f: Option<&impl Fn(String, Vec) -> types::Value>, + // f: Option<&impl Fn(String, Vec) -> types::Value>, ) -> types::Formula { match parse_string(&s) { Some(parse_result) => match parse_result.as_rule() { - Rule::expr => build_formula_with_climber(parse_result.into_inner(), f), + Rule::expr => build_formula_with_climber(parse_result.into_inner()), Rule::string_constant => parse_string_constant(parse_result), _ => types::Formula::Value(types::Value::Error(types::Error::Parse)), }, @@ -72,16 +70,15 @@ fn build_formula_string_single_quote(pair: pest::iterators::Pair) -> types fn build_formula_boolean(boolean_value: bool) -> types::Formula { if boolean_value { - types::Formula::Value(types::Value::Boolean(types::Boolean::True)) + types::Formula::Value(types::Value::Boolean(true)) } else { - types::Formula::Value(types::Value::Boolean(types::Boolean::False)) + types::Formula::Value(types::Value::Boolean(false)) } } fn build_formula_unary_operator( unary_operation: Rule, pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, ) -> types::Formula { let op_type = match unary_operation { Rule::abs => types::Operator::Function(types::Function::Abs), @@ -91,7 +88,7 @@ fn build_formula_unary_operator( }; let operation = types::Expression { op: op_type, - values: vec![build_formula_with_climber(pair.into_inner(), f)], + values: vec![build_formula_with_climber(pair.into_inner())], }; types::Formula::Operation(operation) } @@ -101,13 +98,10 @@ fn build_formula_reference(pair: pest::iterators::Pair) -> types::Formula types::Formula::Reference(string) } -fn build_formula_iterator( - pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, -) -> types::Formula { +fn build_formula_iterator(pair: pest::iterators::Pair) -> types::Formula { let mut vec = Vec::new(); for term in pair.into_inner() { - vec.push(build_formula_with_climber(term.into_inner(), f)); + vec.push(build_formula_with_climber(term.into_inner())); } types::Formula::Iterator(vec) } @@ -115,7 +109,6 @@ fn build_formula_iterator( fn build_formula_collective_operator( collective_operation: Rule, pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, ) -> types::Formula { let mut vec = Vec::new(); for term in pair.into_inner() { @@ -126,7 +119,7 @@ fn build_formula_collective_operator( { vec.push(types::Formula::Value(types::Value::Blank)) } else { - vec.push(build_formula_with_climber(term.into_inner(), f)) + vec.push(build_formula_with_climber(term.into_inner())) } } let op_type = rule_to_function_operator(collective_operation); @@ -156,7 +149,6 @@ fn rule_to_function_operator(collective_operation: Rule) -> types::Operator { fn build_formula_collective_operator_average( collective_operation: Rule, pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, ) -> types::Formula { let mut vec = Vec::new(); for term in pair.into_inner() { @@ -167,7 +159,7 @@ fn build_formula_collective_operator_average( { vec.push(types::Formula::Value(types::Value::Number(0.0))) } else { - vec.push(build_formula_with_climber(term.into_inner(), f)) + vec.push(build_formula_with_climber(term.into_inner())) } } let op_type = rule_to_function_operator(collective_operation); @@ -181,7 +173,6 @@ fn build_formula_collective_operator_average( fn build_formula_collective_operator_and( collective_operation: Rule, pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, ) -> types::Formula { let mut vec = Vec::new(); for term in pair.into_inner() { @@ -190,11 +181,9 @@ fn build_formula_collective_operator_and( | (term.as_str().parse::().unwrap() == ", ") | (term.as_str().parse::().unwrap() == " ,") { - vec.push(types::Formula::Value(types::Value::Boolean( - types::Boolean::False, - ))) + vec.push(types::Formula::Value(types::Value::Boolean(false))) } else { - vec.push(build_formula_with_climber(term.into_inner(), f)) + vec.push(build_formula_with_climber(term.into_inner())) } } let op_type = rule_to_function_operator(collective_operation); @@ -205,10 +194,7 @@ fn build_formula_collective_operator_and( types::Formula::Operation(operation) } -fn build_formula_iff( - pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, -) -> types::Formula { +fn build_formula_iff(pair: pest::iterators::Pair) -> types::Formula { let mut vec = Vec::new(); for term in pair.into_inner() { if (term.as_str().parse::().unwrap() == "") @@ -218,7 +204,7 @@ fn build_formula_iff( { vec.push(types::Formula::Value(types::Value::Blank)) } else { - vec.push(build_formula_with_climber(term.into_inner(), f)) + vec.push(build_formula_with_climber(term.into_inner())) } } let operation = types::Expression { @@ -228,49 +214,82 @@ fn build_formula_iff( types::Formula::Operation(operation) } -fn build_formula_custom_function( - pair: pest::iterators::Pair, - f: Option<&impl Fn(String, Vec) -> types::Value>, -) -> types::Formula { - let mut vec = Vec::new(); - for field in pair.clone().into_inner() { - match field.as_rule() { - Rule::expr => - // vec.push(field.into_inner().as_str().parse::().unwrap()), - // if custom formula is undefined, then don't have anything to push into vec - { - let x = field.into_inner().as_str(); - let y = x.parse::(); - match y { - Ok(_) => vec.push(y.unwrap()), - Err(_) => (), - } - } - _ => (), - } +fn build_formula_custom_function(pair: pest::iterators::Pair) -> types::Formula { + // println!("build_formula_custom_function - {:?}", pair); + + match pair.as_rule() { + Rule::custom_function => {} + _ => return types::Formula::Value(types::Value::Error(types::Error::Reference)), } - let mut ref_string = String::new(); - for field in pair.clone().into_inner() { - ref_string = match field.as_rule() { + + let mut iter = pair.clone().into_inner(); + + let name = match iter.next() { + Some(field) => match field.as_rule() { Rule::reference => field.as_str().parse::().unwrap(), - _ => ref_string, - } - } - match f { - Some(f) => match f(ref_string, vec) { - types::Value::Number(x) => types::Formula::Value(types::Value::Number(x)), - types::Value::Text(s) => types::Formula::Value(types::Value::Text(s)), - types::Value::Boolean(x) => types::Formula::Value(types::Value::Boolean(x)), - types::Value::Error(types::Error::Value) => { - types::Formula::Value(types::Value::Error(types::Error::Value)) - } - types::Value::Iterator(v) => types::Formula::Value(types::Value::Iterator(v)), - types::Value::Date(d) => types::Formula::Value(types::Value::Date(d)), - types::Value::Blank => types::Formula::Value(types::Value::Blank), - _ => types::Formula::Value(types::Value::Error(types::Error::Reference)), + _ => return types::Formula::Value(types::Value::Error(types::Error::Reference)), }, - None => types::Formula::Value(types::Value::Error(types::Error::Reference)), + None => return types::Formula::Value(types::Value::Error(types::Error::Reference)), + }; + + let mut vec = Vec::new(); + for field in iter { + match field.as_rule() { + Rule::empty_param => break, + _ => {} + } + let formula = build_formula_with_climber(field.into_inner()); + vec.push(formula); } + // println!("- fields: {:?}", &vec); + + types::Formula::Operation(types::Expression { + op: types::Operator::Function(types::Function::Custom(name)), + values: vec, + }) + + // let mut vec = Vec::new(); + // for field in pair.clone().into_inner() { + // match field.as_rule() { + // Rule::expr => + // // vec.push(field.into_inner().as_str().parse::().unwrap()), + // // if custom formula is undefined, then don't have anything to push into vec + // { + // let x = field.into_inner().as_str(); + // let y = x.parse::(); + // match y { + // Ok(_) => vec.push(y.unwrap()), + // Err(e) => { + // println!("Failed to parse field - {} : {}", e, x); + // () + // } + // } + // } + // _ => (), + // } + // } + // let mut ref_string = String::new(); + // for field in pair.clone().into_inner() { + // ref_string = match field.as_rule() { + // Rule::reference => field.as_str().parse::().unwrap(), + // _ => ref_string, + // } + // } + // match f { + // Some(f) => match f(ref_string, vec) { + // types::Value::Number(x) => types::Formula::Value(types::Value::Number(x)), + // types::Value::Text(s) => types::Formula::Value(types::Value::Text(s)), + // types::Value::Boolean(x) => types::Formula::Value(types::Value::Boolean(x)), + // types::Value::Error(types::Error::Value) => { + // types::Formula::Value(types::Value::Error(types::Error::Value)) + // } + // types::Value::Iterator(v) => types::Formula::Value(types::Value::Iterator(v)), + // types::Value::Date(d) => types::Formula::Value(types::Value::Date(d)), + // types::Value::Blank => types::Formula::Value(types::Value::Blank), + // _ => types::Formula::Value(types::Value::Error(types::Error::Reference)), + // }, + // None => types::Formula::Value(types::Value::Error(types::Error::Reference)), + // } } fn build_formula_binary_operator( @@ -301,67 +320,65 @@ fn build_formula_binary_operator( } /// Builds Formula Enum using a `pest-PrecClimber`. -fn build_formula_with_climber( - expression: pest::iterators::Pairs, - f: Option<&impl Fn(String, Vec) -> types::Value>, -) -> types::Formula { - let climber = PrecClimber::new(vec![ - Operator::new(Rule::concat, Assoc::Left), - Operator::new(Rule::equal, Assoc::Left) | Operator::new(Rule::not_equal, Assoc::Left), - Operator::new(Rule::greater, Assoc::Left) - | Operator::new(Rule::less, Assoc::Left) - | Operator::new(Rule::greater_or_equal, Assoc::Left) - | Operator::new(Rule::less_or_equal, Assoc::Left), - Operator::new(Rule::add, Assoc::Left) | Operator::new(Rule::subtract, Assoc::Left), - Operator::new(Rule::multiply, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left), - Operator::new(Rule::power, Assoc::Right), - ]); - climber.climb( - expression, - |pair: pest::iterators::Pair| match pair.as_rule() { +fn build_formula_with_climber(expression: pest::iterators::Pairs) -> types::Formula { + let climber = PrattParser::new() + .op(Op::infix(Rule::concat, Assoc::Left)) + .op(Op::infix(Rule::equal, Assoc::Left) | Op::infix(Rule::not_equal, Assoc::Left)) + .op(Op::infix(Rule::greater, Assoc::Left) + | Op::infix(Rule::less, Assoc::Left) + | Op::infix(Rule::greater_or_equal, Assoc::Left) + | Op::infix(Rule::less_or_equal, Assoc::Left)) + .op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::subtract, Assoc::Left)) + .op(Op::infix(Rule::multiply, Assoc::Left) | Op::infix(Rule::divide, Assoc::Left)) + .op(Op::infix(Rule::power, Assoc::Right)); + + climber + .map_primary(|pair: pest::iterators::Pair| match pair.as_rule() { Rule::number => build_formula_number(pair), Rule::string_double_quote => build_formula_string_double_quote(pair), Rule::string_single_quote => build_formula_string_single_quote(pair), Rule::t => build_formula_boolean(true), Rule::f => build_formula_boolean(false), - Rule::abs => build_formula_unary_operator(Rule::abs, pair, f), - Rule::sum => build_formula_collective_operator(Rule::sum, pair, f), - Rule::product => build_formula_collective_operator(Rule::product, pair, f), - Rule::average => build_formula_collective_operator_average(Rule::average, pair, f), - Rule::or => build_formula_collective_operator(Rule::or, pair, f), - Rule::and => build_formula_collective_operator_and(Rule::and, pair, f), - Rule::xor => build_formula_collective_operator(Rule::xor, pair, f), - Rule::not => build_formula_unary_operator(Rule::not, pair, f), + Rule::abs => build_formula_unary_operator(Rule::abs, pair), + Rule::sum => build_formula_collective_operator(Rule::sum, pair), + Rule::product => build_formula_collective_operator(Rule::product, pair), + Rule::average => build_formula_collective_operator_average(Rule::average, pair), + Rule::or => build_formula_collective_operator(Rule::or, pair), + Rule::and => build_formula_collective_operator_and(Rule::and, pair), + Rule::xor => build_formula_collective_operator(Rule::xor, pair), + Rule::not => build_formula_unary_operator(Rule::not, pair), Rule::reference => build_formula_reference(pair), - Rule::iterator => build_formula_iterator(pair, f), - Rule::negate => build_formula_unary_operator(Rule::negate, pair, f), - Rule::expr => build_formula_with_climber(pair.into_inner(), f), - Rule::days => build_formula_collective_operator(Rule::days, pair, f), - Rule::right => build_formula_collective_operator(Rule::right, pair, f), - Rule::left => build_formula_collective_operator(Rule::left, pair, f), - Rule::custom_function => build_formula_custom_function(pair, f), - Rule::iff => build_formula_iff(pair, f), - Rule::atomic_expr => build_formula_with_climber(pair.into_inner(), f), - _ => unreachable!(), - }, - |lhs: types::Formula, op: pest::iterators::Pair, rhs: types::Formula| match op - .as_rule() - { - Rule::add => build_formula_binary_operator(Rule::add, lhs, rhs), - Rule::subtract => build_formula_binary_operator(Rule::subtract, lhs, rhs), - Rule::multiply => build_formula_binary_operator(Rule::multiply, lhs, rhs), - Rule::divide => build_formula_binary_operator(Rule::divide, lhs, rhs), - Rule::power => build_formula_binary_operator(Rule::power, lhs, rhs), - Rule::concat => build_formula_binary_operator(Rule::concat, lhs, rhs), - Rule::equal => build_formula_binary_operator(Rule::equal, lhs, rhs), - Rule::not_equal => build_formula_binary_operator(Rule::not_equal, lhs, rhs), - Rule::greater => build_formula_binary_operator(Rule::greater, lhs, rhs), - Rule::less => build_formula_binary_operator(Rule::less, lhs, rhs), - Rule::greater_or_equal => { - build_formula_binary_operator(Rule::greater_or_equal, lhs, rhs) - } - Rule::less_or_equal => build_formula_binary_operator(Rule::less_or_equal, lhs, rhs), + Rule::iterator => build_formula_iterator(pair), + Rule::negate => build_formula_unary_operator(Rule::negate, pair), + Rule::expr => build_formula_with_climber(pair.into_inner()), + Rule::days => build_formula_collective_operator(Rule::days, pair), + Rule::right => build_formula_collective_operator(Rule::right, pair), + Rule::left => build_formula_collective_operator(Rule::left, pair), + Rule::custom_function => build_formula_custom_function(pair), + Rule::iff => build_formula_iff(pair), + Rule::atomic_expr => build_formula_with_climber(pair.into_inner()), _ => unreachable!(), - }, - ) + }) + .map_infix( + |lhs: types::Formula, op: pest::iterators::Pair, rhs: types::Formula| match op + .as_rule() + { + Rule::add => build_formula_binary_operator(Rule::add, lhs, rhs), + Rule::subtract => build_formula_binary_operator(Rule::subtract, lhs, rhs), + Rule::multiply => build_formula_binary_operator(Rule::multiply, lhs, rhs), + Rule::divide => build_formula_binary_operator(Rule::divide, lhs, rhs), + Rule::power => build_formula_binary_operator(Rule::power, lhs, rhs), + Rule::concat => build_formula_binary_operator(Rule::concat, lhs, rhs), + Rule::equal => build_formula_binary_operator(Rule::equal, lhs, rhs), + Rule::not_equal => build_formula_binary_operator(Rule::not_equal, lhs, rhs), + Rule::greater => build_formula_binary_operator(Rule::greater, lhs, rhs), + Rule::less => build_formula_binary_operator(Rule::less, lhs, rhs), + Rule::greater_or_equal => { + build_formula_binary_operator(Rule::greater_or_equal, lhs, rhs) + } + Rule::less_or_equal => build_formula_binary_operator(Rule::less_or_equal, lhs, rhs), + _ => unreachable!(), + }, + ) + .parse(expression) } diff --git a/src/types.rs b/src/types.rs index 8c38e67..c1a0203 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, FixedOffset}; /// Defines Excel Functions. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub enum Function { Abs, Sum, @@ -15,10 +15,11 @@ pub enum Function { Right, Left, Iff, + Custom(String), } /// Defines Excel Operators. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub enum Operator { Plus, Minus, @@ -46,25 +47,141 @@ pub enum Error { Reference, } -/// Defines boolean types. -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum Boolean { - True, - False, -} +// /// Defines boolean types. +// #[derive(Debug, Copy, Clone, PartialEq)] +// pub enum Boolean { +// True, +// False, +// } /// The result of an evaluation. #[derive(Debug, Clone, PartialEq)] pub enum Value { Number(f32), Text(String), - Boolean(Boolean), + Boolean(bool), Iterator(Vec), Error(Error), Date(DateTime), Blank, } +impl Value { + pub fn as_num(&self) -> Result { + match self { + Value::Number(v) => Ok(*v), + Value::Text(v) => match v.parse::() { + Err(_) => Err(Error::Cast), + Ok(v) => Ok(v), + }, + Value::Boolean(v) => match v { + true => Ok(1.0), + false => Ok(0.0), + }, + Value::Blank => Ok(0.0), + _ => Err(Error::Cast), + } + } + + pub fn as_string(&self) -> Result { + match self { + Value::Number(v) => Ok(format!("{}", v)), + Value::Text(v) => Ok(v.clone()), + Value::Boolean(v) => match v { + true => Ok("1.0".to_owned()), + false => Ok("0.0".to_owned()), + }, + Value::Blank => Ok("".to_owned()), + _ => Err(Error::Cast), + } + } + + pub fn as_bool(&self) -> Result { + match self { + Value::Number(v) => Ok(*v > 0.0), + Value::Text(v) => Ok(v.len() > 0), + Value::Boolean(v) => match v { + true => Ok(true), + false => Ok(false), + }, + Value::Blank => Ok(false), + _ => Err(Error::Cast), + } + } +} + +impl From for Value { + fn from(v: u8) -> Self { + Value::Number(v as f32) + } +} + +impl From for Value { + fn from(v: u32) -> Self { + Value::Number(v as f32) + } +} + +impl From for Value { + fn from(v: i32) -> Self { + Value::Number(v as f32) + } +} + +impl From for Value { + fn from(v: f32) -> Self { + Value::Number(v) + } +} + +impl From<&u8> for Value { + fn from(v: &u8) -> Self { + Value::Number(*v as f32) + } +} + +impl From<&u32> for Value { + fn from(v: &u32) -> Self { + Value::Number(*v as f32) + } +} + +impl From<&i32> for Value { + fn from(v: &i32) -> Self { + Value::Number(*v as f32) + } +} + +impl From<&f32> for Value { + fn from(v: &f32) -> Self { + Value::Number(*v) + } +} + +impl From<&str> for Value { + fn from(v: &str) -> Self { + Value::Text(v.to_owned()) + } +} + +impl From for Value { + fn from(v: String) -> Self { + Value::Text(v) + } +} + +impl From<&String> for Value { + fn from(v: &String) -> Self { + Value::Text(v.clone()) + } +} + +impl From for Value { + fn from(v: bool) -> Self { + Value::Boolean(v) + } +} + /// Defines each term in Expression Struct. #[derive(Debug, Clone)] pub enum Formula { diff --git a/tests/test.rs b/tests/test.rs index 9d88b20..ebe5d03 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -11,14 +11,16 @@ use chrono::{DateTime, Duration, FixedOffset}; use assert_approx_eq::assert_approx_eq; fn evaluate_formula_number(s: &str) -> f32 { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(s); + let result = + calculate::calculate_formula(formula, None::, None::); calculate::result_to_string(result).parse::().unwrap() } fn evaluate_formula_string(s: &str) -> String { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(s); + let result = + calculate::calculate_formula(formula, None::, None::); calculate::result_to_string(result) } @@ -26,8 +28,8 @@ fn evaluate_formula_string_with_reference( s: &str, f: Option<&impl Fn(String) -> types::Value>, ) -> String { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, f); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, None::, f); calculate::result_to_string(result) } @@ -35,8 +37,8 @@ fn evaluate_formula_number_with_reference( s: &str, f: Option<&impl Fn(String) -> types::Value>, ) -> f32 { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, f); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, None::, f); calculate::result_to_string(result).parse::().unwrap() } @@ -44,8 +46,8 @@ fn evaluate_formula_number_with_reference_no_conversion( s: &str, f: Option<&impl Fn(String) -> types::Value>, ) -> types::Value { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, f); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, None::, f); result //calculate::result_to_string(result).parse::().unwrap() } @@ -54,8 +56,8 @@ fn evaluate_formula_boolean_with_reference( s: &str, f: Option<&impl Fn(String) -> types::Value>, ) -> String { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, f); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, None::, f); calculate::result_to_string(result) //.parse::().unwrap() } @@ -63,38 +65,38 @@ fn evaluate_formula_date_with_reference( s: &str, f: Option<&impl Fn(String) -> types::Value>, ) -> String { - let formula = parse_formula::parse_string_to_formula(s, None::); - let result = calculate::calculate_formula(formula, f); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, None::, f); calculate::result_to_string(result) } fn evaluate_formula_number_with_custom_function( s: &str, - custom_function: Option<&impl Fn(String, Vec) -> types::Value>, + custom_function: Option<&impl Fn(String, Vec) -> types::Value>, //reference: Option<&impl Fn(String) -> types::Value>, ) -> f32 { - let formula = parse_formula::parse_string_to_formula(s, custom_function); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, custom_function, None::); calculate::result_to_string(result).parse::().unwrap() } fn evaluate_formula_string_with_custom_function( s: &str, - custom_function: Option<&impl Fn(String, Vec) -> types::Value>, + custom_function: Option<&impl Fn(String, Vec) -> types::Value>, //reference: Option<&impl Fn(String) -> types::Value>, ) -> String { - let formula = parse_formula::parse_string_to_formula(s, custom_function); - let result = calculate::calculate_formula(formula, None::); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, custom_function, None::); calculate::result_to_string(result) } fn _evaluate_formula_number_with_custom_function_and_reference( s: &str, - custom_function: Option<&impl Fn(String, Vec) -> types::Value>, + custom_function: Option<&impl Fn(String, Vec) -> types::Value>, reference: Option<&impl Fn(String) -> types::Value>, ) -> f32 { - let formula = parse_formula::parse_string_to_formula(s, custom_function); - let result = calculate::calculate_formula(formula, reference); + let formula = parse_formula::parse_string_to_formula(s); + let result = calculate::calculate_formula(formula, custom_function, reference); calculate::result_to_string(result).parse::().unwrap() } @@ -571,8 +573,8 @@ fn it_evaluate_references_other_formulas() { #[test] fn it_evaluate_references_boolean_formulas() { let data_function = |s: String| match s.as_str() { - "A" => types::Value::Boolean(types::Boolean::True), - "B" => types::Value::Boolean(types::Boolean::False), + "A" => types::Value::Boolean(true), + "B" => types::Value::Boolean(false), _ => types::Value::Error(types::Error::Value), }; assert_eq!( @@ -584,8 +586,8 @@ fn it_evaluate_references_boolean_formulas() { #[test] fn it_evaluate_references_error_value_formulas() { let data_function = |s: String| match s.as_str() { - "A" => types::Value::Boolean(types::Boolean::True), - "B" => types::Value::Error(types::Error::Value), //types::Value::Boolean(types::Boolean::False), + "A" => types::Value::Boolean(true), + "B" => types::Value::Error(types::Error::Value), //types::Value::Boolean(false), _ => types::Value::Error(types::Error::Value), }; assert_eq!( @@ -720,10 +722,14 @@ fn it_evaluate_date() -> Result<(), ParseError> { #[test] fn it_evaluate_custom_functions_() { - let custom_functions = |s: String, params: Vec| match s.as_str() { - "Increase" => types::Value::Number(params[0] + 1.0), - "SimpleSum" => types::Value::Number(params[0] + params[1]), - "CustomSum" => types::Value::Number(params[0] + params[1] + params[2]), + let custom_functions = |s: String, params: Vec| match s.as_str() { + "Increase" => types::Value::Number(params[0].as_num().unwrap() + 1.0), + "SimpleSum" => { + types::Value::Number(params[0].as_num().unwrap() + params[1].as_num().unwrap()) + } + "CustomSum" => types::Value::Number( + params[0].as_num().unwrap() + params[1].as_num().unwrap() + params[2].as_num().unwrap(), + ), "EqualFive" => types::Value::Number(5.0), "CountText" => types::Value::Text(10.0.to_string()), "CountNumber" => types::Value::Number(20.0), @@ -761,6 +767,38 @@ fn it_evaluate_custom_functions_() { ); } +#[test] +fn it_evaluate_custom_functions_with_reference() { + let custom_functions = |s: String, params: Vec| match s.as_str() { + "Increase" => types::Value::Number(params[0].as_num().unwrap() + 1.0), + "SimpleSum" => { + types::Value::Number(params[0].as_num().unwrap() + params[1].as_num().unwrap()) + } + "CustomSum" => types::Value::Number( + params[0].as_num().unwrap() + params[1].as_num().unwrap() + params[2].as_num().unwrap(), + ), + "EqualFive" => types::Value::Number(5.0), + "CountText" => types::Value::Text(10.0.to_string()), + "CountNumber" => types::Value::Number(20.0), + _ => types::Value::Error(types::Error::Value), + }; + + let data_function = |s: String| match s.as_str() { + "start" => types::Value::Number(5.0), + "end" => types::Value::Number(10.0), + _ => types::Value::Error(types::Error::Value), + }; + + assert_eq!( + _evaluate_formula_number_with_custom_function_and_reference( + &"=Increase(start)", + Some(&custom_functions), + Some(&data_function) + ), + 6.0 + ); +} + #[test] fn it_evaluate_left_and_right_functions() { assert_eq!(evaluate_formula_string(&"=RIGHT(\"apple\", 3)"), "ple",); @@ -1038,9 +1076,9 @@ fn it_evaluates_blanks_with_operators_and_reference() { #[test] fn it_evaluates_blanks_in_boolean_operations() { let data_function = |s: String| match s.as_str() { - "T" => types::Value::Boolean(types::Boolean::True), + "T" => types::Value::Boolean(true), "B" => types::Value::Blank, - "F" => types::Value::Boolean(types::Boolean::False), + "F" => types::Value::Boolean(false), _ => types::Value::Error(types::Error::Value), }; assert_eq!( @@ -1197,7 +1235,7 @@ fn it_evaluates_blanks_string_operations() { #[test] fn it_evaluates_blank_constructors() { - let custom_functions = |s: String, _params: Vec| match s.as_str() { + let custom_functions = |s: String, _params: Vec| match s.as_str() { "BLANK" => types::Value::Blank, _ => types::Value::Error(types::Error::Value), }; @@ -1298,9 +1336,9 @@ fn it_evaluates_blank_in_iterators() { #[test] fn it_evaluates_blank_with_iterators_in_boolean_operations() { let data_function = |s: String| match s.as_str() { - "T" => types::Value::Boolean(types::Boolean::True), + "T" => types::Value::Boolean(true), "B" => types::Value::Blank, - "F" => types::Value::Boolean(types::Boolean::False), + "F" => types::Value::Boolean(false), _ => types::Value::Error(types::Error::Value), }; assert_eq!(