Skip to content

Commit

Permalink
Add Hexadecimal and Binary input support (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
OchirErkhembayar authored Feb 1, 2024
1 parent 65184fa commit 2f82b7b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "qcalc"
version = "0.4.1"
version = "0.5.0"
edition = "2021"
authors = ["ochir <ochir_erkhembayar@yahoo.com>"]
description = """
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The software is provided "as is," without warranty of any kind, express or impli
- Built in functions
- Clearing past expressions
- Resetting variables
- Binary and hexadecimal inputs eg. "0xff + 0b10 / 10"

#### Feature requests / Bug reports
- Feel free to open an issue and i'll look into it
8 changes: 8 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,12 @@ mod tests {
input_and_evaluate(&mut app, "foo(2, 3)");
assert_output(&app, 17.0);
}

#[test]
fn test_bin_hex() {
let mut app = new_app();

input_and_evaluate(&mut app, "0x1f + 0b110 / 2");
assert_output(&app, 34.0);
}
}
62 changes: 55 additions & 7 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,49 @@ impl<'a> Iterator for Tokenizer<'a> {
')' => Token::RParen,
'^' => Token::Power,
'0'..='9' => {
let mut num = next.to_string();
while self.input.peek().is_some_and(|c| c.is_ascii_digit()) {
num.push(self.input.next().unwrap());
}
if self.input.peek().is_some_and(|c| *c == '.') {
num.push(self.input.next().unwrap());
// Check if it's hex
if next == '0'
&& self
.input
.peek()
.is_some_and(|c| matches!(c, 'x' | 'X' | 'b' | 'B'))
{
match self.input.next().unwrap() {
'x' | 'X' => {
let mut hex = String::new();
while self.input.peek().is_some_and(|c| {
c.is_numeric() || matches!(c, 'a'..='f' | 'A'..='F')
}) {
hex.push(self.input.next().unwrap());
}
Token::Num(i32::from_str_radix(&hex, 16).unwrap() as f64)
}
'b' | 'B' => {
let mut hex = String::new();
while self
.input
.peek()
.is_some_and(|c| c.is_numeric() || matches!(c, '0' | '1'))
{
hex.push(self.input.next().unwrap());
}
Token::Num(i32::from_str_radix(&hex, 2).unwrap() as f64)
}
_ => unreachable!(),
}
} else {
let mut num = next.to_string();
while self.input.peek().is_some_and(|c| c.is_ascii_digit()) {
num.push(self.input.next().unwrap());
}
if self.input.peek().is_some_and(|c| *c == '.') {
num.push(self.input.next().unwrap());
while self.input.peek().is_some_and(|c| c.is_ascii_digit()) {
num.push(self.input.next().unwrap());
}
}
Token::Num(num.parse().unwrap())
}
Token::Num(num.parse().unwrap())
}
'A'..='Z' | 'a'..='z' => {
let mut func = next.to_string();
Expand Down Expand Up @@ -171,4 +203,20 @@ mod tests {
let mut tokenizer = Tokenizer::new(str.chars().peekable());
assert_eq!(tokenizer.next(), Some(Token::Num(10.0)));
}

#[test]
fn test_hex() {
let str = "0x1ff";

let mut tokenizer = Tokenizer::new(str.chars().peekable());
assert_eq!(tokenizer.next(), Some(Token::Num(511.0)));
}

#[test]
fn test_bin() {
let str = "0b1100";

let mut tokenizer = Tokenizer::new(str.chars().peekable());
assert_eq!(tokenizer.next(), Some(Token::Num(12.0)));
}
}

0 comments on commit 2f82b7b

Please sign in to comment.