From fac4b4e6fb016a6074513885a8a4d4338d4d3a4f Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Tue, 3 Jun 2025 14:36:32 -0300 Subject: [PATCH] fix generation and expr evaluation --- limbo_sim | Bin 0 -> 4096 bytes simulator.log | 53 ++++++++++++++++++++ simulator/generation/predicate.rs | 45 +++++++---------- simulator/model/query/predicate.rs | 77 ++++++++++++----------------- simulator/model/table.rs | 4 +- 5 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 limbo_sim create mode 100644 simulator.log diff --git a/limbo_sim b/limbo_sim new file mode 100644 index 0000000000000000000000000000000000000000..a7582c3c97f3b7989dfc514a25271a8d1051e5d1 GIT binary patch literal 4096 zcmWFz^vNtqRY=P(%1ta$FlG>7U}9o$P*7lCU|@t|AO#03K;bV?9!MTP(5s7J0AgN{ wDgpdTM`cGtU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1ZWom02k^A for SimplePredicate { Box::new(|rng| { Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Equals, @@ -43,7 +43,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate { let gt_value = GTValue::arbitrary_from(rng, &column_values).0; Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Greater, @@ -54,7 +54,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate { let lt_value = LTValue::arbitrary_from(rng, &column_values).0; Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Less, @@ -69,7 +69,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate { Box::new(|rng| { Expr::Binary( Box::new(Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::NotEquals, @@ -80,7 +80,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate { let lt_value = LTValue::arbitrary_from(rng, &column_values).0; Expr::Binary( Box::new(Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Greater, @@ -91,7 +91,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate { let gt_value = GTValue::arbitrary_from(rng, &column_values).0; Expr::Binary( Box::new(Expr::Qualified( - ast::Name("".to_string()), + ast::Name(table.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Less, @@ -203,10 +203,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate { vec![ Box::new(|_| { Predicate(Expr::Binary( - Box::new(Expr::Qualified( - ast::Name("".to_string()), - ast::Name(column_name.to_string()), - )), + Box::new(Expr::Id(ast::Id(column_name.to_string()))), ast::Operator::Equals, Box::new(Expr::Literal(value.into())), )) @@ -214,10 +211,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate { Box::new(|rng| { let gt_value = GTValue::arbitrary_from(rng, value).0; Predicate(Expr::Binary( - Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), - ast::Name(column_name.to_string()), - )), + Box::new(Expr::Id(ast::Id(column_name.to_string()))), ast::Operator::Greater, Box::new(Expr::Literal(gt_value.into())), )) @@ -225,10 +219,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate { Box::new(|rng| { let lt_value = LTValue::arbitrary_from(rng, value).0; Predicate(Expr::Binary( - Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), - ast::Name(column_name.to_string()), - )), + Box::new(Expr::Id(ast::Id(column_name.to_string()))), ast::Operator::Less, Box::new(Expr::Literal(lt_value.into())), )) @@ -252,7 +243,7 @@ fn produce_true_predicate(rng: &mut R, (t, row): (&Table, &Vec)) Box::new(|_| { Some(Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Equals, @@ -269,7 +260,7 @@ fn produce_true_predicate(rng: &mut R, (t, row): (&Table, &Vec)) } else { Some(Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::NotEquals, @@ -284,7 +275,7 @@ fn produce_true_predicate(rng: &mut R, (t, row): (&Table, &Vec)) let lt_value = LTValue::arbitrary_from(rng, value).0; Some(Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Greater, @@ -298,7 +289,7 @@ fn produce_true_predicate(rng: &mut R, (t, row): (&Table, &Vec)) let gt_value = GTValue::arbitrary_from(rng, value).0; Some(Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Less, @@ -312,7 +303,7 @@ fn produce_true_predicate(rng: &mut R, (t, row): (&Table, &Vec)) LikeValue::arbitrary_from_maybe(rng, value).map(|like| { Predicate(Expr::Like { lhs: Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), not: false, // TODO: also generate this value eventually @@ -339,7 +330,7 @@ fn produce_false_predicate(rng: &mut R, (t, row): (&Table, &Vec)) Box::new(|_| { Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::NotEquals, @@ -355,7 +346,7 @@ fn produce_false_predicate(rng: &mut R, (t, row): (&Table, &Vec)) }; Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Equals, @@ -366,7 +357,7 @@ fn produce_false_predicate(rng: &mut R, (t, row): (&Table, &Vec)) let gt_value = GTValue::arbitrary_from(rng, value).0; Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Greater, @@ -377,7 +368,7 @@ fn produce_false_predicate(rng: &mut R, (t, row): (&Table, &Vec)) let lt_value = LTValue::arbitrary_from(rng, value).0; Predicate(Expr::Binary( Box::new(ast::Expr::Qualified( - ast::Name("".to_string()), + ast::Name(t.name.clone()), ast::Name(column.name.clone()), )), ast::Operator::Less, diff --git a/simulator/model/query/predicate.rs b/simulator/model/query/predicate.rs index 21f52b516..7d1ca3591 100644 --- a/simulator/model/query/predicate.rs +++ b/simulator/model/query/predicate.rs @@ -8,15 +8,6 @@ use crate::model::{ table::{Table, Value}, }; -macro_rules! assert_implemented_predicate_expr { - ($val:expr) => { - assert!(matches!( - $val, - ast::Expr::DoublyQualified(..) | ast::Expr::Qualified(..) | ast::Expr::Literal(..) - )) - }; -} - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Predicate(pub ast::Expr); @@ -30,39 +21,8 @@ impl Predicate { } pub(crate) fn test(&self, row: &[Value], table: &Table) -> bool { - match &self.0 { - ast::Expr::Binary(lhs, operator, rhs) => { - let lhs = expr_to_value(lhs, row, table); - let rhs = expr_to_value(rhs, row, table); - match (lhs, rhs) { - (Some(lhs), Some(rhs)) => lhs.binary_compare(&rhs, *operator), - _ => false, - } - } - ast::Expr::Like { - lhs, - not, - op, - rhs, - escape: _, // TODO: support escape - } => { - let lhs = expr_to_value(lhs, row, table); - let rhs = expr_to_value(rhs, row, table); - let res = match (lhs, rhs) { - (Some(lhs), Some(rhs)) => lhs.like_compare(&rhs, *op), - _ => false, - }; - if *not { - !res - } else { - res - } - } - ast::Expr::Literal(literal) => Value::from(literal).into_bool(), - // TODO: next implement unary operator - ast::Expr::Unary(..) => todo!(), - expr => unimplemented!("{:?}", expr), - } + let value = expr_to_value(&self.0, row, table); + value.map_or(false, |value| value.into_bool()) } } @@ -71,17 +31,42 @@ impl Predicate { // TODO: In the future, we can try to expand this computation if we want to support harder properties that require us // to already know more values before hand fn expr_to_value(expr: &ast::Expr, row: &[Value], table: &Table) -> Option { - assert_implemented_predicate_expr!(expr); match expr { - ast::Expr::DoublyQualified(_, _, col_name) | ast::Expr::Qualified(_, col_name) => table + ast::Expr::DoublyQualified(_, _, ast::Name(col_name)) + | ast::Expr::Qualified(_, ast::Name(col_name)) + | ast::Expr::Id(ast::Id(col_name)) => table .columns .iter() .zip(row.iter()) - .find(|(column, _)| column.name == col_name.0) + .find(|(column, _)| column.name == *col_name) .map(|(_, value)| value) .cloned(), ast::Expr::Literal(literal) => Some(literal.into()), - // TODO: add binary and unary + ast::Expr::Binary(lhs, op, rhs) => { + let lhs = expr_to_value(lhs, row, table); + let rhs = expr_to_value(rhs, row, table); + match (lhs, rhs) { + (Some(lhs), Some(rhs)) => Some(lhs.binary_compare(&rhs, *op)), + _ => None, + } + } + ast::Expr::Like { + lhs, + not, + op, + rhs, + escape: _, // TODO: support escape + } => { + let lhs = expr_to_value(lhs, row, table); + let rhs = expr_to_value(rhs, row, table); + let res = match (lhs, rhs) { + (Some(lhs), Some(rhs)) => lhs.like_compare(&rhs, *op), + _ => return None, + }; + let value: Value = if *not { !res } else { res }.into(); + Some(value) + } + // TODO: add unary _ => unreachable!("{:?}", expr), } } diff --git a/simulator/model/table.rs b/simulator/model/table.rs index a1e5f6948..ffe779f5e 100644 --- a/simulator/model/table.rs +++ b/simulator/model/table.rs @@ -127,7 +127,8 @@ impl Value { } // TODO: support more predicates - pub fn binary_compare(&self, other: &Self, operator: ast::Operator) -> bool { + /// Returns a Value::TRUE or VALUE::FALSE + pub fn binary_compare(&self, other: &Self, operator: ast::Operator) -> Value { match operator { ast::Operator::Add => todo!(), ast::Operator::And => self.into_bool() && other.into_bool(), @@ -153,6 +154,7 @@ impl Value { ast::Operator::RightShift => todo!(), ast::Operator::Subtract => todo!(), } + .into() } // TODO: support more operators. Copy the implementation for exec_glob