mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: add a conatins operator
Adds the `in` operator that checks for fields in tuples and elements in a list. Fixes: #12
This commit is contained in:
parent
d13556b4cd
commit
59343d71d5
@ -52,6 +52,7 @@ mod_keyword: "mod" ;
|
||||
out_keyword: "out" ;
|
||||
assert_keyword: "assert" ;
|
||||
null_keyword: "NULL" ;
|
||||
in_keyword: "in" ;
|
||||
escaped: "\", VISIBLE_CHAR ;
|
||||
str: quot, { escaped | UTF8_CHAR }, quot ;
|
||||
```
|
||||
@ -142,8 +143,8 @@ non_operator_expr: literal
|
||||
```
|
||||
sum_op: plus | minus ;
|
||||
product_op: start | slash ;
|
||||
compare_op: equalequal | gtequal | ltequal | gt | lt ;
|
||||
binary_op: sum_op | product_op | dot | compare_op;
|
||||
compare_op: equalequal | gtequal | ltequal | gt | lt | in_keyword ;
|
||||
binary_op: sum_op | product_op | dot | compare_op ;
|
||||
binary_expr: non_operator_expr, binary_op, expr ;
|
||||
```
|
||||
|
||||
|
@ -87,4 +87,28 @@ assert |(1+1) == (1+1);|;
|
||||
let want = "foo";
|
||||
assert |
|
||||
select want, 1, { foo=2, } == 2;
|
||||
|;
|
||||
|
||||
// Contains comparison operators.
|
||||
assert |
|
||||
"foo" in {
|
||||
foo = "bar",
|
||||
};
|
||||
|;
|
||||
assert |
|
||||
foo in {
|
||||
foo = "bar",
|
||||
};
|
||||
|;
|
||||
assert |
|
||||
"foo" in ["foo", "bar"];
|
||||
|;
|
||||
assert |
|
||||
"foo" in ["bar", "foo", "bar"];
|
||||
|;
|
||||
assert |
|
||||
{ foo = 1 } in ["foo", { foo = 1 }];
|
||||
|;
|
||||
assert |
|
||||
true in [ "foo" in {foo = 1}, false ];
|
||||
|;
|
@ -495,6 +495,7 @@ pub enum BinaryExprType {
|
||||
NotEqual,
|
||||
GTEqual,
|
||||
LTEqual,
|
||||
IN,
|
||||
// Selector operator
|
||||
DOT,
|
||||
}
|
||||
@ -512,6 +513,7 @@ impl BinaryExprType {
|
||||
BinaryExprType::LTEqual => 1,
|
||||
BinaryExprType::GT => 1,
|
||||
BinaryExprType::LT => 1,
|
||||
BinaryExprType::IN => 1,
|
||||
// Sum operators are next least tightly bound
|
||||
BinaryExprType::Add => 2,
|
||||
BinaryExprType::Sub => 2,
|
||||
|
@ -729,8 +729,58 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn do_element_check(
|
||||
&mut self,
|
||||
left: &Expression,
|
||||
right: &Expression,
|
||||
scope: &Scope,
|
||||
) -> Result<Rc<Val>, Box<Error>> {
|
||||
// First we evaluate our right hand side so we have a something to search
|
||||
// inside for our left hand expression.
|
||||
let right_pos = right.pos().clone();
|
||||
let right = self.eval_expr(right, scope)?;
|
||||
// presence checks are only valid for tuples and lists.
|
||||
if !(right.is_tuple() || right.is_list()) {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Invalid righthand type for in operator {}",
|
||||
right.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
right_pos,
|
||||
)));
|
||||
}
|
||||
if let &Val::List(ref els) = right.as_ref() {
|
||||
let left_pos = left.pos().clone();
|
||||
let left = self.eval_expr(left, scope)?;
|
||||
for val in els.iter() {
|
||||
if let Ok(b) = self.do_deep_equal(&left_pos, left.clone(), val.clone()) {
|
||||
if let &Val::Boolean(b) = b.as_ref() {
|
||||
if b {
|
||||
// We found a match
|
||||
return Ok(Rc::new(Val::Boolean(true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We didn't find a match anywhere so return false.
|
||||
return Ok(Rc::new(Val::Boolean(false)));
|
||||
} else {
|
||||
// Handle our tuple case since this isn't a list.
|
||||
let mut child_scope = scope.spawn_child();
|
||||
child_scope.set_curr_val(right.clone());
|
||||
// Search for the field in our tuple or list.
|
||||
let maybe_val = self.do_dot_lookup(left, &child_scope);
|
||||
// Return the result of the search.
|
||||
return Ok(Rc::new(Val::Boolean(maybe_val.is_ok())));
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_binary(&mut self, def: &BinaryOpDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
|
||||
let kind = &def.kind;
|
||||
if let &BinaryExprType::IN = kind {
|
||||
return self.do_element_check(&def.left, &def.right, scope);
|
||||
};
|
||||
let left = self.eval_expr(&def.left, scope)?;
|
||||
let mut child_scope = scope.spawn_child();
|
||||
child_scope.set_curr_val(left.clone());
|
||||
@ -756,8 +806,7 @@ impl<'a> FileBuilder<'a> {
|
||||
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
||||
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
||||
&BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
|
||||
// TODO Handle the whole selector lookup logic here.
|
||||
&BinaryExprType::DOT => panic!("Unraeachable"),
|
||||
&BinaryExprType::IN | &BinaryExprType::DOT => panic!("Unreachable"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,8 @@ make_fn!(
|
||||
do_each!(_ => punct!("<="), (Element::Op(BinaryExprType::LTEqual))),
|
||||
do_each!(_ => punct!(">="), (Element::Op(BinaryExprType::GTEqual))),
|
||||
do_each!(_ => punct!("<"), (Element::Op(BinaryExprType::LT))),
|
||||
do_each!(_ => punct!(">"), (Element::Op(BinaryExprType::GT)))
|
||||
do_each!(_ => punct!(">"), (Element::Op(BinaryExprType::GT))),
|
||||
do_each!(_ => word!("in"), (Element::Op(BinaryExprType::IN)))
|
||||
)
|
||||
);
|
||||
|
||||
@ -191,7 +192,8 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
|
||||
| &BinaryExprType::LT
|
||||
| &BinaryExprType::LTEqual
|
||||
| &BinaryExprType::NotEqual
|
||||
| &BinaryExprType::Equal => {
|
||||
| &BinaryExprType::Equal
|
||||
| &BinaryExprType::IN => {
|
||||
return Result::Complete(i_.clone(), op.clone());
|
||||
}
|
||||
_other => {
|
||||
|
@ -264,6 +264,10 @@ make_fn!(selecttok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "select", WS)
|
||||
);
|
||||
|
||||
make_fn!(intok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "in", WS)
|
||||
);
|
||||
|
||||
make_fn!(macrotok<OffsetStrIter, Token>,
|
||||
do_text_token_tok!(TokenType::BAREWORD, "macro", WS)
|
||||
);
|
||||
@ -385,6 +389,7 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
|
||||
leftsquarebracket,
|
||||
rightsquarebracket,
|
||||
booleantok,
|
||||
intok,
|
||||
lettok,
|
||||
outtok,
|
||||
selecttok,
|
||||
|
Loading…
x
Reference in New Issue
Block a user