mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Boolean Operators.
This commit is contained in:
parent
ea2297a5eb
commit
d40e89fea9
@ -184,3 +184,33 @@ assert {
|
|||||||
ok = (foo in {foo = NULL}),
|
ok = (foo in {foo = NULL}),
|
||||||
desc = "Null valued fields are still present in tuple",
|
desc = "Null valued fields are still present in tuple",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = true && true == true,
|
||||||
|
desc = "&&: truth",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = true && false == false,
|
||||||
|
desc = "&&: propagates false",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = false && true == false,
|
||||||
|
desc = "&&: propagates false part 2",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = true || false == true,
|
||||||
|
desc = "||: propagates true",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = false || true == true,
|
||||||
|
desc = "||: propagates true part 2",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = true || true == true,
|
||||||
|
desc = "||: likes truth",
|
||||||
|
};
|
@ -52,3 +52,13 @@ assert {
|
|||||||
ok = 1 + tpl.one.two * 2 + 3 == 28,
|
ok = 1 + tpl.one.two * 2 + 3 == 28,
|
||||||
desc = "1 + tpl.one.two * 2 + 3 == 28",
|
desc = "1 + tpl.one.two * 2 + 3 == 28",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = (1 == 1) && (1 != 1) == false,
|
||||||
|
desc = "(1 == 1) && (1 != 1) == true",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert {
|
||||||
|
ok = (1 == 1) || (1 != 1) == true,
|
||||||
|
desc = "(1 == 1) && (1 != 1) == true",
|
||||||
|
};
|
@ -392,6 +392,9 @@ pub enum BinaryExprType {
|
|||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
Div,
|
Div,
|
||||||
|
// Boolean
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
// Comparison
|
// Comparison
|
||||||
Equal,
|
Equal,
|
||||||
GT,
|
GT,
|
||||||
@ -428,8 +431,11 @@ impl BinaryExprType {
|
|||||||
// Product operators are next tightly bound
|
// Product operators are next tightly bound
|
||||||
BinaryExprType::Mul => 3,
|
BinaryExprType::Mul => 3,
|
||||||
BinaryExprType::Div => 3,
|
BinaryExprType::Div => 3,
|
||||||
|
// Boolean operators bind tighter than math
|
||||||
|
BinaryExprType::AND => 4,
|
||||||
|
BinaryExprType::OR => 4,
|
||||||
// Dot operators are most tightly bound.
|
// Dot operators are most tightly bound.
|
||||||
BinaryExprType::DOT => 4,
|
BinaryExprType::DOT => 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,13 @@ impl Val {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_bool(&self) -> bool {
|
||||||
|
if let &Val::Boolean(_) = self {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_macro(&self) -> bool {
|
pub fn is_macro(&self) -> bool {
|
||||||
if let &Val::Macro(_) = self {
|
if let &Val::Macro(_) = self {
|
||||||
return true;
|
return true;
|
||||||
|
@ -815,6 +815,57 @@ impl<'a> FileBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_bool_operator(
|
||||||
|
&self,
|
||||||
|
kind: &BinaryExprType,
|
||||||
|
left: &Expression,
|
||||||
|
right: &Expression,
|
||||||
|
scope: &Scope,
|
||||||
|
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||||
|
let left_pos = left.pos();
|
||||||
|
let left = self.eval_expr(left, scope)?;
|
||||||
|
if let Val::Boolean(b) = left.as_ref() {
|
||||||
|
let right_pos = right.pos();
|
||||||
|
let b = *b;
|
||||||
|
if kind == &BinaryExprType::AND {
|
||||||
|
if !b {
|
||||||
|
// short circuit
|
||||||
|
return Ok(Rc::new(Val::Boolean(b)));
|
||||||
|
}
|
||||||
|
let right = self.eval_expr(right, scope)?;
|
||||||
|
if right.is_bool() {
|
||||||
|
return Ok(right);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if b {
|
||||||
|
// short circuit
|
||||||
|
return Ok(Rc::new(Val::Boolean(b)));
|
||||||
|
}
|
||||||
|
let right = self.eval_expr(right, scope)?;
|
||||||
|
if right.is_bool() {
|
||||||
|
return Ok(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(Box::new(error::BuildError::new(
|
||||||
|
format!(
|
||||||
|
"Expected boolean value for operator but got {}",
|
||||||
|
left.type_name()
|
||||||
|
),
|
||||||
|
error::ErrorType::TypeFail,
|
||||||
|
right_pos.clone(),
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
return Err(Box::new(error::BuildError::new(
|
||||||
|
format!(
|
||||||
|
"Expected boolean value for operator but got {}",
|
||||||
|
left.type_name()
|
||||||
|
),
|
||||||
|
error::ErrorType::TypeFail,
|
||||||
|
left_pos.clone(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn do_element_check(
|
fn do_element_check(
|
||||||
&self,
|
&self,
|
||||||
left: &Expression,
|
left: &Expression,
|
||||||
@ -901,6 +952,15 @@ impl<'a> FileBuilder<'a> {
|
|||||||
// TODO Should we support this operation on strings too?
|
// TODO Should we support this operation on strings too?
|
||||||
return self.do_element_check(&def.left, &def.right, scope);
|
return self.do_element_check(&def.left, &def.right, scope);
|
||||||
};
|
};
|
||||||
|
match kind {
|
||||||
|
// We special case the boolean operators because we want them to short circuit.
|
||||||
|
&BinaryExprType::AND | &BinaryExprType::OR => {
|
||||||
|
return self.do_bool_operator(kind, &def.left, &def.right, scope);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
let left = self.eval_expr(&def.left, scope)?;
|
let left = self.eval_expr(&def.left, scope)?;
|
||||||
let mut child_scope = scope.spawn_child();
|
let mut child_scope = scope.spawn_child();
|
||||||
child_scope.set_curr_val(left.clone());
|
child_scope.set_curr_val(left.clone());
|
||||||
@ -932,7 +992,10 @@ impl<'a> FileBuilder<'a> {
|
|||||||
&BinaryExprType::NotREMatch => {
|
&BinaryExprType::NotREMatch => {
|
||||||
self.eval_re_match(left, def.left.pos(), right, def.right.pos(), true)
|
self.eval_re_match(left, def.left.pos(), right, def.right.pos(), true)
|
||||||
}
|
}
|
||||||
&BinaryExprType::IN | &BinaryExprType::DOT => panic!("Unreachable"),
|
&BinaryExprType::IN
|
||||||
|
| &BinaryExprType::DOT
|
||||||
|
| &BinaryExprType::AND
|
||||||
|
| &BinaryExprType::OR => panic!("Unreachable"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,18 @@ make_fn!(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
make_fn!(
|
||||||
|
bool_op_type<SliceIter<Token>, Element>,
|
||||||
|
either!(
|
||||||
|
do_each!(
|
||||||
|
_ => punct!("&&"),
|
||||||
|
(Element::Op(BinaryExprType::AND))),
|
||||||
|
do_each!(
|
||||||
|
_ => punct!("||"),
|
||||||
|
(Element::Op(BinaryExprType::OR)))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Expression> {
|
fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Expression> {
|
||||||
let mut i_ = i.clone();
|
let mut i_ = i.clone();
|
||||||
if eoi(i_.clone()).is_complete() {
|
if eoi(i_.clone()).is_complete() {
|
||||||
@ -73,6 +85,34 @@ fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Express
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_bool_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
|
||||||
|
let mut i_ = i.clone();
|
||||||
|
if eoi(i_.clone()).is_complete() {
|
||||||
|
return Result::Fail(Error::new(
|
||||||
|
format!("Expected Expression found End Of Input"),
|
||||||
|
Box::new(i_),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let el = i_.next();
|
||||||
|
if let Some(&Element::Op(ref op)) = el {
|
||||||
|
match op {
|
||||||
|
BinaryExprType::AND | BinaryExprType::OR => {
|
||||||
|
return Result::Complete(i_.clone(), op.clone());
|
||||||
|
}
|
||||||
|
_other => {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Result::Fail(Error::new(
|
||||||
|
format!(
|
||||||
|
"Error while parsing Binary Expression Unexpected Operator {:?}",
|
||||||
|
el
|
||||||
|
),
|
||||||
|
Box::new(i_),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_dot_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
|
fn parse_dot_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
|
||||||
let mut i_ = i.clone();
|
let mut i_ = i.clone();
|
||||||
if eoi(i_.clone()).is_complete() {
|
if eoi(i_.clone()).is_complete() {
|
||||||
@ -243,7 +283,13 @@ fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> ParseResult<'a, Vec<Elemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 3. Parse an operator.
|
// 3. Parse an operator.
|
||||||
match either!(_i.clone(), dot_op_type, math_op_type, compare_op_type) {
|
match either!(
|
||||||
|
_i.clone(),
|
||||||
|
dot_op_type,
|
||||||
|
math_op_type,
|
||||||
|
compare_op_type,
|
||||||
|
bool_op_type
|
||||||
|
) {
|
||||||
Result::Fail(e) => {
|
Result::Fail(e) => {
|
||||||
if firstrun {
|
if firstrun {
|
||||||
// If we don't find an operator in our first
|
// If we don't find an operator in our first
|
||||||
@ -278,7 +324,8 @@ make_fn!(
|
|||||||
parse_dot_operator,
|
parse_dot_operator,
|
||||||
parse_sum_operator,
|
parse_sum_operator,
|
||||||
parse_product_operator,
|
parse_product_operator,
|
||||||
parse_compare_operator
|
parse_compare_operator,
|
||||||
|
parse_bool_operator
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -258,6 +258,14 @@ make_fn!(fatcommatok<OffsetStrIter, Token>,
|
|||||||
do_text_token_tok!(TokenType::PUNCT, "=>")
|
do_text_token_tok!(TokenType::PUNCT, "=>")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
make_fn!(andtok<OffsetStrIter, Token>,
|
||||||
|
do_text_token_tok!(TokenType::PUNCT, "&&")
|
||||||
|
);
|
||||||
|
|
||||||
|
make_fn!(ortok<OffsetStrIter, Token>,
|
||||||
|
do_text_token_tok!(TokenType::PUNCT, "||")
|
||||||
|
);
|
||||||
|
|
||||||
make_fn!(selecttok<OffsetStrIter, Token>,
|
make_fn!(selecttok<OffsetStrIter, Token>,
|
||||||
do_text_token_tok!(TokenType::BAREWORD, "select", WS)
|
do_text_token_tok!(TokenType::BAREWORD, "select", WS)
|
||||||
);
|
);
|
||||||
@ -376,6 +384,8 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
|
|||||||
lparentok,
|
lparentok,
|
||||||
rparentok,
|
rparentok,
|
||||||
dottok,
|
dottok,
|
||||||
|
andtok,
|
||||||
|
ortok,
|
||||||
plustok,
|
plustok,
|
||||||
dashtok,
|
dashtok,
|
||||||
startok,
|
startok,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user