Browse Source

Implement exponentiation operator (#130)

* 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.
pull/145/head
simon brahan 5 years ago committed by Jason Williams
parent
commit
ce70796581
  1. 2
      src/lib/exec.rs
  2. 4
      src/lib/js/value.rs
  3. 7
      src/lib/syntax/ast/op.rs
  4. 30
      src/lib/syntax/parser.rs

2
src/lib/exec.rs

@ -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,
@ -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,
}))

4
src/lib/js/value.rs

@ -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 {

7
src/lib/syntax/ast/op.rs

@ -24,6 +24,8 @@ pub enum NumOp {
Div,
/// `a * b` - Multiplication
Mul,
/// `a ** b` - Exponentiation
Pow,
/// `a % b` - Modulus
Mod,
}
@ -38,6 +40,7 @@ impl Display for NumOp {
NumOp::Sub => "-",
NumOp::Div => "/",
NumOp::Mul => "*",
NumOp::Pow => "**",
NumOp::Mod => "%",
}
)
@ -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,
@ -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
@ -264,6 +270,7 @@ impl Display for AssignOp {
AssignOp::Add => "+=",
AssignOp::Sub => "-=",
AssignOp::Mul => "*=",
AssignOp::Pow => "**=",
AssignOp::Div => "/=",
AssignOp::Mod => "%=",
AssignOp::And => "&=",

30
src/lib/syntax/parser.rs

@ -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)?
}
@ -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)?
}
@ -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(
@ -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(

Loading…
Cancel
Save