Add Null Coalescing Operator and Ternary Conditional Operator
Closes #1471 Closes #1439
This commit is contained in:
parent
3d3cab4b65
commit
09021ee103
4 changed files with 108 additions and 14 deletions
|
@ -19,6 +19,20 @@ pub fn and(a: Value, b: Value) -> Result<Value, Error> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn tco(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(match a.is_truthy() {
|
||||
true => a,
|
||||
false => b,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn nco(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(match a.is_some() {
|
||||
true => a,
|
||||
false => b,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(a.add(b))
|
||||
}
|
||||
|
@ -200,6 +214,66 @@ mod tests {
|
|||
assert_eq!("0", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tco_true() {
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(2);
|
||||
let res = tco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tco_false_one() {
|
||||
let one = Value::from(0);
|
||||
let two = Value::from(1);
|
||||
let res = tco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tco_false_two() {
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(0);
|
||||
let res = tco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nco_true() {
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(2);
|
||||
let res = nco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nco_false_one() {
|
||||
let one = Value::None;
|
||||
let two = Value::from(1);
|
||||
let res = nco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nco_false_two() {
|
||||
let one = Value::from(1);
|
||||
let two = Value::None;
|
||||
let res = nco(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_basic() {
|
||||
let one = Value::from(5);
|
||||
|
|
|
@ -76,12 +76,24 @@ impl Expression {
|
|||
return Ok(l);
|
||||
}
|
||||
}
|
||||
Operator::Tco => {
|
||||
if let true = l.is_truthy() {
|
||||
return Ok(l);
|
||||
}
|
||||
}
|
||||
Operator::Nco => {
|
||||
if let true = l.is_some() {
|
||||
return Ok(l);
|
||||
}
|
||||
}
|
||||
_ => {} // Continue
|
||||
}
|
||||
let r = self.r.compute(ctx, opt, txn, doc).await?;
|
||||
match self.o {
|
||||
Operator::Or => fnc::operate::or(l, r),
|
||||
Operator::And => fnc::operate::and(l, r),
|
||||
Operator::Tco => fnc::operate::tco(l, r),
|
||||
Operator::Nco => fnc::operate::nco(l, r),
|
||||
Operator::Add => fnc::operate::add(l, r),
|
||||
Operator::Sub => fnc::operate::sub(l, r),
|
||||
Operator::Mul => fnc::operate::mul(l, r),
|
||||
|
|
|
@ -11,8 +11,11 @@ use std::fmt;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
pub enum Operator {
|
||||
//
|
||||
Or, // ||
|
||||
And, // &&
|
||||
Tco, // ?: Ternary conditional operator
|
||||
Nco, // ?? Null coalescing operator
|
||||
//
|
||||
Add, // +
|
||||
Sub, // -
|
||||
|
@ -21,9 +24,8 @@ pub enum Operator {
|
|||
Inc, // +=
|
||||
Dec, // -=
|
||||
//
|
||||
Exact, // ==
|
||||
//
|
||||
Equal, // =
|
||||
Exact, // ==
|
||||
NotEqual, // !=
|
||||
AllEqual, // *=
|
||||
AnyEqual, // ?=
|
||||
|
@ -65,11 +67,13 @@ impl Operator {
|
|||
match self {
|
||||
Operator::Or => 1,
|
||||
Operator::And => 2,
|
||||
Operator::Sub => 4,
|
||||
Operator::Add => 5,
|
||||
Operator::Mul => 6,
|
||||
Operator::Div => 7,
|
||||
_ => 3,
|
||||
Operator::Tco => 3,
|
||||
Operator::Nco => 4,
|
||||
Operator::Sub => 6,
|
||||
Operator::Add => 7,
|
||||
Operator::Mul => 8,
|
||||
Operator::Div => 9,
|
||||
_ => 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,14 +83,16 @@ impl fmt::Display for Operator {
|
|||
f.write_str(match self {
|
||||
Self::Or => "OR",
|
||||
Self::And => "AND",
|
||||
Self::Tco => "?:",
|
||||
Self::Nco => "??",
|
||||
Self::Add => "+",
|
||||
Self::Sub => "-",
|
||||
Self::Mul => "*",
|
||||
Self::Div => "/",
|
||||
Self::Inc => "+=",
|
||||
Self::Dec => "-=",
|
||||
Self::Exact => "==",
|
||||
Self::Equal => "=",
|
||||
Self::Exact => "==",
|
||||
Self::NotEqual => "!=",
|
||||
Self::AllEqual => "*=",
|
||||
Self::AnyEqual => "?=",
|
||||
|
@ -129,6 +135,12 @@ pub fn operator(i: &str) -> IResult<&str, Operator> {
|
|||
pub fn symbols(i: &str) -> IResult<&str, Operator> {
|
||||
let (i, _) = mightbespace(i)?;
|
||||
let (i, v) = alt((
|
||||
alt((
|
||||
map(tag("||"), |_| Operator::Or),
|
||||
map(tag("&&"), |_| Operator::And),
|
||||
map(tag("?:"), |_| Operator::Tco),
|
||||
map(tag("??"), |_| Operator::Nco),
|
||||
)),
|
||||
alt((
|
||||
map(tag("=="), |_| Operator::Exact),
|
||||
map(tag("!="), |_| Operator::NotEqual),
|
||||
|
@ -178,12 +190,8 @@ pub fn phrases(i: &str) -> IResult<&str, Operator> {
|
|||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = alt((
|
||||
alt((
|
||||
map(tag_no_case("&&"), |_| Operator::And),
|
||||
map(tag_no_case("AND"), |_| Operator::And),
|
||||
map(tag_no_case("||"), |_| Operator::Or),
|
||||
map(tag_no_case("OR"), |_| Operator::Or),
|
||||
)),
|
||||
alt((
|
||||
map(tag_no_case("AND"), |_| Operator::And),
|
||||
map(tag_no_case("IS NOT"), |_| Operator::NotEqual),
|
||||
map(tag_no_case("IS"), |_| Operator::Equal),
|
||||
)),
|
||||
|
|
|
@ -610,7 +610,7 @@ impl Value {
|
|||
}
|
||||
|
||||
pub fn is_some(&self) -> bool {
|
||||
!self.is_none()
|
||||
!self.is_none() && !self.is_null()
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
|
|
Loading…
Reference in a new issue