use crate::{ expression::Composite, selection::{Selection, SelectionError, VectoriseError}, selection_functions::{evaluate_selection_function, SFError}, state::{EditorState, GroupedChangeError, StateChange, StateResult}, }; use thiserror::Error; #[derive(Error, Debug)] pub enum EvaluationError { #[error("{0}")] SelectionFunctionError(VectoriseError), #[error("{0}")] SelectionUnionError(SelectionError), #[error("Error in processing group {0}")] GroupError(GroupedChangeError), #[error("Invalid right-only application")] IROApplication, #[error("Not yet implemented {0}")] UnimplementedError(&'static str), } fn commit_if_needed( es: &mut EditorState, changes: Vec, commit: bool, ) -> Vec { if commit { es.commit_changes(changes); Vec::new() } else { changes } } pub fn evaluate( es: &mut EditorState, comp: Composite, left: Option, right: Option, commit: bool, ) -> Result { if left.is_none() && right.is_some() { return Err(EvaluationError::IROApplication); }; match comp { Composite::SelectionFunction { func, search_mod, result_transform, } => { let sel = evaluate_selection_function(es, func, search_mod, result_transform, left, right) .map_err(EvaluationError::SelectionFunctionError)?; Ok((sel, Vec::new())) } Composite::TextFunction { func, swapped } => { Err(EvaluationError::UnimplementedError("text function")) } Composite::Hook { kind, left, right } => Err(EvaluationError::UnimplementedError("hook")), Composite::Train2 { f, g } => { let (left, mut f_changes) = evaluate(es, *f, left, right, commit)?; f_changes = commit_if_needed(es, f_changes, commit); let (sel, g_changes) = evaluate(es, *g, Some(left), None, commit)?; let more_changes = commit_if_needed(es, g_changes, commit); f_changes.extend(more_changes); Ok((sel, f_changes)) } Composite::Train3 { f, g, h } => { let (f_left, mut f_changes) = evaluate(es, *f, left.clone(), right.clone(), commit)?; f_changes = commit_if_needed(es, f_changes, commit); let (g_right, h_changes) = evaluate(es, *h, left, right, commit)?; let h_changes = commit_if_needed(es, h_changes, commit); let (sel, g_changes) = evaluate(es, *g, Some(f_left), Some(g_right), commit)?; let g_changes = commit_if_needed(es, g_changes, commit); f_changes.extend(h_changes); f_changes.extend(g_changes); Ok((sel, f_changes)) } Composite::Group { operations } => { let results: Vec<(Selection, Vec)> = operations .into_iter() .map(|op| evaluate(es, op, left.clone(), right.clone(), commit)) .collect::>()?; let (selections, arms) = results.into_iter().unzip(); let states = if commit { es.commit_changes_grouped(arms).map(|_| Vec::new()) } else { es.validate_grouped_changes(&arms) .map(|_| arms.into_iter().flatten().collect()) } .map_err(EvaluationError::GroupError)?; let sel = Selection::union(selections).map_err(EvaluationError::SelectionUnionError)?; Ok((sel, states)) } } }