Browse Source

Implement Tilde operator (#187)

* implement tilde operator

* add tests for tilde operator
pull/185/head
letmutx 5 years ago committed by Jason Williams
parent
commit
6e04f8f393
  1. 47
      src/lib/exec.rs
  2. 1
      src/lib/syntax/ast/expr.rs
  3. 3
      src/lib/syntax/ast/op.rs
  4. 4
      src/lib/syntax/parser.rs

47
src/lib/exec.rs

@ -266,6 +266,15 @@ impl Executor for Interpreter {
UnaryOp::Minus => to_value(-v_a.to_num()), UnaryOp::Minus => to_value(-v_a.to_num()),
UnaryOp::Plus => to_value(v_a.to_num()), UnaryOp::Plus => to_value(v_a.to_num()),
UnaryOp::Not => Gc::new(!v_a), UnaryOp::Not => Gc::new(!v_a),
UnaryOp::Tilde => {
let num_v_a = v_a.to_num();
// NOTE: possible UB: https://github.com/rust-lang/rust/issues/10184
to_value(if num_v_a.is_nan() {
-1
} else {
!(num_v_a as i32)
})
}
_ => unreachable!(), _ => unreachable!(),
}) })
} }
@ -751,4 +760,42 @@ mod tests {
"#; "#;
assert_eq!(exec(non_num_key_wont_affect_length), String::from("3")); assert_eq!(exec(non_num_key_wont_affect_length), String::from("3"));
} }
#[test]
fn test_tilde_operator() {
let float = r#"
let f = -1.2;
~f
"#;
assert_eq!(exec(float), String::from("0"));
let numeric = r#"
let f = 1789;
~f
"#;
assert_eq!(exec(numeric), String::from("-1790"));
// TODO: enable test after we have NaN
// let nan = r#"
// var m = NaN;
// ~m
// "#;
// assert_eq!(exec(nan), String::from("-1"));
let object = r#"
let m = {};
~m
"#;
assert_eq!(exec(object), String::from("-1"));
let boolean_true = r#"
~true
"#;
assert_eq!(exec(boolean_true), String::from("-2"));
let boolean_false = r#"
~false
"#;
assert_eq!(exec(boolean_false), String::from("-1"));
}
} }

1
src/lib/syntax/ast/expr.rs

@ -100,6 +100,7 @@ impl Operator for ExprDef {
| ExprDef::UnaryOp(UnaryOp::DecrementPost, _) | ExprDef::UnaryOp(UnaryOp::DecrementPost, _)
| ExprDef::UnaryOp(UnaryOp::DecrementPre, _) => 3, | ExprDef::UnaryOp(UnaryOp::DecrementPre, _) => 3,
ExprDef::UnaryOp(UnaryOp::Not, _) ExprDef::UnaryOp(UnaryOp::Not, _)
| ExprDef::UnaryOp(UnaryOp::Tilde, _)
| ExprDef::UnaryOp(UnaryOp::Minus, _) | ExprDef::UnaryOp(UnaryOp::Minus, _)
| ExprDef::TypeOf(_) => 4, | ExprDef::TypeOf(_) => 4,
ExprDef::BinOp(op, _, _) => op.get_precedence(), ExprDef::BinOp(op, _, _) => op.get_precedence(),

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

@ -64,6 +64,8 @@ pub enum UnaryOp {
Plus, Plus,
/// `!a` - get the opposite of the boolean value /// `!a` - get the opposite of the boolean value
Not, Not,
/// `~a` - bitwise-not of the value
Tilde,
} }
impl Display for UnaryOp { impl Display for UnaryOp {
@ -77,6 +79,7 @@ impl Display for UnaryOp {
UnaryOp::Plus => "+", UnaryOp::Plus => "+",
UnaryOp::Minus => "-", UnaryOp::Minus => "-",
UnaryOp::Not => "!", UnaryOp::Not => "!",
UnaryOp::Tilde => "~",
} }
) )
} }

4
src/lib/syntax/parser.rs

@ -566,6 +566,10 @@ impl Parser {
self, self,
ExprDef::UnaryOp(UnaryOp::Not, Box::new(self.parse()?)) ExprDef::UnaryOp(UnaryOp::Not, Box::new(self.parse()?))
), ),
TokenData::Punctuator(Punctuator::Neg) => mk!(
self,
ExprDef::UnaryOp(UnaryOp::Tilde, Box::new(self.parse()?))
),
TokenData::Punctuator(Punctuator::Inc) => mk!( TokenData::Punctuator(Punctuator::Inc) => mk!(
self, self,
ExprDef::UnaryOp(UnaryOp::IncrementPre, Box::new(self.parse()?)) ExprDef::UnaryOp(UnaryOp::IncrementPre, Box::new(self.parse()?))

Loading…
Cancel
Save