mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-23 18:29:50 -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" ;
|
out_keyword: "out" ;
|
||||||
assert_keyword: "assert" ;
|
assert_keyword: "assert" ;
|
||||||
null_keyword: "NULL" ;
|
null_keyword: "NULL" ;
|
||||||
|
in_keyword: "in" ;
|
||||||
escaped: "\", VISIBLE_CHAR ;
|
escaped: "\", VISIBLE_CHAR ;
|
||||||
str: quot, { escaped | UTF8_CHAR }, quot ;
|
str: quot, { escaped | UTF8_CHAR }, quot ;
|
||||||
```
|
```
|
||||||
@ -142,8 +143,8 @@ non_operator_expr: literal
|
|||||||
```
|
```
|
||||||
sum_op: plus | minus ;
|
sum_op: plus | minus ;
|
||||||
product_op: start | slash ;
|
product_op: start | slash ;
|
||||||
compare_op: equalequal | gtequal | ltequal | gt | lt ;
|
compare_op: equalequal | gtequal | ltequal | gt | lt | in_keyword ;
|
||||||
binary_op: sum_op | product_op | dot | compare_op;
|
binary_op: sum_op | product_op | dot | compare_op ;
|
||||||
binary_expr: non_operator_expr, binary_op, expr ;
|
binary_expr: non_operator_expr, binary_op, expr ;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -87,4 +87,28 @@ assert |(1+1) == (1+1);|;
|
|||||||
let want = "foo";
|
let want = "foo";
|
||||||
assert |
|
assert |
|
||||||
select want, 1, { foo=2, } == 2;
|
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,
|
NotEqual,
|
||||||
GTEqual,
|
GTEqual,
|
||||||
LTEqual,
|
LTEqual,
|
||||||
|
IN,
|
||||||
// Selector operator
|
// Selector operator
|
||||||
DOT,
|
DOT,
|
||||||
}
|
}
|
||||||
@ -512,6 +513,7 @@ impl BinaryExprType {
|
|||||||
BinaryExprType::LTEqual => 1,
|
BinaryExprType::LTEqual => 1,
|
||||||
BinaryExprType::GT => 1,
|
BinaryExprType::GT => 1,
|
||||||
BinaryExprType::LT => 1,
|
BinaryExprType::LT => 1,
|
||||||
|
BinaryExprType::IN => 1,
|
||||||
// Sum operators are next least tightly bound
|
// Sum operators are next least tightly bound
|
||||||
BinaryExprType::Add => 2,
|
BinaryExprType::Add => 2,
|
||||||
BinaryExprType::Sub => 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>> {
|
fn eval_binary(&mut self, def: &BinaryOpDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let kind = &def.kind;
|
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 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());
|
||||||
@ -756,8 +806,7 @@ impl<'a> FileBuilder<'a> {
|
|||||||
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
||||||
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
||||||
&BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
|
&BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
|
||||||
// TODO Handle the whole selector lookup logic here.
|
&BinaryExprType::IN | &BinaryExprType::DOT => panic!("Unreachable"),
|
||||||
&BinaryExprType::DOT => panic!("Unraeachable"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,8 @@ make_fn!(
|
|||||||
do_each!(_ => punct!("<="), (Element::Op(BinaryExprType::LTEqual))),
|
do_each!(_ => punct!("<="), (Element::Op(BinaryExprType::LTEqual))),
|
||||||
do_each!(_ => punct!(">="), (Element::Op(BinaryExprType::GTEqual))),
|
do_each!(_ => punct!(">="), (Element::Op(BinaryExprType::GTEqual))),
|
||||||
do_each!(_ => punct!("<"), (Element::Op(BinaryExprType::LT))),
|
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::LT
|
||||||
| &BinaryExprType::LTEqual
|
| &BinaryExprType::LTEqual
|
||||||
| &BinaryExprType::NotEqual
|
| &BinaryExprType::NotEqual
|
||||||
| &BinaryExprType::Equal => {
|
| &BinaryExprType::Equal
|
||||||
|
| &BinaryExprType::IN => {
|
||||||
return Result::Complete(i_.clone(), op.clone());
|
return Result::Complete(i_.clone(), op.clone());
|
||||||
}
|
}
|
||||||
_other => {
|
_other => {
|
||||||
|
@ -264,6 +264,10 @@ make_fn!(selecttok<OffsetStrIter, Token>,
|
|||||||
do_text_token_tok!(TokenType::BAREWORD, "select", WS)
|
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>,
|
make_fn!(macrotok<OffsetStrIter, Token>,
|
||||||
do_text_token_tok!(TokenType::BAREWORD, "macro", WS)
|
do_text_token_tok!(TokenType::BAREWORD, "macro", WS)
|
||||||
);
|
);
|
||||||
@ -385,6 +389,7 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
|
|||||||
leftsquarebracket,
|
leftsquarebracket,
|
||||||
rightsquarebracket,
|
rightsquarebracket,
|
||||||
booleantok,
|
booleantok,
|
||||||
|
intok,
|
||||||
lettok,
|
lettok,
|
||||||
outtok,
|
outtok,
|
||||||
selecttok,
|
selecttok,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user