Skip to content

Commit

Permalink
Implement exponentiation operator (#130)
Browse files Browse the repository at this point in the history
* Exponentiation (**) now works.

Added missing NumOp type, token match, and calculation.

* Assignment exponentiation (**=) now works.

Added missing AssignOp type, token match, and calculation.

This fixes #89.
  • Loading branch information
simonbrahan authored and jasonwilliams committed Oct 7, 2019
1 parent 1ff7b5e commit ce70796
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lib/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fn exec_assign_op(op: &AssignOp, v_a: ValueData, v_b: ValueData) -> Value {
AssignOp::Add => v_a + v_b,
AssignOp::Sub => v_a - v_b,
AssignOp::Mul => v_a * v_b,
AssignOp::Pow => v_a.as_num_to_power(v_b),
AssignOp::Div => v_a / v_b,
AssignOp::Mod => v_a % v_b,
AssignOp::And => v_a & v_b,
Expand Down Expand Up @@ -227,6 +228,7 @@ impl Executor for Interpreter {
NumOp::Add => v_a + v_b,
NumOp::Sub => v_a - v_b,
NumOp::Mul => v_a * v_b,
NumOp::Pow => v_a.as_num_to_power(v_b),
NumOp::Div => v_a / v_b,
NumOp::Mod => v_a % v_b,
}))
Expand Down
4 changes: 4 additions & 0 deletions src/lib/js/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,10 @@ impl ValueData {
}
}
}

pub fn as_num_to_power(&self, other: ValueData) -> ValueData {
ValueData::Number(self.to_num().powf(other.to_num()))
}
}

impl Default for ValueData {
Expand Down
7 changes: 7 additions & 0 deletions src/lib/syntax/ast/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub enum NumOp {
Div,
/// `a * b` - Multiplication
Mul,
/// `a ** b` - Exponentiation
Pow,
/// `a % b` - Modulus
Mod,
}
Expand All @@ -38,6 +40,7 @@ impl Display for NumOp {
NumOp::Sub => "-",
NumOp::Div => "/",
NumOp::Mul => "*",
NumOp::Pow => "**",
NumOp::Mod => "%",
}
)
Expand Down Expand Up @@ -193,6 +196,7 @@ impl Operator for BinOp {
}
fn get_precedence(&self) -> u64 {
match *self {
BinOp::Num(NumOp::Pow) => 4,
BinOp::Num(NumOp::Mul) | BinOp::Num(NumOp::Div) | BinOp::Num(NumOp::Mod) => 5,
BinOp::Num(NumOp::Add) | BinOp::Num(NumOp::Sub) => 6,
BinOp::Bit(BitOp::Shl) | BinOp::Bit(BitOp::Shr) => 7,
Expand Down Expand Up @@ -239,6 +243,8 @@ pub enum AssignOp {
Sub,
/// `a *= b` - Mul assign
Mul,
/// `a **= b` - Exponent assign
Pow,
/// `a /= b` - Div assign
Div,
/// `a %= b` - Modulus assign
Expand All @@ -264,6 +270,7 @@ impl Display for AssignOp {
AssignOp::Add => "+=",
AssignOp::Sub => "-=",
AssignOp::Mul => "*=",
AssignOp::Pow => "**=",
AssignOp::Div => "/=",
AssignOp::Mod => "%=",
AssignOp::And => "&=",
Expand Down
30 changes: 30 additions & 0 deletions src/lib/syntax/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,9 @@ impl Parser {
TokenData::Punctuator(Punctuator::AssignMul) => {
result = self.binop(BinOp::Assign(AssignOp::Mul), expr)?
}
TokenData::Punctuator(Punctuator::AssignPow) => {
result = self.binop(BinOp::Assign(AssignOp::Pow), expr)?
}
TokenData::Punctuator(Punctuator::AssignDiv) => {
result = self.binop(BinOp::Assign(AssignOp::Div), expr)?
}
Expand Down Expand Up @@ -711,6 +714,9 @@ impl Parser {
TokenData::Punctuator(Punctuator::Mul) => {
result = self.binop(BinOp::Num(NumOp::Mul), expr)?
}
TokenData::Punctuator(Punctuator::Pow) => {
result = self.binop(BinOp::Num(NumOp::Pow), expr)?
}
TokenData::Punctuator(Punctuator::Div) => {
result = self.binop(BinOp::Num(NumOp::Div), expr)?
}
Expand Down Expand Up @@ -1148,6 +1154,22 @@ mod tests {
Expr::new(ExprDef::Const(Const::Num(2.0))),
)],
);
check_parser(
"a ** b",
&[create_bin_op(
BinOp::Num(NumOp::Pow),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a**2",
&[create_bin_op(
BinOp::Num(NumOp::Pow),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Const(Const::Num(2.0))),
)],
);
check_parser(
"a % b",
&[create_bin_op(
Expand Down Expand Up @@ -1299,6 +1321,14 @@ mod tests {
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a **= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Pow),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a /= b",
&[create_bin_op(
Expand Down

0 comments on commit ce70796

Please sign in to comment.