This commit is contained in:
Piyush मिश्रः 2022-01-18 01:42:46 +05:30
parent ea374f5607
commit 9853da6332
6 changed files with 588 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/history.txt

320
Cargo.lock generated Normal file
View File

@ -0,0 +1,320 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "clipboard-win"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8"
dependencies = [
"error-code",
"str-buf",
"winapi",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "endian-type"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
[[package]]
name = "error-code"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff"
dependencies = [
"libc",
"str-buf",
]
[[package]]
name = "fd-lock"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0010f02effd88c702318c5dde0463206be67495d0b4d906ba7c0a8f166cc7f06"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "nibble_vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
dependencies = [
"smallvec",
]
[[package]]
name = "nix"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
]
[[package]]
name = "radix_trie"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
dependencies = [
"endian-type",
"nibble_vec",
]
[[package]]
name = "redox_syscall"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall",
]
[[package]]
name = "rustyline"
version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbd4eaf7a7738f76c98e4f0395253ae853be3eb018f7b0bb57fe1b6c17e31874"
dependencies = [
"bitflags",
"cfg-if",
"clipboard-win",
"dirs-next",
"fd-lock",
"libc",
"log",
"memchr",
"nix",
"radix_trie",
"scopeguard",
"smallvec",
"unicode-segmentation",
"unicode-width",
"utf8parse",
"winapi",
]
[[package]]
name = "sangnak"
version = "0.1.0"
dependencies = [
"clap",
"rustyline",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "str-buf"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[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-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "sangnak"
version = "0.1.0"
authors = ["Piyush Mishra <piyush.raj.kit@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rustyline = "8.2.0"
clap = "2.33.3"

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Sangnak
It is a a simple command line calculator.
### Features
* Parsing and claculating expressions
* Support for brackets
* It have a shell

62
src/main.rs Normal file
View File

@ -0,0 +1,62 @@
mod solve;
use clap::{Arg, App};
use rustyline::error::ReadlineError;
use rustyline::Editor;
fn start_shell() {
let mut rl = Editor::<()>::new();
rl.load_history("history.txt").unwrap_or(());
loop {
let readline = rl.readline("\x1b[1;32m>>\x1b[1;97m ");
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
if line == "quit" || line == "exit" {
break;
}
if let Ok(out) = solve::solve(&line) {
println!("{}", out);
}
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
rl.save_history("history.txt").unwrap();
}
fn main() {
let matches = App::new("Calculator")
.version("0.1.0")
.author("Piyush Mishra <piyush.raj.kit@gmail.com>")
.about("Calculate with expression")
.arg(Arg::with_name("expression")
.short("e")
.long("expr")
.value_name("EXPRESSION")
.help("Expression to calculate")
.takes_value(true))
.get_matches();
match matches.value_of("expression") {
Some(exp) => {
if let Ok(out) = solve::solve(exp) {
println!("{}", out);
}
}, None => start_shell()
}
}

184
src/solve.rs Normal file
View File

@ -0,0 +1,184 @@
use std::fmt;
use std::error::Error;
use Khand::*;
use Opr::*;
#[derive(Debug)]
enum Khand {
NUM(f64),
OPR(Opr),
NIL
}
#[derive(Debug)]
enum Opr {
DIV,
MUL,
ADD,
SUB
}
#[derive(Debug)]
pub struct WorngStatementError;
impl fmt::Display for WorngStatementError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SuperError is here!")
}
}
impl Error for WorngStatementError {}
pub fn solve(exp: &str) -> Result<f64, WorngStatementError> {
let chars = exp.replace(" ", "").chars().collect::<Vec<char>>();
match solve_expression(&chars, None) {
Ok((out, _)) => Ok(out),
Err(err) => Err(err)
}
}
fn solve_expression(exp: &Vec<char>, start: Option<usize>) -> Result<(f64, usize), WorngStatementError> {
// println!("start: {:?}", start);
let mut khand: Vec<Khand> = Vec::new();
let mut div: Vec<usize> = Vec::new();
let mut mul: Vec<usize> = Vec::new();
let mut add: Vec<usize> = Vec::new();
let mut sub: Vec<usize> = Vec::new();
let mut buf = String::new();
let mut index: usize = start.unwrap_or(0);
while index < exp.len() {
let chr = exp[index];
// println!("LOOP: ({}) {:?}", chr, khand);
let is_part_of_number = ('0' <= chr && chr <= '9') || (buf.len() > 0 && chr == '.');
if is_part_of_number {
buf.push(chr);
// println!(" BUF: {}", buf);
}
if (!is_part_of_number || (index+1 >= exp.len())) && buf.len() > 0 {
match buf.parse::<f64>() {
Ok(num) => khand.push(NUM(num)),
Err(_) => return Err(WorngStatementError)
}
buf = String::new();
}
if chr == '(' {
let (out,i) = solve_expression(exp, Some(index +1))?;
khand.push(NUM(out));
index = i;
} else if chr == ')' && start.is_some() {
break;
}
match chr {
'/' => {
div.push(khand.len());
khand.push(OPR(DIV));
},
'*' => {
mul.push(khand.len());
khand.push(OPR(MUL));
},
'+' => {
add.push(khand.len());
khand.push(OPR(ADD));
},
'-' => {
sub.push(khand.len());
khand.push(OPR(SUB));
},
_ => {}
}
index += 1;
}
// println!("AFTER LOOP: {:?}", khand);
for i in div {
let (left, left_index) = get_left(&khand, i)?;
let (right, right_index) = get_right(&khand, i)?;
khand[i] = NUM(left/right);
khand[left_index] = NIL;
khand[right_index] = NIL;
// println!("DIV: {:?}", khand);
}
for i in mul {
let (left, left_index) = get_left(&khand, i)?;
let (right, right_index) = get_right(&khand, i)?;
khand[i] = NUM(left*right);
khand[left_index] = NIL;
khand[right_index] = NIL;
// println!("MUL: {:?}", khand);
}
for i in add {
let (left, left_index) = get_left(&khand, i)?;
let (right, right_index) = get_right(&khand, i)?;
khand[i] = NUM(left+right);
khand[left_index] = NIL;
khand[right_index] = NIL;
// println!("ADD: {:?}", khand);
}
for i in sub {
let (left, left_index) = get_left(&khand, i)?;
let (right, right_index) = get_right(&khand, i)?;
khand[i] = NUM(left-right);
khand[left_index] = NIL;
khand[right_index] = NIL;
// println!("SUB: {:?}", khand);
}
// println!("CLOSING: {}", get_right(&khand, 0)?.0);
Ok((get_right(&khand, 0)?.0, index))
}
fn get_left(khand: &Vec<Khand>, i: usize) -> Result<(f64, usize), WorngStatementError> {
if khand.len() == 1 {
match khand[0] {
NUM(num) => return Ok((num, i)),
_ => return Err(WorngStatementError)
}
}
let mut i = i;
loop {
i -= 1;
if let NUM(num) = match khand.get(i) {
Some(num) => num,
None => return Err(WorngStatementError)
} {
return Ok((*num, i));
}
}
}
fn get_right(khand: &Vec<Khand>, i: usize) -> Result<(f64, usize), WorngStatementError> {
if khand.len() == 1 {
match khand[0] {
NUM(num) => return Ok((num, i)),
_ => return Err(WorngStatementError)
}
}
let mut i = i;
loop {
i += 1;
if let NUM(num) = match khand.get(i) {
Some(num) => num,
None => return Err(WorngStatementError)
} {
return Ok((*num, i));
}
}
}