mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-08 09:44:21 +01:00
Introduce walker expressions for ast::Expr
This commit is contained in:
@@ -2600,3 +2600,390 @@ pub fn unwrap_parens_owned(expr: ast::Expr) -> Result<(ast::Expr, usize)> {
|
||||
_ => Ok((expr, paren_count)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively walks an immutable expression, applying a function to each sub-expression.
|
||||
pub fn walk_expr<F>(expr: &ast::Expr, func: &mut F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&ast::Expr) -> Result<()>,
|
||||
{
|
||||
func(expr)?;
|
||||
match expr {
|
||||
ast::Expr::Between {
|
||||
lhs, start, end, ..
|
||||
} => {
|
||||
walk_expr(lhs, func)?;
|
||||
walk_expr(start, func)?;
|
||||
walk_expr(end, func)?;
|
||||
}
|
||||
ast::Expr::Binary(lhs, _, rhs) => {
|
||||
walk_expr(lhs, func)?;
|
||||
walk_expr(rhs, func)?;
|
||||
}
|
||||
ast::Expr::Case {
|
||||
base,
|
||||
when_then_pairs,
|
||||
else_expr,
|
||||
} => {
|
||||
if let Some(base_expr) = base {
|
||||
walk_expr(base_expr, func)?;
|
||||
}
|
||||
for (when_expr, then_expr) in when_then_pairs {
|
||||
walk_expr(when_expr, func)?;
|
||||
walk_expr(then_expr, func)?;
|
||||
}
|
||||
if let Some(else_expr) = else_expr {
|
||||
walk_expr(else_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Cast { expr, .. } => {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
ast::Expr::Collate(expr, _) => {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
ast::Expr::Exists(_select) | ast::Expr::Subquery(_select) => {
|
||||
// TODO: Walk through select statements if needed
|
||||
}
|
||||
ast::Expr::FunctionCall {
|
||||
args,
|
||||
order_by,
|
||||
filter_over,
|
||||
..
|
||||
} => {
|
||||
if let Some(args) = args {
|
||||
for arg in args {
|
||||
walk_expr(arg, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by) = order_by {
|
||||
for sort_col in order_by {
|
||||
walk_expr(&sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(filter_over) = filter_over {
|
||||
if let Some(filter_clause) = &filter_over.filter_clause {
|
||||
walk_expr(filter_clause, func)?;
|
||||
}
|
||||
if let Some(over_clause) = &filter_over.over_clause {
|
||||
match over_clause.as_ref() {
|
||||
ast::Over::Window(window) => {
|
||||
if let Some(partition_by) = &window.partition_by {
|
||||
for part_expr in partition_by {
|
||||
walk_expr(part_expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by_clause) = &window.order_by {
|
||||
for sort_col in order_by_clause {
|
||||
walk_expr(&sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(frame_clause) = &window.frame_clause {
|
||||
walk_expr_frame_bound(&frame_clause.start, func)?;
|
||||
if let Some(end_bound) = &frame_clause.end {
|
||||
walk_expr_frame_bound(end_bound, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Over::Name(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::FunctionCallStar { filter_over, .. } => {
|
||||
if let Some(filter_over) = filter_over {
|
||||
if let Some(filter_clause) = &filter_over.filter_clause {
|
||||
walk_expr(filter_clause, func)?;
|
||||
}
|
||||
if let Some(over_clause) = &filter_over.over_clause {
|
||||
match over_clause.as_ref() {
|
||||
ast::Over::Window(window) => {
|
||||
if let Some(partition_by) = &window.partition_by {
|
||||
for part_expr in partition_by {
|
||||
walk_expr(part_expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by_clause) = &window.order_by {
|
||||
for sort_col in order_by_clause {
|
||||
walk_expr(&sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(frame_clause) = &window.frame_clause {
|
||||
walk_expr_frame_bound(&frame_clause.start, func)?;
|
||||
if let Some(end_bound) = &frame_clause.end {
|
||||
walk_expr_frame_bound(end_bound, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Over::Name(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::InList { lhs, rhs, .. } => {
|
||||
walk_expr(lhs, func)?;
|
||||
if let Some(rhs_exprs) = rhs {
|
||||
for expr in rhs_exprs {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::InSelect { lhs, rhs: _, .. } => {
|
||||
walk_expr(lhs, func)?;
|
||||
// TODO: Walk through select statements if needed
|
||||
}
|
||||
ast::Expr::InTable { lhs, args, .. } => {
|
||||
walk_expr(lhs, func)?;
|
||||
if let Some(arg_exprs) = args {
|
||||
for expr in arg_exprs {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::IsNull(expr) | ast::Expr::NotNull(expr) => {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
ast::Expr::Like {
|
||||
lhs, rhs, escape, ..
|
||||
} => {
|
||||
walk_expr(lhs, func)?;
|
||||
walk_expr(rhs, func)?;
|
||||
if let Some(esc_expr) = escape {
|
||||
walk_expr(esc_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Parenthesized(exprs) => {
|
||||
for expr in exprs {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Raise(_, expr) => {
|
||||
if let Some(raise_expr) = expr {
|
||||
walk_expr(raise_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Unary(_, expr) => {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
ast::Expr::Id(_)
|
||||
| ast::Expr::Column { .. }
|
||||
| ast::Expr::RowId { .. }
|
||||
| ast::Expr::Literal(_)
|
||||
| ast::Expr::DoublyQualified(..)
|
||||
| ast::Expr::Name(_)
|
||||
| ast::Expr::Qualified(..)
|
||||
| ast::Expr::Variable(_) => {
|
||||
// No nested expressions
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn walk_expr_frame_bound<F>(bound: &ast::FrameBound, func: &mut F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&ast::Expr) -> Result<()>,
|
||||
{
|
||||
match bound {
|
||||
ast::FrameBound::Following(expr) | ast::FrameBound::Preceding(expr) => {
|
||||
walk_expr(expr, func)?;
|
||||
}
|
||||
ast::FrameBound::CurrentRow
|
||||
| ast::FrameBound::UnboundedFollowing
|
||||
| ast::FrameBound::UnboundedPreceding => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Recursively walks a mutable expression, applying a function to each sub-expression.
|
||||
pub fn walk_expr_mut<F>(expr: &mut ast::Expr, func: &mut F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&mut ast::Expr) -> Result<()>,
|
||||
{
|
||||
func(expr)?;
|
||||
match expr {
|
||||
ast::Expr::Between {
|
||||
lhs, start, end, ..
|
||||
} => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
walk_expr_mut(start, func)?;
|
||||
walk_expr_mut(end, func)?;
|
||||
}
|
||||
ast::Expr::Binary(lhs, _, rhs) => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
walk_expr_mut(rhs, func)?;
|
||||
}
|
||||
ast::Expr::Case {
|
||||
base,
|
||||
when_then_pairs,
|
||||
else_expr,
|
||||
} => {
|
||||
if let Some(base_expr) = base {
|
||||
walk_expr_mut(base_expr, func)?;
|
||||
}
|
||||
for (when_expr, then_expr) in when_then_pairs {
|
||||
walk_expr_mut(when_expr, func)?;
|
||||
walk_expr_mut(then_expr, func)?;
|
||||
}
|
||||
if let Some(else_expr) = else_expr {
|
||||
walk_expr_mut(else_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Cast { expr, .. } => {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
ast::Expr::Collate(expr, _) => {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
ast::Expr::Exists(_) | ast::Expr::Subquery(_) => {
|
||||
// TODO: Walk through select statements if needed
|
||||
}
|
||||
ast::Expr::FunctionCall {
|
||||
args,
|
||||
order_by,
|
||||
filter_over,
|
||||
..
|
||||
} => {
|
||||
if let Some(args) = args {
|
||||
for arg in args {
|
||||
walk_expr_mut(arg, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by) = order_by {
|
||||
for sort_col in order_by {
|
||||
walk_expr_mut(&mut sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(filter_over) = filter_over {
|
||||
if let Some(filter_clause) = &mut filter_over.filter_clause {
|
||||
walk_expr_mut(filter_clause, func)?;
|
||||
}
|
||||
if let Some(over_clause) = &mut filter_over.over_clause {
|
||||
match over_clause.as_mut() {
|
||||
ast::Over::Window(window) => {
|
||||
if let Some(partition_by) = &mut window.partition_by {
|
||||
for part_expr in partition_by {
|
||||
walk_expr_mut(part_expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by_clause) = &mut window.order_by {
|
||||
for sort_col in order_by_clause {
|
||||
walk_expr_mut(&mut sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(frame_clause) = &mut window.frame_clause {
|
||||
walk_expr_mut_frame_bound(&mut frame_clause.start, func)?;
|
||||
if let Some(end_bound) = &mut frame_clause.end {
|
||||
walk_expr_mut_frame_bound(end_bound, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Over::Name(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::FunctionCallStar { filter_over, .. } => {
|
||||
if let Some(filter_over) = filter_over {
|
||||
if let Some(filter_clause) = &mut filter_over.filter_clause {
|
||||
walk_expr_mut(filter_clause, func)?;
|
||||
}
|
||||
if let Some(over_clause) = &mut filter_over.over_clause {
|
||||
match over_clause.as_mut() {
|
||||
ast::Over::Window(window) => {
|
||||
if let Some(partition_by) = &mut window.partition_by {
|
||||
for part_expr in partition_by {
|
||||
walk_expr_mut(part_expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(order_by_clause) = &mut window.order_by {
|
||||
for sort_col in order_by_clause {
|
||||
walk_expr_mut(&mut sort_col.expr, func)?;
|
||||
}
|
||||
}
|
||||
if let Some(frame_clause) = &mut window.frame_clause {
|
||||
walk_expr_mut_frame_bound(&mut frame_clause.start, func)?;
|
||||
if let Some(end_bound) = &mut frame_clause.end {
|
||||
walk_expr_mut_frame_bound(end_bound, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Over::Name(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::InList { lhs, rhs, .. } => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
if let Some(rhs_exprs) = rhs {
|
||||
for expr in rhs_exprs {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::InSelect { lhs, rhs: _, .. } => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
// TODO: Walk through select statements if needed
|
||||
}
|
||||
ast::Expr::InTable { lhs, args, .. } => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
if let Some(arg_exprs) = args {
|
||||
for expr in arg_exprs {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::IsNull(expr) | ast::Expr::NotNull(expr) => {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
ast::Expr::Like {
|
||||
lhs, rhs, escape, ..
|
||||
} => {
|
||||
walk_expr_mut(lhs, func)?;
|
||||
walk_expr_mut(rhs, func)?;
|
||||
if let Some(esc_expr) = escape {
|
||||
walk_expr_mut(esc_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Parenthesized(exprs) => {
|
||||
for expr in exprs {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Raise(_, expr) => {
|
||||
if let Some(raise_expr) = expr {
|
||||
walk_expr_mut(raise_expr, func)?;
|
||||
}
|
||||
}
|
||||
ast::Expr::Unary(_, expr) => {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
ast::Expr::Id(_)
|
||||
| ast::Expr::Column { .. }
|
||||
| ast::Expr::RowId { .. }
|
||||
| ast::Expr::Literal(_)
|
||||
| ast::Expr::DoublyQualified(..)
|
||||
| ast::Expr::Name(_)
|
||||
| ast::Expr::Qualified(..)
|
||||
| ast::Expr::Variable(_) => {
|
||||
// No nested expressions
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn walk_expr_mut_frame_bound<F>(bound: &mut ast::FrameBound, func: &mut F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&mut ast::Expr) -> Result<()>,
|
||||
{
|
||||
match bound {
|
||||
ast::FrameBound::Following(expr) | ast::FrameBound::Preceding(expr) => {
|
||||
walk_expr_mut(expr, func)?;
|
||||
}
|
||||
ast::FrameBound::CurrentRow
|
||||
| ast::FrameBound::UnboundedFollowing
|
||||
| ast::FrameBound::UnboundedPreceding => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user