Merge pull request #4 from PlexSheep/devel
Shunting yard generates reverse polish notation
This commit is contained in:
commit
801e052ce2
|
@ -1,2 +1,4 @@
|
|||
/target
|
||||
/bin/**
|
||||
Cargo.lock
|
||||
Cargo.lock
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
||||
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'rclc'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"run",
|
||||
"--bin=rclc",
|
||||
"--package=rust_command_line_calculator",
|
||||
],
|
||||
"filter": {
|
||||
"name": "rclc",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": ["(())()"],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'rclc'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=rclc",
|
||||
"--package=rust_command_line_calculator",
|
||||
],
|
||||
"filter": {
|
||||
"name": "rclc",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,452 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"is-terminal",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rust_command_line_calculator"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"num",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"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 = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rust_command_line_calculator"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||
license = "GPL3"
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
use std::fmt;
|
||||
use std::{fmt, error::Error, num::IntErrorKind};
|
||||
use regex::Regex;
|
||||
|
||||
pub mod shunting_yard;
|
||||
|
||||
fn normalize_string(to_normalize: String) -> String {
|
||||
let mut normalized_text = to_normalize;
|
||||
normalized_text.retain(|c| !c.is_whitespace());
|
||||
normalized_text = normalized_text.to_string();
|
||||
normalized_text
|
||||
}
|
||||
|
||||
// In an expression like `sqrt(25)` the Task would correspond to `sqrt`. This is the enum to
|
||||
// configure possible Tasks.
|
||||
// None means, the Expression doesn't send it's Value to a Task Handler
|
||||
#[derive(Debug)] // automatically generate Debug Formatter
|
||||
pub enum Task {
|
||||
None,
|
||||
Sqrt,
|
||||
Power,
|
||||
Log(u64),
|
||||
Root(u64),
|
||||
Power(f64),
|
||||
Log(f64),
|
||||
}
|
||||
|
||||
// How to clone a Task, i was supprised I had to do it myself.
|
||||
|
@ -18,39 +27,83 @@ impl Clone for Task {
|
|||
// This can probably be done cleaner than with a verbose match. FIXME
|
||||
match self {
|
||||
Task::None => Task::None,
|
||||
Task::Sqrt => Task::Sqrt,
|
||||
Task::Power => Task::Power,
|
||||
Task::Root(depth) => Task::Root(*depth),
|
||||
Task::Power(exp) => Task::Power(*exp),
|
||||
Task::Log(base) => Task::Log(*base), // TODO add base for log
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new(task_text: &str) -> Task {
|
||||
match task_text {
|
||||
pub fn new(task_text: &str, task_param: &str) -> Task {
|
||||
if task_text.is_empty() {
|
||||
return Task::None;
|
||||
}
|
||||
let task_text = task_text.to_lowercase();
|
||||
match task_text.as_str() {
|
||||
"none" => Task::None,
|
||||
"sqrt" => Task::Sqrt,
|
||||
"power"|"pow" => Task::Power,
|
||||
"log"|"ln" => Task::Log(10), // TODO add base
|
||||
"sqrt"|"root" => {
|
||||
if task_param.is_empty() {
|
||||
return Task::Root(2);
|
||||
}
|
||||
let pot_param = task_param.parse::<u64>();
|
||||
match pot_param {
|
||||
Ok(value) => {Task::Root(value)},
|
||||
Err(error) => {
|
||||
eprintln!("could not parse task parameter: {error}");
|
||||
std::process::exit(1);
|
||||
},
|
||||
}
|
||||
},
|
||||
"power"|"pow"|"sq" => {
|
||||
if task_param.is_empty() {
|
||||
return Task::Power(2.0);
|
||||
}
|
||||
let pot_param = task_param.parse::<f64>();
|
||||
match pot_param {
|
||||
Ok(value) => {Task::Power(value)},
|
||||
Err(error) => {
|
||||
eprintln!("could not parse task parameter: {error}");
|
||||
std::process::exit(1);
|
||||
},
|
||||
}
|
||||
},
|
||||
"log"|"ln" => {
|
||||
if task_param.is_empty() {
|
||||
return Task::Log(10.0);
|
||||
}
|
||||
let pot_param = task_param.parse::<f64>();
|
||||
match pot_param {
|
||||
Ok(value) => {Task::Log(value)},
|
||||
Err(error) => {
|
||||
eprintln!("could not parse task parameter: {error}");
|
||||
std::process::exit(1);
|
||||
},
|
||||
}
|
||||
},
|
||||
// what to do if a bad task was given:
|
||||
&_ => {eprintln!("Bad Task: {}", task_text); std::process::exit(1); },
|
||||
// this would be throwing an error and aborting
|
||||
//&_ => {eprintln!("Bad Task: {}", task_text); std::process::exit(1); },
|
||||
_ => Task::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// An Expression is something that can be calculated. 20+5 is an expression. Expressions can
|
||||
// contain other
|
||||
// Expressions and have tasks: 20+sqrt(20+5)
|
||||
// Expressions and have tasks: 20+log_10(20+5)
|
||||
// Tasks may have parameters, denoted using an underscore '_'
|
||||
// Expressions are marked down with braces and a task before those braces:
|
||||
// task(Expression)
|
||||
// once the Value of the Expression got calculated, the calculated value should be sent to the
|
||||
// TaskHandler, if the Task of the Expression is not Task::None
|
||||
pub struct Expression {
|
||||
text: String,
|
||||
pub text: String,
|
||||
full_text: String,
|
||||
task: Task,
|
||||
complex: bool,
|
||||
inner_value: f64,
|
||||
outer_value: f64,
|
||||
outer_value: Result<f64, String>,
|
||||
children: Vec<Expression>,
|
||||
depth: u8,
|
||||
}
|
||||
|
||||
// Debug Formatter for Expression
|
||||
|
@ -58,11 +111,12 @@ impl fmt::Debug for Expression {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Expression")
|
||||
.field("text", &self.text)
|
||||
.field("full text", &self.full_text)
|
||||
.field("task", &self.task)
|
||||
.field("is complex?", &self.complex)
|
||||
.field("inner value", &self.inner_value)
|
||||
.field("outer value", &self.outer_value)
|
||||
.field("children", &self.children)
|
||||
.field("depth", &self.depth)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -72,15 +126,56 @@ impl Clone for Expression{
|
|||
fn clone(&self) -> Self {
|
||||
Expression {
|
||||
text: self.text.clone(),
|
||||
full_text: self.full_text.clone(),
|
||||
task: self.task.clone(),
|
||||
complex: self.complex.clone(), // TODO add support for complex numbers
|
||||
inner_value: self.inner_value.clone(),
|
||||
outer_value: self.outer_value.clone(),
|
||||
children: self.children.clone(),
|
||||
depth: self.depth.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_brace_groups(haystack: String) -> Vec<Vec<(usize, usize)>> {
|
||||
|
||||
// TODO add support for diffrent braces
|
||||
// TODO add error if not all braces are closed
|
||||
let mut parenthesis_group: Vec<(usize, usize)> = Vec::new();
|
||||
let mut parenthesis_open: usize = 0;
|
||||
let mut parenthesis_open_processed: usize = 0;
|
||||
let mut parenthesis_closed_processed: usize = 0;
|
||||
let mut parenthesis_last_opened: Vec<usize> = Vec::new();
|
||||
//let mut brackets_group: Vec<(usize, usize)> = Vec::new();
|
||||
//let mut brackets_open: usize = 0;
|
||||
//let mut square_braces_group: Vec<(usize, usize)> = Vec::new();
|
||||
//let mut square_braces_open: usize = 0;
|
||||
// first open stuff
|
||||
for (index, char) in haystack.chars().enumerate() {
|
||||
match char {
|
||||
'(' => {
|
||||
parenthesis_group.push((index, 0));
|
||||
parenthesis_open = parenthesis_open + 1;
|
||||
parenthesis_last_opened.push(parenthesis_open_processed);
|
||||
parenthesis_open_processed = parenthesis_open_processed + 1;
|
||||
},
|
||||
')' => {
|
||||
parenthesis_group[parenthesis_last_opened[parenthesis_last_opened.len() - 1]].1 = index;
|
||||
parenthesis_open = parenthesis_open - 1;
|
||||
parenthesis_closed_processed = parenthesis_closed_processed + 1;
|
||||
parenthesis_last_opened.pop();
|
||||
// TODO add error if no parenthesis is open yet.
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
// now iterate backwards and search for closing things
|
||||
|
||||
let brace_groups = vec![parenthesis_group/*, square_braces_group, brackets_group*/];
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&brace_groups);
|
||||
return brace_groups;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main logic for the Expression struct
|
||||
*/
|
||||
|
@ -90,66 +185,133 @@ impl Expression {
|
|||
* example: "12 + log_10(10 + 15) + 3"
|
||||
* has a sub expression log_10(10 + 5), which has Task::Log with base 10
|
||||
*/
|
||||
pub fn new(expression_text: String, task: Task) -> Expression {
|
||||
pub fn new(expression_text: String, expression_full_text: String, task: Task, depth: u8) -> Expression {
|
||||
|
||||
// find children
|
||||
// TODO add error for unused task parameters
|
||||
let re_sub_expression = Regex::new(r"\w+\(.+?\)").unwrap();
|
||||
if re_sub_expression.is_match(&expression_text) {
|
||||
let mut children: Vec<Expression> = Vec::new();
|
||||
for sub_expression_text in re_sub_expression.captures_iter(&expression_text) {
|
||||
// if any task parameters are set ( syntax: task_para(expression) )
|
||||
if sub_expression_text[0].contains('_') {
|
||||
let task_and_expr: Vec<&str> = sub_expression_text[0].split(['_', '(']).collect();
|
||||
// check if we are too deep
|
||||
if depth > 254 {
|
||||
eprintln!("Expression '{}' has a too deep family tree. Maximum generations are 254.", expression_text);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let task_text = task_and_expr[0].clone().to_lowercase();
|
||||
let task_param = task_and_expr[1].clone().to_string();
|
||||
let task = match task_text.as_str() {
|
||||
"none" => Task::None,
|
||||
"sqrt" => Task::Sqrt,
|
||||
"power" => Task::Power,
|
||||
"log" => {let base: u64 = task_param.parse().unwrap(); Task::Log(base)},
|
||||
// what to do if a bad task was given:
|
||||
&_ => {eprintln!("Bad Task: {}", task_text); std::process::exit(1); },
|
||||
};
|
||||
let expression_inner = task_and_expr[2].clone().to_string();
|
||||
children.push(Expression::new(expression_inner, task));
|
||||
}
|
||||
// if there are no parameters we need to do diffrent splitting and assume defaults
|
||||
else {
|
||||
let task_and_expr: Vec<&str> = sub_expression_text[0].split(['(']).collect();
|
||||
let expression_text = normalize_string(expression_text);
|
||||
let mut task_text_full: String;
|
||||
let mut children: Vec<Expression> = Vec::new();
|
||||
|
||||
let task_text = task_and_expr[0].clone().to_lowercase();
|
||||
let task = match task_text.as_str() {
|
||||
"none" => Task::None,
|
||||
"sqrt" => Task::Sqrt,
|
||||
"power" => Task::Power,
|
||||
"log" => Task::Log(10),
|
||||
// what to do if a bad task was given:
|
||||
&_ => {eprintln!("Bad Task: {}", task_text); std::process::exit(1); },
|
||||
};
|
||||
let expression_inner = task_and_expr[1].clone().to_string();
|
||||
children.push(Expression::new(expression_inner, task));
|
||||
let re_contains_sub_expression= Regex::new(r"(\(.*\))|(\[.*\])|(\{.*\})").unwrap();
|
||||
|
||||
if re_contains_sub_expression.is_match(expression_text.as_str()) {
|
||||
let brace_groups: Vec<Vec<(usize, usize)>> = find_brace_groups(expression_text.clone());
|
||||
|
||||
let mut brace_groups_texts: Vec<String> = Vec::new();
|
||||
|
||||
// 1 brace group per possible combination, by default, this is only (), so 1 iteration.
|
||||
// This is still O(n¹)
|
||||
for brace_group in brace_groups {
|
||||
for pair in brace_group {
|
||||
let text = &expression_text[pair.0..pair.1 + 1];
|
||||
let text = &text[1..text.len() - 1];
|
||||
brace_groups_texts.push(text.to_string());
|
||||
// we have the expression_text, now we just need to get the task until we can
|
||||
// pass these parameters into Expression::new(). This is the recursive part.
|
||||
let possible_task = &expression_text[..pair.0].chars().rev().collect::<String>();
|
||||
let mut stop_at: usize = 0;
|
||||
for (index, char) in possible_task.chars().enumerate() {
|
||||
if !(char.is_alphanumeric()) {
|
||||
break;
|
||||
}
|
||||
stop_at = index;
|
||||
}
|
||||
dbg!(&stop_at);
|
||||
// needed for none task: '1 + (1 + 1)'
|
||||
let fixup = if stop_at == 0 { 0 } else { 1 };
|
||||
task_text_full = possible_task.clone()[..stop_at+ fixup].chars().rev().collect::<String>();
|
||||
let task: Task;
|
||||
if task_text_full.contains('_') {
|
||||
let split: Vec<&str> = task_text_full.split('_').collect();
|
||||
task = Task::new(split[0], split[1]);
|
||||
}
|
||||
else {
|
||||
task = Task::new(task_text_full.as_str(), "");
|
||||
}
|
||||
let child_full_text = task_text_full + "(" + text + ")";
|
||||
let child = Expression::new(text.to_string(), child_full_text, task, depth+1);
|
||||
children.push(child);
|
||||
}
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(children);
|
||||
}
|
||||
}
|
||||
|
||||
let expression = Expression {
|
||||
text: expression_text,
|
||||
// TODO generate these from the text!
|
||||
task: task,
|
||||
full_text: normalize_string(expression_full_text),
|
||||
task,
|
||||
complex: false,
|
||||
inner_value: 0.0,
|
||||
outer_value: 0.0,
|
||||
children: Vec::new(),
|
||||
outer_value: Err("Value not yet calculated.".to_string()),
|
||||
children,
|
||||
depth,
|
||||
};
|
||||
expression
|
||||
}
|
||||
|
||||
pub fn process(&self) {
|
||||
println!("{}", self.text);
|
||||
// calculate value for expression.
|
||||
pub fn process(self) -> Result<f64, String> {
|
||||
let mut normalized_text = self.normalize_text();
|
||||
//let re_numeric = Regex::new(r"\d+(\.\d+)?");
|
||||
/*
|
||||
* Algorithm:
|
||||
*
|
||||
* First, search child expressions in normalized_text by searching for the text of all
|
||||
* children in normalized_text. If an expression is found, a value for it should be
|
||||
* calculated (recursive!) and the text should be substituted with the calculated value.
|
||||
* If a child expression is not found in the normalized_text, throw an error, as an
|
||||
* expression has a child but does not contain it's text. (note: a childs child
|
||||
* expressions are not the child expression of the original expression, so no need to
|
||||
* worry about the order of substituting texts for values.)
|
||||
*
|
||||
* Once there are no more child expressions in the normalized_text, we can use the
|
||||
* shunting yards algorithm to calculate the result. I'm not yet sure, if I want to use
|
||||
* another developers shunting yard algorithm or implement it by myself.
|
||||
*/
|
||||
|
||||
// TODO check if we have any unknown values.
|
||||
|
||||
// iterate through children, substitute childrens text with childrens results (as string
|
||||
// slice).
|
||||
for child in self.children {
|
||||
//normalized_text = normalized_text.replace(child.full_text.clone().as_str(), child.process().expect(self.text).as_str());
|
||||
let child_full_text = match child.clone().process() {
|
||||
Ok(result) => result.to_string(),
|
||||
Err(err) => {
|
||||
eprintln!(
|
||||
"Could not calculate result of child expression '{}': {}",
|
||||
child.text,
|
||||
"error placeholder TODO"
|
||||
);
|
||||
std::process::exit(2);
|
||||
}
|
||||
};
|
||||
dbg!(&child.full_text);
|
||||
dbg!(&child_full_text);
|
||||
normalized_text = normalized_text.replace(child.full_text.as_str(), child_full_text.as_str());
|
||||
}
|
||||
dbg!(&normalized_text);
|
||||
// TODO Shunting yards algorithm, as we now have only calculatable values left.
|
||||
// Implement this as public module in shunting_yard.rs
|
||||
// self.result = MYRESULT
|
||||
let rpn = shunting_yard::form_reverse_polish_notation(&normalized_text);
|
||||
match rpn {
|
||||
Ok(valid_rpn) => {
|
||||
dbg!(&valid_rpn);
|
||||
return shunting_yard::calc_reverse_polish_notation(valid_rpn);
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Could not calculate a result for expression '{}': {err}", self.text);
|
||||
std::process::exit(2);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper for normalize_string()
|
||||
fn normalize_text(&self) -> String {
|
||||
normalize_string(self.text.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
|
||||
/*
|
||||
* Custom made implementation of the shunting yard algorithm.
|
||||
* Makes a regular mathmatical expression into reverse polish notation,
|
||||
* a + b -> a b +
|
||||
* a * b + c -> a b * c +
|
||||
* and so on.
|
||||
* these can be easily interpreted by an algorithm to calculate the value of any given term.
|
||||
*
|
||||
* note: this version of shunting yard does not implement functions. They are handled by the
|
||||
* expression parser.
|
||||
*/
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Associativity {
|
||||
Right,
|
||||
Left
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct Operator {
|
||||
character: char,
|
||||
precedence: u8,
|
||||
associativity: Associativity
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
pub fn is_operator(c: char) -> bool {
|
||||
for op in OPERATORS {
|
||||
if c == op.character { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_operator(c: char) -> Option<Operator> {
|
||||
match c {
|
||||
'+' => Some(ADDITION),
|
||||
'-' => Some(SUBTRACTION),
|
||||
'*' => Some(MULTIPLICATION),
|
||||
'/' => Some(DIVISION),
|
||||
'^' => Some(EXPONENTIATION),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ADDITION: Operator = Operator {
|
||||
character: '+',
|
||||
precedence: 2,
|
||||
associativity: Associativity::Left
|
||||
};
|
||||
|
||||
const SUBTRACTION: Operator = Operator {
|
||||
character: '-',
|
||||
precedence: 2,
|
||||
associativity: Associativity::Left
|
||||
};
|
||||
|
||||
const MULTIPLICATION: Operator = Operator {
|
||||
character: '*',
|
||||
precedence: 2,
|
||||
associativity: Associativity::Left
|
||||
};
|
||||
|
||||
const DIVISION: Operator = Operator {
|
||||
character: '/',
|
||||
precedence: 2,
|
||||
associativity: Associativity::Left
|
||||
};
|
||||
|
||||
const EXPONENTIATION: Operator = Operator {
|
||||
character: '*',
|
||||
precedence: 2,
|
||||
associativity: Associativity::Right
|
||||
};
|
||||
|
||||
const OPERATORS: [Operator; 5] = [ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, EXPONENTIATION];
|
||||
|
||||
pub fn form_reverse_polish_notation(regular_math: &str) -> Result<Vec<String>, String> {
|
||||
let mut output_queue: Vec<Vec<char>> = Vec::new();
|
||||
let mut input_queue: Vec<char> = regular_math.chars().rev().collect();
|
||||
let mut operator_stack: Vec<char> = Vec::new();
|
||||
let mut currently_processing_numeric_group = false;
|
||||
let mut current_numeric_group: Vec<char> = Vec::new();
|
||||
let mut current_numeric_group_has_point = false;
|
||||
|
||||
// while there are tokens to br read:
|
||||
while !(input_queue.is_empty()) {
|
||||
// read a token
|
||||
let token: char = input_queue.pop().unwrap();
|
||||
dbg!(&token);
|
||||
|
||||
// if the token is:
|
||||
// a number:
|
||||
if token.is_numeric() | (token == '.') {
|
||||
// put it into the output_queue
|
||||
current_numeric_group.push(token);
|
||||
currently_processing_numeric_group = true;
|
||||
if (token == '.') & (!current_numeric_group_has_point) {
|
||||
current_numeric_group_has_point = true;
|
||||
}
|
||||
else if (token == '.') & (current_numeric_group_has_point) {
|
||||
return Err("Numeric group contains too many '.' Only one is allowed.".to_string());
|
||||
}
|
||||
}
|
||||
// a function
|
||||
// handled by the expression parser
|
||||
|
||||
// a operator o1
|
||||
else if Operator::is_operator(token) {
|
||||
|
||||
// numeric group is done, push it.
|
||||
if currently_processing_numeric_group {
|
||||
output_queue.push(current_numeric_group);
|
||||
current_numeric_group = Vec::new();
|
||||
currently_processing_numeric_group = false;
|
||||
current_numeric_group_has_point = false;
|
||||
}
|
||||
|
||||
// (get the constant Operator (which is a struct) that fits to that token.)
|
||||
let o1 = match Operator::get_operator(token) {
|
||||
Some(valid_op) => valid_op,
|
||||
None => {panic!("Operator '{}' not found.", token);},
|
||||
};
|
||||
|
||||
// while there is an operator o2 at the top of the stack
|
||||
if !operator_stack.is_empty() {
|
||||
dbg!(&operator_stack);
|
||||
let o2 = match Operator::get_operator(*(operator_stack.clone().last().clone().unwrap())) {
|
||||
Some(valid_op) => valid_op,
|
||||
None => {panic!("Operator '{}' not found.", token);},
|
||||
};
|
||||
// and
|
||||
// (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1
|
||||
// is left associative))
|
||||
while ((operator_stack.last().is_some()) & ((o2.precedence > o1.precedence) | ((o1.precedence == o2.precedence) & (o1.associativity == Associativity::Left)))) {
|
||||
// pop o2 from the operator stack into the output queue.
|
||||
// after this debug statement, the operator_stack is empty for no reason!!!!
|
||||
// FIXME
|
||||
let my_c = match operator_stack.pop() {
|
||||
Some(c) => c,
|
||||
None => {panic!("weirdly gone!")},
|
||||
};
|
||||
output_queue.push(vec![my_c]);
|
||||
}
|
||||
}
|
||||
operator_stack.push(o1.character);
|
||||
}
|
||||
/*
|
||||
// Unnessecary, will be processed by the expression parser
|
||||
else if '(' == token {
|
||||
println!("(");
|
||||
}
|
||||
else if ')' == token {
|
||||
println!(")");
|
||||
}
|
||||
*/
|
||||
else {
|
||||
return Err(("Unrecognized token: '".to_string() + token.to_string().as_str() + "'").to_string());
|
||||
}
|
||||
}
|
||||
// numeric group is done, push it.
|
||||
if currently_processing_numeric_group {
|
||||
output_queue.push(current_numeric_group);
|
||||
}
|
||||
dbg!(&output_queue);
|
||||
|
||||
// afterwards, process any operators still on the operator_stack
|
||||
while !(operator_stack.is_empty()) {
|
||||
output_queue.push(vec![operator_stack.pop().unwrap()]);
|
||||
}
|
||||
|
||||
dbg!(&output_queue);
|
||||
let mut rpn: Vec<String> = Vec::new();
|
||||
for group in output_queue {
|
||||
rpn.push(group.iter().cloned().collect::<String>());
|
||||
}
|
||||
Ok(rpn)
|
||||
}
|
||||
|
||||
// after we have the rpn, we may want to calculate the values with it.
|
||||
pub fn calc_reverse_polish_notation(rpn: Vec<String>) -> Result<f64, String> {
|
||||
Ok(0.0)
|
||||
}
|
58
src/main.rs
58
src/main.rs
|
@ -1,7 +1,6 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use clap::Parser;
|
||||
|
||||
mod expression_parser;
|
||||
mod linear_algebra;
|
||||
|
||||
use expression_parser::Expression;
|
||||
use expression_parser::Task;
|
||||
|
@ -10,25 +9,30 @@ use expression_parser::Task;
|
|||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Arg {
|
||||
// /// Optional subcommand
|
||||
// #[command(subcommand)]
|
||||
// command: Option<Commands>,
|
||||
|
||||
/// Show verbose output
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
|
||||
/// An expression that should be used to calculate something
|
||||
///Syntax: '1 + task_param(inner) + 1 '{n}
|
||||
///{n}
|
||||
///Specify an expression, any expression may contain child expressions, which can be denoted{n}
|
||||
///with parenthesis '(child)'. Expressions may have a task applied to them, such as a
|
||||
///logarithm{n} or drawing a root. To apply a task to a expression, simply write the name of{n}
|
||||
///the task before denoting an expression: 'myTask(myExpression)'. You can apply a parameter{n}
|
||||
///to some tasks by using an underscore '_': 'myTask_myParameter(myExpression)'.{n}
|
||||
///{n}
|
||||
///List of Tasks:{n}
|
||||
///{n}
|
||||
///"none" explicitly set no task for expression{n}
|
||||
/// parameter: none
|
||||
///{n}
|
||||
///"root" or "sqrt" draw the root of the expression{n}
|
||||
/// parameter: draw n'th root of expression, default is 2.0{n}
|
||||
///{n}
|
||||
///"power" or "pow" or "sq" apply an exponent to the expression{n}
|
||||
/// parameter: specify exponent n, default is 2.0{n}
|
||||
///{n}
|
||||
///"log" or "ln" apply a logarithm to the expression{n}
|
||||
/// parameter: specify base n, default is 10{n}
|
||||
expressions: Vec<String>,
|
||||
}
|
||||
|
||||
//#[derive(Subcommand)]
|
||||
//enum Commands {
|
||||
// /// Assert if two expressions are equal to each other
|
||||
// Equal {
|
||||
// }
|
||||
//}
|
||||
|
||||
fn main() {
|
||||
let args = Arg::parse();
|
||||
let mut expression_vec: Vec<Expression> = Vec::new();
|
||||
|
@ -41,11 +45,21 @@ fn main() {
|
|||
expression_texts_concat.push(args.expressions.join(" ").trim().to_string());
|
||||
|
||||
for expression_text in expression_texts_concat {
|
||||
expression_vec.push(Expression::new(expression_text, Task::None));
|
||||
expression_vec.push(Expression::new(expression_text.clone(), expression_text, Task::None, 0));
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
dbg!(&expression_vec);
|
||||
}
|
||||
|
||||
for expression in expression_vec {
|
||||
expression.process();
|
||||
match expression.clone().process() {
|
||||
Ok(result) => {
|
||||
println!("{result}");
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Could not calculate expression '{}': {}", &expression.text, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Reference in New Issue