use crate::frontend::ast::{Expr, Literal, MatchArm, Pattern};
use crate::runtime::{InterpreterError, Value};
use std::sync::Arc;
pub fn eval_if_expr<F>(
condition: &Expr,
then_branch: &Expr,
else_branch: Option<&Expr>,
mut eval_expr: F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let condition_val = eval_expr(condition)?;
if condition_val.is_truthy() {
eval_expr(then_branch)
} else if let Some(else_expr) = else_branch {
eval_expr(else_expr)
} else {
Ok(Value::Nil)
}
}
pub fn eval_let_expr<F1, F2>(
name: &str,
value: &Expr,
_body: &Expr,
mut eval_expr: F1,
mut with_variable: F2,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(
&str,
Value,
&mut dyn FnMut(&Expr) -> Result<Value, InterpreterError>,
) -> Result<Value, InterpreterError>,
{
let val = eval_expr(value)?;
with_variable(name, val, &mut eval_expr)
}
pub fn eval_for_loop<F1, F2>(
var: &str,
iter: &Expr,
_body: &Expr,
mut eval_expr: F1,
mut with_variable: F2,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(
&str,
Value,
&mut dyn FnMut(&Expr) -> Result<Value, InterpreterError>,
) -> Result<Value, InterpreterError>,
{
let iter_val = eval_expr(iter)?;
match &iter_val {
Value::Array(_) => eval_array_iteration(&iter_val, var, &mut with_variable, &mut eval_expr),
Value::Range { .. } => {
eval_range_iteration(&iter_val, var, &mut with_variable, &mut eval_expr)
}
_ => Err(InterpreterError::TypeError(format!(
"Cannot iterate over {}",
iter_val.type_name()
))),
}
}
pub fn eval_loop_condition<F>(condition: &Expr, eval_expr: &mut F) -> Result<bool, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
Ok(eval_expr(condition)?.is_truthy())
}
pub fn eval_loop_body<F>(
body: &Expr,
last_val: &mut Value,
eval_expr: &mut F,
) -> Result<Option<Value>, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
match eval_expr(body) {
Ok(val) => {
*last_val = val;
Ok(None)
}
Err(InterpreterError::Break(None, val)) => Ok(Some(val)),
Err(InterpreterError::Continue(_)) => Ok(None),
Err(e) => Err(e),
}
}
pub fn run_while_loop<F>(
condition: &Expr,
body: &Expr,
eval_expr: &mut F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let mut last_val = Value::Nil;
loop {
if !eval_loop_condition(condition, eval_expr)? {
break;
}
if let Some(break_val) = eval_loop_body(body, &mut last_val, eval_expr)? {
return Ok(break_val);
}
}
Ok(last_val)
}
pub fn eval_while_loop<F>(
condition: &Expr,
body: &Expr,
mut eval_expr: F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
run_while_loop(condition, body, &mut eval_expr)
}
pub fn eval_match_arm<F1, F2>(
arm: &MatchArm,
value: &Value,
pattern_matches: &mut F2,
eval_expr: &mut F1,
) -> Result<Option<Value>, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(&Pattern, &Value) -> Result<bool, InterpreterError>,
{
if pattern_matches(&arm.pattern, value)? && eval_match_guard(arm.guard.as_deref(), eval_expr)? {
return Ok(Some(eval_expr(&arm.body)?));
}
Ok(None)
}
pub fn eval_match_guard<F>(
guard: Option<&Expr>,
eval_expr: &mut F,
) -> Result<bool, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
if let Some(guard_expr) = guard {
Ok(eval_expr(guard_expr)?.is_truthy())
} else {
Ok(true) }
}
pub fn find_matching_arm<F1, F2>(
arms: &[MatchArm],
value: &Value,
pattern_matches: &mut F2,
eval_expr: &mut F1,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(&Pattern, &Value) -> Result<bool, InterpreterError>,
{
for arm in arms {
if let Some(result) = eval_match_arm(arm, value, pattern_matches, eval_expr)? {
return Ok(result);
}
}
Err(InterpreterError::RuntimeError(
"No matching pattern found in match expression".to_string(),
))
}
pub fn eval_match<F1, F2>(
expr: &Expr,
arms: &[MatchArm],
mut eval_expr: F1,
mut pattern_matches: F2,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(&Pattern, &Value) -> Result<bool, InterpreterError>,
{
let value = eval_expr(expr)?;
find_matching_arm(arms, &value, &mut pattern_matches, &mut eval_expr)
}
pub fn eval_block_expr<F>(statements: &[Expr], mut eval_expr: F) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let mut last_val = Value::Nil;
for stmt in statements {
last_val = eval_expr(stmt)?; }
Ok(last_val)
}
pub fn eval_list_expr<F>(elements: &[Expr], mut eval_expr: F) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let mut values = Vec::new();
for element in elements {
values.push(eval_expr(element)?);
}
Ok(Value::from_array(values))
}
pub fn eval_tuple_expr<F>(elements: &[Expr], mut eval_expr: F) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let mut values = Vec::new();
for element in elements {
values.push(eval_expr(element)?);
}
Ok(Value::Tuple(Arc::from(values.as_slice())))
}
pub fn eval_range_expr<F>(
start: &Expr,
end: &Expr,
inclusive: bool,
mut eval_expr: F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let start_val = eval_expr(start)?;
let end_val = eval_expr(end)?;
Ok(Value::Range {
start: Box::new(start_val),
end: Box::new(end_val),
inclusive,
})
}
pub fn eval_array_init_expr<F>(
value_expr: &Expr,
size_expr: &Expr,
mut eval_expr: F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let value = eval_expr(value_expr)?;
let size_val = eval_expr(size_expr)?;
if let Value::Integer(size) = size_val {
if size >= 0 {
let mut values = Vec::new();
for _ in 0..size {
values.push(value.clone());
}
Ok(Value::from_array(values))
} else {
Err(InterpreterError::RuntimeError(
"Array size must be non-negative".to_string(),
))
}
} else {
Err(InterpreterError::TypeError(
"Array size must be integer".to_string(),
))
}
}
pub fn eval_return_expr<F>(
value: Option<&Expr>,
mut eval_expr: F,
) -> Result<Value, InterpreterError>
where
F: FnMut(&Expr) -> Result<Value, InterpreterError>,
{
let return_value = if let Some(expr) = value {
eval_expr(expr)?
} else {
Value::Nil
};
Err(InterpreterError::Return(return_value))
}
pub fn eval_array_iteration<F1, F2>(
array: &Value,
var: &str,
with_variable: &mut F2,
eval_expr: &mut F1,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(
&str,
Value,
&mut dyn FnMut(&Expr) -> Result<Value, InterpreterError>,
) -> Result<Value, InterpreterError>,
{
if let Value::Array(arr) = array {
let mut last_val = Value::Nil;
for item in arr.iter() {
let should_continue =
execute_iteration_step(var, item.clone(), with_variable, eval_expr, &mut last_val)?;
if !should_continue {
break;
}
}
Ok(last_val)
} else {
Err(InterpreterError::TypeError(format!(
"Expected array, got {}",
array.type_name()
)))
}
}
fn execute_iteration_step<F1, F2>(
loop_var: &str,
value: Value,
with_variable: &mut F2,
eval_expr: &mut F1,
last_val: &mut Value,
) -> Result<bool, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(
&str,
Value,
&mut dyn FnMut(&Expr) -> Result<Value, InterpreterError>,
) -> Result<Value, InterpreterError>,
{
match with_variable(loop_var, value, eval_expr) {
Ok(result_val) => {
*last_val = result_val;
Ok(true) }
Err(InterpreterError::Break(None, break_val)) => {
*last_val = break_val;
Ok(false) }
Err(InterpreterError::Continue(_)) => Ok(true), Err(e) => Err(e),
}
}
pub fn eval_range_iteration<F1, F2>(
range: &Value,
var: &str,
with_variable: &mut F2,
eval_expr: &mut F1,
) -> Result<Value, InterpreterError>
where
F1: FnMut(&Expr) -> Result<Value, InterpreterError>,
F2: FnMut(
&str,
Value,
&mut dyn FnMut(&Expr) -> Result<Value, InterpreterError>,
) -> Result<Value, InterpreterError>,
{
if let Value::Range { .. } = range {
let (start_val, end_val, inclusive) = extract_range_bounds(range)?;
let iter = create_range_iterator(start_val, end_val, inclusive);
let mut last_val = Value::Nil;
for i in iter {
let should_continue = execute_iteration_step(
var,
Value::Integer(i),
with_variable,
eval_expr,
&mut last_val,
)?;
if !should_continue {
break;
}
}
Ok(last_val)
} else {
Err(InterpreterError::TypeError(format!(
"Expected range, got {}",
range.type_name()
)))
}
}
fn value_to_integer(value: &Value, context: &str) -> Result<i64, InterpreterError> {
match value {
Value::Integer(i) => Ok(*i),
_ => Err(InterpreterError::TypeError(format!(
"{context} must be integer"
))),
}
}
pub fn extract_range_bounds(range: &Value) -> Result<(i64, i64, bool), InterpreterError> {
if let Value::Range {
start,
end,
inclusive,
} = range
{
let start_val = value_to_integer(start, "Range start")?;
let end_val = value_to_integer(end, "Range end")?;
Ok((start_val, end_val, *inclusive))
} else {
Err(InterpreterError::TypeError(
"Expected range value".to_string(),
))
}
}
pub fn handle_loop_control(
result: Result<Value, InterpreterError>,
last_val: &mut Value,
) -> Result<Option<Value>, InterpreterError> {
match result {
Ok(val) => {
*last_val = val;
Ok(None)
}
Err(InterpreterError::Break(None, val)) => Ok(Some(val)),
Err(InterpreterError::Continue(_)) => Ok(None),
Err(e) => Err(e),
}
}
pub fn create_range_iterator(
start: i64,
end: i64,
inclusive: bool,
) -> Box<dyn Iterator<Item = i64>> {
if inclusive {
Box::new(start..=end)
} else {
Box::new(start..end)
}
}
pub fn match_wildcard_pattern(_value: &Value) -> bool {
true }
pub fn match_literal_pattern(lit: &Literal, value: &Value) -> Result<bool, InterpreterError> {
let pattern_val = crate::runtime::eval_literal::eval_literal(lit);
Ok(pattern_val == *value)
}
pub fn match_identifier_pattern(_name: &str, _value: &Value) -> bool {
true }
fn patterns_match_values(patterns: &[Pattern], values: &[Value]) -> Result<bool, InterpreterError> {
if patterns.len() != values.len() {
return Ok(false);
}
for (pat, val) in patterns.iter().zip(values.iter()) {
if !pattern_matches_simple(pat, val)? {
return Ok(false);
}
}
Ok(true)
}
pub fn match_list_pattern(patterns: &[Pattern], value: &Value) -> Result<bool, InterpreterError> {
match value {
Value::Array(arr) => patterns_match_values(patterns, arr),
_ => Ok(false),
}
}
pub fn match_tuple_pattern(patterns: &[Pattern], value: &Value) -> Result<bool, InterpreterError> {
match value {
Value::Tuple(elements) => patterns_match_values(patterns, elements),
_ => Ok(false),
}
}
pub fn pattern_matches_simple(pattern: &Pattern, value: &Value) -> Result<bool, InterpreterError> {
match pattern {
Pattern::Wildcard => Ok(match_wildcard_pattern(value)),
Pattern::Literal(lit) => match_literal_pattern(lit, value),
Pattern::Identifier(name) => Ok(match_identifier_pattern(name, value)),
Pattern::List(patterns) => match_list_pattern(patterns, value),
Pattern::Tuple(patterns) => match_tuple_pattern(patterns, value),
_ => Ok(false), }
}
#[cfg(test)]
#[path = "eval_control_flow_new_tests.rs"]
mod tests;
#[cfg(test)]
#[path = "eval_control_flow_new_r130_tests.rs"]
mod round_130_tests;
#[cfg(test)]
#[path = "eval_control_flow_new_coverage_tests.rs"]
mod coverage_tests;