use vibesql_ast::ProceduralStatement;
use vibesql_storage::Database;
use vibesql_types::SqlValue;
use super::executor::evaluate_expression;
use crate::{
errors::ExecutorError,
procedural::{ControlFlow, ExecutionContext},
};
pub fn execute_if(
condition: &vibesql_ast::Expression,
then_statements: &[ProceduralStatement],
else_statements: &Option<Vec<ProceduralStatement>>,
ctx: &mut ExecutionContext,
db: &mut Database,
) -> Result<ControlFlow, ExecutorError> {
let condition_value = evaluate_expression(condition, db, ctx)?;
let is_true = match condition_value {
SqlValue::Boolean(b) => b,
SqlValue::Integer(i) => i != 0,
SqlValue::Null => false,
_ => {
return Err(ExecutorError::TypeError(format!(
"IF condition must evaluate to boolean, got {:?}",
condition_value
)))
}
};
if is_true {
for stmt in then_statements {
let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
if flow != ControlFlow::Continue {
return Ok(flow);
}
}
} else if let Some(else_stmts) = else_statements {
for stmt in else_stmts {
let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
if flow != ControlFlow::Continue {
return Ok(flow);
}
}
}
Ok(ControlFlow::Continue)
}
pub fn execute_while(
condition: &vibesql_ast::Expression,
statements: &[ProceduralStatement],
ctx: &mut ExecutionContext,
db: &mut Database,
) -> Result<ControlFlow, ExecutorError> {
loop {
let condition_value = evaluate_expression(condition, db, ctx)?;
let is_true = match condition_value {
SqlValue::Boolean(b) => b,
SqlValue::Integer(i) => i != 0,
SqlValue::Null => false,
_ => {
return Err(ExecutorError::TypeError(format!(
"WHILE condition must evaluate to boolean, got {:?}",
condition_value
)))
}
};
if !is_true {
break;
}
for stmt in statements {
let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
match flow {
ControlFlow::Continue => {}
ControlFlow::Return(_) => return Ok(flow),
ControlFlow::Leave(_) => return Ok(flow),
ControlFlow::Iterate(_) => break, }
}
}
Ok(ControlFlow::Continue)
}
pub fn execute_loop(
statements: &[ProceduralStatement],
ctx: &mut ExecutionContext,
db: &mut Database,
) -> Result<ControlFlow, ExecutorError> {
loop {
for stmt in statements {
let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
match flow {
ControlFlow::Continue => {}
ControlFlow::Return(_) => return Ok(flow),
ControlFlow::Leave(_) => return Ok(ControlFlow::Continue), ControlFlow::Iterate(_) => break,
}
}
}
}
pub fn execute_repeat(
statements: &[ProceduralStatement],
condition: &vibesql_ast::Expression,
ctx: &mut ExecutionContext,
db: &mut Database,
) -> Result<ControlFlow, ExecutorError> {
loop {
for stmt in statements {
let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
match flow {
ControlFlow::Continue => {}
ControlFlow::Return(_) => return Ok(flow),
ControlFlow::Leave(_) => return Ok(flow),
ControlFlow::Iterate(_) => break, }
}
let condition_value = evaluate_expression(condition, db, ctx)?;
let should_exit = match condition_value {
SqlValue::Boolean(b) => b,
SqlValue::Integer(i) => i != 0,
SqlValue::Null => false,
_ => {
return Err(ExecutorError::TypeError(format!(
"REPEAT UNTIL condition must evaluate to boolean, got {:?}",
condition_value
)))
}
};
if should_exit {
break;
}
}
Ok(ControlFlow::Continue)
}