aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/evaluate.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rprt-engine/src/evaluate.rs')
-rw-r--r--rprt-engine/src/evaluate.rs47
1 files changed, 40 insertions, 7 deletions
diff --git a/rprt-engine/src/evaluate.rs b/rprt-engine/src/evaluate.rs
index cf60ad4..4f567fb 100644
--- a/rprt-engine/src/evaluate.rs
+++ b/rprt-engine/src/evaluate.rs
@@ -3,6 +3,7 @@ use crate::{
selection::{Selection, SelectionError, VectoriseError},
selection_functions::{evaluate_selection_function, SFError},
state::{EditorState, GroupedChangeError, StateChange, StateResult},
+ text::Text,
};
use thiserror::Error;
@@ -21,6 +22,30 @@ pub enum EvaluationError {
UnimplementedError(&'static str),
#[error("Hook used in niladic context")]
NiladicRightHook,
+ #[error("Text argument provided to a selection function")]
+ TextArgument,
+}
+
+// Helper functions
+
+// Absolutely crazy that in 2026 Rust doesn't have a built-in Either type OR
+// (even better) a way to do anonymous sum types! Of course it has anonymous
+// product types, but big Cartesian doesn't want you to have +
+
+#[derive(Clone)]
+enum Either<L, R> {
+ L(L),
+ R(R),
+}
+
+fn ensure_selection(
+ left: Option<Either<Selection, Text>>,
+) -> Result<Option<Selection>, EvaluationError> {
+ match left {
+ Some(Either::L(left)) => Ok(Some(left)),
+ None => Ok(None),
+ _ => Err(EvaluationError::TextArgument),
+ }
}
fn commit_if_needed(
@@ -39,7 +64,7 @@ fn commit_if_needed(
fn _eval(
es: &mut EditorState,
comp: Composite,
- left: Option<Selection>,
+ left: Option<Either<Selection, Text>>,
right: Option<Selection>,
commit: bool,
) -> Result<StateResult, EvaluationError> {
@@ -53,6 +78,7 @@ fn _eval(
search_mod,
result_transform,
} => {
+ let left: Option<Selection> = ensure_selection(left)?;
let sel =
evaluate_selection_function(es, func, search_mod, result_transform, left, right)
.map_err(EvaluationError::SelectionFunctionError)?;
@@ -65,8 +91,12 @@ fn _eval(
HookKind::Before => {
let (f_result, mut changes) = _eval(es, *f, left.clone(), None, commit)?;
changes = commit_if_needed(es, changes, commit);
- let (sel, g_changes) =
- _eval(es, *g, Some(f_result), right.or_else(|| left), commit)?;
+ let right = if right.is_some() {
+ Ok(right)
+ } else {
+ ensure_selection(left)
+ }?;
+ let (sel, g_changes) = _eval(es, *g, Either::L(f_result).into(), right, commit)?;
let more_changes = commit_if_needed(es, g_changes, commit);
changes.extend(more_changes);
Ok((sel, changes))
@@ -75,8 +105,11 @@ fn _eval(
if left.is_none() {
return Err(EvaluationError::NiladicRightHook);
}
- let (g_result, mut changes) =
- _eval(es, *g, right.or_else(|| left.clone()), None, commit)?;
+ let combi_left = match right {
+ Some(right) => Some(Either::L(right)),
+ None => left.clone(),
+ };
+ let (g_result, mut changes) = _eval(es, *g, combi_left, None, commit)?;
changes = commit_if_needed(es, changes, commit);
let (sel, f_changes) = _eval(es, *f, left.clone(), Some(g_result), commit)?;
let more_changes = commit_if_needed(es, f_changes, commit);
@@ -87,7 +120,7 @@ fn _eval(
Composite::Train2 { f, g } => {
let (left, mut f_changes) = _eval(es, *f, left, right, commit)?;
f_changes = commit_if_needed(es, f_changes, commit);
- let (sel, g_changes) = _eval(es, *g, Some(left), None, commit)?;
+ let (sel, g_changes) = _eval(es, *g, Some(Either::L(left)), None, commit)?;
let more_changes = commit_if_needed(es, g_changes, commit);
f_changes.extend(more_changes);
Ok((sel, f_changes))
@@ -97,7 +130,7 @@ fn _eval(
f_changes = commit_if_needed(es, f_changes, commit);
let (g_right, h_changes) = _eval(es, *h, left, right, commit)?;
let h_changes = commit_if_needed(es, h_changes, commit);
- let (sel, g_changes) = _eval(es, *g, Some(f_left), Some(g_right), commit)?;
+ let (sel, g_changes) = _eval(es, *g, Some(Either::L(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);