Skip to content

Commit

Permalink
Fix pow
Browse files Browse the repository at this point in the history
  • Loading branch information
OchirErkhembayar committed Feb 2, 2024
1 parent ecfdce4 commit f57988b
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 26 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.6.1"
version = "0.6.2"
edition = "2021"
authors = ["ochir <ochir_erkhembayar@yahoo.com>"]
description = """
Expand Down
4 changes: 4 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ mod tests {
input_and_evaluate(&mut app, "let foo = sqrt(144)");
input_and_evaluate(&mut app, "foo");
assert_output(&app, 12.0);

input_and_evaluate(&mut app, "let foo = -2 ** 3");
input_and_evaluate(&mut app, "foo");
assert_output(&app, -8 as f64);
}

#[test]
Expand Down
12 changes: 11 additions & 1 deletion src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ impl Value {
_ => unreachable!(),
}
}

fn pow(&self, rhs: Self) -> Self {
match (self, rhs) {
(Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs.pow(rhs as u32)),
(Value::Float(lhs), Value::Float(rhs)) => Value::Float(lhs.powf(rhs)),
(Value::Int(lhs), Value::Float(rhs)) => Value::Float((*lhs as f64).powf(rhs)),
(Value::Float(lhs), Value::Int(rhs)) => Value::Float(lhs.powi(rhs as i32)),
_ => panic!("Cannot add non numeric types"),
}
}
}

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -162,6 +172,7 @@ impl Interpreter {
Token::BitXor => (left ^ right)?,
Token::Shl => (left << right)?,
Token::Shr => (left >> right)?,
Token::Pow => left.pow(right),
_ => unreachable!(),
};
Ok(val)
Expand Down Expand Up @@ -210,7 +221,6 @@ impl Interpreter {
};
let val = match func {
Func::Abs => return Ok(val.abs()),
Func::Pow(exp) => arg.powf(*exp),
Func::Sin => arg.sin(),
Func::Sinh => arg.sinh(),
Func::Asin => arg.asin(),
Expand Down
30 changes: 11 additions & 19 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const COSH: &str = "cosh";
const ACOS: &str = "acos";
const ACOSH: &str = "acosh";
const ABS: &str = "abs";
const POW: &str = "pow";
const SIN: &str = "sin";
const SINH: &str = "sinh";
const ASIN: &str = "asin";
Expand Down Expand Up @@ -49,7 +48,6 @@ pub struct ParseErr {
#[derive(Debug, PartialEq, Clone)]
pub enum Func {
Abs,
Pow(f64),
Sin,
Sinh,
Asin,
Expand Down Expand Up @@ -283,11 +281,21 @@ impl<'a> Parser<'a> {
}

fn factor(&mut self) -> Result<Expr, ParseErr> {
let mut expr = self.unary()?;
let mut expr = self.exponent()?;
while *self.peek() == Token::Div
|| *self.peek() == Token::Mult
|| *self.peek() == Token::Mod
{
let operator = self.advance();
let right = self.exponent()?;
expr = Expr::Binary(Box::new(expr), operator, Box::new(right));
}
Ok(expr)
}

fn exponent(&mut self) -> Result<Expr, ParseErr> {
let mut expr = self.unary()?;
while *self.peek() == Token::Pow {
let operator = self.advance();
let right = self.unary()?;
expr = Expr::Binary(Box::new(expr), operator, Box::new(right));
Expand Down Expand Up @@ -351,21 +359,6 @@ impl<'a> Parser<'a> {
self.advance();
let func = match func.as_str() {
ABS => Func::Abs,
POW => {
if matches!(self.peek(), Token::Float(_) | Token::Int(_)) {
let base = match self.advance() {
Token::Float(float) => float,
Token::Int(int) => int as f64,
_ => unreachable!(),
};
Func::Pow(base)
} else {
return Err(ParseErr::new(
self.peek().clone(),
"Missing exponent for pow function",
));
}
}
SIN => Func::Sin,
SINH => Func::Sinh,
ASIN => Func::Asin,
Expand Down Expand Up @@ -440,7 +433,6 @@ impl Display for Func {
"{}",
match self {
Func::Abs => ABS,
Func::Pow(exp) => return inner_write(format!("pow({})", exp), f),
Func::Sin => SIN,
Func::Sinh => SINH,
Func::Asin => ASIN,
Expand Down
11 changes: 10 additions & 1 deletion src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum Token {
Mult,
Plus,
Minus,
Pow,
Not,
RParen,
LParen,
Expand All @@ -48,6 +49,7 @@ impl std::fmt::Display for Token {
Token::Div => inner_write('/', f),
Token::Plus => inner_write('+', f),
Token::Minus => inner_write('-', f),
Token::Pow => inner_write("**", f),
Token::Not => inner_write('!', f),
Token::BitOr => inner_write('|', f),
Token::BitAnd => inner_write('&', f),
Expand Down Expand Up @@ -97,7 +99,14 @@ impl<'a> Iterator for Tokenizer<'a> {
'+' => Token::Plus,
'-' => Token::Minus,
'%' => Token::Mod,
'*' => Token::Mult,
'*' => {
if self.input.peek().is_some_and(|c| *c == '*') {
self.input.next().unwrap();
Token::Pow
} else {
Token::Mult
}
}
'!' => Token::Not,
'&' => Token::BitAnd,
'^' => Token::BitXor,
Expand Down
4 changes: 1 addition & 3 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,10 @@ sin(_rads_) sinh(_rads_) asin(_rads_) asinh(_rads_) sqrt(_arg_)
tan(_rads_) tanh(_rads_) atan(_rads_) atanh(_rads_) cube(_arg_)
log_base_(_arg_) ln(_arg_) cbrt(_arg_) ceil(_arg_) exp(_arg_)
degs(_rads_) rads(_degs_) round(_arg_) floor(_arg_) exp2(_arg_)
fract(_arg_) recip(_arg_)
fract(_arg_) recip(_arg_) abs(_arg_)
Examples: \"log10(100)\", \"cos(pi)\"
Absolute value: |-123| == 123
Creating variables: \"let x = 5 * 20\"
Shortcuts
Expand Down

0 comments on commit f57988b

Please sign in to comment.